How to set a gdb breakpoint on a label in all template function instantiations

799 views Asked by At

Suppose I have the following C++:

template <int I> int bar(int i) {
  ++i;
label1:
  return I * i;
}
int main(int argc, char **) { return bar<2>(argc); }

Is it possible to set a gdb breakpoint on label1 for all instantiations of bar? In the above, it is easy -- there is just one instantiation. In my actual use case there are a large number spread all over the code base.

Said another way, in my gdb commandfile, is there a way to avoid the need to know a priori about every template instantiation of bar? In my actual use case, my aim is to emit some information about program state at the point of the labels (worry not, no programs were harmed by goto).

I know I can set a breakpoint on the label for a specific instantiation of bar as follows:

break -function bar<2> -label label1

I also know about rbreak which can be used to break on the entry of all template functions, but apparently does not have the -label option. I don't want to break on the entry point -- just the the label(s). I also looked to see if I could combine rbreak with until label1 but that didn't work.

Two other approaches I've considered are:

  1. grep for the labels (or could even just be specially formed comments), emit line numbers and use this information to populate/generate my gdb command file with source file and line number break points. This will definitely work, but was sort of hoping to avoid the need to "generate" my command file.
  2. Since I intend to implement some gdb Python pretty printers, perhaps I can parse the source from within python to get the line numbers and subsequently set the breakpoints. I'm just learning the Python API and it wasn't immediately obvious how to get the equivalent of list from within the gdb python package.

Any suggestions?

2

There are 2 answers

0
Employed Russian On

This answer shows how to iterate over all global symbols in a program.

For your test program, it yields:

bar<2>(int) True
main(int, char**) True

From here, you can easily find all instantiations of bar<>(), and set breakpoints on them using Python breakpoints API.

(gdb) py
>gdb.Breakpoint(function='bar<2>(int)', label='label1')
Breakpoint 1 at 0x1158: file t.cc, line 3.

Using function='bar<2>' also works.

0
Luke Peterson On

Per the suggestion from Employed Russian, I came up with the following gdb python script:

import re


class Custombreakpoint(gdb.Breakpoint):
    def __init__(self, function, label):
        super().__init__(function=function, label=label, internal=True)

    def stop(self):
        I = gdb.parse_and_eval("I")
        i = gdb.parse_and_eval("i")
        print(f"I = {I}, i = {i}")
        return False

pattern = re.compile('.*foo.*')
for sym in gdb.lookup_global_symbol('main').symtab.global_block():
    if sym.is_function:
        match = pattern.search(sym.name)
        if match:
            Custombreakpoint(function=match.string, label='label1')

gdb.execute('run')
gdb.execute('quit')

Which yields the following output:

$ g++ -g ./test.cc && gdb --command=test.py ./a.out                                                                                                                                      
Reading symbols from ./a.out...                                                                                                                                                                                      
I = 2, i = 2                                                                                                                                                                                                         
I = 3, i = 2                                                                                                                                                                                                         
[Inferior 1 (process 17224) exited with code 012]

This will allow me to do exactly what I want to do in my actual use case. Thanks for the help!