Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Here's some stack-walk code for Windows I wrote some years ago. Here's the kind of output it produces:</p> <pre><code>Walking stack. 0 DebugBreak 1 ThreadFunc2 e:\c\source\stackwalk2a.cpp(72) 2 ThreadFunc1 e:\c\source\stackwalk2a.cpp(79) 3 TargetThread e:\c\source\stackwalk2a.cpp(86) 4 BaseThreadInitThunk 5 RtlUserThreadStart End of stack walk. </code></pre> <p>The main thing that's missing is anything about the exception type. If you're talking about a native structured/vectored exception, I'm pretty sure that should be retrievable too. Retrieving types of C++ exceptions might be a little more difficult (but I'm not really sure -- it might be pretty easy).</p> <pre><code>#include &lt;windows.h&gt; #include &lt;winnt.h&gt; #include &lt;string&gt; #include &lt;vector&gt; #include &lt;Psapi.h&gt; #include &lt;algorithm&gt; #include &lt;iomanip&gt; #include &lt;iostream&gt; #include &lt;stdexcept&gt; #include &lt;iterator&gt; #pragma comment(lib, "psapi.lib") #pragma comment(lib, "dbghelp.lib") // Some versions of imagehlp.dll lack the proper packing directives themselves // so we need to do it. #pragma pack( push, before_imagehlp, 8 ) #include &lt;imagehlp.h&gt; #pragma pack( pop, before_imagehlp ) struct module_data { std::string image_name; std::string module_name; void *base_address; DWORD load_size; }; typedef std::vector&lt;module_data&gt; ModuleList; HANDLE thread_ready; bool show_stack(std::ostream &amp;, HANDLE hThread, CONTEXT&amp; c); DWORD __stdcall TargetThread( void *arg ); void ThreadFunc1(); void ThreadFunc2(); DWORD Filter( EXCEPTION_POINTERS *ep ); void *load_modules_symbols( HANDLE hProcess, DWORD pid ); int main( void ) { DWORD thread_id; thread_ready = CreateEvent( NULL, false, false, NULL ); HANDLE thread = CreateThread( NULL, 0, TargetThread, NULL, 0, &amp;thread_id ); WaitForSingleObject( thread_ready, INFINITE ); CloseHandle(thread_ready); return 0; } // if you use C++ exception handling: install a translator function // with set_se_translator(). In the context of that function (but *not* // afterwards), you can either do your stack dump, or save the CONTEXT // record as a local copy. Note that you must do the stack dump at the // earliest opportunity, to avoid the interesting stack-frames being gone // by the time you do the dump. DWORD Filter(EXCEPTION_POINTERS *ep) { HANDLE thread; DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &amp;thread, 0, false, DUPLICATE_SAME_ACCESS); std::cout &lt;&lt; "Walking stack."; show_stack(std::cout, thread, *(ep-&gt;ContextRecord)); std::cout &lt;&lt; "\nEnd of stack walk.\n"; CloseHandle(thread); return EXCEPTION_EXECUTE_HANDLER; } void ThreadFunc2() { __try { DebugBreak(); } __except (Filter(GetExceptionInformation())) { } SetEvent(thread_ready); } void ThreadFunc1(void (*f)()) { f(); } // We'll do a few levels of calls from our thread function so // there's something on the stack to walk... // DWORD __stdcall TargetThread(void *) { ThreadFunc1(ThreadFunc2); return 0; } class SymHandler { HANDLE p; public: SymHandler(HANDLE process, char const *path=NULL, bool intrude = false) : p(process) { if (!SymInitialize(p, path, intrude)) throw(std::logic_error("Unable to initialize symbol handler")); } ~SymHandler() { SymCleanup(p); } }; #ifdef _M_X64 STACKFRAME64 init_stack_frame(CONTEXT c) { STACKFRAME64 s; s.AddrPC.Offset = c.Rip; s.AddrPC.Mode = AddrModeFlat; s.AddrStack.Offset = c.Rsp; s.AddrStack.Mode = AddrModeFlat; s.AddrFrame.Offset = c.Rbp; s.AddrFrame.Mode = AddrModeFlat; return s; } #else STACKFRAME64 init_stack_frame(CONTEXT c) { STACKFRAME64 s; s.AddrPC.Offset = c.Eip; s.AddrPC.Mode = AddrModeFlat; s.AddrStack.Offset = c.Esp; s.AddrStack.Mode = AddrModeFlat; s.AddrFrame.Offset = c.Ebp; s.AddrFrame.Mode = AddrModeFlat; return s; } #endif void sym_options(DWORD add, DWORD remove=0) { DWORD symOptions = SymGetOptions(); symOptions |= add; symOptions &amp;= ~remove; SymSetOptions(symOptions); } class symbol { typedef IMAGEHLP_SYMBOL64 sym_type; sym_type *sym; static const int max_name_len = 1024; public: symbol(HANDLE process, DWORD64 address) : sym((sym_type *)::operator new(sizeof(*sym) + max_name_len)) { memset(sym, '\0', sizeof(*sym) + max_name_len); sym-&gt;SizeOfStruct = sizeof(*sym); sym-&gt;MaxNameLength = max_name_len; DWORD64 displacement; if (!SymGetSymFromAddr64(process, address, &amp;displacement, sym)) throw(std::logic_error("Bad symbol")); } std::string name() { return std::string(sym-&gt;Name); } std::string undecorated_name() { std::vector&lt;char&gt; und_name(max_name_len); UnDecorateSymbolName(sym-&gt;Name, &amp;und_name[0], max_name_len, UNDNAME_COMPLETE); return std::string(&amp;und_name[0], strlen(&amp;und_name[0])); } }; bool show_stack(std::ostream &amp;os, HANDLE hThread, CONTEXT&amp; c) { HANDLE process = GetCurrentProcess(); int frame_number=0; DWORD offset_from_symbol=0; IMAGEHLP_LINE64 line = {0}; SymHandler handler(process); sym_options(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); void *base = load_modules_symbols(process, GetCurrentProcessId()); STACKFRAME64 s = init_stack_frame(c); line.SizeOfStruct = sizeof line; IMAGE_NT_HEADERS *h = ImageNtHeader(base); DWORD image_type = h-&gt;FileHeader.Machine; do { if (!StackWalk64(image_type, process, hThread, &amp;s, &amp;c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) return false; os &lt;&lt; std::setw(3) &lt;&lt; "\n" &lt;&lt; frame_number &lt;&lt; "\t"; if ( s.AddrPC.Offset != 0 ) { std::cout &lt;&lt; symbol(process, s.AddrPC.Offset).undecorated_name(); if (SymGetLineFromAddr64( process, s.AddrPC.Offset, &amp;offset_from_symbol, &amp;line ) ) os &lt;&lt; "\t" &lt;&lt; line.FileName &lt;&lt; "(" &lt;&lt; line.LineNumber &lt;&lt; ")"; } else os &lt;&lt; "(No Symbols: PC == 0)"; ++frame_number; } while (s.AddrReturn.Offset != 0); return true; } class get_mod_info { HANDLE process; static const int buffer_length = 4096; public: get_mod_info(HANDLE h) : process(h) {} module_data operator()(HMODULE module) { module_data ret; char temp[buffer_length]; MODULEINFO mi; GetModuleInformation(process, module, &amp;mi, sizeof(mi)); ret.base_address = mi.lpBaseOfDll; ret.load_size = mi.SizeOfImage; GetModuleFileNameEx(process, module, temp, sizeof(temp)); ret.image_name = temp; GetModuleBaseName(process, module, temp, sizeof(temp)); ret.module_name = temp; std::vector&lt;char&gt; img(ret.image_name.begin(), ret.image_name.end()); std::vector&lt;char&gt; mod(ret.module_name.begin(), ret.module_name.end()); SymLoadModule64(process, 0, &amp;img[0], &amp;mod[0], (DWORD64)ret.base_address, ret.load_size); return ret; } }; void *load_modules_symbols(HANDLE process, DWORD pid) { ModuleList modules; DWORD cbNeeded; std::vector&lt;HMODULE&gt; module_handles(1); EnumProcessModules(process, &amp;module_handles[0], module_handles.size() * sizeof(HMODULE), &amp;cbNeeded); module_handles.resize(cbNeeded/sizeof(HMODULE)); EnumProcessModules(process, &amp;module_handles[0], module_handles.size() * sizeof(HMODULE), &amp;cbNeeded); std::transform(module_handles.begin(), module_handles.end(), std::back_inserter(modules), get_mod_info(process)); return modules[0].base_address; } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload