Skip to content

Commit

Permalink
Add DbgEng TTD API and UI
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnKServices authored and xusheng6 committed Mar 21, 2024
1 parent 6e3c9b7 commit 7cd1812
Show file tree
Hide file tree
Showing 14 changed files with 905 additions and 3 deletions.
11 changes: 11 additions & 0 deletions api/debuggerapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -505,17 +505,26 @@ namespace BinaryNinjaDebuggerAPI {
DebugStopReason AttachAndWait();

bool Go();
bool GoReverse();
bool StepInto(BNFunctionGraphType il = NormalFunctionGraph);
bool StepIntoReverse(BNFunctionGraphType il = NormalFunctionGraph);
bool StepOver(BNFunctionGraphType il = NormalFunctionGraph);
bool StepOverReverse(BNFunctionGraphType il = NormalFunctionGraph);
bool StepReturn();
bool StepReturnReverse();

bool RunTo(uint64_t remoteAddresses);
bool RunTo(const std::vector<uint64_t>& remoteAddresses);
void Pause();

DebugStopReason GoAndWait();
DebugStopReason GoReverseAndWait();
DebugStopReason StepIntoAndWait(BNFunctionGraphType il = NormalFunctionGraph);
DebugStopReason StepIntoReverseAndWait(BNFunctionGraphType il = NormalFunctionGraph);
DebugStopReason StepOverAndWait(BNFunctionGraphType il = NormalFunctionGraph);
DebugStopReason StepOverReverseAndWait(BNFunctionGraphType il);
DebugStopReason StepReturnAndWait();
DebugStopReason StepReturnReverseAndWait();
DebugStopReason RunToAndWait(uint64_t remoteAddresses);
DebugStopReason RunToAndWait(const std::vector<uint64_t>& remoteAddresses);
DebugStopReason PauseAndWait();
Expand Down Expand Up @@ -562,6 +571,7 @@ namespace BinaryNinjaDebuggerAPI {

size_t RegisterEventCallback(
std::function<void(const DebuggerEvent& event)> callback, const std::string& name = "");
void RecordTrace();
static void DebuggerEventCallback(void* ctxt, BNDebuggerEvent* view);

void RemoveEventCallback(size_t index);
Expand All @@ -580,6 +590,7 @@ namespace BinaryNinjaDebuggerAPI {

std::string GetAddressInformation(uint64_t address);
bool IsFirstLaunch();
bool IsTTD();

void PostDebuggerEvent(const DebuggerEvent& event);
};
Expand Down
52 changes: 52 additions & 0 deletions api/debuggercontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,13 +299,24 @@ bool DebuggerController::Go()
return BNDebuggerGo(m_object);
}

bool DebuggerController::GoReverse()
{
return BNDebuggerGoReverse(m_object);
}


DebugStopReason DebuggerController::GoAndWait()
{
return BNDebuggerGoAndWait(m_object);
}


DebugStopReason DebuggerController::GoReverseAndWait()
{
return BNDebuggerGoReverseAndWait(m_object);
}


bool DebuggerController::Launch()
{
return BNDebuggerLaunch(m_object);
Expand Down Expand Up @@ -404,18 +415,36 @@ bool DebuggerController::StepInto(BNFunctionGraphType il)
}


bool DebuggerController::StepIntoReverse(BNFunctionGraphType il)
{
return BNDebuggerStepIntoReverse(m_object, il);
}


bool DebuggerController::StepOver(BNFunctionGraphType il)
{
return BNDebuggerStepOver(m_object, il);
}


bool DebuggerController::StepOverReverse(BNFunctionGraphType il)
{
return BNDebuggerStepOverReverse(m_object, il);
}


bool DebuggerController::StepReturn()
{
return BNDebuggerStepReturn(m_object);
}


bool DebuggerController::StepReturnReverse()
{
return BNDebuggerStepReturnReverse(m_object);
}


bool DebuggerController::RunTo(uint64_t remoteAddresses)
{
return RunTo(std::vector<uint64_t> {remoteAddresses});
Expand All @@ -434,17 +463,34 @@ DebugStopReason DebuggerController::StepIntoAndWait(BNFunctionGraphType il)
}


DebugStopReason DebuggerController::StepIntoReverseAndWait(BNFunctionGraphType il)
{
return BNDebuggerStepIntoReverseAndWait(m_object, il);
}


DebugStopReason DebuggerController::StepOverAndWait(BNFunctionGraphType il)
{
return BNDebuggerStepOverAndWait(m_object, il);
}


DebugStopReason DebuggerController::StepOverReverseAndWait(BNFunctionGraphType il)
{
return BNDebuggerStepOverReverseAndWait(m_object, il);
}


DebugStopReason DebuggerController::StepReturnAndWait()
{
return BNDebuggerStepReturnAndWait(m_object);
}

DebugStopReason DebuggerController::StepReturnReverseAndWait()
{
return BNDebuggerStepReturnReverseAndWait(m_object);
}


DebugStopReason DebuggerController::RunToAndWait(uint64_t remoteAddresses)
{
Expand Down Expand Up @@ -829,6 +875,12 @@ bool DebuggerController::IsFirstLaunch()
}


bool DebuggerController::IsTTD()
{
return BNDebuggerIsTTD(m_object);
}


void DebuggerController::PostDebuggerEvent(const DebuggerEvent &event)
{
BNDebuggerEvent* evt = new BNDebuggerEvent;
Expand Down
19 changes: 18 additions & 1 deletion api/ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,11 @@ extern "C"
DebugAdapterStepReturn,
DebugAdapterPause,
DebugAdapterQuit,
DebugAdapterDetach
DebugAdapterDetach,
DebugAdapterStepIntoReverse,
DebugAdapterStepOverReverse,
DebugAdapterGoReverse,
DebugAdapterStepReturnReverse,
} BNDebuggerAdapterOperation;


Expand Down Expand Up @@ -395,19 +399,31 @@ extern "C"
DEBUGGER_FFI_API BNDebugStopReason BNDebuggerAttachAndWait(BNDebuggerController* controller);

DEBUGGER_FFI_API bool BNDebuggerGo(BNDebuggerController* controller);
DEBUGGER_FFI_API bool BNDebuggerGoReverse(BNDebuggerController* controller);

DEBUGGER_FFI_API bool BNDebuggerStepInto(BNDebuggerController* controller, BNFunctionGraphType il);
DEBUGGER_FFI_API bool BNDebuggerStepIntoReverse(BNDebuggerController* controller, BNFunctionGraphType il);
DEBUGGER_FFI_API bool BNDebuggerStepOver(BNDebuggerController* controller, BNFunctionGraphType il);
DEBUGGER_FFI_API bool BNDebuggerStepOverReverse(BNDebuggerController* controller, BNFunctionGraphType il);
DEBUGGER_FFI_API bool BNDebuggerStepReturn(BNDebuggerController* controller);
DEBUGGER_FFI_API bool BNDebuggerStepReturnReverse(BNDebuggerController* controller);
DEBUGGER_FFI_API bool BNDebuggerRunTo(
BNDebuggerController* controller, const uint64_t* remoteAddresses, size_t count);
DEBUGGER_FFI_API void BNDebuggerPause(BNDebuggerController* controller);

DEBUGGER_FFI_API BNDebugStopReason BNDebuggerGoAndWait(BNDebuggerController* controller);
DEBUGGER_FFI_API BNDebugStopReason BNDebuggerGoReverseAndWait(BNDebuggerController* controller);
DEBUGGER_FFI_API BNDebugStopReason BNDebuggerStepIntoAndWait(
BNDebuggerController* controller, BNFunctionGraphType il);
DEBUGGER_FFI_API BNDebugStopReason BNDebuggerStepIntoReverseAndWait(
BNDebuggerController* controller, BNFunctionGraphType il);

DEBUGGER_FFI_API BNDebugStopReason BNDebuggerStepOverAndWait(
BNDebuggerController* controller, BNFunctionGraphType il);
DEBUGGER_FFI_API BNDebugStopReason BNDebuggerStepOverReverseAndWait(
BNDebuggerController* controller, BNFunctionGraphType il);
DEBUGGER_FFI_API BNDebugStopReason BNDebuggerStepReturnAndWait(BNDebuggerController* controller);
DEBUGGER_FFI_API BNDebugStopReason BNDebuggerStepReturnReverseAndWait(BNDebuggerController* controller);
DEBUGGER_FFI_API BNDebugStopReason BNDebuggerRunToAndWait(
BNDebuggerController* controller, const uint64_t* remoteAddresses, size_t count);
DEBUGGER_FFI_API BNDebugStopReason BNDebuggerPauseAndWait(BNDebuggerController* controller);
Expand Down Expand Up @@ -471,6 +487,7 @@ extern "C"

DEBUGGER_FFI_API char* BNDebuggerGetAddressInformation(BNDebuggerController* controller, uint64_t address);
DEBUGGER_FFI_API bool BNDebuggerIsFirstLaunch(BNDebuggerController* controller);
DEBUGGER_FFI_API bool BNDebuggerIsTTD(BNDebuggerController* controller);

DEBUGGER_FFI_API void BNDebuggerPostDebuggerEvent(BNDebuggerController* controller, BNDebuggerEvent* event);

Expand Down
133 changes: 132 additions & 1 deletion api/python/debuggercontroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,17 @@ def go(self) -> bool:
"""
return dbgcore.BNDebuggerGo(self.handle)

# TODO: Improve the documentation on reverse-execution functions
def go_reverse(self) -> bool:
"""
Resume the target in reverse.
The call is asynchronous and returns before the target stops.
:return: the reason for the stop
"""
return dbgcore.BNDebuggerGoReverse(self.handle)

def step_into(self, il: binaryninja.FunctionGraphType = binaryninja.FunctionGraphType.NormalFunctionGraph) -> bool:
"""
Perform a step into on the target.
Expand All @@ -850,6 +861,27 @@ def step_into(self, il: binaryninja.FunctionGraphType = binaryninja.FunctionGrap
"""
return dbgcore.BNDebuggerStepInto(self.handle, il)

def step_into_reverse(self, il: binaryninja.FunctionGraphType = binaryninja.FunctionGraphType.NormalFunctionGraph) -> bool:
"""
Perform a step into on the target in reverse.
When the previous instruction is not a call, step backwards. When the previous instruction is a call,
follow the call into the last instruction of the function.
The operation can be performed on an IL level specified by the ``il`` parameter, which then either executes the
next IL instruction, or follow into the IL function. Note, the underlying operation is still performed at the
disassembly level because that is the only thing a debugger understands. The high-level operations are simulated
on top of the disassembly and analysis.
Some limitations are known with stepping into on IL.
The call is asynchronous and returns before the target stops.
:param il: optional IL level to perform the operation at
:return: the reason for the stop
"""
return dbgcore.BNDebuggerStepIntoReverse(self.handle, il)

def step_over(self, il: binaryninja.FunctionGraphType = binaryninja.FunctionGraphType.NormalFunctionGraph) -> bool:
"""
Perform a step over on the target.
Expand All @@ -871,6 +903,27 @@ def step_over(self, il: binaryninja.FunctionGraphType = binaryninja.FunctionGrap
"""
return dbgcore.BNDebuggerStepOver(self.handle, il)

def step_over_reverse(self, il: binaryninja.FunctionGraphType = binaryninja.FunctionGraphType.NormalFunctionGraph) -> bool:
"""
Perform a step over on the target in reverse.
When the previous instruction is not a call, step backwards. When the previous instruction is a call,
step back over the call.
The operation can be performed on an IL level specified by the ``il`` parameter, which then either executes the
next IL instruction, or completes the IL function. Note, the underlying operation is still performed at the
disassembly level because that is the only thing a debugger understands. The high-level operations are simulated
on top of the disassembly and analysis.
Some limitations are known with stepping over on IL.
The call is asynchronous and returns before the target stops.
:param il: optional IL level to perform the operation at
:return: the reason for the stop
"""
return dbgcore.BNDebuggerStepOverReverse(self.handle, il)

def step_return(self) -> bool:
"""
Perform a step return on the target.
Expand All @@ -890,6 +943,26 @@ def step_return(self) -> bool:
:return: the reason for the stop
"""
return dbgcore.BNDebuggerStepReturn(self.handle)

def step_return_reverse(self) -> bool:
"""
Perform a step return on the target in reverse.
Step return reverses the execution of the current function and returns to its caller. This operation relies
heavily on stack frame analysis, which is done by the DebugAdapters.
If a DebugAdapter does not support (i.e., overload) this function, a fallback handling is provided by the
DebuggerController. It checks the MLIL function and put breakpoints on all returning instructions and then resume
the target. By the time it breaks, the target is about to return from the current function.
This fallback behavior is slightly different from that offered by the LLDB and DbgEng adapter, which returns
from the current function and break afterwards.
The call is asynchronous and returns before the target stops.
:return: the reason for the stop
"""
return dbgcore.BNDebuggerStepReturnReverse(self.handle)

def run_to(self, address) -> bool:
"""
Expand Down Expand Up @@ -925,10 +998,20 @@ def go_and_wait(self) -> DebugStopReason:
"""
return DebugStopReason(dbgcore.BNDebuggerGoAndWait(self.handle))

def go_reverse_and_wait(self) -> DebugStopReason:
"""
Resume the target in reverse.
The call is blocking and only returns when the target stops.
:return: the reason for the stop
"""
return DebugStopReason(dbgcore.BNDebuggerGoReverseAndWait(self.handle))

def step_into_and_wait(self, il: binaryninja.FunctionGraphType =
binaryninja.FunctionGraphType.NormalFunctionGraph) -> DebugStopReason:
"""
Perform a step into on the target.
Perform a step into on the target in reverse.
When the next instruction is not a call, execute the next instruction. When the next instruction is a call,
follow the call the get into the first instruction of the call.
Expand All @@ -947,6 +1030,28 @@ def step_into_and_wait(self, il: binaryninja.FunctionGraphType =
"""
return DebugStopReason(dbgcore.BNDebuggerStepIntoAndWait(self.handle, il))


def step_into_reverse_and_wait(self, il: binaryninja.FunctionGraphType =
binaryninja.FunctionGraphType.NormalFunctionGraph) -> DebugStopReason:
"""
Perform a reverse step into on the target.
When the previous instruction is not a call, reverse the program to the previous state. When the previous instruction is a call,
follow the call to get into the last instruction of the call.
The operation can be performed on an IL level specified by the ``il`` parameter, which then either reverses the current IL instruction, or follow into the previous IL function. Note, the underlying operation is still performed at the
disassembly level because that is the only thing a debugger understands. The high-level operations are simulated
on top of the disassembly and analysis.
Some limitations are known with stepping into on IL.
The call is blocking and only returns when the target stops.
:param il: optional IL level to perform the operation at
:return: the reason for the stop
"""
return DebugStopReason(dbgcore.BNDebuggerStepIntoReverseAndWait(self.handle, il))

def step_over_and_wait(self, il: binaryninja.FunctionGraphType =
binaryninja.FunctionGraphType.NormalFunctionGraph) -> DebugStopReason:
"""
Expand All @@ -969,6 +1074,28 @@ def step_over_and_wait(self, il: binaryninja.FunctionGraphType =
"""
return DebugStopReason(dbgcore.BNDebuggerStepOverAndWait(self.handle, il))

def step_over_reverse_and_wait(self, il: binaryninja.FunctionGraphType =
binaryninja.FunctionGraphType.NormalFunctionGraph) -> DebugStopReason:
"""
Perform a step over on the target in reverse.
When the next instruction is not a call, execute the next instruction. When the next instruction is a call,
complete the execution of the function and break at next instruction.
The operation can be performed on an IL level specified by the ``il`` parameter, which then either executes the
next IL instruction, or completes the IL function. Note, the underlying operation is still performed at the
disassembly level because that is the only thing a debugger understands. The high-level operations are simulated
on top of the disassembly and analysis.
Some limitations are known with stepping over on IL.
The call is blocking and only returns when the target stops.
:param il: optional IL level to perform the operation at
:return: the reason for the stop
"""
return DebugStopReason(dbgcore.BNDebuggerStepOverReverseAndWait(self.handle, il))

def step_return_and_wait(self) -> DebugStopReason:
"""
Perform a step return on the target.
Expand Down Expand Up @@ -1392,6 +1519,10 @@ def get_addr_info(self, addr: int):
def is_first_launch(self):
return dbgcore.BNDebuggerIsFirstLaunch(self.handle)

@property
def is_ttd(self):
return dbgcore.BNDebuggerIsTTD(self.handle)

def __del__(self):
if dbgcore is not None:
dbgcore.BNDebuggerFreeController(self.handle)
Expand Down
Loading

0 comments on commit 7cd1812

Please sign in to comment.