Je cherche un outil comme ltrace ou strace qui peut tracer des fonctions définies localement dans un exécutable. ltrace ne trace que les appels de bibliothèque dynamics et strace trace uniquement les appels système. Par exemple, compte tenu du programme C suivant:
#include int sortingple ( int x ) { return 3 * x; } int main (void) { printf("%d\n", sortingple(10)); return 0; }
L’exécution du programme avec ltrace
affichera l’appel à printf
car il s’agit d’une fonction de bibliothèque standard (qui est une bibliothèque dynamic sur mon système) et strace
affichera tous les appels système du code de démarrage, les appels système utilisés pour implémenter le code d’arrêt, mais je veux quelque chose qui va me montrer que la fonction sortingple
été appelée. En supposant que les fonctions locales n’ont pas été incorporées par un compilateur optimisant et que le binary n’a pas été supprimé (symboles supprimés), existe-t-il un outil capable de le faire?
modifier
Quelques précisions:
En supposant que vous voulez seulement être averti pour des fonctions spécifiques, vous pouvez le faire comme ceci:
comstackr avec des informations de debug
donné
#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; }
Utilisez gdb pour tracer:
[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)
Voici ce que je fais pour collecter les adresses de toutes les fonctions:
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
Notez qu'au lieu d'imprimer simplement l'image courante ( bt 1
), vous pouvez faire ce que vous voulez, en imprimant la valeur de certains éléments globaux, en exécutant des commandes shell ou en envoyant quelque chose si la fonction fatal_bomb_exploded
est fatal_bomb_exploded
🙂 Langue a changé "messages entre les deux. Mais ça se déroule facilement. Pas grand chose
System Tap peut être utilisé sur une machine Linux moderne (Fedora 10, RHEL 5, etc.).
Commencez par télécharger le script para-callgraph.stp .
Puis lancez:
$ 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
Voir aussi: Observer, mettre à jour le système et mettre à jour les fichiers
En supposant que vous vouliez tracer toutes les fonctions dans ~/Desktop/datalog-2.2/datalog
en l’appelant avec les parameters -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
En supposant que vous pouvez recomstackr (pas de changement de source requirejs) le code que vous voulez tracer avec l’option -finstrument-functions
option gcc, vous pouvez utiliser etrace pour obtenir le graphe d’appel de fonction.
Voici à quoi ressemble la sortie:
\-- 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
Sur Solaris, truss (équivalent à strace) peut filtrer la bibliothèque à tracer. Je suis surpris quand j’ai découvert que strace n’avait pas une telle capacité.
$ sudo yum install frysk $ ftrace -sym:'*' -- ./a.out
Plus: ftrace.1
Si vous externalisez cette fonction dans une bibliothèque externe, vous devriez également pouvoir la voir s’appeler (avec ltrace).
La raison pour laquelle cela fonctionne est que ltrace se place entre votre application et la bibliothèque et que lorsque tout le code est internalisé avec un fichier, il ne peut pas intercepter l’appel.
ie: ltrace xterm
crache des trucs des librairies X, et X est loin d’être un système.
En dehors de cela, la seule façon réelle de le faire est l’interception à la compilation via des indicateurs de prof ou des symboles de débogage.
Je viens de parcourir cette application, qui semble intéressante:
http://www.gnu.org/fr/software/cflow/
Mais je ne pense pas que ce soit ce que vous voulez.
Si les fonctions ne sont pas intégrées, vous pourriez même avoir de la chance en utilisant objdump -d
.
Pour un exemple, prenons un butin au début de la routine 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
Il faut un peu d’effort pour parcourir l’ensemble de l’assembleur, mais vous pouvez voir tous les appels possibles d’une fonction donnée. Il n’est pas aussi facile à utiliser que gprof
ou certains des autres utilitaires mentionnés, mais il présente plusieurs avantages distincts:
gprof
affichera uniquement les appels de fonctions exécutés. Il existe un script shell pour automatiser les appels de fonctions de suivi avec gdb. Mais il ne peut pas s’attacher au processus en cours.
blog.superadditive.com/2007/12/01/call-graphs-using-the-gnu-project-debugger/
Copie de la page – http://web.archive.org/web/20090317091725/http://blog.superadditive.com/2007/12/01/call-graphs-using-the-gnu-project-debugger/
Copie de l’outil – callgraph.tar.gz
http://web.archive.org/web/20090317091725/http://superadditive.com/software/callgraph.tar.gz
Il vide toutes les fonctions du programme et génère un fichier de commandes gdb avec des points d’arrêt sur chaque fonction. A chaque point d’arrêt, “backtrace 2” et “continue” sont exécutés.
Ce script est plutôt lent sur big porject (~ des milliers de fonctions), donc j’ajoute un filtre sur la liste des fonctions (via egrep). C’était très facile et j’utilise ce script presque tous les jours.
Gprof pourrait être ce que vous voulez
Voir les traces, un framework de traçage pour les applications Linux C / C ++: https://github.com/baruch/traces#readme
Cela nécessite de recomstackr votre code avec son instrument, mais il fournira une liste de toutes les fonctions, de leurs parameters et de leurs valeurs de retour. Il y a un interactif pour permettre la navigation facile des échantillons de données volumineux.
J’espère que les outils callgrind ou cachegrind de Valgrind vous donneront les informations recherchées.
NOTE: Ce n’est pas le ftrace basé sur le kernel Linux, mais plutôt un outil que j’ai récemment conçu pour effectuer le traçage et le contrôle des fonctions locales. Linux ELF x86_64 / x86_32 sont pris en charge publiquement.