Skip to content

Commit 58537bf

Browse files
committed
Fix Python API docs. Fix #675
1 parent 8111cb4 commit 58537bf

File tree

1 file changed

+67
-13
lines changed

1 file changed

+67
-13
lines changed

api/python/debuggercontroller.py

Lines changed: 67 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -502,26 +502,80 @@ class DebuggerController:
502502
503503
>>> bv = load("test/binaries/helloworld")
504504
>>> dbg = DebuggerController(bv)
505-
>>> dbg.launch()
505+
>>> dbg.launch_and_wait()
506+
<DebugStopReason.Breakpoint: 6>
507+
508+
When the ``launch_and_wait()`` returns ``DebugStopReason.Breakpoint``, it means the debugger has launched the target
509+
successfully, and the target stopped at the entry point of the binary. Now we can perform other control operations
510+
on it, e.g., resume the target by calling ``step_into_and_wait()``.
511+
512+
>>> dbg.step_into_and_wait()
513+
<DebugStopReason.SingleStep: 4>
514+
515+
For all the API functions that resume the target, e.g., launch go, step into, etc, there are two variants of them.
516+
One of them resumes the target and waits for it to stop again synchronously, ``step_into_and_wait`` will do a step
517+
into, and it only returns AFTER the target stops again. This is more frequently used, and is suitable for automating
518+
a sequence of actions. However, after calling such a synchronous API, if for any reason the target does not stop as
519+
expected, Binary Ninja might be confused or hang.
520+
521+
The second set of API works asynchronously. For example, ``step into`` will only do a step into, but does NOT wait
522+
for the target to stop again. Usually the asynchronous API is used with ``register_event_callback`` to listen for
523+
the relevant events (e.g., target resumed, stopped, etc). The asynchronous API is harder to use and is only
524+
recommended when the synchronous version does not suit your need. The Binary Ninja debugger UI uses the
525+
asynchronous API.
526+
527+
To retrieve all the registers, run `regs`:
528+
529+
>>> dbg.regs
530+
{'x0': <DebugRegister: x0, 0x1>, ...}
531+
532+
More often we only need get the value of one regisgter:
533+
534+
>>> dbg.regs['x1']
535+
<DebugRegister: x1, 0x16fdffa70, &"/Users/xxxx//debugger/test/binaries/Darwin-arm64-signed/helloworld">
536+
537+
The result contains the register value as well as a string that can be dereferenced at its value.
538+
539+
``ip`` returns the current intrudction pointer, and `stack_pointer`` returns the stack pointer:
540+
541+
>>> dbg.stack_pointer
542+
6171916256
543+
>>> dbg.ip
544+
4294983364
545+
546+
To read/write memory value, use ``read_memory``/``write_memory``. Or you can directly read/write the binary view
547+
object returned by `dbg.data`.
548+
549+
>>> dbg.read_memory(dbg.ip, 0x10)
550+
<binaryninja.databuffer.DataBuffer object at 0x32ffa2f90>
551+
>>> dbg.data.read(dbg.ip, 0x10)
552+
b'\xfd{\x03\xa9\xfd\xc3\x00\x91\xbf\xc3\x1f\xb8\xa0\x83\x1f\xb8'
553+
554+
>>> dbg.write_memory(dbg.stack_pointer, b'a' * 0x10)
506555
True
556+
>>> dbg.data.write(dbg.stack_pointer, b'a' * 0x10)
557+
16
558+
559+
``modules`` returns the list of modules, `threads` returns the list of threads.
507560
508-
When the ``launch()`` returns True, it means the debugger has launched the target successfully. The target breaks at
509-
the entry point of the binary. Now we can perform other control operations on it, e.g., resume the target by calling
510-
``go()``.
561+
Breakpoints can be added via `add_breakpoint`:
511562
512-
>>> dbg.go()
563+
>>> dbg.add_breakpoint(0x100003ed0)
564+
565+
And it will be hit after we resume the target with ``go_and_wait``:
566+
567+
>>> dbg.go_and_wait()
568+
<DebugStopReason.Breakpoint: 6>
569+
570+
We can resume it again:
571+
572+
>>> dbg.go_and_wait()
513573
<DebugStopReason.ProcessExited: 2>
514574
515575
Since there are no other breakpoints in the target, the process executes and then exits.
516576
517-
All target control functions, e.g., ``go()``, ``step_into()``, etc, are blocking. They will not return until the
518-
target breaks. In the future, we will switch to an asynchronous communication model where these functions return
519-
before the operation is performed.
520-
521-
Starting from 4.1.5542-dev (0ad6b08b), the debugger no longer involves two binary views during debugging. Instead,
522-
it always uses the incoming binary view that is used to create the controller, and memory regions that are not
523-
present in the original binary view are represented using the new MemoryRegion API. The binary view can be accessed
524-
by the ``data`` property.
577+
For more examples of using the debugger Python API, feel free to get some inspirations from our
578+
[unit tests](https://github.com/Vector35/debugger/blob/dev/test/debugger_test.py)
525579
526580
"""
527581
def __init__(self, bv: binaryninja.BinaryView):

0 commit comments

Comments
 (0)