web-dev-qa-db-fra.com

Comment faire backtrace () / backtrace_symbols () afficher les noms des fonctions?

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;
}
83
Lyke

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

60
Matthew Slattery

Utilisez la commande addr2line pour mapper les adresses exécutables au nom de fichier du code source + numéro de ligne. Donner la -f option pour obtenir également les noms des fonctions.

Sinon, essayez libunwind .

29
Nemo

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:

https://github.com/ianlancetaylor/libbacktrace

11
Erwan Legrand

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;
        }
}
2
Billg