backtrace()
et backtrace_symbols()
spécifiques à Linux vous permettent de produire une trace d'appel du programme. Cependant, il imprime uniquement les adresses des fonctions, pas leurs noms pour mon programme. Comment puis-je également leur faire imprimer les noms des fonctions? J'ai essayé de compiler le programme avec -g
aussi bien que -ggdb
. Le cas de test ci-dessous imprime simplement ceci:
BACKTRACE ------------ ./A.out () [0x8048616] ./A.out () [0x8048623] /Lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413] ./A.out () [0x8048421] ------ ----------------
Je voudrais que les 2 premiers éléments affichent également les noms des fonctions, foo
et main
Code:
#include <execinfo.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
static void full_write(int fd, const char *buf, size_t len)
{
while (len > 0) {
ssize_t ret = write(fd, buf, len);
if ((ret == -1) && (errno != EINTR))
break;
buf += (size_t) ret;
len -= (size_t) ret;
}
}
void print_backtrace(void)
{
static const char start[] = "BACKTRACE ------------\n";
static const char end[] = "----------------------\n";
void *bt[1024];
int bt_size;
char **bt_syms;
int i;
bt_size = backtrace(bt, 1024);
bt_syms = backtrace_symbols(bt, bt_size);
full_write(STDERR_FILENO, start, strlen(start));
for (i = 1; i < bt_size; i++) {
size_t len = strlen(bt_syms[i]);
full_write(STDERR_FILENO, bt_syms[i], len);
full_write(STDERR_FILENO, "\n", 1);
}
full_write(STDERR_FILENO, end, strlen(end));
free(bt_syms);
}
void foo()
{
print_backtrace();
}
int main()
{
foo();
return 0;
}
Les symboles sont extraits de la table des symboles dynamiques; vous avez besoin du -rdynamic
option à gcc
, ce qui lui fait passer un drapeau à l'éditeur de liens qui garantit que tous les symboles sont placés dans le tableau.
(Voir la page Options de lien du manuel GCC , et/ou la page Backtraces du manuel glibc . )
L'excellente Libbacktrace d'Ian Lance Taylor résout ce problème. Il gère le déroulement de la pile et prend en charge les symboles ELF ordinaires et les symboles de débogage DWARF.
Libbacktrace ne nécessite pas d'exporter tous les symboles, ce qui serait moche, et ASLR ne le casse pas.
Libbacktrace faisait à l'origine partie de la distribution GCC. Maintenant, une version autonome peut être trouvée sur Github:
la réponse en haut a un bug si ret == -1 et errno est EINTER vous devriez réessayer, mais ne comptez pas ret comme copié (ne va pas créer un compte juste pour cela, si vous ne l'aimez pas dur)
static void full_write(int fd, const char *buf, size_t len)
{
while (len > 0) {
ssize_t ret = write(fd, buf, len);
if ((ret == -1) {
if (errno != EINTR))
break;
//else
continue;
}
buf += (size_t) ret;
len -= (size_t) ret;
}
}