Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
cc9cbe0
Initial plan
Copilot Sep 24, 2025
a40c090
Add hardware breakpoint type enum and standardized interface
Copilot Sep 24, 2025
4821d72
Add API and FFI support for hardware breakpoints
Copilot Sep 24, 2025
02b5be8
Update documentation with hardware breakpoint API usage
Copilot Sep 24, 2025
8eb9cb5
Complete hardware breakpoint implementation with examples
Copilot Sep 24, 2025
6c7f08f
Add hardware breakpoint support to DbgEng adapter and UI enhancements
Copilot Sep 25, 2025
eb6fa67
Add comprehensive hardware breakpoint support for all debug adapters …
Copilot Sep 25, 2025
fa29c5e
Fix build
xusheng6 Dec 5, 2025
f28f770
Enhance breakpoint widget UI with improved hardware breakpoint support
xusheng6 Dec 5, 2025
8ebc5ec
Refactor FFI methods and add hardware breakpoint events
xusheng6 Dec 5, 2025
6fac994
Track hardware breakpoints in DebuggerBreakpoints for proper list dis…
xusheng6 Dec 5, 2025
0141eb8
Unify software and hardware breakpoints
xusheng6 Dec 5, 2025
2188fdf
Fix hardware breakpoint display in the breakpoint widget
xusheng6 Dec 9, 2025
e8e3978
Fix hardware breakpoint caching for all debug adapters
xusheng6 Dec 9, 2025
55a37d7
Temporary fix to make hardware breakpoints work across launch
xusheng6 Dec 9, 2025
325acf7
WIP on hardware breakpoint
xusheng6 Dec 10, 2025
afbd762
Support disabling hardware breakpoint
xusheng6 Dec 11, 2025
ed7ba46
Add "add hardware breakpoint..." to context menu
xusheng6 Dec 11, 2025
59afe8a
Customize the default selected entry in add hardware breakpoint dialog
xusheng6 Dec 11, 2025
ce74b21
Fix keybinding
xusheng6 Dec 11, 2025
4e9593e
Add tooltip text for breakpoints widget
xusheng6 Dec 11, 2025
c8c96db
Use a different icon for hardware breakpoint
xusheng6 Dec 11, 2025
32c003a
Fix hardware breakpoint not working when ASLR is active
xusheng6 Dec 11, 2025
f0d57d4
Fix hardware breakpoint toggling and disabling
xusheng6 Dec 12, 2025
d0a5c28
Translate hardware breakpoints added during debugging via address to …
xusheng6 Dec 12, 2025
82d4f38
Fix hardware breakpoint when it is added during debugging
xusheng6 Dec 12, 2025
6ee4668
Fix hw breakpoint not removed from the breakpoint widget list after t…
xusheng6 Dec 12, 2025
02db70e
Add hardware breakpoint for GDB MI adapter
xusheng6 Dec 19, 2025
4fec779
Add hardware breakpoint for GDB MI adapter
xusheng6 Dec 22, 2025
db33a5c
Fix hardware breakpoint for dbgeng adapter
xusheng6 Dec 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions api/debuggerapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,12 +354,25 @@ namespace BinaryNinjaDebuggerAPI {
};


// Breakpoint types - used to specify the type of breakpoint to set
enum DebugBreakpointType
{
SoftwareBreakpoint = 0, // Default software breakpoint
HardwareExecuteBreakpoint = 1, // Hardware execution breakpoint
HardwareReadBreakpoint = 2, // Hardware read watchpoint
HardwareWriteBreakpoint = 3, // Hardware write watchpoint
HardwareAccessBreakpoint = 4 // Hardware read/write watchpoint
};


struct DebugBreakpoint
{
std::string module;
uint64_t offset;
uint64_t address;
bool enabled;
DebugBreakpointType type = SoftwareBreakpoint;
size_t size = 1; // Size in bytes for hardware breakpoints/watchpoints (1, 2, 4, 8)
};


Expand Down Expand Up @@ -726,6 +739,18 @@ namespace BinaryNinjaDebuggerAPI {
bool ContainsBreakpoint(uint64_t address);
bool ContainsBreakpoint(const ModuleNameAndOffset& breakpoint);

// Hardware breakpoint and watchpoint support - absolute address
bool AddHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size = 1);
bool RemoveHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size = 1);
bool EnableHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size = 1);
bool DisableHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size = 1);

// Hardware breakpoint and watchpoint support - module+offset (ASLR-safe)
bool AddHardwareBreakpoint(const ModuleNameAndOffset& location, DebugBreakpointType type, size_t size = 1);
bool RemoveHardwareBreakpoint(const ModuleNameAndOffset& location, DebugBreakpointType type, size_t size = 1);
bool EnableHardwareBreakpoint(const ModuleNameAndOffset& location, DebugBreakpointType type, size_t size = 1);
bool DisableHardwareBreakpoint(const ModuleNameAndOffset& location, DebugBreakpointType type, size_t size = 1);

uint64_t IP();
uint64_t GetLastIP();
bool SetIP(uint64_t address);
Expand Down
52 changes: 52 additions & 0 deletions api/debuggercontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,8 @@ std::vector<DebugBreakpoint> DebuggerController::GetBreakpoints()
bp.offset = breakpoints[i].offset;
bp.address = breakpoints[i].address;
bp.enabled = breakpoints[i].enabled;
bp.type = (DebugBreakpointType)breakpoints[i].type;
bp.size = breakpoints[i].size;
result[i] = bp;
}

Expand Down Expand Up @@ -799,6 +801,56 @@ bool DebuggerController::ContainsBreakpoint(const ModuleNameAndOffset& breakpoin
}


bool DebuggerController::AddHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size)
{
return BNDebuggerAddHardwareBreakpoint(m_object, address, (BNDebugBreakpointType)type, size);
}


bool DebuggerController::RemoveHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size)
{
return BNDebuggerRemoveHardwareBreakpoint(m_object, address, (BNDebugBreakpointType)type, size);
}


bool DebuggerController::EnableHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size)
{
return BNDebuggerEnableHardwareBreakpoint(m_object, address, (BNDebugBreakpointType)type, size);
}


bool DebuggerController::DisableHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size)
{
return BNDebuggerDisableHardwareBreakpoint(m_object, address, (BNDebugBreakpointType)type, size);
}


// Hardware breakpoint methods - module+offset (ASLR-safe)

bool DebuggerController::AddHardwareBreakpoint(const ModuleNameAndOffset& location, DebugBreakpointType type, size_t size)
{
return BNDebuggerAddRelativeHardwareBreakpoint(m_object, location.module.c_str(), location.offset, (BNDebugBreakpointType)type, size);
}


bool DebuggerController::RemoveHardwareBreakpoint(const ModuleNameAndOffset& location, DebugBreakpointType type, size_t size)
{
return BNDebuggerRemoveRelativeHardwareBreakpoint(m_object, location.module.c_str(), location.offset, (BNDebugBreakpointType)type, size);
}


bool DebuggerController::EnableHardwareBreakpoint(const ModuleNameAndOffset& location, DebugBreakpointType type, size_t size)
{
return BNDebuggerEnableRelativeHardwareBreakpoint(m_object, location.module.c_str(), location.offset, (BNDebugBreakpointType)type, size);
}


bool DebuggerController::DisableHardwareBreakpoint(const ModuleNameAndOffset& location, DebugBreakpointType type, size_t size)
{
return BNDebuggerDisableRelativeHardwareBreakpoint(m_object, location.module.c_str(), location.offset, (BNDebugBreakpointType)type, size);
}


uint64_t DebuggerController::RelativeAddressToAbsolute(const ModuleNameAndOffset& address)
{
return BNDebuggerRelativeAddressToAbsolute(m_object, address.module.c_str(), address.offset);
Expand Down
42 changes: 34 additions & 8 deletions api/ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,25 @@ extern "C"
} BNDebugRegister;


typedef enum BNDebugBreakpointType
{
BNSoftwareBreakpoint = 0, // Default software breakpoint
BNHardwareExecuteBreakpoint = 1, // Hardware execution breakpoint
BNHardwareReadBreakpoint = 2, // Hardware read watchpoint
BNHardwareWriteBreakpoint = 3, // Hardware write watchpoint
BNHardwareAccessBreakpoint = 4 // Hardware read/write watchpoint
} BNDebugBreakpointType;


typedef struct BNDebugBreakpoint
{
// TODO: we should add an absolute address to this, along with a boolean telling whether it is valid
char* module;
uint64_t offset;
uint64_t address;
bool enabled;
BNDebugBreakpointType type;
size_t size; // Size in bytes for hardware breakpoints/watchpoints (1, 2, 4, 8)
} BNDebugBreakpoint;


Expand Down Expand Up @@ -248,14 +260,8 @@ extern "C"
TargetExitedEventType,
DetachedEventType,

AbsoluteBreakpointAddedEvent,
RelativeBreakpointAddedEvent,
AbsoluteBreakpointRemovedEvent,
RelativeBreakpointRemovedEvent,
AbsoluteBreakpointEnabledEvent,
RelativeBreakpointEnabledEvent,
AbsoluteBreakpointDisabledEvent,
RelativeBreakpointDisabledEvent,
// Unified breakpoint change event - use this for all breakpoint changes (add/remove/enable/disable)
BreakpointChangedEvent,

ActiveThreadChangedEvent,

Expand Down Expand Up @@ -597,6 +603,26 @@ extern "C"
DEBUGGER_FFI_API bool BNDebuggerContainsRelativeBreakpoint(
BNDebuggerController* controller, const char* module, uint64_t offset);

// Hardware breakpoint and watchpoint support
DEBUGGER_FFI_API bool BNDebuggerAddHardwareBreakpoint(BNDebuggerController* controller, uint64_t address,
BNDebugBreakpointType type, size_t size);
DEBUGGER_FFI_API bool BNDebuggerRemoveHardwareBreakpoint(BNDebuggerController* controller, uint64_t address,
BNDebugBreakpointType type, size_t size);
DEBUGGER_FFI_API bool BNDebuggerEnableHardwareBreakpoint(BNDebuggerController* controller, uint64_t address,
BNDebugBreakpointType type, size_t size);
DEBUGGER_FFI_API bool BNDebuggerDisableHardwareBreakpoint(BNDebuggerController* controller, uint64_t address,
BNDebugBreakpointType type, size_t size);

// Hardware breakpoint methods - module+offset (ASLR-safe)
DEBUGGER_FFI_API bool BNDebuggerAddRelativeHardwareBreakpoint(BNDebuggerController* controller, const char* module,
uint64_t offset, BNDebugBreakpointType type, size_t size);
DEBUGGER_FFI_API bool BNDebuggerRemoveRelativeHardwareBreakpoint(BNDebuggerController* controller, const char* module,
uint64_t offset, BNDebugBreakpointType type, size_t size);
DEBUGGER_FFI_API bool BNDebuggerEnableRelativeHardwareBreakpoint(BNDebuggerController* controller, const char* module,
uint64_t offset, BNDebugBreakpointType type, size_t size);
DEBUGGER_FFI_API bool BNDebuggerDisableRelativeHardwareBreakpoint(BNDebuggerController* controller, const char* module,
uint64_t offset, BNDebugBreakpointType type, size_t size);

DEBUGGER_FFI_API uint64_t BNDebuggerGetIP(BNDebuggerController* controller);
DEBUGGER_FFI_API uint64_t BNDebuggerGetLastIP(BNDebuggerController* controller);
DEBUGGER_FFI_API bool BNDebuggerSetIP(BNDebuggerController* controller, uint64_t address);
Expand Down
30 changes: 25 additions & 5 deletions api/python/debuggercontroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,27 +368,31 @@ class DebugBreakpoint:
* ``offset``: the offset of the breakpoint to the start of the module
* ``address``: the absolute address of the breakpoint
* ``enabled``: whether the breakpoint is enabled (read-only)
* ``type``: the type of breakpoint (Software, HardwareExecute, HardwareRead, HardwareWrite, HardwareAccess)
* ``size``: the size in bytes for hardware breakpoints/watchpoints (1, 2, 4, or 8)

"""
def __init__(self, module, offset, address, enabled):
def __init__(self, module, offset, address, enabled, bp_type=DebugBreakpointType.BNSoftwareBreakpoint, size=1):
self.module = module
self.offset = offset
self.address = address
self.enabled = enabled
self.type = bp_type
self.size = size

def __eq__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return self.module == other.module and self.offset == other.offset and self.address == other.address \
and self.enabled == other.enabled
and self.enabled == other.enabled and self.type == other.type and self.size == other.size

def __ne__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return not (self == other)

def __hash__(self):
return hash((self.module, self.offset, self.address, self.enabled))
return hash((self.module, self.offset, self.address, self.enabled, self.type, self.size))

def __setattr__(self, name, value):
try:
Expand All @@ -398,7 +402,22 @@ def __setattr__(self, name, value):

def __repr__(self):
status = "enabled" if self.enabled else "disabled"
return f"<DebugBreakpoint: {self.module}:{self.offset:#x}, {self.address:#x}, {status}>"

# Get type string (S, HE, HR, HW, HA)
if self.type == DebugBreakpointType.BNSoftwareBreakpoint:
type_str = "S"
elif self.type == DebugBreakpointType.BNHardwareExecuteBreakpoint:
type_str = "HE"
elif self.type == DebugBreakpointType.BNHardwareReadBreakpoint:
type_str = "HR"
elif self.type == DebugBreakpointType.BNHardwareWriteBreakpoint:
type_str = "HW"
elif self.type == DebugBreakpointType.BNHardwareAccessBreakpoint:
type_str = "HA"
else:
type_str = "?"

return f"<DebugBreakpoint: {self.module}:{self.offset:#x}, {self.address:#x}, type={type_str}, {status}>"


class ModuleNameAndOffset:
Expand Down Expand Up @@ -2053,7 +2072,8 @@ def breakpoints(self) -> DebugBreakpoints:
breakpoints = dbgcore.BNDebuggerGetBreakpoints(self.handle, count)
result = []
for i in range(0, count.value):
bp = DebugBreakpoint(breakpoints[i].module, breakpoints[i].offset, breakpoints[i].address, breakpoints[i].enabled)
bp = DebugBreakpoint(breakpoints[i].module, breakpoints[i].offset, breakpoints[i].address,
breakpoints[i].enabled, breakpoints[i].type, breakpoints[i].size)
result.append(bp)

dbgcore.BNDebuggerFreeBreakpoints(breakpoints, count.value)
Expand Down
Binary file added breakpoint_widget_enhanced.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 25 additions & 1 deletion cli/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,31 @@ int main(int argc, const char* argv[])
size_t i = 0;
for (const auto& breakpoint : debugger->GetBreakpoints())
{
Log::print(" breakpoint[{}] @ 0x{:X} is {}{}\n", i, breakpoint.address,
// Convert breakpoint type to short string representation
std::string typeStr;
switch (breakpoint.type)
{
case BinaryNinjaDebuggerAPI::SoftwareBreakpoint:
typeStr = "S";
break;
case BinaryNinjaDebuggerAPI::HardwareExecuteBreakpoint:
typeStr = "HE";
break;
case BinaryNinjaDebuggerAPI::HardwareReadBreakpoint:
typeStr = "HR";
break;
case BinaryNinjaDebuggerAPI::HardwareWriteBreakpoint:
typeStr = "HW";
break;
case BinaryNinjaDebuggerAPI::HardwareAccessBreakpoint:
typeStr = "HA";
break;
default:
typeStr = "?";
break;
}

Log::print(" breakpoint[{}] @ 0x{:X} type={} is {}{}\n", i, breakpoint.address, typeStr,
breakpoint.enabled ? Log::Style(0, 255, 0) : Log::Style(255, 0, 0),
breakpoint.enabled ? "active" : "inactive");
i++;
Expand Down
28 changes: 28 additions & 0 deletions core/adapters/corelliumadapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,34 @@ bool CorelliumAdapter::SupportFeature(DebugAdapterCapacity feature)
}


bool CorelliumAdapter::AddHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size)
{
// Hardware breakpoints are not yet implemented for Corellium adapter
return false;
}


bool CorelliumAdapter::RemoveHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size)
{
// Hardware breakpoints are not yet implemented for Corellium adapter
return false;
}


bool CorelliumAdapter::AddHardwareBreakpoint(const ModuleNameAndOffset& location, DebugBreakpointType type, size_t size)
{
// Hardware breakpoints are not yet implemented for Corellium adapter
return false;
}


bool CorelliumAdapter::RemoveHardwareBreakpoint(const ModuleNameAndOffset& location, DebugBreakpointType type, size_t size)
{
// Hardware breakpoints are not yet implemented for Corellium adapter
return false;
}


void CorelliumAdapter::InvalidateCache()
{
m_regCache.reset();
Expand Down
6 changes: 6 additions & 0 deletions core/adapters/corelliumadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@ namespace BinaryNinjaDebugger
bool ResumeThread(std::uint32_t tid) override;
DebugBreakpoint AddBreakpoint(const ModuleNameAndOffset& address, unsigned long breakpoint_type = 0) override;

// Hardware breakpoint support - not implemented
bool AddHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size = 1) override;
bool RemoveHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size = 1) override;
bool AddHardwareBreakpoint(const ModuleNameAndOffset& location, DebugBreakpointType type, size_t size = 1) override;
bool RemoveHardwareBreakpoint(const ModuleNameAndOffset& location, DebugBreakpointType type, size_t size = 1) override;

void GenerateDefaultAdapterSettings(BinaryView* data);
Ref<Settings> GetAdapterSettings() override;
};
Expand Down
Loading