Skip to content

Commit bc7dc52

Browse files
Copilotxusheng6
andcommitted
Refine enable/disable breakpoint actions and disabled breakpoint rendering
1. Merge Enable/Disable actions into dynamic single action that changes name based on breakpoint state 2. Add Solo Breakpoint action to context menu 3. Change disabled breakpoint rendering to show "🛑︎" tag without line highlighting 4. Handle case where IP and disabled breakpoint are on same line (shows "🛑︎➞" with IP highlighting) Co-authored-by: xusheng6 <[email protected]>
1 parent 66c75e5 commit bc7dc52

File tree

2 files changed

+196
-41
lines changed

2 files changed

+196
-41
lines changed

ui/renderlayer.cpp

Lines changed: 114 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,18 @@ void DebuggerRenderLayer::ApplyToBlock(Ref<BasicBlock> block, std::vector<Disass
5353
continue;
5454

5555
bool hasPC = (line.addr == ipAddr) && paused;
56-
// Only render enabled breakpoints
57-
bool hasBreakpoint = false;
56+
bool hasEnabledBreakpoint = false;
57+
bool hasDisabledBreakpoint = false;
58+
5859
if (breakpointEnabledMap.count(line.addr) > 0)
5960
{
60-
hasBreakpoint = breakpointEnabledMap[line.addr];
61+
if (breakpointEnabledMap[line.addr])
62+
hasEnabledBreakpoint = true;
63+
else
64+
hasDisabledBreakpoint = true;
6165
}
6266

63-
if (hasPC && hasBreakpoint)
67+
if (hasPC && hasEnabledBreakpoint)
6468
{
6569
bool appliedTag = false;
6670
for (size_t i = 0; i < line.tokens.size(); i++)
@@ -87,6 +91,34 @@ void DebuggerRenderLayer::ApplyToBlock(Ref<BasicBlock> block, std::vector<Disass
8791
line.highlight.b = 0;
8892
line.highlight.alpha = 255;
8993
}
94+
else if (hasPC && hasDisabledBreakpoint)
95+
{
96+
// PC at a disabled breakpoint - show both indicators, no breakpoint highlighting
97+
bool appliedTag = false;
98+
for (size_t i = 0; i < line.tokens.size(); i++)
99+
{
100+
if (line.tokens[i].type == TagToken)
101+
{
102+
line.tokens[i].text = "🛑︎➞";
103+
appliedTag = true;
104+
break;
105+
}
106+
}
107+
if (!appliedTag)
108+
{
109+
InstructionTextToken indicator(BNInstructionTextTokenType::TagToken, "🛑︎➞");
110+
line.tokens.insert(line.tokens.begin(), indicator);
111+
}
112+
113+
line.highlight.style = StandardHighlightColor;
114+
line.highlight.color = BlueHighlightColor;
115+
line.highlight.mixColor = NoHighlightColor;
116+
line.highlight.mix = 0;
117+
line.highlight.r = 0;
118+
line.highlight.g = 0;
119+
line.highlight.b = 0;
120+
line.highlight.alpha = 255;
121+
}
90122
else if (hasPC)
91123
{
92124
bool appliedTag = false;
@@ -114,7 +146,7 @@ void DebuggerRenderLayer::ApplyToBlock(Ref<BasicBlock> block, std::vector<Disass
114146
line.highlight.b = 0;
115147
line.highlight.alpha = 255;
116148
}
117-
else if (hasBreakpoint)
149+
else if (hasEnabledBreakpoint)
118150
{
119151
bool appliedTag = false;
120152
for (size_t i = 0; i < line.tokens.size(); i++)
@@ -141,6 +173,26 @@ void DebuggerRenderLayer::ApplyToBlock(Ref<BasicBlock> block, std::vector<Disass
141173
line.highlight.b = 0;
142174
line.highlight.alpha = 255;
143175
}
176+
else if (hasDisabledBreakpoint)
177+
{
178+
// Disabled breakpoint - show tag but no line highlighting
179+
bool appliedTag = false;
180+
for (size_t i = 0; i < line.tokens.size(); i++)
181+
{
182+
if (line.tokens[i].type == TagToken)
183+
{
184+
line.tokens[i].text = "…🛑︎";
185+
appliedTag = true;
186+
break;
187+
}
188+
}
189+
if (!appliedTag)
190+
{
191+
InstructionTextToken indicator(BNInstructionTextTokenType::TagToken, "🛑︎");
192+
line.tokens.insert(line.tokens.begin(), indicator);
193+
}
194+
// No line highlighting for disabled breakpoints
195+
}
144196
}
145197
}
146198

@@ -167,14 +219,18 @@ void DebuggerRenderLayer::ApplyToHighLevelILBody(Ref<Function> function, std::ve
167219
{
168220
DisassemblyTextLine& line = linearLine.contents;
169221
bool hasPC = (line.addr == ipAddr) && paused;
170-
// Only render enabled breakpoints
171-
bool hasBreakpoint = false;
222+
bool hasEnabledBreakpoint = false;
223+
bool hasDisabledBreakpoint = false;
224+
172225
if (breakpointEnabledMap.count(line.addr) > 0)
173226
{
174-
hasBreakpoint = breakpointEnabledMap[line.addr];
227+
if (breakpointEnabledMap[line.addr])
228+
hasEnabledBreakpoint = true;
229+
else
230+
hasDisabledBreakpoint = true;
175231
}
176232

177-
if (hasPC && hasBreakpoint)
233+
if (hasPC && hasEnabledBreakpoint)
178234
{
179235
bool appliedTag = false;
180236
for (size_t i = 0; i < line.tokens.size(); i++)
@@ -201,6 +257,34 @@ void DebuggerRenderLayer::ApplyToHighLevelILBody(Ref<Function> function, std::ve
201257
line.highlight.b = 0;
202258
line.highlight.alpha = 255;
203259
}
260+
else if (hasPC && hasDisabledBreakpoint)
261+
{
262+
// PC at a disabled breakpoint - show both indicators, no breakpoint highlighting
263+
bool appliedTag = false;
264+
for (size_t i = 0; i < line.tokens.size(); i++)
265+
{
266+
if (line.tokens[i].type == TagToken)
267+
{
268+
line.tokens[i].text = "🛑︎➞";
269+
appliedTag = true;
270+
break;
271+
}
272+
}
273+
if (!appliedTag)
274+
{
275+
InstructionTextToken indicator(BNInstructionTextTokenType::TagToken, "🛑︎➞");
276+
line.tokens.insert(line.tokens.begin(), indicator);
277+
}
278+
279+
line.highlight.style = StandardHighlightColor;
280+
line.highlight.color = BlueHighlightColor;
281+
line.highlight.mixColor = NoHighlightColor;
282+
line.highlight.mix = 0;
283+
line.highlight.r = 0;
284+
line.highlight.g = 0;
285+
line.highlight.b = 0;
286+
line.highlight.alpha = 255;
287+
}
204288
else if (hasPC)
205289
{
206290
bool appliedTag = false;
@@ -228,7 +312,7 @@ void DebuggerRenderLayer::ApplyToHighLevelILBody(Ref<Function> function, std::ve
228312
line.highlight.b = 0;
229313
line.highlight.alpha = 255;
230314
}
231-
else if (hasBreakpoint)
315+
else if (hasEnabledBreakpoint)
232316
{
233317
bool appliedTag = false;
234318
for (size_t i = 0; i < line.tokens.size(); i++)
@@ -255,6 +339,26 @@ void DebuggerRenderLayer::ApplyToHighLevelILBody(Ref<Function> function, std::ve
255339
line.highlight.b = 0;
256340
line.highlight.alpha = 255;
257341
}
342+
else if (hasDisabledBreakpoint)
343+
{
344+
// Disabled breakpoint - show tag but no line highlighting
345+
bool appliedTag = false;
346+
for (size_t i = 0; i < line.tokens.size(); i++)
347+
{
348+
if (line.tokens[i].type == TagToken)
349+
{
350+
line.tokens[i].text = "…🛑︎";
351+
appliedTag = true;
352+
break;
353+
}
354+
}
355+
if (!appliedTag)
356+
{
357+
InstructionTextToken indicator(BNInstructionTextTokenType::TagToken, "🛑︎");
358+
line.tokens.insert(line.tokens.begin(), indicator);
359+
}
360+
// No line highlighting for disabled breakpoints
361+
}
258362
}
259363
}
260364

ui/ui.cpp

Lines changed: 82 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -811,38 +811,25 @@ void GlobalDebuggerUI::SetupMenu(UIContext* context)
811811
requireBinaryView));
812812
debuggerMenu->addAction("Toggle Breakpoint", "Breakpoint");
813813

814-
// Helper function to check if there's an enabled breakpoint at the current address
815-
auto hasEnabledBreakpoint = [](BinaryView* view, uint64_t addr) -> bool {
814+
// Helper function to check if there's a breakpoint at the current address and return its enabled state
815+
auto getBreakpointEnabledState = [](BinaryView* view, uint64_t addr) -> std::pair<bool, bool> {
816816
auto controller = DebuggerController::GetController(view);
817817
if (!controller)
818-
return false;
819-
820-
std::vector<DebugBreakpoint> breakpoints = controller->GetBreakpoints();
821-
for (const auto& bp : breakpoints)
822-
{
823-
if (bp.address == addr)
824-
return bp.enabled;
825-
}
826-
return false;
827-
};
828-
829-
// Helper function to check if there's a disabled breakpoint at the current address
830-
auto hasDisabledBreakpoint = [](BinaryView* view, uint64_t addr) -> bool {
831-
auto controller = DebuggerController::GetController(view);
832-
if (!controller)
833-
return false;
818+
return {false, false}; // {hasBreakpoint, isEnabled}
834819

835820
std::vector<DebugBreakpoint> breakpoints = controller->GetBreakpoints();
836821
for (const auto& bp : breakpoints)
837822
{
838823
if (bp.address == addr)
839-
return !bp.enabled;
824+
return {true, bp.enabled};
840825
}
841-
return false;
826+
return {false, false};
842827
};
843828

844-
// Register "Enable Breakpoint" action (shown when breakpoint is disabled)
829+
// Register dynamic "Enable/Disable Breakpoint" action
845830
UIAction::registerAction("Enable Breakpoint");
831+
UIAction::registerAction("Disable Breakpoint");
832+
846833
context->globalActions()->bindAction("Enable Breakpoint",
847834
UIAction(
848835
[=](const UIActionContext& ctxt) {
@@ -852,26 +839,32 @@ void GlobalDebuggerUI::SetupMenu(UIContext* context)
852839
if (!controller)
853840
return;
854841

842+
auto [hasBreakpoint, isEnabled] = getBreakpointEnabledState(ctxt.binaryView, ctxt.address);
855843
bool isAbsoluteAddress = controller->IsConnected();
844+
856845
if (isAbsoluteAddress)
857846
{
858-
controller->EnableBreakpoint(ctxt.address);
847+
if (isEnabled)
848+
controller->DisableBreakpoint(ctxt.address);
849+
else
850+
controller->EnableBreakpoint(ctxt.address);
859851
}
860852
else
861853
{
862854
std::string filename = controller->GetInputFile();
863855
uint64_t offset = ctxt.address - controller->GetViewFileSegmentsStart();
864856
ModuleNameAndOffset info = {filename, offset};
865-
controller->EnableBreakpoint(info);
857+
if (isEnabled)
858+
controller->DisableBreakpoint(info);
859+
else
860+
controller->EnableBreakpoint(info);
866861
}
867862
},
868863
[=](const UIActionContext& ctxt) {
869-
return ctxt.binaryView && hasDisabledBreakpoint(ctxt.binaryView, ctxt.address);
864+
auto [hasBreakpoint, isEnabled] = getBreakpointEnabledState(ctxt.binaryView, ctxt.address);
865+
return ctxt.binaryView && hasBreakpoint && !isEnabled;
870866
}));
871-
debuggerMenu->addAction("Enable Breakpoint", "Breakpoint");
872-
873-
// Register "Disable Breakpoint" action (shown when breakpoint is enabled)
874-
UIAction::registerAction("Disable Breakpoint");
867+
875868
context->globalActions()->bindAction("Disable Breakpoint",
876869
UIAction(
877870
[=](const UIActionContext& ctxt) {
@@ -881,24 +874,82 @@ void GlobalDebuggerUI::SetupMenu(UIContext* context)
881874
if (!controller)
882875
return;
883876

877+
auto [hasBreakpoint, isEnabled] = getBreakpointEnabledState(ctxt.binaryView, ctxt.address);
884878
bool isAbsoluteAddress = controller->IsConnected();
879+
885880
if (isAbsoluteAddress)
886881
{
887-
controller->DisableBreakpoint(ctxt.address);
882+
if (isEnabled)
883+
controller->DisableBreakpoint(ctxt.address);
884+
else
885+
controller->EnableBreakpoint(ctxt.address);
888886
}
889887
else
890888
{
891889
std::string filename = controller->GetInputFile();
892890
uint64_t offset = ctxt.address - controller->GetViewFileSegmentsStart();
893891
ModuleNameAndOffset info = {filename, offset};
894-
controller->DisableBreakpoint(info);
892+
if (isEnabled)
893+
controller->DisableBreakpoint(info);
894+
else
895+
controller->EnableBreakpoint(info);
895896
}
896897
},
897898
[=](const UIActionContext& ctxt) {
898-
return ctxt.binaryView && hasEnabledBreakpoint(ctxt.binaryView, ctxt.address);
899+
auto [hasBreakpoint, isEnabled] = getBreakpointEnabledState(ctxt.binaryView, ctxt.address);
900+
return ctxt.binaryView && hasBreakpoint && isEnabled;
899901
}));
902+
903+
debuggerMenu->addAction("Enable Breakpoint", "Breakpoint");
900904
debuggerMenu->addAction("Disable Breakpoint", "Breakpoint");
901905

906+
// Register "Solo Breakpoint" action
907+
UIAction::registerAction("Solo Breakpoint");
908+
context->globalActions()->bindAction("Solo Breakpoint",
909+
UIAction(
910+
[=](const UIActionContext& ctxt) {
911+
if (!ctxt.binaryView)
912+
return;
913+
auto controller = DebuggerController::GetController(ctxt.binaryView);
914+
if (!controller)
915+
return;
916+
917+
// Get the current address breakpoint location
918+
bool isAbsoluteAddress = controller->IsConnected();
919+
ModuleNameAndOffset currentInfo;
920+
if (!isAbsoluteAddress)
921+
{
922+
std::string filename = controller->GetInputFile();
923+
uint64_t offset = ctxt.address - controller->GetViewFileSegmentsStart();
924+
currentInfo = {filename, offset};
925+
}
926+
927+
// Disable all breakpoints
928+
std::vector<DebugBreakpoint> breakpoints = controller->GetBreakpoints();
929+
for (const auto& bp : breakpoints)
930+
{
931+
ModuleNameAndOffset info;
932+
info.module = bp.module;
933+
info.offset = bp.offset;
934+
controller->DisableBreakpoint(info);
935+
}
936+
937+
// Enable the current breakpoint
938+
if (isAbsoluteAddress)
939+
{
940+
controller->EnableBreakpoint(ctxt.address);
941+
}
942+
else
943+
{
944+
controller->EnableBreakpoint(currentInfo);
945+
}
946+
},
947+
[=](const UIActionContext& ctxt) {
948+
auto [hasBreakpoint, isEnabled] = getBreakpointEnabledState(ctxt.binaryView, ctxt.address);
949+
return ctxt.binaryView && hasBreakpoint;
950+
}));
951+
debuggerMenu->addAction("Solo Breakpoint", "Breakpoint");
952+
902953
UIAction::registerAction("Connect to Debug Server");
903954
context->globalActions()->bindAction("Connect to Debug Server",
904955
UIAction(

0 commit comments

Comments
 (0)