The ``DebuggerController`` object is the core of the debugger. Most debugger operations can be performed on it. It takes in a ``BinaryView`` and creates a debugger for it. If a debugger is already existing for the very same BinaryView object, the debugger is returned. Most operatio
| 490 | |
| 491 | |
| 492 | class DebuggerController: |
| 493 | """ |
| 494 | The ``DebuggerController`` object is the core of the debugger. Most debugger operations can be performed on it. |
| 495 | It takes in a ``BinaryView`` and creates a debugger for it. If a debugger is already existing for the very same |
| 496 | BinaryView object, the debugger is returned. |
| 497 | |
| 498 | Most operations of the debugger are performed on this class. For example, we can launch the debugger as follows:: |
| 499 | |
| 500 | >>> bv = load("test/binaries/helloworld") |
| 501 | >>> dbg = DebuggerController(bv) |
| 502 | >>> dbg.launch() |
| 503 | True |
| 504 | |
| 505 | When the ``launch()`` returns True, it means the debugger has launched the target successfully. The target breaks at |
| 506 | the entry point of the binary. Now we can perform other control operations on it, e.g., resume the target by calling |
| 507 | ``go()``. |
| 508 | |
| 509 | >>> dbg.go() |
| 510 | <DebugStopReason.ProcessExited: 2> |
| 511 | |
| 512 | Since there are no other breakpoints in the target, the process executes and then exits. |
| 513 | |
| 514 | All target control funciotns, e.g., ``go()``, ``step_into()``, etc, are blocking. They will not return until the |
| 515 | target breaks. In the future, we will switch to an asyunchrounous communication model where these functions return |
| 516 | before the operation is performed. |
| 517 | |
| 518 | For each insteance of DebuggerController, there are two BinaryViews associated with it. The first one is the |
| 519 | original BinaryView that gets rebased to the proper offset according to the target's actual base. The second is a |
| 520 | "live" BinaryView that represents the entire memory space of the target process. They can be accessed by ``data`` |
| 521 | and ``live_view``, respectively. |
| 522 | |
| 523 | """ |
| 524 | def __init__(self, bv: binaryninja.BinaryView): |
| 525 | # bv.handle has type binaryninja.core.BNBinaryView, which is different from dbgcore.BNBinaryView, |
| 526 | # so the casting here is necessary |
| 527 | # A different way to deal with is that instead of defining a BNBinaryView struct in the _debuggercore.py, |
| 528 | # do from binaryninja._binaryninjacore import BNBinaryView |
| 529 | bv_obj = ctypes.cast(bv.handle, ctypes.POINTER(dbgcore.BNBinaryView)) |
| 530 | self.handle = dbgcore.BNGetDebuggerController(bv_obj) |
| 531 | |
| 532 | def destroy(self): |
| 533 | """ |
| 534 | Delete the DebuggerController object. Intended for internal use. Ordinary users do not need to call it. |
| 535 | """ |
| 536 | dbgcore.BNDebuggerDestroyController(self.handle) |
| 537 | |
| 538 | @property |
| 539 | def data(self) -> binaryninja.BinaryView: |
| 540 | """Get the (rebased) BinaryView of the debugger""" |
| 541 | result = dbgcore.BNDebuggerGetData(self.handle) |
| 542 | if result is None: |
| 543 | return None |
| 544 | result = ctypes.cast(result, ctypes.POINTER(binaryninja.core.BNBinaryView)) |
| 545 | if result is None: |
| 546 | return None |
| 547 | return binaryninja.BinaryView(handle=result) |
| 548 | |
| 549 | @property |
nothing calls this directly
no outgoing calls
no test coverage detected