O Linux específico backtrace()
e backtrace_symbols()
permite que você produza um rastreamento de chamada do programa. No entanto, ele apenas imprime endereços de função, não seus nomes para meu programa. Como posso fazer com que eles também imprimam os nomes das funções? Tentei compilar o programa com -g
o também -ggdb
. O caso de teste abaixo apenas imprime isso:
BACKTRACE ------------ ./a.out () [0x8048616] ./a.out () [0x8048623] /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413] ./a.out () [0x8048421] ----------------------
Eu gostaria que os 2 primeiros itens também mostrassem os nomes das funções, foo
emain
Código:
#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;
}
backtrace_symbols_fd
executa a mesma operação quebacktrace_symbols()
, mas as strings resultantes são imediatamente gravadas no descritor de arquivofd
.Respostas:
Os símbolos são retirados da tabela de símbolos dinâmicos; você precisa da
-rdynamic
opção paragcc
, o que o faz passar um sinalizador para o vinculador que garante que todos os símbolos sejam colocados na tabela.(Consulte a página Opções de link do manual GCC e / ou a página Backtraces do manual glibc .)
fonte
libunwind
que @Nemo menciona, funciona para funções estáticas.ADD_COMPILE_OPTIONS(-rdynamic)
. Em vez disso, ele precisa serADD_LINK_OPTIONS(-rdynamic)
ou equivalente para ter o comportamento desejado.Use o comando addr2line para mapear endereços executáveis para o nome do arquivo do código-fonte + número da linha. Dê a
-f
opção de obter nomes de funções também.Como alternativa, tente o libunwind .
fonte
addr2line
funcionavam de forma confiável até mesmo para endereços em objetos compartilhados (?) Mas sim, em plataformas modernas você precisaria saber o endereço de carga real do objeto realocável até mesmo para fazer esta operação em princípio .O excelente Libbacktrace de Ian Lance Taylor resolve esse problema. Ele lida com o desenrolar da pilha e oferece suporte a símbolos ELF comuns e símbolos de depuração DWARF.
Libbacktrace não exige a exportação de todos os símbolos, o que seria feio, e o ASLR não o quebra.
Libbacktrace era originalmente parte da distribuição GCC. Agora, uma versão autônoma pode ser encontrada no Github:
https://github.com/ianlancetaylor/libbacktrace
fonte
a resposta no topo tem um bug se ret == -1 e errno for EINTER você deve tentar novamente, mas não contar ret como copiado (não vou fazer uma conta apenas para isso, se você não gosta de ser difícil)
fonte
Boost backtrace
Muito conveniente porque imprime ambos:
automaticamente para você.
Resumo de uso:
Eu forneci um exemplo mínimo executável para ele e muitos outros métodos em: imprimir pilha de chamadas em C ou C ++
fonte