Obtain the current stack information on Linux and Windows.
The output stack information is often used when writing stable and reliable software services, so that users/developers can obtain accurate operation information. It is often used in log output, error reporting, and exception detection.
In Linux, there are simple functions to get stack information:
#include <stdio.h>#include <execinfo.h>#include <signal.h>#include <stdlib.h>#include <unistd.h>void handler(int sig) { void *array[5]; size_t size; // get void*'s for all entries on the stack size = backtrace(array, 5); // print out all the frames to stderr fprintf(stderr, "Error: signal %d:\n", sig); char** msgs = backtrace_symbols(array, size); for(int i=1;i<size && msgs[i];++i) printf("[%d] %s\n", i, msgs[i]); exit(1);}void baz() { int *foo = (int*)-1; // make a bad pointer printf("%d\n", *foo); // causes segfault}void bar() { baz(); }void foo() { bar(); }int main(int argc, char **argv) { signal(SIGSEGV, handler); // install our handler foo(); // this will call foo, bar, and baz. baz segfaults.}
The above code is slightly modified from the reference stackoverflow. The core function is backtrace and backtrace_symbols.
In Windows, StackWalker is recommended as the open source code. It supports X86, AMD64, and IA64.
If you need the simplest code, the code I extracted below is much more complex than Linux. (The implementation of many functions of Win is more complicated. Of course, many functions are much simpler than those of Linux .)
I will give some explanations later.
#include "stdafx.h"#include <Windows.h>#include <iostream>#include <DbgHelp.h>#include <TlHelp32.h>using namespace std;HANDLE ph;void baz(){ int* v = 0; *v = 0;}void bar(){ baz();}void foo(){ __try { bar(); } __except(EXCEPTION_EXECUTE_HANDLER) { auto sire = SymInitialize(ph, 0, FALSE); sire = SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_FAIL_CRITICAL_ERRORS); CONTEXT ctx = { 0 }; ctx.ContextFlags = CONTEXT_FULL; RtlCaptureContext(&ctx); STACKFRAME64 sf = { 0 }; #ifdef _M_IX86 // ignore IA64 auto imageType = IMAGE_FILE_MACHINE_I386; sf.AddrPC.Offset = ctx.Eip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrFrame.Offset = ctx.Ebp; sf.AddrFrame.Mode = AddrModeFlat; sf.AddrStack.Offset = ctx.Esp; sf.AddrStack.Mode = AddrModeFlat; #elif _M_X64 auto imageType = IMAGE_FILE_MACHINE_AMD64; sf.AddrPC.Offset = ctx.Rip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrFrame.Offset = ctx.Rsp; sf.AddrFrame.Mode = AddrModeFlat; sf.AddrStack.Offset = ctx.Rsp; sf.AddrStack.Mode = AddrModeFlat; #endif MODULEENTRY32 me; auto snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); auto info = Module32First(snap, &me); while (info) { auto dw = SymLoadModule64(ph, 0, me.szExePath, me.szModule, (DWORD64)me.modBaseAddr, me.modBaseSize); if (!Module32Next(snap, &me))break; } CloseHandle(snap); auto thread = GetCurrentThread(); PIMAGEHLP_SYMBOL64 sym = (IMAGEHLP_SYMBOL64 *)malloc(sizeof(IMAGEHLP_SYMBOL64) + 100); if (!sym) return; memset(sym, 0, sizeof(IMAGEHLP_SYMBOL64) + 100); sym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); sym->MaxNameLength = 100; IMAGEHLP_LINE64 line = { 0 }; line.SizeOfStruct = sizeof(line); for (;;) { auto result = StackWalk(imageType, ph, thread, &sf, &ctx, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0); if (result) { DWORD64 offset = 0; DWORD offset_for_line = 0; CHAR und_fullname[100]; if (sf.AddrPC.Offset != 0) { if (SymGetSymFromAddr64(ph, sf.AddrPC.Offset, &offset, sym)) { UnDecorateSymbolName(sym->Name, und_fullname, 100, UNDNAME_COMPLETE); cout << und_fullname; } if (SymGetLineFromAddr64(ph, sf.AddrPC.Offset, &offset_for_line, &line)) { cout << " " << line.FileName << "(" << line.LineNumber << ")"; } cout << endl; } } else break; } SymCleanup(ph); }}int main(){ ph = GetCurrentProcess(); foo(); return 0;}
For compilation, please link dbghelp. lib
The core is StackWalk, SymGetSymFromAddr64, and SymGetLineFromAddr64.
StackWalk is used to obtain the next stack.
SymGetSymFromAddr64 is used to obtain the current function name.
SymGetLineFromAddr64 is used to obtain the file and row number of the function.
To ensure that the three functions work properly, you must initialize the SymInitialize function to obtain the current thread description table (RtlCaptureContext) and load the used modules (SymLoadModule64 ).
The <DbgHelp. h> <TlHelp32.h> header files are used.
After the above code is executed, stack information is output on the console.
Refer:
Https://stackoverflow.com/questions/77005/how-to-generate-a-stacktrace-when-my-gcc-c-app-crashes
Http://www.codeproject.com/KB/threads/StackWalker.aspx