blob: 20f659ee6fa376db742274bee9f64bbacc9e1170 [file] [log] [blame]
// 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/debug_agent/process_breakpoint.h"
#include <inttypes.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/syscalls/exception.h>
#include "src/developer/debug/debug_agent/breakpoint.h"
#include "src/developer/debug/debug_agent/debugged_thread.h"
#include "src/developer/debug/debug_agent/hardware_breakpoint.h"
#include "src/developer/debug/debug_agent/software_breakpoint.h"
#include "src/developer/debug/shared/logging/logging.h"
#include "src/lib/fxl/strings/string_printf.h"
namespace debug_agent {
ProcessBreakpoint::ProcessBreakpoint(Breakpoint* breakpoint, DebuggedProcess* process,
uint64_t address)
: process_(process), address_(address), weak_factory_(this) {
breakpoints_.push_back(breakpoint);
}
ProcessBreakpoint::~ProcessBreakpoint() = default;
zx_status_t ProcessBreakpoint::Init() { return Update(); }
fxl::WeakPtr<ProcessBreakpoint> ProcessBreakpoint::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
zx_status_t ProcessBreakpoint::RegisterBreakpoint(Breakpoint* breakpoint) {
// Shouldn't get duplicates.
if (std::find(breakpoints_.begin(), breakpoints_.end(), breakpoint) != breakpoints_.end())
return ZX_ERR_ALREADY_BOUND;
// Should be the same type.
if (Type() != breakpoint->settings().type)
return ZX_ERR_INVALID_ARGS;
breakpoints_.push_back(breakpoint);
// Check if we need to install/uninstall a breakpoint.
return Update();
}
bool ProcessBreakpoint::UnregisterBreakpoint(Breakpoint* breakpoint) {
DEBUG_LOG(Breakpoint) << "Unregistering breakpoint " << breakpoint->settings().id << " ("
<< breakpoint->settings().name << ").";
auto found = std::find(breakpoints_.begin(), breakpoints_.end(), breakpoint);
if (found == breakpoints_.end()) {
FX_NOTREACHED(); // Should always be found.
} else {
breakpoints_.erase(found);
}
// Check if we need to install/uninstall a breakpoint.
Update();
return !breakpoints_.empty();
}
bool ProcessBreakpoint::ShouldHitThread(zx_koid_t thread_koid) const {
for (const Breakpoint* bp : breakpoints_) {
if (bp->AppliesToThread(process_->koid(), thread_koid))
return true;
}
return false;
}
void ProcessBreakpoint::OnHit(debug_ipc::BreakpointType exception_type,
std::vector<debug_ipc::BreakpointStats>* hit_breakpoints) {
hit_breakpoints->clear();
for (Breakpoint* breakpoint : breakpoints_) {
// Only care for breakpoints that match the exception type.
if (!Breakpoint::DoesExceptionApply(breakpoint->settings().type, exception_type))
continue;
breakpoint->OnHit();
// The breakpoint stats are for the client, don't tell it about our internal ones.
if (!breakpoint->is_debug_agent_internal())
hit_breakpoints->push_back(breakpoint->stats());
}
}
void ProcessBreakpoint::BeginStepOver(DebuggedThread* thread) {
// Note that this request may get silently dropped in some edge cases (see EnqueueStepOver
// comment) so don't keep any state about this request.
process_->EnqueueStepOver(this, thread);
}
} // namespace debug_agent