Breakpoints

final class ntoseye.Breakpoints

The code breakpoints and data watchpoints, with their IDs as keys (dbg.breakpoints).

__contains__(key: Any, /) → bool
__getitem__(key: int, /) → Breakpoint

The breakpoint with an ID.

__iter__() → Iterator[Breakpoint]
__len__() → int
add(target: int | str, *, condition: str | None = None, hardware: bool = False, unchecked: bool = False, when: Callable[[Stop], object] | None = None, pass_count: int = 0, one_shot: bool = False, process: Process | int | None = None, thread: Thread | int | None = None, processor: Cpu | int | None = None, action: str | None = None) → Breakpoint

Add a code breakpoint at an address or a symbolic spec.

An instruction must start at the breakpoint, which ntoseye checks as bp and bu do: it raises NtoseyeError for an address inside an instruction, and when nothing says where instructions start there, it sets the breakpoint and adds a warning to dbg.notices(). unchecked=True skips the check (bp /a).

hardware=True sets a debug-register execute breakpoint instead of patching code. The target resolves to an address once, when you call this method, and does not resolve again after a module reload or a reboot. The secure kernel (VTL1) accepts only this kind of breakpoint, for example add(dbg.secure_kernel.symbols["securekernel!Func"], hardware=True).

add_exit(reason: int | str, partition: int | None = None, vp: int | None = None, *, condition: str | None = None, when: Callable[[Stop], object] | None = None, pass_count: int = 0, one_shot: bool = False, processor: Cpu | int | None = None, action: str | None = None) → Breakpoint

Add a VM-exit breakpoint, as !hvexit does: a debug-register execute breakpoint on the Windows hypervisor’s VM-exit entry point that stops only for an exit with basic exit reason (Intel SDM Appendix C), a number or a name ("cpuid", "rdmsr", "ept_violation"), and, with partition and vp, only from that partition or VP. Every exit enters there, so the guest runs far slower while it is set; ntoseye resumes the other exits without a stop, before any when= callback runs. A hit whose caller or exit ntoseye cannot tell stops. A condition sees the caller’s registers at its exit and reads its memory, as for add_hypercall(). Needs the gdb backend and the VM’s hv-evmcs enlightenment. This feature is experimental.

add_hypercall(call: int | str, partition: int | None = None, vp: int | None = None, *, condition: str | None = None, when: Callable[[Stop], object] | None = None, pass_count: int = 0, one_shot: bool = False, processor: Cpu | int | None = None, action: str | None = None) → Breakpoint

Add a hypercall breakpoint, as !hvbp does: a debug-register execute breakpoint on the Windows hypervisor’s handler of call, a call code or a name ("HvCallPostMessage", or "HvCall0004" as x hv!* names a code the TLFS does not), that stops only when the caller made that call, and, with partition (a partition ID) and vp (a VP index in it), only when the caller is that partition or VP. ntoseye resumes the other hits without a stop, before any when= callback runs. A hit whose caller ntoseye cannot tell stops. A condition sees the caller’s registers at its VMCALL ("rdx == 0xfb"), not the hypervisor’s at the handler, and reads the caller’s memory: the $p operators its guest physical memory ("$pqwo(rdx+8) == 1" tests a slow call’s input), the others its virtual memory. Needs the gdb backend and the VM’s hv-evmcs enlightenment. This feature is experimental.

add_pattern(pattern: str, *, condition: str | None = None, when: Callable[[Stop], object] | None = None, pass_count: int = 0, one_shot: bool = False, process: Process | int | None = None, thread: Thread | int | None = None, processor: Cpu | int | None = None, action: str | None = None, limit: int = 256) → list[Breakpoint]

Add symbol-identity breakpoints for the names that match a glob (bm).

add_source(file: str, line: int, *, condition: str | None = None, when: Callable[[Stop], object] | None = None, pass_count: int = 0, one_shot: bool = False, process: Process | int | None = None, thread: Thread | int | None = None, processor: Cpu | int | None = None, action: str | None = None) → list[Breakpoint]

Add a source breakpoint at each address that matches file:line.

commands() → BreakpointCommands

Print the commands that set the current breakpoints again.

The output has one line for each breakpoint, in ID order. An address breakpoint shows as bp <address>, a symbolic or source breakpoint as bu <symbol> (as bm creates it), a hardware breakpoint as ba <access><size> <address>, and a hypercall breakpoint as !hvbp <code> [partition-id [vp-index]], without its pass count, which !hvbp does not take. Each line also has the /1, /p, /t, and /c options of the breakpoint, its condition (as /w), its pass count, and its command string. To set the same breakpoints again, run the lines, either by pasting them or by saving them to a file for $$<. WinDbg puts a breakpoint ID in each line, but these lines have none because the ntoseye bp command does not take one, so the new breakpoints get new IDs. A disabled breakpoint comes back enabled.

get(key: int) → Breakpoint | None

The breakpoint with an ID.

list() → list[BreakpointInfo]

List all breakpoints.

The status column shows e for enabled, d for disabled, or o for owed. An owed breakpoint is a kernel code breakpoint that waits for its page to become resident.

watch(target: int | str, *, access: Literal['write', 'read_write'] = ..., length: int = 1, condition: str | None = None, when: Callable[[Stop], object] | None = None, pass_count: int = 0, one_shot: bool = False, process: Process | int | None = None, thread: Thread | int | None = None, processor: Cpu | int | None = None, action: str | None = None) → Breakpoint

Add a hardware data watchpoint.