// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/developer/debug/zxdb/client/breakpoint_impl.h"

#include <inttypes.h>

#include <algorithm>
#include <map>
#include <sstream>

#include "src/developer/debug/shared/message_loop.h"
#include "src/developer/debug/shared/zx_status.h"
#include "src/developer/debug/zxdb/client/breakpoint_location_impl.h"
#include "src/developer/debug/zxdb/client/breakpoint_observer.h"
#include "src/developer/debug/zxdb/client/process.h"
#include "src/developer/debug/zxdb/client/remote_api.h"
#include "src/developer/debug/zxdb/client/session.h"
#include "src/developer/debug/zxdb/client/system.h"
#include "src/developer/debug/zxdb/client/target.h"
#include "src/developer/debug/zxdb/client/thread.h"
#include "src/developer/debug/zxdb/common/err.h"
#include "src/developer/debug/zxdb/expr/permissive_input_location.h"
#include "src/developer/debug/zxdb/symbols/loaded_module_symbols.h"
#include "src/developer/debug/zxdb/symbols/module_symbols.h"
#include "src/developer/debug/zxdb/symbols/process_symbols.h"
#include "src/developer/debug/zxdb/symbols/resolve_options.h"
#include "src/developer/debug/zxdb/symbols/target_symbols.h"

namespace zxdb {

namespace {

uint32_t next_breakpoint_id = 1;

debug_ipc::Stop SettingsStopToIpcStop(BreakpointSettings::StopMode mode) {
  switch (mode) {
    case BreakpointSettings::StopMode::kNone:
      return debug_ipc::Stop::kNone;
    case BreakpointSettings::StopMode::kThread:
      return debug_ipc::Stop::kThread;
    case BreakpointSettings::StopMode::kProcess:
      return debug_ipc::Stop::kProcess;
    case BreakpointSettings::StopMode::kAll:
      return debug_ipc::Stop::kAll;
  }
}

}  // namespace

struct BreakpointImpl::ProcessRecord {
  // Helper to return whether there are any enabled locations for this process.
  bool HasEnabledLocation() const {
    for (const auto& loc : locs) {
      if (loc.second.IsEnabled())
        return true;
    }
    return false;
  }

  // Helper to add a list of locations to the locs array. Returns true if anything was added (this
  // makes the call site cleaner).
  bool AddLocations(BreakpointImpl* bp, Process* process, const std::vector<Location>& locations) {
    for (const auto& loc : locations) {
      locs.emplace(std::piecewise_construct, std::forward_as_tuple(loc.address()),
                   std::forward_as_tuple(bp, process, loc.address()));
    }
    return !locations.empty();
  }

  // Set when we're registered as an observer for this process.
  bool observing = false;

  // All resolved locations indexed by address.
  std::map<uint64_t, BreakpointLocationImpl> locs;
};

BreakpointImpl::BreakpointImpl(Session* session, bool is_internal)
    : Breakpoint(session),
      is_internal_(is_internal),
      backend_id_(next_breakpoint_id++),
      impl_weak_factory_(this) {
  session->process_observers().AddObserver(this);
  session->target_observers().AddObserver(this);
}

BreakpointImpl::~BreakpointImpl() {
  if (backend_installed_ && settings_.enabled) {
    // Breakpoint was installed and the process still exists.
    settings_.enabled = false;
    SendBackendRemove();
  }

  session()->target_observers().RemoveObserver(this);
  session()->process_observers().RemoveObserver(this);
  if (registered_as_thread_observer_)
    session()->thread_observers().RemoveObserver(this);
}

BreakpointSettings BreakpointImpl::GetSettings() const { return settings_; }

void BreakpointImpl::SetSettings(const BreakpointSettings& settings, SetCallback cb) {
  settings_ = settings;

  bool changed = false;
  for (Target* target : session()->system().GetTargets()) {
    Process* process = target->GetProcess();
    if (process && CouldApplyToProcess(process))
      changed |= RegisterProcess(process);
  }

  // Add or remove thread notifications as required.
  if (settings_.scope.thread() && !registered_as_thread_observer_) {
    session()->thread_observers().AddObserver(this);
    registered_as_thread_observer_ = true;
  } else if (!settings_.scope.thread() && registered_as_thread_observer_) {
    session()->thread_observers().RemoveObserver(this);
    registered_as_thread_observer_ = false;
  }

  SyncBackend(std::move(cb));

  if (changed && !IsInternal()) {
    for (auto& observer : session()->breakpoint_observers())
      observer.OnBreakpointMatched(this, true);
  }
}

bool BreakpointImpl::IsInternal() const { return is_internal_; }

std::vector<const BreakpointLocation*> BreakpointImpl::GetLocations() const {
  std::vector<const BreakpointLocation*> result;
  for (auto& proc : procs_) {
    for (auto& pair : proc.second.locs)
      result.push_back(&pair.second);
  }
  return result;
}

std::vector<BreakpointLocation*> BreakpointImpl::GetLocations() {
  std::vector<BreakpointLocation*> result;
  for (auto& proc : procs_) {
    for (auto& pair : proc.second.locs)
      result.push_back(&pair.second);
  }
  return result;
}

debug_ipc::BreakpointStats BreakpointImpl::GetStats() { return stats_; }

void BreakpointImpl::UpdateStats(const debug_ipc::BreakpointStats& stats) { stats_ = stats; }

void BreakpointImpl::BackendBreakpointRemoved() { backend_installed_ = false; }

void BreakpointImpl::WillDestroyTarget(Target* target) {
  if (target == settings_.scope.target()) {
    // As with threads going away, when the target goes away for a target-scoped breakpoint, convert
    // to a disabled system-wide breakpoint.
    settings_.scope = ExecutionScope();
    settings_.enabled = false;
  }
}

void BreakpointImpl::DidCreateProcess(Process* process, bool autoattached, uint64_t timestamp) {
  if (CouldApplyToProcess(process)) {
    if (RegisterProcess(process)) {
      SyncBackend();

      if (!IsInternal()) {
        for (auto& observer : session()->breakpoint_observers())
          observer.OnBreakpointMatched(this, false);
      }
    }
  }
}

void BreakpointImpl::WillDestroyProcess(Process* process, ProcessObserver::DestroyReason,
                                        int exit_code, uint64_t timestamp) {
  auto found = procs_.find(process);
  if (found == procs_.end())
    return;

  // Only need to update the backend if there was an enabled address associated with this process.
  bool send_update = found->second.HasEnabledLocation();

  // When the process exits, disable breakpoints that are entirely address-based since the addresses
  // will normally change when a process is loaded.
  if (AllLocationsAddresses())
    settings_.enabled = false;

  procs_.erase(found);

  // Needs to be done after the ProcessRecord is removed.
  if (send_update)
    SyncBackend();
}

void BreakpointImpl::DidLoadModuleSymbols(Process* process, LoadedModuleSymbols* module) {
  if (!CouldApplyToProcess(process))
    return;  // Irrelevant process.

  FindNameContext find_context(process->GetSymbols());

  ResolveOptions options = GetResolveOptions();
  bool needs_sync = false;
  for (const auto& loc : ExpandPermissiveInputLocationNames(find_context, settings_.locations)) {
    needs_sync |=
        procs_[process].AddLocations(this, process, module->ResolveInputLocation(loc, options));
  }

  if (needs_sync) {
    SyncBackend();

    if (!IsInternal()) {
      for (auto& observer : session()->breakpoint_observers())
        observer.OnBreakpointMatched(this, false);
    }
  }
}

void BreakpointImpl::WillUnloadModuleSymbols(Process* process, LoadedModuleSymbols* module) {
  // TODO(bug 61248) need to get the address range of this module and then remove all breakpoints in
  // that range.
}

void BreakpointImpl::WillDestroyThread(Thread* thread) {
  if (settings_.scope.thread() == thread) {
    // When the thread is destroyed that the breakpoint is associated with, disable the breakpoint
    // and convert to a target-scoped breakpoint. This will preserve its state without us having to
    // maintain some "defunct thread" association. The user can associate it with a new thread and
    // re-enable as desired.
    settings_.scope = ExecutionScope(thread->GetProcess()->GetTarget());
    settings_.enabled = false;

    // Don't need more thread notifications.
    FX_DCHECK(registered_as_thread_observer_);
    session()->thread_observers().RemoveObserver(this);
    registered_as_thread_observer_ = false;
  }
}

void BreakpointImpl::SyncBackend(SetCallback cb) {
  bool has_locations = HasEnabledLocation();

  if (backend_installed_ && !has_locations) {
    SendBackendRemove(std::move(cb));
  } else if (has_locations) {
    SendBackendAddOrChange(std::move(cb));
  } else if (cb) {
    // The backend doesn't know about it and we don't require anything, but we still need to issue
    // the callback (non-reentrantly).
    debug::MessageLoop::Current()->PostTask(FROM_HERE,
                                            [cb = std::move(cb)]() mutable { cb(Err()); });
  }
}

void BreakpointImpl::SendBackendAddOrChange(SetCallback cb) {
  backend_installed_ = true;

  debug_ipc::AddOrChangeBreakpointRequest request;
  request.breakpoint.id = backend_id_;
  request.breakpoint.type = settings_.type;
  request.breakpoint.name = settings_.name;
  request.breakpoint.stop = SettingsStopToIpcStop(settings_.stop_mode);
  request.breakpoint.one_shot = settings_.one_shot;
  request.breakpoint.has_automation = settings_.has_automation;
  request.breakpoint.instructions = settings_.instructions;

  for (const auto& proc : procs_) {
    for (const auto& pair : proc.second.locs) {
      if (!pair.second.IsEnabled())
        continue;

      debug_ipc::ProcessBreakpointSettings addition;
      addition.id.process = proc.first->GetKoid();

      if (settings_.scope.type() == ExecutionScope::kThread) {
        if (Thread* thread = settings_.scope.thread())
          addition.id.thread = thread->GetKoid();
      }

      if (BreakpointSettings::TypeHasSize(settings_.type)) {
        uint64_t address = pair.second.address();
        addition.address_range = {address, address + settings_.byte_size};
      } else {
        addition.address = pair.second.address();
      }
      request.breakpoint.locations.push_back(addition);
    }
  }

  session()->remote_api()->AddOrChangeBreakpoint(
      request, [breakpoint = impl_weak_factory_.GetWeakPtr(), cb = std::move(cb)](
                   const Err& err, debug_ipc::AddOrChangeBreakpointReply reply) mutable {
        if (breakpoint) {
          breakpoint->OnAddOrChangeComplete(err, std::move(reply), std::move(cb));
        } else if (cb) {
          cb(Err("Breakpoint deleted."));
        }
      });
}

void BreakpointImpl::SendBackendRemove(SetCallback cb) {
  debug_ipc::RemoveBreakpointRequest request;
  request.breakpoint_id = backend_id_;

  session()->remote_api()->RemoveBreakpoint(
      request, [breakpoint = impl_weak_factory_.GetWeakPtr(), cb = std::move(cb)](
                   const Err& err, debug_ipc::RemoveBreakpointReply reply) mutable {
        if (breakpoint) {
          breakpoint->OnRemoveComplete(err, std::move(reply), std::move(cb));
        } else if (cb) {
          cb(Err("Breakpoint deleted."));
        }
      });

  backend_installed_ = false;
}

void BreakpointImpl::OnAddOrChangeComplete(const Err& input_err,
                                           debug_ipc::AddOrChangeBreakpointReply reply,
                                           SetCallback cb) {
  // Map transport errors and remote errors to a single error.
  Err err = input_err;
  if (err.ok())
    err = Err(reply.status);

  if (err.has_error()) {
    // Provide a better explanation for some common failures.
    if (err.type() == ErrType::kNoResources) {
      err = Err(err.type(),
                "Could not set the breakpoint.\n\n"
                "Is this a hardware breakpoint? Check \"sys-info\" to verify the number\n"
                "available within the system.");
    } else if (err.type() == ErrType::kNotSupported) {
      err = Err(err.type(),
                "Could not set the breakpoint.\n\n"
                "This kernel command-line flag \"kernel.enable-debugging-syscalls\" is\n"
                "likely not set.");
    }
  }

  if (cb) {
    cb(err);
  } else if (err.has_error()) {
    // There was no callback given, issue the global notification to show the error.
    for (auto& observer : session()->breakpoint_observers())
      observer.OnBreakpointUpdateFailure(this, err);
  }
}

void BreakpointImpl::OnRemoveComplete(const Err& err, debug_ipc::RemoveBreakpointReply reply,
                                      SetCallback cb) {
  if (cb) {
    cb(err);
  } else if (err.has_error()) {
    // There was no callback given, issue the global notification to show the error.
    for (auto& observer : session()->breakpoint_observers())
      observer.OnBreakpointUpdateFailure(this, err);
  }
}

void BreakpointImpl::DidChangeLocation() { SyncBackend(); }

bool BreakpointImpl::CouldApplyToProcess(Process* process) const {
  // When applied to all processes, we need all notifications.
  if (settings_.scope.type() == ExecutionScope::kSystem)
    return true;

  // Target- and thread-specific breakpoints only watch their process.
  return settings_.scope.target() == process->GetTarget();
}

bool BreakpointImpl::HasEnabledLocation() const {
  if (!settings_.enabled)
    return false;
  for (const auto& proc : procs_) {
    if (proc.second.HasEnabledLocation())
      return true;
  }
  return false;
}

bool BreakpointImpl::RegisterProcess(Process* process) {
  // Clear existing locations for this process.
  ProcessRecord& record = procs_[process];
  bool changed = !record.locs.empty();
  record.locs.clear();

  // Resolve addresses.
  ResolveOptions options = GetResolveOptions();
  FindNameContext find_context(process->GetSymbols());

  changed |=
      record.AddLocations(this, process,
                          ResolvePermissiveInputLocations(process->GetSymbols(), options,
                                                          find_context, settings_.locations));
  return changed;
}

ResolveOptions BreakpointImpl::GetResolveOptions() const {
  ResolveOptions options;
  // We don't need the result to be symbolized unless required by skip_function_prologue.

  if (AllLocationsAddresses()) {
    // Only need addresses. Don't try to skip function prologues when the user gives an address or
    // the address might move.
    options.symbolize = false;
    options.skip_function_prologue = false;
  } else {
    // When breaking on symbols or lines, skip function prologues so the function parameters
    // can be displayed properly (they're not always correct in the prologue) as well as backtraces
    // (on ARM, the link register is saved in the prologue so things may look funny before that).
    // Function prologues require symbolization so we ask for both.
    //
    // TODO(bug 45309) we will need an option to control this like other debuggers. LLDB has a
    // per-breakpoint setting and a global default preference. In GDB you can do "break *Foo" to
    // skip the prologue.
    options.symbolize = true;
    options.skip_function_prologue = true;
  }

  return options;
}

bool BreakpointImpl::AllLocationsAddresses() const {
  return !settings_.locations.empty() &&
         std::all_of(settings_.locations.begin(), settings_.locations.end(),
                     [](const auto& loc) { return loc.type == InputLocation::Type::kAddress; });
}

}  // namespace zxdb
