https://github.com/jimingham updated https://github.com/llvm/llvm-project/pull/171236
>From b9ebcb580ea13ee2f1a6491e03249062889eb12d Mon Sep 17 00:00:00 2001 From: Jim Ingham <[email protected]> Date: Mon, 8 Dec 2025 16:26:51 -0800 Subject: [PATCH 1/2] Add a _regexp-break-add and some more tests for the b alias. This commit leaves "b" aliased to the old _regexp-break for now. --- .../source/Interpreter/CommandInterpreter.cpp | 90 ++++++++++++++++++- .../TestRegexpBreakCommand.py | 33 +++++-- .../API/terminal/TestEditlineCompletions.py | 2 +- 3 files changed, 117 insertions(+), 8 deletions(-) diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index ffcc9ceeb2a93..28b868da26740 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -316,6 +316,11 @@ void CommandInterpreter::Initialize() { AddAlias("continue", cmd_obj_sp); } + // At this point, I'm leaving "b" command aliased to "_regexp-break". There's + // a catch-all regexp in the command that takes any unrecognized input and + // runs it as `break set <input>` and switching the command to break add + // would change that behavior. People who want to use the break add for the + // "b" alias can do so in their .lldbinit. cmd_obj_sp = GetCommandSPExact("_regexp-break"); if (cmd_obj_sp) AddAlias("b", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); @@ -610,7 +615,7 @@ void CommandInterpreter::LoadCommandDictionary() { {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$", "breakpoint set --name '%1'"}}; // clang-format on - + size_t num_regexes = std::size(break_regexes); std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_up( @@ -668,6 +673,89 @@ void CommandInterpreter::LoadCommandDictionary() { } } + // clang-format off + // FIXME: It would be simpler to just use the linespec's directly here, but + // the `b` alias allows "foo.c : 12 : 45" but the linespec parser + // is more rigorous, and doesn't strip spaces, so the two are not equivalent. + const char *break_add_regexes[][2] = { + {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", + "breakpoint add file --file '%1' --line %2 --column %3"}, + {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", + "breakpoint add file --file '%1' --line %2"}, + {"^/([^/]+)/$", "breakpoint add pattern -- %1"}, + {"^([[:digit:]]+)[[:space:]]*$", + "breakpoint add file --line %1"}, + {"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", + "breakpoint add address %1"}, + {"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$", + "breakpoint add name '%1'"}, + {"^(-.*)$", + "breakpoint add name '%1'"}, + {"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$", + "breakpoint add name '%2' --shlib '%1'"}, + {"^\\&(.*[^[:space:]])[[:space:]]*$", + "breakpoint add name '%1' --skip-prologue=0"}, + {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$", + "breakpoint add name '%1'"}}; + // clang-format on + + size_t num_add_regexes = std::size(break_add_regexes); + + std::unique_ptr<CommandObjectRegexCommand> break_add_regex_cmd_up( + new CommandObjectRegexCommand( + *this, "_regexp-break-add", + "Set a breakpoint using one of several shorthand formats, or list " + "the existing breakpoints if no arguments are provided.", + "\n" + "_regexp-break-add <filename>:<linenum>:<colnum>\n" + " main.c:12:21 // Break at line 12 and column " + "21 of main.c\n\n" + "_regexp-break-add <filename>:<linenum>\n" + " main.c:12 // Break at line 12 of " + "main.c\n\n" + "_regexp-break-add <linenum>\n" + " 12 // Break at line 12 of current " + "file\n\n" + "_regexp-break-add 0x<address>\n" + " 0x1234000 // Break at address " + "0x1234000\n\n" + "_regexp-break-add <name>\n" + " main // Break in 'main' after the " + "prologue\n\n" + "_regexp-break-add &<name>\n" + " &main // Break at first instruction " + "in 'main'\n\n" + "_regexp-break-add <module>`<name>\n" + " libc.so`malloc // Break in 'malloc' from " + "'libc.so'\n\n" + "_regexp-break-add /<source-regex>/\n" + " /break here/ // Break on source lines in " + "current file\n" + " // containing text 'break " + "here'.\n" + "_regexp-break-add\n" + " // List the existing " + "breakpoints\n", + lldb::eSymbolCompletion | lldb::eSourceFileCompletion, false)); + + if (break_add_regex_cmd_up) { + bool success = true; + for (size_t i = 0; i < num_add_regexes; i++) { + success = break_add_regex_cmd_up->AddRegexCommand(break_add_regexes[i][0], + break_add_regexes[i][1]); + if (!success) + break; + } + success = + break_add_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full"); + + if (success) { + CommandObjectSP break_add_regex_cmd_sp(break_add_regex_cmd_up.release()); + m_command_dict[std::string(break_add_regex_cmd_sp->GetCommandName())] = + break_add_regex_cmd_sp; + } + } + std::unique_ptr<CommandObjectRegexCommand> tbreak_regex_cmd_up( new CommandObjectRegexCommand( *this, "_regexp-tbreak", diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestRegexpBreakCommand.py b/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestRegexpBreakCommand.py index 235a41d1adef3..adece955a492f 100644 --- a/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestRegexpBreakCommand.py +++ b/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestRegexpBreakCommand.py @@ -10,11 +10,16 @@ class RegexpBreakCommandTestCase(TestBase): - def test(self): + def test_set_version(self): """Test _regexp-break command.""" self.build() - self.regexp_break_command() + self.regexp_break_command("_regexp-break") + def test_add_version(self): + """Test _regexp-break-add command.""" + self.build() + self.regexp_break_command("_regexp-break-add") + def setUp(self): # Call super's setUp(). TestBase.setUp(self) @@ -22,12 +27,12 @@ def setUp(self): self.source = "main.c" self.line = line_number(self.source, "// Set break point at this line.") - def regexp_break_command(self): + def regexp_break_command(self, cmd_name): """Test the super consie "b" command, which is analias for _regexp-break.""" exe = self.getBuildArtifact("a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) - break_results = lldbutil.run_break_set_command(self, "b %d" % self.line) + break_results = lldbutil.run_break_set_command(self, f"{cmd_name} {self.line}") lldbutil.check_breakpoint_result( self, break_results, @@ -37,7 +42,7 @@ def regexp_break_command(self): ) break_results = lldbutil.run_break_set_command( - self, "b %s:%d" % (self.source, self.line) + self, f"{cmd_name} {self.source}:{self.line}" ) lldbutil.check_breakpoint_result( self, @@ -50,7 +55,7 @@ def regexp_break_command(self): # Check breakpoint with full file path. full_path = os.path.join(self.getSourceDir(), self.source) break_results = lldbutil.run_break_set_command( - self, "b %s:%d" % (full_path, self.line) + self, f"{cmd_name} {full_path}:{self.line}" ) lldbutil.check_breakpoint_result( self, @@ -60,6 +65,22 @@ def regexp_break_command(self): num_locations=1, ) + # Check breakpoint with symbol name. I'm also passing in + # the module so I can check the number of locations. + exe_spec = lldb.SBFileSpec(exe) + exe_filename = exe_spec.basename + cmd = f"{cmd_name} {exe_filename}`main" + print(f"About to run: '{cmd}'") + break_results = lldbutil.run_break_set_command( + self, cmd + ) + lldbutil.check_breakpoint_result( + self, + break_results, + symbol_name="main", + num_locations=1 + ) + self.runCmd("run", RUN_SUCCEEDED) # The stop reason of the thread should be breakpoint. diff --git a/lldb/test/API/terminal/TestEditlineCompletions.py b/lldb/test/API/terminal/TestEditlineCompletions.py index b4ea0f39ec10c..ac1d3f90e2970 100644 --- a/lldb/test/API/terminal/TestEditlineCompletions.py +++ b/lldb/test/API/terminal/TestEditlineCompletions.py @@ -72,11 +72,11 @@ def test_completion_pagination(self): self.child.expect("Available completions:") self.child.expect(" _regexp-attach") self.child.expect(" _regexp-break") + self.child.expect(" _regexp-break-add") self.child.expect(" _regexp-bt") self.child.expect(" _regexp-display") self.child.expect(" _regexp-down") self.child.expect(" _regexp-env") - self.child.expect(" _regexp-jump") self.child.expect("More") @skipIfAsan >From 65c4a750f57d1f759dd7f1897c3f82d1ab4a1062 Mon Sep 17 00:00:00 2001 From: Jim Ingham <[email protected]> Date: Mon, 8 Dec 2025 16:45:45 -0800 Subject: [PATCH 2/2] formatting --- lldb/source/Interpreter/CommandInterpreter.cpp | 8 ++++---- .../breakpoint_command/TestRegexpBreakCommand.py | 11 +++-------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index 28b868da26740..188b5f407cb40 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -318,7 +318,7 @@ void CommandInterpreter::Initialize() { // At this point, I'm leaving "b" command aliased to "_regexp-break". There's // a catch-all regexp in the command that takes any unrecognized input and - // runs it as `break set <input>` and switching the command to break add + // runs it as `break set <input>` and switching the command to break add // would change that behavior. People who want to use the break add for the // "b" alias can do so in their .lldbinit. cmd_obj_sp = GetCommandSPExact("_regexp-break"); @@ -615,7 +615,7 @@ void CommandInterpreter::LoadCommandDictionary() { {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$", "breakpoint set --name '%1'"}}; // clang-format on - + size_t num_regexes = std::size(break_regexes); std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_up( @@ -741,8 +741,8 @@ void CommandInterpreter::LoadCommandDictionary() { if (break_add_regex_cmd_up) { bool success = true; for (size_t i = 0; i < num_add_regexes; i++) { - success = break_add_regex_cmd_up->AddRegexCommand(break_add_regexes[i][0], - break_add_regexes[i][1]); + success = break_add_regex_cmd_up->AddRegexCommand( + break_add_regexes[i][0], break_add_regexes[i][1]); if (!success) break; } diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestRegexpBreakCommand.py b/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestRegexpBreakCommand.py index adece955a492f..930d497032171 100644 --- a/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestRegexpBreakCommand.py +++ b/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestRegexpBreakCommand.py @@ -19,7 +19,7 @@ def test_add_version(self): """Test _regexp-break-add command.""" self.build() self.regexp_break_command("_regexp-break-add") - + def setUp(self): # Call super's setUp(). TestBase.setUp(self) @@ -71,14 +71,9 @@ def regexp_break_command(self, cmd_name): exe_filename = exe_spec.basename cmd = f"{cmd_name} {exe_filename}`main" print(f"About to run: '{cmd}'") - break_results = lldbutil.run_break_set_command( - self, cmd - ) + break_results = lldbutil.run_break_set_command(self, cmd) lldbutil.check_breakpoint_result( - self, - break_results, - symbol_name="main", - num_locations=1 + self, break_results, symbol_name="main", num_locations=1 ) self.runCmd("run", RUN_SUCCEEDED) _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
