[c] backtrace () / backtrace_symbols ()에서 함수 이름을 인쇄하는 방법은 무엇입니까?

Linux 전용 backtrace()이며 backtrace_symbols()프로그램의 호출 추적을 생성 할 수 있습니다. 그러나 내 프로그램의 이름이 아닌 함수 주소 만 인쇄합니다. 함수 이름도 인쇄하도록하려면 어떻게해야합니까? 나는 -g뿐만 아니라 -ggdb. 아래 테스트 사례는 다음과 같이 인쇄합니다.

    백 트레이스 ------------
    ./a.out () [0x8048616]
    ./a.out () [0x8048623]
    /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413]
    ./a.out () [0x8048421]
    ----------------------
    

또한 함수 이름을 표시하는 최초의 2 개 항목을 원하는 것 foomain

암호:

#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;
}



답변

기호는 동적 기호 테이블에서 가져옵니다. 에 대한 -rdynamic옵션 이 필요합니다. gcc이렇게하면 모든 기호가 테이블에 배치 되도록하는 플래그를 링커에 전달 합니다.

( GCC 매뉴얼Link Options 페이지 및 / 또는 glibc 매뉴얼Backtraces 페이지를 참조하십시오 .)


답변

addr2line 명령 을 사용하여 실행 가능한 주소를 소스 코드 파일 이름 + 줄 번호에 매핑합니다. -f함수 이름도 가져 오는 옵션을 제공하십시오 .

또는 libunwind를 시도하십시오 .


답변

Ian Lance Taylor의 뛰어난 Libbacktrace가이 문제를 해결합니다. 스택 해제를 처리하고 일반 ELF 기호와 DWARF 디버깅 기호를 모두 지원합니다.

Libbacktrace는 추악한 모든 기호를 내보낼 필요가 없으며 ASLR은이를 깨뜨리지 않습니다.

Libbacktrace는 원래 GCC 배포의 일부였습니다. 이제 독립 실행 형 버전은 Github에서 찾을 수 있습니다.

https://github.com/ianlancetaylor/libbacktrace


답변

ret == -1이고 errno가 EINTER이면 상단의 답변에 버그가 있습니다. 다시 시도해야하지만 ret을 복사 된 것으로 계산하지 않습니다 (강하게 마음에 들지 않으면 계정을 만들지 않음).

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


답변

역 추적 향상

다음 두 가지를 모두 인쇄하므로 매우 편리합니다.

  • 얽 히지 않은 C ++ 함수 이름
  • 줄 번호

당신을 위해 자동으로.

사용 요약 :

#define BOOST_STACKTRACE_USE_ADDR2LINE
#include <boost/stacktrace.hpp>

std::cout << boost::stacktrace::stacktrace() << std::endl;

나는 그것에 대한 최소한의 실행 가능한 예제와 다른 많은 방법을 제공했습니다 : C 또는 C ++의 print call stack


답변