programing

C에서 스택 트레이스를 취득하려면 어떻게 해야 합니까?

kingscode 2022. 8. 18. 21:33
반응형

C에서 스택 트레이스를 취득하려면 어떻게 해야 합니까?

이것을 하기 위한 표준 C 함수는 없다는 것을 알고 있습니다.Windows 및 *nix에서 이를 위한 기술은 무엇인지 궁금했습니다(Windows XP가 현재 가장 중요한 OS입니다).

backtrace() , , , , 입니다.backtrace_symbols():

man 페이지부터:

#include <execinfo.h>
#include <stdio.h>
...
void* callstack[128];
int i, frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames);
for (i = 0; i < frames; ++i) {
    printf("%s\n", strs[i]);
}
free(strs);
...

중 는 OOP의 입니다.backtrace_symbols()예외 클래스 생성자에 있습니다.따라서 이러한 유형의 예외를 슬로우할 때마다 스택트레이스가 생성됩니다.그럼 출력 기능만 제공하면 됩니다.예를 들어 다음과 같습니다.

class MyException : public std::exception {

    char ** strs;
    MyException( const std::string & message ) {
         int i, frames = backtrace(callstack, 128);
         strs = backtrace_symbols(callstack, frames);
    }

    void printStackTrace() {
        for (i = 0; i < frames; ++i) {
            printf("%s\n", strs[i]);
        }
        free(strs);
    }
};

...

try {
   throw MyException("Oops!");
} catch ( MyException e ) {
    e.printStackTrace();
}

짜잔!

주의: 최적화 플래그를 활성화하면 스택트레이스가 부정확해질 수 있습니다.이 기능은 디버깅플래그를 켜고 최적화 플래그를 끄고 사용하는 것이 이상적입니다.

는 glibc를 제공합니다.backtrace()★★★★★★ 。

http://www.gnu.org/software/libc/manual/html_node/Backtraces.html

의 , Windows 의 경우,CaptureStackBackTrace()에서는, 「 」 「 」보다 필요한 옵션도 .StackWalk64())CaptureStackBackTrace() (더 되다StackWalk64()

Windows 의 경우는, StackWalk64() API 를 확인합니다(32비트 Windows 에서도).UNIX의 경우 OS의 네이티브 방식을 사용하여 작업을 수행하거나 가능하면 glibc의 백트레이스()로 폴백해야 합니다.

그러나 Stacktrace를 네이티브 코드로 사용하는 것은 좋은 생각이 아닙니다.그것은 불가능하기 때문이 아니라, 통상적으로 잘못된 것을 달성하려고 하기 때문입니다.

대부분의 경우, 예를 들어 예외가 검출되었을 때, 어설션이 실패했을 때, 또는 그 중에서도 최악의 경우, 가장 잘못된 경우 등, 예외적인 상황에서 스택 트레이스를 취득하려고 합니다.

마지막 문제를 고려하면 대부분의 API에서는 메모리를 명시적으로 할당하거나 내부적으로 할당해야 합니다.프로그램이 현재 있는 취약한 상태에서 그렇게 하면 상황이 더 악화될 수 있습니다.예를 들어, 크래시 리포트(또는 코어 덤프)에는 문제의 실제 원인은 반영되지 않지만 처리에는 실패합니다.

대부분의 사람들이 스택 트레이스를 받을 때 그렇게 하려고 하는 것 같기 때문에 당신은 치명적인 오류를 다루려고 하는 것 같습니다.그렇다면 디버거(개발 중)에 의존하여 프로세스의 코어 덤프를 실제 가동(또는 Windows의 미니 덤프)으로 합니다.적절한 기호 관리와 함께 사후 분석을 통해 원인을 파악하는 데 문제가 없습니다.

스택을 뒤로 이동하면 됩니다.그러나 실제로는 각 기능의 시작 부분에서 콜 스택에 식별자를 추가하고 마지막에 팝업한 후 콘텐츠를 인쇄하는 것이 더 쉬운 경우가 많습니다.다소 PITA이지만, 잘 작동하여 결국 시간을 절약할 수 있습니다.

언와인드 라이브러리를 사용해야 합니다.

unw_cursor_t cursor; unw_context_t uc;
unw_word_t ip, sp;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
unsigned long a[100];
int ctr = 0;

while (unw_step(&cursor) > 0) {
  unw_get_reg(&cursor, UNW_REG_IP, &ip);
  unw_get_reg(&cursor, UNW_REG_SP, &sp);
  if (ctr >= 10) break;
  a[ctr++] = ip;
}

공유 라이브러리에서 전화를 걸지 않는 한 이 접근법도 정상적으로 작동합니다.

를 사용할 수 있습니다.addr2line명령어를 사용하여 해당 PC의 소스 함수/행 번호를 가져옵니다.

플랫폼 독립적인 방법은 없습니다.

최적화를 하지 않고 코드를 실행하는 것이 가장 가까운 방법입니다.그러면 프로세스에 접속하여(visual c++ 디버거 또는 GDB를 사용하여) 사용 가능한 스택트레이스를 얻을 수 있습니다.

Solaris에는 pstack 명령어가 있으며 Linux에도 복사되었습니다.

지난 몇 년간 나는 Ian Lance Taylor의 libbacktrace를 사용해 왔다.모든 기호를 내보내야 하는 GNU C 라이브러리의 함수보다 훨씬 깨끗합니다.libunwind보다 역추적 생성에 더 많은 유틸리티를 제공합니다.마지막으로 다음과 같은 외부 툴을 필요로 하는 접근 방식으로는 ASLR에 지지 않습니다.addr2line.

Libbacktrace는 처음에는 GCC 배포의 일부였지만, 현재는 BSD 라이선스로 작성자가 스탠드아론 라이브러리로 사용할 수 있게 되었습니다.

https://github.com/ianlancetaylor/libbacktrace

글을 쓸 때 libbacktrace에서 지원되지 않는 플랫폼에서 백트레이스를 생성할 필요가 없는 한 다른 것은 사용하지 않습니다.

언급URL : https://stackoverflow.com/questions/105659/how-can-one-grab-a-stack-trace-in-c

반응형