17
//gdb-call-lambda.cpp 
#include <iostream>                                                             
                                                                                
void do_something(void) {                                                       
        std::cout << "blah blah" << std::endl;                                  
                                                                                
        auto lambda_func = [](void){                                            
                std::cout << "in lambda" << std::endl;                          
                return;                                                         
        };                                                                      
                                                                                
        lambda_func();                                                          
                                                                                
        std::cout << "..." << std::endl;                                        
                                                                                
        return;                                                                 
}                                                                               
                                                                                
int main(int argc, char **argv) {                                               
        do_something();                                                         
        return 0;                                                               
}

In this example program, if you compile (g++ gdb-call-lambda.cpp --std=c++11 -g) and then run it in gdb (gdb ./a.out), you can have GDB call any "normal" function. Example:

(gdb) break main
Breakpoint 1 at 0x4008e7: file gdb-call-lambda.cpp, line 20.
(gdb) r
Starting program: /home/keithb/dev/mytest/gdb-call-lambda/a.out 

Breakpoint 1, main (argc=1, argv=0x7fffffffdfb8) at gdb-call-lambda.cpp:20
20      do_something();
(gdb) call do_something()
blah blah
in lambda
...

However, if you then try to call the lambda:

(gdb) break do_something
Breakpoint 2 at 0x400891: file gdb-call-lambda.cpp, line 5.
(gdb) c
Continuing.

Breakpoint 2, do_something () at gdb-call-lambda.cpp:5
5       std::cout << "blah blah" << std::endl;
(gdb) n
blah blah
12      lambda_func();
(gdb) n
in lambda
14      std::cout << "..." << std::endl;
(gdb) call lambda_func()
Invalid data type for function to be called

GDB kinda freaks out. So my question is thus: how do you call a lambda in GDB? Asking GDB what it expects reveals nothing of interest when compared to a normal function:

(gdb) whatis lambda_func
type = __lambda0
(gdb) whatis do_something
type = void (void)

I went to see if lambda_func has any special members, eg a function pointer to call, akin to std::function and/or std::bind:

(gdb) print lambda_func
$1 = {<No data fields>}

No special members? Okay maybe it's just a glorified function pointer?

(gdb) call ((void (void)) lambda_func)()

Program received signal SIGSEGV, Segmentation fault.
0x00007fffffffdeaf in ?? ()
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on".
Evaluation of the expression containing the function
(at 0x0x7fffffffdeaf) will be abandoned.
When the function is done executing, GDB will silently stop.

So I'm not even 100% sure what order to pass any arguments or especially captured types.

I tried additionally call lambda_func.operator()(), call lambda_func::operator(), call lambda_func::operator()(), call __lambda0, call __lambda0(), call __lambda0::operator(), call __lambda0::operator()(), all to no avail.

A search on google reveals things about setting breakpoints in lambdas, but nothing on how to call those lambdas from the debugger.

For what it's worth, this is on Ubuntu 14.04 64-bit using g++ 4.8.2-19ubuntu1 and gdb 7.7-0ubuntu3.1

user202729
  • 3,358
  • 3
  • 25
  • 36
inetknght
  • 4,300
  • 1
  • 26
  • 52
  • Does calling `lambda_func.operator()` work? – John Jul 21 '14 at 23:12
  • It does not. I tried additionally `call lambda_func.operator()()`, `call lambda_func::operator()`, `call lambda_func::operator()()`, `call __lambda0`, `call __lambda0()`, call `__lambda0::operator()`, `call __lambda0::operator()()`, all to no avail. – inetknght Jul 21 '14 at 23:25
  • lldb gives a different error message: `error: call to a function '$_0::operator()() const' ('_ZNK3$_0clEv') that is not present in the target error: warning: function '::operator()' has internal linkage but is not defined error: The expression could not be prepared to run in the target` – tclamb Jul 22 '14 at 17:25
  • I'm not familiar with using lldb. If this is also difficult in lldb, then perhaps either a similar question could be created or mine could be edited to include lldb information? – inetknght Jul 22 '14 at 18:46

3 Answers3

10

I was expecting call __lambdaX::operator()() works but it doesn't. I think it is related to GCC implementation. I am not sure if there is a better way but this is my workaround solution when I need to call lambda in GDB.

Briefly, GDB has disassemble command and it gives __lambda0::operator()() const as debug information at the call instruction line. Then, convert that address into a function pointer and call it.

Example explains better.

$ g++ -g -std=c++0x lambda.cpp 
$ ./a.out 
blah blah
in lambda
...

GDB:

$ gdb ./a.out 
GNU gdb (GDB) Fedora 7.7.1-13.fc20
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...done.
(gdb) b do_something()
Breakpoint 1 at 0x4008a3: file lambda.cpp, line 4.
(gdb) run
Starting program: /home/alper/cplusplus/a.out 

Breakpoint 1, do_something () at lambda.cpp:4
4           std::cout << "blah blah" << std::endl;                                  
Missing separate debuginfos, use: 
(gdb) n
blah blah
11          lambda_func();

Disassemble do_something

(gdb) disassemble do_something
Dump of assembler code for function do_something():
   0x40089b <+0>:   push   %rbp
   0x40089c <+1>:   mov    %rsp,%rbp
   0x40089f <+4>:   sub    $0x10,%rsp
=> 0x4008a3 <+8>:   mov    $0x4009fb,%esi
   0x4008a8 <+13>:  mov    $0x601060,%edi
   0x4008ad <+18>:  callq  0x400750 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
   0x4008b2 <+23>:  mov    $0x400770,%esi
   0x4008b7 <+28>:  mov    %rax,%rdi
   0x4008ba <+31>:  callq  0x400760 <_ZNSolsEPFRSoS_E@plt>
   0x4008bf <+36>:  lea    -0x1(%rbp),%rax
   0x4008c3 <+40>:  mov    %rax,%rdi
   0x4008c6 <+43>:  callq  0x400870 <__lambda0::operator()() const>
   0x4008cb <+48>:  mov    $0x400a05,%esi
   0x4008d0 <+53>:  mov    $0x601060,%edi
   0x4008d5 <+58>:  callq  0x400750 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
   0x4008da <+63>:  mov    $0x400770,%esi
   0x4008df <+68>:  mov    %rax,%rdi
   0x4008e2 <+71>:  callq  0x400760 <_ZNSolsEPFRSoS_E@plt>
   0x4008e7 <+76>:  nop
   0x4008e8 <+77>:  leaveq 
   0x4008e9 <+78>:  retq   

GDB outputs line callq 0x400870 <__lambda0::operator()() const> so convert 0x400870 into a function pointer and call it.

(gdb) call ((void (*)()) 0x400870)()
in lambda
(gdb) call ((void (*)()) 0x400870)()
in lambda
(gdb) call ((void (*)()) 0x400870)()
in lambda

Note: If GCC inlines the lambda, there is nothing to call. For example, if the example above is compiled with optimisation switch -O3, there is no line with __lambda0::operator()() const in GDB disassemble output.

Alper
  • 12,860
  • 2
  • 31
  • 41
  • While not exactly an ideal solution, this certainly does provide the ability to call a void() function. With some playing around, I'm sure I can figure out how to call lambdas with other signatures too. Thanks! – inetknght Jul 28 '14 at 17:13
  • @inetknght 7 years passed, do you find a better solution? – John Nov 01 '21 at 02:15
  • Nope and this problem still exists. – inetknght Nov 22 '21 at 00:25
1

In a less synthetic use case I had success in calling the lambda by calling it as

call myLambda.operator()(param1,param2)

But in the test case in the OP GDB appears to think the function is inlined — even though it's not. I've reported this as bug 28137.

Ruslan
  • 18,162
  • 8
  • 67
  • 136
  • "a less synthetic use case"? What's that? Could you please explain that in more detail? – John Nov 01 '21 at 02:18
  • @John it just means an actual case of a complicated program that's hard to reduce to a [mcve]. – Ruslan Nov 01 '21 at 07:58
0

Note: these methods are not guaranteed to work with C++14 generic lambda.

Case 1. When modifying the source code is allowed

Requires modifying the source code for each individual lambda.

Method 1.1. std::function

Wrap the lambda in a std::function, and explicitly instantiate it. (it does have an extra performance hit for dynamically allocate memory, but it doesn't matter because this is only the debug build)

If the lambda itself does not take any local data types as input or return one, it's possible to explicitly instantiate the whole class

Otherwise, operator() can be instantiated by using it in the program.

#include<iostream>
#include<functional>

template class std::function<int(int)>; // explicit instantiation

int main(){
   auto a=[](int x){
      std::cout<<x<<'\n';
      return x+1;
   };
   std::function a_function{a};
   a_function(1); // implicit instantiation
   __builtin_trap();
}

Call in gdb as a_function.operator()(1).

Reference:

Method 1.2: store the address of the lambda

Program:

#include<iostream>

int main(){
   auto a=[](int x){
      std::cout<<x<<'\n';
      return x+1;
   };
   auto a_operator_call=&decltype(a)::operator();
   __builtin_trap();
}

Call like this: (requires appropriate compilation option so that value of a_operator_call is not optimized out)

(gdb) print (a.*a_operator_call)(1)
1
$1 = 2

Reference:

Case 2. When modifying the source code is not allowed

Case 2.1. Global lambda

#include<iostream>

auto a=[](int x){
   std::cout<<x<<'\n';
   return x+1;
};

int main(){
   __builtin_trap();
}

You need to disable xmethod (at least in my current gdb version. I think it's a bug) and call with the syntax a.operator()(...):

(gdb) print a
$1 = {<No data fields>}

(gdb) print a(1)
Invalid data type for function to be called.

(gdb) print a.operator()(1)
Python Exception <class 'TypeError'> expected string or bytes-like object:
Error while looking for matching xmethod workers defined in Python.

(gdb) disable xmethod

(gdb) print a.operator()(1)
1
$2 = 2

Reference:

Case 2.2. Local lambda

Note: for this method it may be required to compile with -fkeep-inline-functions.

Consider a simple program

#include<iostream>

int main(){
   auto a=[](int x){
      std::cout<<x<<'\n';
      return x+1;
   };
   __builtin_trap();
}

And see what symbols are generated in the executable:

(gdb) shell nm --demangle ./a.out |grep lambda
000000000001fe4c t main::{lambda(int)#1}::operator()(int) const
000000000001ff5c t main::{lambda(int)#1}::operator int (*)(int)() const
000000000001ff40 t main::{lambda(int)#1}::_FUN(int)

(gdb) print 'main::{lambda(int)#1}::operator()(int) const'
$1 = {int (const struct {...} * const, int)} 0x555555573e4c <operator()(int) const>

(gdb) print 'main::{lambda(int)#1}::operator()(int) const' (a, 1)
No symbol "(null)" in current context.

(gdb) set $c='main::{lambda(int)#1}::operator()(int) const'

(gdb) print (a.*$c)(1)
Non-pointer-to-member value used in pointer-to-member construct

(gdb) print $c(&a, 1)
1
$2 = 2

You can see that the symbol has the type of a function pointer, not a pointer-to-member-function, so it must be called with normal syntax (although as can be seen in method 1.2 above gdb does support function-to-member dereference)

It's possible (for example with a Python program) to

  • automatically parse the symbols with lambda in its demangled name

  • get its type with maintenance print type command

  • on lambda invocation: get the lambda object's actual type with the maintenance print type command

    (ptype alone is insufficient as some different types have identical string representation and considered equal by gdb, see example below)

  • then match the types against each other to determine the correct symbol.

Failed attempts

  • Use gdb:

    (gdb) print a
    $1 = {<No data fields>}
    
    (gdb) ptype a
    type = struct {
    }
    
    (gdb) ptype $c
    type = int (*)(const struct {...} * const, int)
    
  • Use Python API:

    Unfortunately, for some reason it consider different types with identical definition equal.

    For example in this program:

    #include<iostream>
    
    int main(){
        auto a=[](int x){ std::cout<<x<<'\n'; return x+1; };
        auto b=[](int x){ std::cout<<x<<'\n'; return x+2; };
        struct{ int x; } c;
        struct{ int x; } d;
        struct{ int y; } e;
        __builtin_trap();
    }
    

    in an IPython interactive shell embedded in gdb:

    In [1]: gdb.parse_and_eval("a").type == gdb.parse_and_eval("b").type
    Out[38]: True
    
    In [39]: gdb.parse_and_eval("c").type == gdb.parse_and_eval("d").type
    Out[39]: True
    
    In [40]: gdb.parse_and_eval("c").type == gdb.parse_and_eval("e").type
    Out[40]: False
    

Things that can be tried out (although not necessary in this particular case)

  • -fno-inline-functions
  • -fkeep-inline-functions
  • -gdwarf-5
  • -g3
  • __attribute__((used))
  • -fno-eliminate-unused-debug-types
  • -fkeep-static-functions
  • -fkeep-static-consts

Reference:

user202729
  • 3,358
  • 3
  • 25
  • 36