Don't let exception terminate 'rbreak'

'rbreak' searches symbols and then sets a number of breakpoints.  If
setting one of the breakpoints fails, then 'rbreak' will terminate
before examining the remaining symbols.

However, it seems to me that it is better for 'rbreak' to keep going
in this situation.  That is what this patch implements.

This problem can be seen by writing an Ada program that uses "pragma
import" to reference a symbol that does not have debug info.  In this
case, the program will link but setting a breakpoint on the imported
name will not work.

I don't think it's possible to write a reliable test for this, as it
depends on the order in which symtabs are examined.

New in v2: rbreak now shows how many breakpoints it made and also how
many errors it encountered.

Regression tested on x86-64 Fedora 40.

Approved-By: Andrew Burgess <aburgess@redhat.com>
This commit is contained in:
Tom Tromey
2024-05-24 10:51:02 -06:00
parent 72491a6a7e
commit 59d25b31eb
7 changed files with 78 additions and 19 deletions

View File

@@ -869,6 +869,24 @@ scoped_rbreak_breakpoints::~scoped_rbreak_breakpoints ()
prev_breakpoint_count = rbreak_start_breakpoint_count;
}
/* See breakpoint.h. */
int
scoped_rbreak_breakpoints::first_breakpoint () const
{
return rbreak_start_breakpoint_count + 1;
}
/* See breakpoint.h. */
int
scoped_rbreak_breakpoints::last_breakpoint () const
{
return (rbreak_start_breakpoint_count == breakpoint_count
? -1
: breakpoint_count);
}
/* Used in run_command to zero the hit count when a new run starts. */
void

View File

@@ -1970,6 +1970,14 @@ public:
scoped_rbreak_breakpoints ();
~scoped_rbreak_breakpoints ();
/* Return the number of first breakpoint made while this object is
in scope. */
int first_breakpoint () const;
/* Return the number of the most recent breakpoint made while this
object is in scope, or -1 if no breakpoints were made. */
int last_breakpoint () const;
DISABLE_COPY_AND_ASSIGN (scoped_rbreak_breakpoints);
};

View File

@@ -46,6 +46,7 @@
#include "fnmatch.h"
#include "hashtab.h"
#include "typeprint.h"
#include "exceptions.h"
#include "gdbsupport/gdb_obstack.h"
#include "block.h"
@@ -5615,28 +5616,53 @@ rbreak_command (const char *regexp, int from_tty)
std::vector<symbol_search> symbols = spec.search ();
scoped_rbreak_breakpoints finalize;
int err_count = 0;
for (const symbol_search &p : symbols)
{
if (p.msymbol.minsym == NULL)
try
{
struct symtab *symtab = p.symbol->symtab ();
const char *fullname = symtab_to_fullname (symtab);
if (p.msymbol.minsym == NULL)
{
struct symtab *symtab = p.symbol->symtab ();
const char *fullname = symtab_to_fullname (symtab);
string = string_printf ("%s:'%s'", fullname,
p.symbol->linkage_name ());
break_command (&string[0], from_tty);
print_symbol_info (p.symbol, p.block, nullptr);
string = string_printf ("%s:'%s'", fullname,
p.symbol->linkage_name ());
break_command (&string[0], from_tty);
print_symbol_info (p.symbol, p.block, nullptr);
}
else
{
string = string_printf ("'%s'",
p.msymbol.minsym->linkage_name ());
break_command (&string[0], from_tty);
gdb_printf ("<function, no debug info> %s;\n",
p.msymbol.minsym->print_name ());
}
}
else
catch (const gdb_exception_error &ex)
{
string = string_printf ("'%s'",
p.msymbol.minsym->linkage_name ());
break_command (&string[0], from_tty);
gdb_printf ("<function, no debug info> %s;\n",
p.msymbol.minsym->print_name ());
exception_print (gdb_stderr, ex);
++err_count;
}
}
int first_bp = finalize.first_breakpoint ();
int last_bp = finalize.last_breakpoint ();
if (last_bp == -1)
gdb_printf (_("No breakpoints made.\n"));
else if (first_bp == last_bp)
gdb_printf (_("Successfully created breakpoint %d.\n"), first_bp);
else
gdb_printf (_("Successfully created breakpoints %d-%d.\n"),
first_bp, last_bp);
if (err_count > 0)
gdb_printf (_("%d breakpoints failed due to errors, see above.\n"),
err_count);
}

View File

@@ -153,7 +153,8 @@ foreach_with_prefix language_choice { "auto" "ada" "c" } {
"Breakpoint.*file .*proc_in_ada.adb,.*" \
$rbreak_func_in_ada($ada_match) \
"Breakpoint.*file .*some_c.c,.*" \
$rbreak_func_in_c($c_match)
$rbreak_func_in_c($c_match) \
"Successfully created breakpoints $decimal-$decimal."
]
delete_breakpoints
}

View File

@@ -525,7 +525,7 @@ if $use_gdb_stub {
}
#test rbreak
gdb_test "rbreak" "rbreak"
gdb_test "rbreak" "No breakpoints made."
# test restore
gdb_test "restore" "You can't do that without a process to debug\."

View File

@@ -41,7 +41,12 @@ if { $result != 0 || $realsrcfile2 == "" } {
clean_restart ${testfile}
gdb_test "rbreak $realsrcfile2:func" "^Breakpoint 1 at 0x\[0-9a-f\]+: file [string_to_regexp ${subdir}/${srcfile2}], line \[0-9\]+\\.\r\nvoid func\\(void\\);" "rbreak XXX/fullpath-expand-func.c:func"
gdb_test "rbreak $realsrcfile2:func" \
[multi_line \
"Breakpoint 1 at 0x\[0-9a-f\]+: file [string_to_regexp ${subdir}/${srcfile2}], line \[0-9\]+\\." \
"void func\\(void\\);" \
"Successfully created breakpoint 1."] \
"rbreak XXX/fullpath-expand-func.c:func"
# Verify the compilation pathnames are as expected:
gdb_test "list func" "\tfunc \\(void\\)\r\n.*"

View File

@@ -41,8 +41,9 @@ gdb_test_no_output "set basenames-may-differ on"
gdb_test "rbreak realname-expand-real.c:func" \
[multi_line "" \
"Breakpoint 1 at $hex: file \[^\r\n\]*/realname-expand-link\\.c, line $decimal\\." \
"void func\\(void\\);"]
"Breakpoint 1 at $hex: file \[^\r\n\]*/realname-expand-link\\.c, line $decimal\\." \
"void func\\(void\\);" \
"Successfully created breakpoint 1."]
delete_breakpoints