Creating Stacktrace for Exception in C ++ with MinGW

The message " How to generate stacktrace when a gcc C ++ application crashes " explains how a stack trace can be generated when an application crashes. But the gcc version does not work on Windows MinGW. In fact, it does not even compile due to the missing execinfo.h header.

Is there something already available for MinGW on xp windows and above?

EDIT

Using the steps below, stop varnishing was possible. But I do not get the desired result when I try to go through the stack in a catch block after an exception. I can only get the name of the function throwing the exception, and after that it shows the list β†’ main β†’ etc.

Steps:

  • First answer provided by post of Win32 API stack using MinGW / MSYS? Jose Luis Sebriana led to a link where the stack trace of Mr.Edd library can be found http://www.mr-edd.co.uk/code/stack_trace

  • The stack vulnerability available in the link above depends on dbghelp.dll. Since MinGW does not provide an import library, it was generated using dlltool of mingw. The team for which is located

    dlltool -k -d dbghelp.def -l dbghelp.a

    Note1: .def file was found in the Wine project

    Note2: library generation does not work with all versions of MinGW. I am having trouble creating it using version 4.4.1, but it worked fine with 4.6.1

  • The -lbfd, -lintl, and -liberty libraries were also used to link with -ldbghelp

  • Structured exception handling was used from the link http://www.programmingunlimited.net/siteexec/content.cgi?page=mingw-seh

Code view

  • Try as shown below. This part registers an exception handler

    { __SEH_EXCEPTION_REGISTRATION _lseh_er; __SEH_HANDLER _lseh_handler; _lseh_er.handler = reinterpret_cast<PEXCEPTION_HANDLER>(__SEH_HANDLER::ExceptionRouter); _lseh_er.exthandler = &_lseh_handler; asm volatile ("movl %%fs:0, %0" : "=r" (_lseh_er.prev)); asm volatile ("movl %0, %%fs:0" : : "r" (&_lseh_er)); int _lseh_setjmp_res = setjmp(_lseh_handler.context); while(true) { if(_lseh_setjmp_res != 0) { break; } 
  • The ExceptionRounter function calls another ExceptionHandler function, where context and record are copied. The implementation is as follows.

     EXCEPTION_DISPOSITION __SEH_HANDLER::ExceptionHandler(PEXCEPTION_RECORD pRecord, __SEH_EXCEPTION_REGISTRATION* pReg, PCONTEXT pContext, PEXCEPTION_RECORD pRecord2) { CopyMemory(&excContext, pContext, sizeof(_CONTEXT)); CopyMemory(&excRecord, pRecord, sizeof(_EXCEPTION_RECORD)); // Jump back to the function where the exception actually occurred. The 1 is the // return code that will be returned by set_jmp. longjmp(context, 1); } 
  • After that, my code that throws an exception

  • Next, the implementation of catch or seh_excep is executed.

     break; } PEXCEPTION_RECORD rec = &_lseh_handler.excRecord; PCONTEXT ctx = &_lseh_handler.excContext; asm volatile ("movl %0, %%fs:0" : : "r" (_lseh_er.prev)); if(_lseh_setjmp_res != 0) 
  • Then the code appears to go to the stack from the Mr.Edd stackupler server.

     lock lk(g_fill_frames_mtx); symbol_context sc; bfd_context bfdc; STACKFRAME frame = empty_pod; CONTEXT context = empty_pod; context.ContextFlags = CONTEXT_FULL; /*Below part is commented as the context of the exception causing code has to be used and not the current context*/ /* windows_dll kernel32("kernel32.dll"); void (WINAPI *RtlCaptureContext_)(CONTEXT*) = kernel32.function("RtlCaptureContext"); RtlCaptureContext_(&context); */ context = _lseh_handler.excContex; frame.AddrPC.Offset = context.Eip; frame.AddrPC.Mode = AddrModeFlat; frame.AddrStack.Offset = context.Esp; frame.AddrStack.Mode = AddrModeFlat; frame.AddrFrame.Offset = context.Ebp; frame.AddrFrame.Mode = AddrModeFlat; HANDLE process = GetCurrentProcess(); HANDLE thread = GetCurrentThread(); bool skip = true; bool has_limit = limit != 0; char symbol_buffer[sizeof(IMAGEHLP_SYMBOL) + 255]; char module_name_raw[MAX_PATH]; const DWORD machine = IMAGE_FILE_MACHINE_I386; while(StackWalk(machine, process, thread, &frame, &context, 0, SymFunctionTableAccess, SymGetModuleBase, 0)) { if (skip) { skip = false; continue; } if (has_limit && limit-- == 0) break; IMAGEHLP_SYMBOL *symbol = reinterpret_cast<IMAGEHLP_SYMBOL *>(symbol_buffer); symbol->SizeOfStruct = (sizeof *symbol) + 255; symbol->MaxNameLength = 254; DWORD module_base = SymGetModuleBase(process, frame.AddrPC.Offset); std::string module_name = unknown_module; if (module_base && GetModuleFileNameA(reinterpret_cast<HINSTANCE>(module_base), module_name_raw, MAX_PATH)) module_name = module_name_raw; std::string func = bfdc.get_function_name(frame.AddrPC.Offset); if (func.empty()) { DWORD dummy = 0; BOOL got_symbol = SymGetSymFromAddr(process, frame.AddrPC.Offset, &dummy, symbol); func = got_symbol ? symbol->Name : unknown_function; } dbg::stack_frame f(reinterpret_cast<const void *>(frame.AddrPC.Offset), func, module_name); frames.push_back(f); } } } std::copy(frames.begin(), frames.end(), std::ostream_iterator<dbg::stack_frame>(std::cout, "\n")); 

Regards, Shreias

+4
source share
1 answer

LibSEH is available at http://www.programmingunlimited.net/siteexec/content.cgi?page=libseh fixed the problem.

From the answers I received, I could conclude that in my implementation the exception handling code was called in the same context as the code that caused the exception. This will overwrite the now unnecessary part of the stack.

However, the filter functions of the exception handling are performed in a different context and by placing the stack tracer in the filter function, the desired results can be achieved.

Thus, I used libseh, which provides exception handling functions similar to those found in MSVC, and wrote a stack tracer in the filter function.

0
source

All Articles