@@ -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