Debug Agent (debug_agent)

debug_agent is the target-side backend stub for the Fuchsia debugger. It runs on the target Fuchsia system (and experimentally on Linux hosts). It communicates over debug_ipc (../ipc) with the zxdb frontend (../zxdb) on the developer's workstation.

User Documentation

Read the debugger setup and usage guides for user-facing workflows.

Manual Testing

Test these four workflows whenever you edit process attachment or component starting:

  • run-component fuchsia-pkg://fuchsia.com/debug_agent#meta/debug_agent.cm (or another component URL).
  • attach some_filter when a matching process already exists.
  • attach some_filter before a matching process starts.
  • attach 56421 to attach by numeric PID/KOID (debug_agent uses separate code paths for PID and filter attachment).

Interface

Public headers expose these core classes and helpers:

  • debug_agent::DebugAgent / debug_agent::DebugAgentOptions: Core backend state machine managing attached jobs, processes, breakpoints, filters, and RemoteAPI dispatch (debug_agent.h).
  • debug_agent::DebugAgentServer: fuchsia.debugger.DebugAgent FIDL server that bridges FIDL requests and FilterIterator attachment into DebugAgent (debug_agent_server.h).
  • debug_agent::DebuggedJob / debug_agent::DebuggedJobCreateInfo: Job exception channel observer that intercepts newly starting processes (debugged_job.h).
  • debug_agent::DebuggedProcess / debug_agent::DebuggedProcessCreateInfo: Per-process state controller managing threads, memory access, module notifications, stdout/stderr capture, and serialized breakpoint step-over queues (debugged_process.h).
  • debug_agent::DebuggedThread: Per-thread execution state, suspension ref-counting (ClientSuspend, InternalSuspend), single-stepping, and register/exception handling (debugged_thread.h).
  • debug_agent::Breakpoint / debug_agent::ProcessBreakpoint: Logical (Breakpoint) and per-process address/range (ProcessBreakpoint) breakpoint abstractions (breakpoint.h, process_breakpoint.h).
  • debug_agent::SoftwareBreakpoint, debug_agent::HardwareBreakpoint, debug_agent::Watchpoint: Concrete ProcessBreakpoint subclasses for instruction-patching traps, CPU debug register breakpoints, and memory read/write watchpoints (software_breakpoint.h, hardware_breakpoint.h, watchpoint.h).
  • debug_agent::RemoteAPI / debug_agent::RemoteAPIAdapter: Abstract RPC handler interface for debug_ipc requests and stream dispatch adapter (remote_api.h, remote_api_adapter.h).
  • debug_agent::SystemInterface / debug_agent::ZirconSystemInterface: Abstract and Zircon-backed representations of the target job tree, component manager, and limbo provider (system_interface.h, zircon_system_interface.h).
  • debug_agent::ComponentManager: Component lifecycle event listener, test runner (fuchsia.test.manager), and component matcher (component_manager.h).
  • debug_agent::LimboProvider: Interface to ProcessLimbo for inspecting, claiming, and releasing crashed processes waiting in limbo (limbo_provider.h).
  • debug_agent::ExceptionHandle: Wrapper around a kernel exception token and its resolution state (exception_handle.h).
  • debug_agent::Filter: Job, process name, and component moniker/URL filter matcher (filter.h).
  • debug_agent::UnwindStack: Stack unwinding wrapper around //src/lib/unwinder (unwind.h).
  • debug_agent::AutomationHandler: Executor for automated memory and register readout instructions attached to breakpoint hits (automation_handler.h).
  • posix: Allocation-free POSIX/Linux system call helpers (HANDLE_EINTR, IGNORE_EINTR, linux::DirReaderLinux, posix::ShuffleFileDescriptors).

Invariants

Callers and implementations must preserve these invariants:

  • Initialize a debug::PlatformMessageLoop (debug::MessageLoopFuchsia on Fuchsia) on the current thread before constructing DebugAgent. The debug::StreamBuffer passed to DebugAgent::Connect or RemoteAPIAdapter must outlive the adapter.
  • DebugAgent::SendNotification requires ipc_version_ > 0 (negotiated via the IPC Hello handshake) before serializing notifications to a stream.
  • Call Init() and check for an OK debug::Status before using any DebuggedJob or DebuggedProcess instance.
  • A DebuggedThread runs only when neither client_suspend_handle_ nor any internal SuspendHandle token exists.
  • DebuggedProcess serializes breakpoint step-overs through step_over_queue_ so only one ProcessBreakpoint steps over at a time. DebuggedProcess ignores duplicate step-over requests for the same thread and breakpoint.
  • SoftwareBreakpoint::StepOverCleanup must run only after the next queued breakpoint's ExecuteStepOver acquires its suspend tokens. It uses a per-thread multimap (suspend_tokens_) to prevent premature thread resumption between consecutive step-overs.
  • Processes claimed from LimboProvider lack ZX_RIGHT_DESTROY. When killing a from_limbo process fails with ZX_ERR_ACCESS_DENIED, DebugAgent detaches, records its KOID in killed_limbo_procs_, and calls LimboProvider::ReleaseProcess once it re-enters limbo.
  • ProcessBreakpoint::OnHit does not delete one-shot breakpoints internally. Callers must inspect BreakpointStats::should_delete and delete the breakpoint afterward to avoid self-deletion during hit handling.
  • SystemInterface is non-movable because ComponentManager holds a raw back-pointer to it.
  • Recursive filter matching creates new kComponentMonikerPrefix filters only for moniker patterns not already present in DebugAgent::filters_.
  • DebuggedJob and AttachConfig distinguish the exclusive "job" exception channel (crash exceptions) from the non-exclusive "job debugger" channel (ZX_EXCP_PROCESS_STARTING). Process attachment uses the process debugger exception channel instead.
  • Job attachments with kMinimal or kNone priority do not claim the debugger exception channel and do not receive upfront ZX_EXCP_PROCESS_STARTING or ZX_EXCP_THREAD_STARTING notifications. Exception handlers in DebuggedJob and DebuggedProcess must lazily create DebuggedProcess and call PopulateCurrentThreads upon receiving an exception.

Side Effects

debug_agent produces these target and IPC side effects:

  • Reads and writes debuggee process virtual memory (including instruction patching in SoftwareBreakpoint) and thread general/debug registers (HardwareBreakpoint, Watchpoint, single-stepping, and unwinding).
  • Binds to Zircon job and process exception channels, suspends and resumes threads via SuspendHandle tokens, and resolves or forwards kernel exceptions via ExceptionHandle.
  • Exchanges messages with zxdb clients over debug_ipc streams (BufferedStream / RemoteAPIAdapter) and serves the fuchsia.debugger.DebugAgent FIDL protocol via DebugAgentServer.
  • Calls Fuchsia services to start binaries, components, and tests (BinaryLauncher, ComponentManager), watch component lifecycle events, and claim or release crashed processes in ProcessLimbo.
  • Deleting the last DebugAgentObserver without an active debug_ipc client quits the message loop and exits debug_agent.
  • Captures debuggee stdout/stderr streams to emit NotifyIO messages to the client, and generates process minidumps on request.

Verification

Run these commands to build and test debug_agent:

  • Build: fx build //src/developer/debug/debug_agent
  • Test: fx test debug_agent_unit_tests.cm debug_agent_launcher_unit_tests debug_agent_integration_tests