parametros - llamadas al sistema linux
Herramienta para rastrear llamadas a funciones locales en Linux (12)
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
-
cd /usr/src/linux-`uname -r`/tools/perf
-
for i in `./perf probe -F -x ~/Desktop/datalog-2.2/datalog`; do sudo ./perf probe -x ~/Desktop/datalog-2.2/datalog $i; done
-
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
-
sudo ./perf report -G
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 programa C:
#include <stdio.h>
int triple ( int x )
{
return 3 * x;
}
int main (void)
{
printf("%d/n", triple(10));
return 0;
}
Ejecutar el programa 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 compilador 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 compilar el (los) programa (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.
Asumiendo que puede volver a compilar (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.
Con suerte, las herramientas callgrind o cachegrind de Valgrind brindarán la información que busca.
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 programa 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.
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.
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 compilació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 <program>
.
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 <main>:
8053270: 8d 4c 24 04 lea 0x4(%esp),%ecx
--
8053299: 89 1c 24 mov %ebx,(%esp)
805329c: e8 8f 60 ff ff call 8049330 <strlen@plt>
80532a1: 8d 04 03 lea (%ebx,%eax,1),%eax
--
80532cf: 89 04 24 mov %eax,(%esp)
80532d2: e8 b9 c9 00 00 call 805fc90 <xmalloc_set_program_name>
80532d7: 8b 5d 9c mov 0xffffff9c(%ebp),%ebx
--
80532e4: 89 04 24 mov %eax,(%esp)
80532e7: e8 b4 a7 00 00 call 805daa0 <expandargv>
80532ec: 8b 55 9c mov 0xffffff9c(%ebp),%edx
--
8053302: 89 0c 24 mov %ecx,(%esp)
8053305: e8 d6 2a 00 00 call 8055de0 <prune_options>
805330a: e8 71 ac 00 00 call 805df80 <unlock_std_streams>
805330f: e8 4c 2f 00 00 call 8056260 <gcc_init_libintl>
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 <signal@plt>
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 compilar una aplicación para usarla
- Muestra todas las llamadas a funciones posibles, mientras que algo como
gprof
solo mostrará las llamadas a funciones ejecutadas.
Suponiendo que solo desea que se le notifiquen funciones específicas, puede hacerlo así:
compila con información de depuración (como ya tienes información de símbolos, probablemente también tengas suficientes errores)
dado
#include <iostream>
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 recopilar 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 fotograma 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.
Ver los rastros, un marco de seguimiento para las aplicaciones Linux C / C ++: https://github.com/baruch/traces#readme
Requiere recompilar 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.
Gprof podría ser lo que quieras
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
$ sudo yum install frysk
$ ftrace -sym:''*'' -- ./a.out
Más: ftrace.1