2014-06-20 23 views
12
#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;                
} 

W tym przykładzie programu, jeśli kompilacji (g++ gdb-call-lambda.cpp --std=c++11 -g), a następnie uruchomić go w gdb (gdb ./a.out), można mieć GDB wywołać dowolną funkcję „normalną”. Przykład:Wywołanie funkcji lambda w 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 
... 

Jednakże, jeśli następnie spróbuj wywołać 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 trochę wpada w panikę. Tak więc moje pytanie brzmi: jak nazwać lambda w GDB? Zadawanie GDB czego oczekuje ujawnia nic interesującego w porównaniu do normalnej funkcji:

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

poszedłem zobaczyć jeśli lambda_func ma żadnych specjalnych elementów, na przykład wskaźnik funkcja zadzwonić, zbliżona do std :: funkcji i/lub std :: bind:

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

Brak specjalnych członków? Okej, może to tylko gloryfikowany wskaźnik funkcji?

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

Tak więc nie jestem nawet w 100% pewien, w jakiej kolejności przekazywać jakiekolwiek argumenty, a zwłaszcza przechwycone typy.

Próbowałem dodatkowo call lambda_func.operator()(), call lambda_func::operator(), call lambda_func::operator()(), call __lambda0, call __lambda0(), call __lambda0::operator(), call __lambda0::operator()(), wszystko bezskutecznie.

Wyszukiwanie w google ujawnia rzeczy dotyczące ustawiania punktów przerwania w lambdach, ale nic, jak wywołać te lambdy z debuggera.

Na co warto, to na Ubuntu 14.04 64-bit przy użyciu g ++ 4.8.2-19ubuntu1 i gdb 7.7-0ubuntu3.1

+0

Czy wywołanie 'lambda_func.operator()' działa? – John

+0

Nie ma. Próbowałem dodatkowo 'call lambda_func.operator()()', 'call lambda_func :: operator()', 'call lambda_func :: operator()()', 'call __lambda0',' call __lambda0() ', wywołanie' __lambda0 :: operator() ',' call __lambda0 :: operator()() ', wszystko bez skutku. – inetknght

+0

lldb podaje inny komunikat o błędzie: 'error: wywołanie funkcji '$ _0 :: operator()() const' ('_ZNK3 $ _0clEv'), którego nie ma w docelowym błędzie : ostrzeżenie: funkcja ' :: operator() 'ma wewnętrzne powiązanie, ale nie jest zdefiniowany błąd: Wyrażenie nie może być przygotowane do uruchomienia w celu ' – tclamb

Odpowiedz

6

Spodziewałem call __lambdaX::operator()() działa, ale tak nie jest. Myślę, że jest to związane z implementacją GCC. Nie jestem pewien, czy istnieje lepszy sposób, ale to jest moje rozwiązanie, gdy potrzebuję wywołać lambda w GDB.

W skrócie, GDB ma polecenie disassemble i podaje __lambda0::operator()() const jako informację debugowania na linii instrukcji call. Następnie przekonwertuj ten adres na wskaźnik funkcji i wywołaj go.

Przykład wyjaśnia lepiej.

$ 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 <[email protected]> 
    0x4008b2 <+23>: mov $0x400770,%esi 
    0x4008b7 <+28>: mov %rax,%rdi 
    0x4008ba <+31>: callq 0x400760 <[email protected]> 
    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 <[email protected]> 
    0x4008da <+63>: mov $0x400770,%esi 
    0x4008df <+68>: mov %rax,%rdi 
    0x4008e2 <+71>: callq 0x400760 <[email protected]> 
    0x4008e7 <+76>: nop 
    0x4008e8 <+77>: leaveq 
    0x4008e9 <+78>: retq 

GDB wyjścia linia callq 0x400870 <__lambda0::operator()() const> więc konwertować 0x400870 do wskaźnika funkcji i wywołać ją.

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

Uwaga: jeśli GCC dodaje lambdę, nie ma nic do połączenia. Na przykład, jeśli powyższy przykład został skompilowany za pomocą przełącznika optymalizacji -O3, nie ma linii z __lambda0::operator()() const w wyjściu GDB disassemble.

+0

Chociaż nie jest to idealne rozwiązanie, to z pewnością zapewnia możliwość wywoływania funkcji void(). Przy odrobinie zabawy, jestem pewien, że mogę wymyślić, jak nazwać lambdasa również innymi sygnaturami. Dzięki! – inetknght