blob: e91368164f41b752ba4f64e212af33428e58a117 [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.
#ifndef SRC_DEVELOPER_DEBUG_DEBUG_AGENT_BREAKPOINT_H_
#define SRC_DEVELOPER_DEBUG_DEBUG_AGENT_BREAKPOINT_H_
#include <zircon/types.h>
#include <set>
#include <string>
#include "src/developer/debug/ipc/records.h"
#include "src/lib/fxl/macros.h"
namespace debug_agent {
// A single breakpoint may apply to many processes and many addresses (even in
// the same process). These instances are called ProcessBreakpoints.
//
// Multiple Breakpoints can also correspond to the same ProcessBreakpoint if
// they have the same process/address.
class Breakpoint {
public:
// Normally an exception applies to a breakpoint only if both types match. But in the case of
// watchpoints, they can be triggered either by a read or a write exception, so a same address
// could apply or not depending on the type of the breakpoint (eg. a read exception would apply
// to both read and read/write breakpoints).
//
// All checks to see if an exception matches a breakpoint should be done by this function and not
// directly checking |type()|.
static bool DoesExceptionApply(debug_ipc::BreakpointType exception,
debug_ipc::BreakpointType bp_type);
enum class HitResult {
// Breakpoint was hit and the hit count was incremented.
kHit,
// One-shot breakpoint hit. The caller should delete this breakpoint
// when it sees this result.
kOneShotHit,
// This will need to be expanded to include "kContinue" to indicate that
// this doesn't count as hitting the breakpoint (for when we implement
// "break on hit count == 5" or "multiple of 7").
};
// The process delegate should outlive the Breakpoint object. It allows
// Breakpoint dependencies to be mocked for testing.
class ProcessDelegate {
public:
// Called to register a new ProcessBreakpoint with the appropriate
// location. If this fails, the breakpoint has not been set.
virtual zx_status_t RegisterBreakpoint(Breakpoint* bp, zx_koid_t process_koid,
uint64_t address);
// Called When the breakpoint no longer applies to this location.
virtual void UnregisterBreakpoint(Breakpoint* bp, zx_koid_t process_koid, uint64_t address);
virtual zx_status_t RegisterWatchpoint(Breakpoint* bp, zx_koid_t process_koid,
const debug_ipc::AddressRange& range);
virtual void UnregisterWatchpoint(Breakpoint* bp, zx_koid_t process_koid,
const debug_ipc::AddressRange& range);
};
// Some breakpoints are internally generated by the debug_agent. These are different than the
// internal breakpoints set by the zxdb frontend which we see as nrmal breakpoints. Our internal
// breakpoints are never sent to the client.
explicit Breakpoint(ProcessDelegate* process_delegate, bool is_debug_agent_internal = false);
~Breakpoint();
bool is_debug_agent_internal() const { return is_debug_agent_internal_; }
const debug_ipc::BreakpointStats& stats() const { return stats_; }
// Calling SetSettings() will update the settings and install/move the breakpoint as required.
// The one taking an address is for internal process-wide software breakpoints that have no ID.
zx_status_t SetSettings(const debug_ipc::BreakpointSettings& settings);
zx_status_t SetSettings(std::string name, zx_koid_t process_koid, uint64_t address);
const debug_ipc::BreakpointSettings& settings() const { return settings_; }
// A breakpoint can be set to apply to a specific set of threads. A thread
// hitting an exception needs to query whether it should apply to it or not.
bool AppliesToThread(zx_koid_t process_koid, zx_koid_t thread_koid) const;
// Notification that this breakpoint was just hit.
HitResult OnHit();
private:
zx_status_t SetBreakpointLocations(const debug_ipc::BreakpointSettings&);
zx_status_t SetWatchpointLocations(const debug_ipc::BreakpointSettings&);
// A process koid + address identifies one unique location.
using LocationPair = std::pair<zx_koid_t, uint64_t>;
using WatchpointLocationPair = std::pair<zx_koid_t, debug_ipc::AddressRange>;
struct WatchpointLocationPairCompare {
bool operator()(const WatchpointLocationPair&, const WatchpointLocationPair&) const;
};
ProcessDelegate* process_delegate_; // Non-owning.
bool is_debug_agent_internal_;
debug_ipc::BreakpointSettings settings_;
debug_ipc::BreakpointStats stats_;
std::set<LocationPair> locations_;
std::set<WatchpointLocationPair, WatchpointLocationPairCompare> watchpoint_locations_;
FXL_DISALLOW_COPY_AND_ASSIGN(Breakpoint);
};
} // namespace debug_agent
#endif // SRC_DEVELOPER_DEBUG_DEBUG_AGENT_BREAKPOINT_H_