태그 보관물: stack-trace

stack-trace

C에서 스택 추적을 어떻게 잡을 수 있습니까? 표준 C 함수가 없다는 것을

이 작업을 수행하는 표준 C 함수가 없다는 것을 알고 있습니다. Windows와 * nix에서 이에 대한 기술이 무엇인지 궁금합니다. (Windows XP는 지금이 작업을 수행하는 가장 중요한 OS입니다.)



답변

glibc는 backtrace () 함수를 제공합니다.

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


답변

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 ()의 결과를 저장하는 것입니다. 따라서 해당 유형의 예외를 throw 할 때마다 스택 추적이 있습니다. 그런 다음 인쇄 기능을 제공하십시오. 예를 들면 :

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

따다!

참고 : 최적화 플래그를 활성화하면 결과 스택 추적이 부정확해질 수 있습니다. 이상적으로는 디버그 플래그를 켜고 최적화 플래그를 끈 상태에서이 기능을 사용하는 것이 좋습니다.


답변

Windows의 경우 StackWalk64 () API (32 비트 Windows에서도)를 확인하십시오. UNIX의 경우 OS의 기본 방식을 사용하거나 가능한 경우 glibc의 backtrace ()로 대체해야합니다.

그러나 네이티브 코드에서 Stacktrace를 사용하는 것은 거의 좋은 생각이 아닙니다. 가능하지 않기 때문이 아니라 일반적으로 잘못된 것을 달성하려고하기 때문입니다.

대부분의 경우 사람들은 예외가 잡히면 어설 션이 실패하거나 최악의 경우와 같은 예외적 인 상황에서 스택 추적을 시도하거나 치명적인 “예외”또는 세분화 위반.

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

대부분의 사람들이 스택 추적을 얻을 때이를 시도하는 것처럼 보이는 것처럼 치명적인 오류 처리를 시도하고 있다고 가정합니다. 그렇다면 디버거 (개발 중)에 의존하고 프로덕션에서 프로세스 코어 덤프 (또는 Windows의 미니 덤프)를 허용합니다. 적절한 기호 관리와 함께 사후에 원인이되는 명령어를 파악하는 데 문제가 없어야합니다.


답변

unwind 라이브러리를 사용해야합니다 .

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

공유 라이브러리에서 호출하지 않으면 접근 방식도 잘 작동합니다.

addr2lineLinux 에서 명령을 사용 하여 해당 PC의 소스 기능 / 줄 번호를 가져올 수 있습니다 .


답변

이를 수행하는 플랫폼 독립적 인 방법은 없습니다.

가장 가까운 방법은 최적화없이 코드를 실행하는 것입니다. 이렇게하면 (Visual C ++ 디버거 또는 GDB를 사용하여) 프로세스에 연결하고 사용 가능한 스택 추적을 얻을 수 있습니다.


답변

Windows의 경우 CaptureStackBackTrace()도 옵션으로, 사용자 쪽에서 준비 코드가 덜 필요합니다 StackWalk64(). (또한 내가 가진 비슷한 시나리오의 CaptureStackBackTrace()경우 StackWalk64().) 보다 (더 안정적으로) 더 잘 작동 합니다.)


답변

Solaris에는 Linux에도 복사 된 pstack 명령이 있습니다.