Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to step debug into std::function user code from C++ functional with GDB?

Tags:

c++

gdb

For example, with:

#include <functional>
#include <iostream>

int myfunc(int i){ return i + 1; }

int main() {
    std::function<int(int)> f = myfunc;
    int i = f(1);
    std::cout << i << std::endl;
}

compiled with:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp

if I try to do a step into the call f(1), then it first leads me in to C++ standard library code, and I either have to think really hard and do the right next/step sequence, or be dumb and hit step 17 times before reaching the actual myfunc call.

Is there an easier way to go about this, maybe with some existing GDB/Python script?

This was basically done by Microsoft people for Visual Studio as mentioned at: https://devblogs.microsoft.com/cppblog/improving-the-debugging-experience-for-stdfunction/

I like it that is is possible to step into the stdlibc++ by default in Ubuntu and have already used it before, but it would be awesome if GDB could step into std::function user code by default, and have some other mechanism to go into libstdc++ for this specific case.

I'm tempted to go a bit cheeky and just use the following Python GDB script that repeats a command n times: gdb - perform a command n times which allows me to do:

repeat-cmd 17 s

Related: QtCreator debugger: step into std::function

Tested in Ubuntu 18.04, GDB 8.1, GCC 7.4.


People also ask

How do I go to a specific function in GDB?

To execute one line of code, type "step" or "s". If the line to be executed is a function call, gdb will step into that function and start executing its code one line at a time. If you want to execute the entire function with one keypress, type "next" or "n".

Can I call a function in GDB?

To call a function in the program, GDB has to temporarily modify the state of the inferior. This has potentially undesired side effects. Also, having GDB call nested functions is likely to be erroneous and may even crash the program being debugged.


1 Answers

The first thing which will not work in your use case is

gdb skip -gfile bits/*.h

As you already mentioned, this will skip also over your code which was called from within the std library.

Next idea: Skipping over functions with "known name". As we have typically std:: in front of the function name a used the following .gdbinit. It looks much better:

sys.path.insert(0, '/usr/share/gcc-9/python/')
from libstdcxx.v6.printers import register_libstdcxx_printers
register_libstdcxx_printers (None)

import gdb
import re

def stop_handler(event):
    frame_name = gdb.selected_frame().name();
    if re.search("(operator new.*)|(^__gnu_cxx::.*)|(^std::.*)", frame_name) != None:
        gdb.execute("step")

gdb.events.stop.connect(stop_handler)
end

I searched now a while to find something to get the current file/line-number combination into python but did not find anything. Is there any python access to the current file name and line number? If so, this will be much simpler in this case. Would be nice if someone can add some info's here!

Remark: in ddd that will work not very well, as an internal step from python will not be recognized by the gui. So the green arrow stays on the last stepped line and not the current one. If someone knows also a trick in such a case, any help is welcome!

UPDATE:

If you use the following as .gdbinit

python
import sys
sys.path.insert(0, '/usr/share/gcc-9/python/')
from libstdcxx.v6.printers import register_libstdcxx_printers
register_libstdcxx_printers (None)

import gdb
import re

def stop_handler(event):
    sal = gdb.selected_frame().find_sal()
    if sal == None:
        gdb.execute("step")
    else:
        symtab = sal.symtab;
        if symtab == None:
            gdb.execute("step")
        else:
            file_name = symtab.fullname();
            if re.search("(.*bits.*)", file_name ) != None:
                gdb.execute("step")

gdb.events.stop.connect(stop_handler)
end

Everything works perfectly on my pc. As an additional hint: If using ddd, you can open the backtrace window and then the green arrow will follow also the python internal gdb steps. That works perfectly for me! Thanks for the question! :-)

Maybe the regexp can be updated to fit for filtering more external libs or to be more selective.

like image 131
Klaus Avatar answered Oct 03 '22 19:10

Klaus