Skip to content

Commit 591d6cf

Browse files
Copilotxusheng6
andcommitted
Add hardware breakpoint type enum and standardized interface
Co-authored-by: xusheng6 <[email protected]>
1 parent 4f6080f commit 591d6cf

File tree

9 files changed

+270
-10
lines changed

9 files changed

+270
-10
lines changed

core/adapters/esrevenadapter.cpp

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,20 +1068,80 @@ bool EsrevenAdapter::StepOverReverse()
10681068
return status != InternalError;
10691069
}
10701070

1071-
bool EsrevenAdapter::AddHardwareWriteBreakpoint(uint64_t address)
1071+
bool EsrevenAdapter::AddHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size)
10721072
{
10731073
if (m_isTargetRunning || !m_rspConnector)
10741074
return false;
10751075

1076-
return this->m_rspConnector->TransmitAndReceive(RspData("Z2,{:x},{}", address, 1)).AsString() != "OK";
1076+
std::string command;
1077+
switch (type)
1078+
{
1079+
case HardwareExecuteBreakpoint:
1080+
// Z1 = hardware execution breakpoint
1081+
command = fmt::format("Z1,{:x},{}", address, size);
1082+
break;
1083+
case HardwareReadBreakpoint:
1084+
// Z3 = hardware read watchpoint
1085+
command = fmt::format("Z3,{:x},{}", address, size);
1086+
break;
1087+
case HardwareWriteBreakpoint:
1088+
// Z2 = hardware write watchpoint
1089+
command = fmt::format("Z2,{:x},{}", address, size);
1090+
break;
1091+
case HardwareAccessBreakpoint:
1092+
// Z4 = hardware access watchpoint (read/write)
1093+
command = fmt::format("Z4,{:x},{}", address, size);
1094+
break;
1095+
default:
1096+
return false;
1097+
}
1098+
1099+
return m_rspConnector->TransmitAndReceive(RspData(command)).AsString() == "OK";
10771100
}
10781101

1079-
bool EsrevenAdapter::RemoveHardwareWriteBreakpoint(uint64_t address)
1102+
1103+
bool EsrevenAdapter::RemoveHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size)
10801104
{
10811105
if (m_isTargetRunning || !m_rspConnector)
10821106
return false;
10831107

1084-
return this->m_rspConnector->TransmitAndReceive(RspData("Z2,{:x},{}", address, 1)).AsString() != "OK";
1108+
std::string command;
1109+
switch (type)
1110+
{
1111+
case HardwareExecuteBreakpoint:
1112+
// z1 = remove hardware execution breakpoint
1113+
command = fmt::format("z1,{:x},{}", address, size);
1114+
break;
1115+
case HardwareReadBreakpoint:
1116+
// z3 = remove hardware read watchpoint
1117+
command = fmt::format("z3,{:x},{}", address, size);
1118+
break;
1119+
case HardwareWriteBreakpoint:
1120+
// z2 = remove hardware write watchpoint
1121+
command = fmt::format("z2,{:x},{}", address, size);
1122+
break;
1123+
case HardwareAccessBreakpoint:
1124+
// z4 = remove hardware access watchpoint (read/write)
1125+
command = fmt::format("z4,{:x},{}", address, size);
1126+
break;
1127+
default:
1128+
return false;
1129+
}
1130+
1131+
return m_rspConnector->TransmitAndReceive(RspData(command)).AsString() == "OK";
1132+
}
1133+
1134+
1135+
bool EsrevenAdapter::AddHardwareWriteBreakpoint(uint64_t address)
1136+
{
1137+
// Delegate to new standardized method
1138+
return AddHardwareBreakpoint(address, HardwareWriteBreakpoint, 1);
1139+
}
1140+
1141+
bool EsrevenAdapter::RemoveHardwareWriteBreakpoint(uint64_t address)
1142+
{
1143+
// Delegate to new standardized method
1144+
return RemoveHardwareBreakpoint(address, HardwareWriteBreakpoint, 1);
10851145
}
10861146

10871147
bool EsrevenAdapter::StepReturnReverse()

core/adapters/esrevenadapter.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,11 @@ namespace BinaryNinjaDebugger
156156
bool ResumeThread(std::uint32_t tid) override;
157157
DebugBreakpoint AddBreakpoint(const ModuleNameAndOffset& address, unsigned long breakpoint_type = 0) override;
158158

159-
// Temporary internal methods
159+
// Hardware breakpoint and watchpoint support
160+
bool AddHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size = 1) override;
161+
bool RemoveHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size = 1) override;
162+
163+
// Legacy methods - kept for backward compatibility
160164
bool AddHardwareWriteBreakpoint(uint64_t address);
161165
bool RemoveHardwareWriteBreakpoint(uint64_t address);
162166

core/adapters/gdbadapter.cpp

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,20 +1116,80 @@ bool GdbAdapter::StepOverReverse()
11161116
return status != InternalError;
11171117
}
11181118

1119-
bool GdbAdapter::AddHardwareWriteBreakpoint(uint64_t address)
1119+
bool GdbAdapter::AddHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size)
11201120
{
11211121
if (m_isTargetRunning || !m_rspConnector)
11221122
return false;
11231123

1124-
return this->m_rspConnector->TransmitAndReceive(RspData("Z2,{:x},{}", address, 1)).AsString() != "OK";
1124+
std::string command;
1125+
switch (type)
1126+
{
1127+
case HardwareExecuteBreakpoint:
1128+
// Z1 = hardware execution breakpoint
1129+
command = fmt::format("Z1,{:x},{}", address, size);
1130+
break;
1131+
case HardwareReadBreakpoint:
1132+
// Z3 = hardware read watchpoint
1133+
command = fmt::format("Z3,{:x},{}", address, size);
1134+
break;
1135+
case HardwareWriteBreakpoint:
1136+
// Z2 = hardware write watchpoint
1137+
command = fmt::format("Z2,{:x},{}", address, size);
1138+
break;
1139+
case HardwareAccessBreakpoint:
1140+
// Z4 = hardware access watchpoint (read/write)
1141+
command = fmt::format("Z4,{:x},{}", address, size);
1142+
break;
1143+
default:
1144+
return false;
1145+
}
1146+
1147+
return m_rspConnector->TransmitAndReceive(RspData(command)).AsString() == "OK";
11251148
}
11261149

1127-
bool GdbAdapter::RemoveHardwareWriteBreakpoint(uint64_t address)
1150+
1151+
bool GdbAdapter::RemoveHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size)
11281152
{
11291153
if (m_isTargetRunning || !m_rspConnector)
11301154
return false;
11311155

1132-
return this->m_rspConnector->TransmitAndReceive(RspData("Z2,{:x},{}", address, 1)).AsString() != "OK";
1156+
std::string command;
1157+
switch (type)
1158+
{
1159+
case HardwareExecuteBreakpoint:
1160+
// z1 = remove hardware execution breakpoint
1161+
command = fmt::format("z1,{:x},{}", address, size);
1162+
break;
1163+
case HardwareReadBreakpoint:
1164+
// z3 = remove hardware read watchpoint
1165+
command = fmt::format("z3,{:x},{}", address, size);
1166+
break;
1167+
case HardwareWriteBreakpoint:
1168+
// z2 = remove hardware write watchpoint
1169+
command = fmt::format("z2,{:x},{}", address, size);
1170+
break;
1171+
case HardwareAccessBreakpoint:
1172+
// z4 = remove hardware access watchpoint (read/write)
1173+
command = fmt::format("z4,{:x},{}", address, size);
1174+
break;
1175+
default:
1176+
return false;
1177+
}
1178+
1179+
return m_rspConnector->TransmitAndReceive(RspData(command)).AsString() == "OK";
1180+
}
1181+
1182+
1183+
bool GdbAdapter::AddHardwareWriteBreakpoint(uint64_t address)
1184+
{
1185+
// Delegate to new standardized method
1186+
return AddHardwareBreakpoint(address, HardwareWriteBreakpoint, 1);
1187+
}
1188+
1189+
bool GdbAdapter::RemoveHardwareWriteBreakpoint(uint64_t address)
1190+
{
1191+
// Delegate to new standardized method
1192+
return RemoveHardwareBreakpoint(address, HardwareWriteBreakpoint, 1);
11331193
}
11341194

11351195
bool GdbAdapter::StepReturnReverse()

core/adapters/gdbadapter.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,11 @@ namespace BinaryNinjaDebugger
156156
bool ResumeThread(std::uint32_t tid) override;
157157
DebugBreakpoint AddBreakpoint(const ModuleNameAndOffset& address, unsigned long breakpoint_type = 0) override;
158158

159-
// Temporary internal methods
159+
// Hardware breakpoint and watchpoint support
160+
bool AddHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size = 1) override;
161+
bool RemoveHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size = 1) override;
162+
163+
// Legacy methods - kept for backward compatibility
160164
bool AddHardwareWriteBreakpoint(uint64_t address);
161165
bool RemoveHardwareWriteBreakpoint(uint64_t address);
162166

core/adapters/lldbadapter.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,16 @@ std::vector<DebugFrame> LldbAdapter::GetFramesOfThread(uint32_t tid)
908908

909909
DebugBreakpoint LldbAdapter::AddBreakpoint(const std::uintptr_t address, unsigned long breakpoint_type)
910910
{
911+
// Check if this is a hardware breakpoint type
912+
if (breakpoint_type == HardwareExecuteBreakpoint)
913+
{
914+
if (AddHardwareBreakpoint(address, HardwareExecuteBreakpoint))
915+
return DebugBreakpoint(address, 0, true); // Use 0 as ID for hardware breakpoints for now
916+
else
917+
return DebugBreakpoint {};
918+
}
919+
920+
// Default software breakpoint
911921
SBBreakpoint bp = m_target.BreakpointCreateByAddress(address);
912922
if (!bp.IsValid())
913923
return DebugBreakpoint {};
@@ -984,6 +994,96 @@ std::vector<DebugBreakpoint> LldbAdapter::GetBreakpointList() const
984994
}
985995

986996

997+
bool LldbAdapter::AddHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size)
998+
{
999+
if (!m_targetActive)
1000+
return false;
1001+
1002+
switch (type)
1003+
{
1004+
case HardwareExecuteBreakpoint:
1005+
{
1006+
// Use LLDB command to set hardware execution breakpoint
1007+
std::string command = fmt::format("breakpoint set --address 0x{:x} -H", address);
1008+
auto result = InvokeBackendCommand(command);
1009+
return result.find("Breakpoint") != std::string::npos;
1010+
}
1011+
case HardwareReadBreakpoint:
1012+
{
1013+
// Use LLDB watchpoint command for read
1014+
std::string command = fmt::format("watchpoint set expression -w read -s {} -- 0x{:x}", size, address);
1015+
auto result = InvokeBackendCommand(command);
1016+
return result.find("Watchpoint") != std::string::npos;
1017+
}
1018+
case HardwareWriteBreakpoint:
1019+
{
1020+
// Use LLDB watchpoint command for write
1021+
std::string command = fmt::format("watchpoint set expression -w write -s {} -- 0x{:x}", size, address);
1022+
auto result = InvokeBackendCommand(command);
1023+
return result.find("Watchpoint") != std::string::npos;
1024+
}
1025+
case HardwareAccessBreakpoint:
1026+
{
1027+
// Use LLDB watchpoint command for read/write
1028+
std::string command = fmt::format("watchpoint set expression -w read_write -s {} -- 0x{:x}", size, address);
1029+
auto result = InvokeBackendCommand(command);
1030+
return result.find("Watchpoint") != std::string::npos;
1031+
}
1032+
default:
1033+
return false;
1034+
}
1035+
}
1036+
1037+
1038+
bool LldbAdapter::RemoveHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size)
1039+
{
1040+
if (!m_targetActive)
1041+
return false;
1042+
1043+
switch (type)
1044+
{
1045+
case HardwareExecuteBreakpoint:
1046+
{
1047+
// Find and delete hardware breakpoint at address
1048+
for (size_t i = 0; i < m_target.GetNumBreakpoints(); i++)
1049+
{
1050+
auto bp = m_target.GetBreakpointAtIndex(i);
1051+
if (bp.IsHardware())
1052+
{
1053+
for (size_t j = 0; j < bp.GetNumLocations(); j++)
1054+
{
1055+
auto location = bp.GetLocationAtIndex(j);
1056+
auto bpAddress = location.GetAddress().GetLoadAddress(m_target);
1057+
if (address == bpAddress)
1058+
{
1059+
return m_target.BreakpointDelete(bp.GetID());
1060+
}
1061+
}
1062+
}
1063+
}
1064+
return false;
1065+
}
1066+
case HardwareReadBreakpoint:
1067+
case HardwareWriteBreakpoint:
1068+
case HardwareAccessBreakpoint:
1069+
{
1070+
// Find and delete watchpoint at address
1071+
for (size_t i = 0; i < m_target.GetNumWatchpoints(); i++)
1072+
{
1073+
auto wp = m_target.GetWatchpointAtIndex(i);
1074+
if (wp.GetWatchAddress() == address)
1075+
{
1076+
return m_target.DeleteWatchpoint(wp.GetID());
1077+
}
1078+
}
1079+
return false;
1080+
}
1081+
default:
1082+
return false;
1083+
}
1084+
}
1085+
1086+
9871087
static intx::uint512 SBValueToUint512(lldb::SBValue& reg_val) {
9881088
using namespace lldb;
9891089
using namespace intx;

core/adapters/lldbadapter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ namespace BinaryNinjaDebugger {
9494

9595
std::vector<DebugBreakpoint> GetBreakpointList() const override;
9696

97+
// Hardware breakpoint and watchpoint support
98+
bool AddHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size = 1) override;
99+
bool RemoveHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size = 1) override;
100+
97101
std::unordered_map<std::string, DebugRegister> ReadAllRegisters() override;
98102

99103
DebugRegister ReadRegister(const std::string& reg) override;

core/debugadapter.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,17 @@ bool DebugAdapter::SetTTDPosition(const TTDPosition& position)
205205
// Default implementation returns false for adapters that don't support TTD
206206
return false;
207207
}
208+
209+
210+
bool DebugAdapter::AddHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size)
211+
{
212+
// Default implementation returns false for adapters that don't support hardware breakpoints
213+
return false;
214+
}
215+
216+
217+
bool DebugAdapter::RemoveHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size)
218+
{
219+
// Default implementation returns false for adapters that don't support hardware breakpoints
220+
return false;
221+
}

core/debugadapter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,10 @@ namespace BinaryNinjaDebugger {
264264

265265
virtual std::vector<DebugBreakpoint> GetBreakpointList() const = 0;
266266

267+
// Hardware breakpoint and watchpoint support
268+
virtual bool AddHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size = 1);
269+
virtual bool RemoveHardwareBreakpoint(uint64_t address, DebugBreakpointType type, size_t size = 1);
270+
267271
virtual std::unordered_map<std::string, DebugRegister> ReadAllRegisters() = 0;
268272

269273
virtual DebugRegister ReadRegister(const std::string& reg) = 0;

core/debuggercommon.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,14 @@ namespace BinaryNinjaDebugger {
152152

153153
TTDCallEvent() : threadId(0), uniqueThreadId(0), functionAddress(0), returnAddress(0), returnValue(0), hasReturnValue(false) {}
154154
};
155+
156+
// Breakpoint types - used to specify the type of breakpoint to set
157+
enum DebugBreakpointType
158+
{
159+
SoftwareBreakpoint = 0, // Default software breakpoint
160+
HardwareExecuteBreakpoint = 1, // Hardware execution breakpoint
161+
HardwareReadBreakpoint = 2, // Hardware read watchpoint
162+
HardwareWriteBreakpoint = 3, // Hardware write watchpoint
163+
HardwareAccessBreakpoint = 4 // Hardware read/write watchpoint
164+
};
155165
}; // namespace BinaryNinjaDebugger

0 commit comments

Comments
 (0)