Herramienta para rastrear llamadas a funciones locales en Linux

Estoy buscando una herramienta como ltrace o strace que pueda rastrear funciones definidas localmente en un ejecutable. ltrace solo rastrea las llamadas dinámicas de la biblioteca y solo rastrea las llamadas al sistema. Por ejemplo, dado el siguiente progtwig C:

#include  int triple ( int x ) { return 3 * x; } int main (void) { printf("%d\n", triple(10)); return 0; } 

Ejecutar el progtwig con ltrace mostrará la llamada a printf ya que es una función de biblioteca estándar (que es una biblioteca dinámica en mi sistema) y strace mostrará todas las llamadas al sistema desde el código de inicio, las llamadas al sistema utilizadas para implementar printf y el código de apagado, pero quiero algo que me muestre que se llamó a la función triple . Asumiendo que las funciones locales no han sido inlineadas por un comstackdor de optimización y que el binario no se ha eliminado (símbolos eliminados), ¿hay alguna herramienta que pueda hacer esto?

Editar

Un par de aclaraciones:

  • Está bien si la herramienta también proporciona información de rastreo para funciones no locales.
  • No quiero tener que volver a comstackr el (los) progtwig (s) con soporte para herramientas específicas, la información del símbolo en el ejecutable debería ser suficiente.
  • Sería realmente bueno si pudiera usar la herramienta para adjuntar a procesos existentes como puedo con ltrace / strace.

Suponiendo que solo desea que se le notifiquen funciones específicas, puede hacerlo así:

comstack con información de depuración (como ya tienes información de símbolos, probablemente también tengas suficientes errores)

dado

 #include  int fac(int n) { if(n == 0) return 1; return n * fac(n-1); } int main() { for(int i=0;i<4;i++) std::cout << fac(i) << std::endl; } 

Use gdb para rastrear:

 [js@HOST2 cpp]$ g++ -g3 test.cpp [js@HOST2 cpp]$ gdb ./a.out (gdb) b fac Breakpoint 1 at 0x804866a: file test.cpp, line 4. (gdb) commands 1 Type commands for when breakpoint 1 is hit, one per line. End with a line saying just "end". >silent >bt 1 >c >end (gdb) run Starting program: /home/js/cpp/a.out #0 fac (n=0) at test.cpp:4 1 #0 fac (n=1) at test.cpp:4 #0 fac (n=0) at test.cpp:4 1 #0 fac (n=2) at test.cpp:4 #0 fac (n=1) at test.cpp:4 #0 fac (n=0) at test.cpp:4 2 #0 fac (n=3) at test.cpp:4 #0 fac (n=2) at test.cpp:4 #0 fac (n=1) at test.cpp:4 #0 fac (n=0) at test.cpp:4 6 Program exited normally. (gdb) 

Esto es lo que hago para recostackr todas las direcciones de las funciones:

 tmp=$(mktemp) readelf -s ./a.out | gawk ' { if($4 == "FUNC" && $2 != 0) { print "# code for " $NF; print "b *0x" $2; print "commands"; print "silent"; print "bt 1"; print "c"; print "end"; print ""; } }' > $tmp; gdb --command=$tmp ./a.out; rm -f $tmp 

Tenga en cuenta que en lugar de simplemente imprimir el fotogtwig actual ( bt 1 ), puede hacer lo que desee, imprimiendo el valor de algo global, ejecutando algún comando de shell o enviando algo por correo si golpea la función fatal_bomb_exploded 🙂 Lamentablemente, gcc genera algunos "Current El idioma cambió "mensajes intermedios". Pero eso es fácil de resolver. No es gran cosa.

System Tap se puede usar en una caja Linux moderna (Fedora 10, RHEL 5, etc.).

Primero descargue el script para-callgraph.stp .

Entonces corre:

 $ sudo stap para-callgraph.stp 'process("/bin/ls").function("*")' -c /bin/ls 0 ls(12631):->main argc=0x1 argv=0x7fff1ec3b038 276 ls(12631): ->human_options spec=0x0 opts=0x61a28c block_size=0x61a290 365 ls(12631): <-human_options return=0x0 496 ls(12631): ->clone_quoting_options o=0x0 657 ls(12631): ->xmemdup p=0x61a600 s=0x28 815 ls(12631): ->xmalloc n=0x28 908 ls(12631): <-xmalloc return=0x1efe540 950 ls(12631): <-xmemdup return=0x1efe540 990 ls(12631): <-clone_quoting_options return=0x1efe540 1030 ls(12631): ->get_quoting_style o=0x1efe540 

Ver también: Observe, systemtap y oprofile updates

Usando Uprobes (desde Linux 3.5)

Asumiendo que quería rastrear todas las funciones en ~/Desktop/datalog-2.2/datalog cuando lo llama con los parámetros -l ~/Desktop/datalog-2.2/add.lua ~/Desktop/datalog-2.2/test.dl

  1. cd /usr/src/linux-`uname -r`/tools/perf
  2. for i in `./perf probe -F -x ~/Desktop/datalog-2.2/datalog`; do sudo ./perf probe -x ~/Desktop/datalog-2.2/datalog $i; done
  3. sudo ./perf record -agR $(for j in $(sudo ./perf probe -l | cut -d' ' -f3); do echo "-e $j"; done) ~/Desktop/datalog-2.2/datalog -l ~/Desktop/datalog-2.2/add.lua ~/Desktop/datalog-2.2/test.dl
  4. sudo ./perf report -G

lista de funciones en binario de datosárbol de llamadas al seleccionar dl_pushlstring, que muestra cómo el llamado archivo de carga llamado dl_load llamó al programa llamado regla que llamó literalmente y que a su vez llamó a otras funciones que terminaron llamando a dl_pushlstring, escanear (padre: programa, es decir, el tercer escaneo desde la parte superior) que llamó dl_pushstring y así sucesivamente

Asumiendo que puede volver a comstackr (no se requiere cambio de fuente) el código que desea rastrear con la opción gcc -finstrument-functions , puede usar etrace para obtener el gráfico de llamadas de función.

Así es como se ve el resultado:

 \-- main | \-- Crumble_make_apple_crumble | | \-- Crumble_buy_stuff | | | \-- Crumble_buy | | | \-- Crumble_buy | | | \-- Crumble_buy | | | \-- Crumble_buy | | | \-- Crumble_buy | | \-- Crumble_prepare_apples | | | \-- Crumble_skin_and_dice | | \-- Crumble_mix | | \-- Crumble_finalize | | | \-- Crumble_put | | | \-- Crumble_put | | \-- Crumble_cook | | | \-- Crumble_put | | | \-- Crumble_bake 

En Solaris, el truss (equivalente de la cadena) tiene la capacidad de filtrar la biblioteca que se debe rastrear. Me sorprendió cuando descubrí que strace no tiene esa capacidad.

 $ sudo yum install frysk $ ftrace -sym:'*' -- ./a.out 

Más: ftrace.1

Si externaliza esa función en una biblioteca externa, también debería poder verla recibiendo llamadas, (con ltrace).

El motivo por el que esto funciona es porque ltrace se ubica entre su aplicación y la biblioteca, y cuando todo el código se internaliza con un archivo, no puede interceptar la llamada.

es decir: ltrace xterm

arroja cosas de las bibliotecas X, y X es apenas un sistema.

Fuera de esto, la única manera real de hacerlo es interceptar en tiempo de comstackción a través de banderas prof o símbolos de depuración.

Acabo de ejecutar esta aplicación, que se ve interesante:

http://www.gnu.org/software/cflow/

Pero no creo que sea eso lo que quieres.

Si las funciones no están en línea, incluso podría tener suerte usando objdump -d .

Por ejemplo, tomemos un botín al comienzo de la rutina main de GCC 4.3.2:

 $ objdump `which gcc` -d | grep '\(call\|main\)' 08053270 
: 8053270: 8d 4c 24 04 lea 0x4(%esp),%ecx -- 8053299: 89 1c 24 mov %ebx,(%esp) 805329c: e8 8f 60 ff ff call 8049330 80532a1: 8d 04 03 lea (%ebx,%eax,1),%eax -- 80532cf: 89 04 24 mov %eax,(%esp) 80532d2: e8 b9 c9 00 00 call 805fc90 80532d7: 8b 5d 9c mov 0xffffff9c(%ebp),%ebx -- 80532e4: 89 04 24 mov %eax,(%esp) 80532e7: e8 b4 a7 00 00 call 805daa0 80532ec: 8b 55 9c mov 0xffffff9c(%ebp),%edx -- 8053302: 89 0c 24 mov %ecx,(%esp) 8053305: e8 d6 2a 00 00 call 8055de0 805330a: e8 71 ac 00 00 call 805df80 805330f: e8 4c 2f 00 00 call 8056260 8053314: c7 44 24 04 01 00 00 movl $0x1,0x4(%esp) -- 805331c: c7 04 24 02 00 00 00 movl $0x2,(%esp) 8053323: e8 78 5e ff ff call 80491a0 8053328: 83 e8 01 sub $0x1,%eax

Se necesita un poco de esfuerzo para recorrer todo el ensamblador, pero puede ver todas las llamadas posibles de una función determinada. No es tan fácil de usar como gprof o algunas de las otras utilidades mencionadas, pero tiene varias ventajas distintas:

  • Por lo general, no es necesario volver a comstackr una aplicación para usarla
  • Muestra todas las llamadas a funciones posibles, mientras que algo como gprof solo mostrará las llamadas a funciones ejecutadas.

Existe un script de shell para automatizar las llamadas a la función de rastreo con gdb. Pero no se puede unir al proceso de ejecución.

blog.superadditive.com/2007/12/01/call-graphs-using-the-gnu-project-debugger/

Copia de la página – http://web.archive.org/web/20090317091725/http://blog.superadditive.com/2007/12/01/call-graphs-using-the-gnu-project-debugger/

Copia de la herramienta – callgraph.tar.gz

http://web.archive.org/web/20090317091725/http://superadditive.com/software/callgraph.tar.gz

Vacia todas las funciones del progtwig y genera un archivo de comando gdb con puntos de corte en cada función. En cada punto de interrupción, se ejecutan “backtrace 2” y “continue”.

Este script es bastante lento en big porject (~ miles de funciones), así que agrego un filtro en la lista de funciones (a través de egrep). Fue muy fácil, y uso este script casi todos los días.

Gprof podría ser lo que quieras

Ver los rastros, un marco de seguimiento para las aplicaciones Linux C / C ++: https://github.com/baruch/traces#readme

Requiere recomstackr su código con su instrumento o, pero proporcionará una lista de todas las funciones, sus parámetros y valores de retorno. Hay un interactivo para permitir la navegación fácil de grandes muestras de datos.

Con suerte, las herramientas callgrind o cachegrind de Valgrind le brindarán la información que busca.

NOTA: Esta no es la ruta de acceso basada en el kernel de Linux, sino más bien una herramienta que diseñé recientemente para realizar el seguimiento de funciones locales y controlar el flujo. Linux ELF x86_64 / x86_32 son compatibles públicamente.

https://github.com/leviathansecurity/ftrace