역추적()/backtrace_symbols() 기능 이름을 인쇄하는 방법?
리눅스 관련backtrace()
그리고backtrace_symbols()
프로그램의 통화 추적을 생성할 수 있다.하지만 기능 주소만 출력하고 내 프로그램의 이름은 인쇄하지 않는다.어떻게 하면 그들이 함수 이름도 인쇄하게 할 수 있을까? 나는 프로그램을 컴파일해 보았다.-g
게다가-ggdb
. 아래 테스트 케이스는 다음과 같이 인쇄한다.
백트레이스 ------------./a.out³ [0x8048616]./a.out³ [0x8048623]/lib/libc.so.6(_libc_start_main+0xf3) [0x4a937413]./a.out³ [0x8048421]----------------------
처음 두 개 항목에도 기능 이름을 표시했으면 좋겠는데foo
그리고main
코드:
#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 매뉴얼의 링크 옵션 페이지 및/또는 glibc 매뉴얼의 백트레이스 페이지를 참조하십시오.)
이안 랜스 테일러의 뛰어난 리백트레이스가 이 문제를 해결한다.스택 언더블링을 처리하며 일반 ELF 기호와 DEMP 디버깅 기호를 모두 지원한다.
Libbacktrace는 못생길 수 있는 모든 기호를 내보낼 필요가 없으며, ASLR은 이를 깨지 않는다.
Libbacktrace는 원래 GCC 배포의 일부였다.이제 독립형 버전은 Github에서 찾을 수 있다.
https://github.com/ianlancetaylor/libbacktrace
실행 가능한 주소를 소스 코드 파일 이름+라인 번호에 매핑하려면 addr2line 명령을 사용하십시오.내놔!-f
함수 이름도 가져오는 옵션.
또는 Libunwind를 사용해 보십시오.
부스트 역추적
다음 두 가지를 모두 인쇄하므로 매우 편리함:
- Unmangled C++ 함수 이름
- 줄넘기
널 위해 자동으로.
사용량 요약:
#define BOOST_STACKTRACE_USE_ADDR2LINE
#include <boost/stacktrace.hpp>
std::cout << boost::stacktrace::stacktrace() << std::endl;
나는 그것과 많은 다른 방법들에 최소한의 실행 가능한 예를 제공했다: C 또는 C++로 통화 스택을 인쇄
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;
}
}
'Programing' 카테고리의 다른 글
Java에서 개인 정적 변수의 용도는 무엇인가? (0) | 2022.05.04 |
---|---|
v-for를 사용하여 어레이의 일부만 반복하는 방법 (0) | 2022.05.04 |
알 수 없는 작업: Vuex를 사용하여 카운터가 증가하지 않음(VueJS) (0) | 2022.05.04 |
들여쓰기 #defines (0) | 2022.05.04 |
Vuex 비동기식 계산 이미지가 제대로 작동하지 않는 v-carouzl을 사용하여 Vuetify (0) | 2022.05.04 |