在GDB中调用lambda函数

时间:2014-06-20 14:43:42

标签: c++11 lambda gdb

#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;                                                               
}

在这个示例程序中,如果编译(g++ gdb-call-lambda.cpp --std=c++11 -g)然后在gdb(gdb ./a.out)中运行它,则可以让GDB调用任何“普通”函数。例如:

(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
...

但是,如果您尝试调用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有点吓坏了。所以我的问题是:你如何在GDB中调用lambda?询问GDB与正常函数相比,它所期望的东西没有任何兴趣:

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

我去看看lambda_func是否有任何特殊成员,例如一个调用的函数指针,类似于std :: function和/或std :: bind:

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

没有特别会员?好吧也许它只是一个美化的函数指针?

(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.

所以我甚至不能100%确定传递任何参数或特别是捕获类型的命令。

我又尝试了call lambda_func.operator()()call lambda_func::operator()call lambda_func::operator()()call __lambda0call __lambda0()call __lambda0::operator()call __lambda0::operator()(),徒劳无功。

谷歌搜索揭示了在lambdas中设置断点的事情,但没有关于如何从调试器中调用这些lambda的事情。

对于它的价值,这是使用g ++ 4.8.2-19ubuntu1和gdb 7.7-0ubuntu3.1的64位Ubuntu 14.04

2 个答案:

答案 0 :(得分:6)

我期待call __lambdaX::operator()()有效,但事实并非如此。我认为这与GCC的实施有关。我不确定是否有更好的方法,但当我需要在GDB中调用lambda时,这是我的解决方法。

简而言之,GDB具有disassemble命令,并在__lambda0::operator()() const指令行提供call作为调试信息。然后,将该地址转换为函数指针并调用它。

示例解释得更好。

$ 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();

反汇编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输出行callq 0x400870 <__lambda0::operator()() const>,因此将0x400870转换为函数指针并调用它。

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

注意:如果GCC内联lambda,则无需调用。例如,如果上面的示例是使用优化开关-O3编译的,则GDB __lambda0::operator()() const输出中没有disassemble行。

答案 1 :(得分:1)

在一个不太合成的用例中,我成功地将 lambda 调用为

call myLambda.operator()(param1,param2)

但在 OP GDB 的测试用例中,似乎认为该函数是内联的——即使它不是。我已将此报告为 bug 28137