// getstacktrace - Traces the stack as far back as possible, or until 'maxdepth' // frames have been traced. Populates the CallStack with one entry for each // stack frame traced. // // Note: This function uses a documented Windows API to walk the stack. This // API is supposed to be the most reliable way to walk the stack. It claims // to be able to walk stack frames that do not follow the conventional stack // frame layout. However, this robustness comes at a cost: it is *extremely* // slow compared to walking frames by following frame (base) pointers. // // - maxdepth (IN): Maximum number of frames to trace back. // // - framepointer (IN): Frame (base) pointer at which to begin the stack trace. // If NULL, then the stack trace will begin at this function. // // Return Value: // // None. // VOID SafeCallStack::getstacktrace (UINT32 maxdepth, SIZE_T *framepointer) { DWORD architecture; CONTEXT context; UINT32 count = 0; STACKFRAME64 frame; SIZE_T programcounter; SIZE_T stackpointer; if (framepointer == NULL) { // Begin the stack trace with the current frame. Obtain the current // frame pointer. FRAMEPOINTER(framepointer); } // Get the required values for initialization of the STACKFRAME64 structure // to be passed to StackWalk64(). Required fields are AddrPC and AddrFrame. #if defined(_M_IX86) || defined(_M_X64) architecture = X86X64ARCHITECTURE; programcounter = *(framepointer + 1); stackpointer = *framepointer; // An approximation. context.BPREG = *framepointer; context.IPREG = programcounter; context.SPREG = stackpointer; #else // If you want to retarget Visual Leak Detector to another processor // architecture then you'll need to provide architecture-specific code to // obtain the program counter and stack pointer from the given frame pointer. #error "Visual Leak Detector is not supported on this architecture." #endif // _M_IX86 || _M_X64 // Initialize the STACKFRAME64 structure. memset(&frame, 0x0, sizeof(frame)); frame.AddrFrame.Offset = *framepointer; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrPC.Offset = programcounter; frame.AddrPC.Mode = AddrModeFlat; frame.AddrStack.Offset = stackpointer; frame.AddrStack.Mode = AddrModeFlat; // Walk the stack. while (count < maxdepth) { count++; if (!pStackWalk64(architecture, currentprocess, currentthread, &frame, &context, NULL, pSymFunctionTableAccess64, pSymGetModuleBase64, NULL)) { // Couldn't trace back through any more frames. break; } if (frame.AddrFrame.Offset == 0) { // End of stack. break; } // Push this frame's program counter onto the CallStack. push_back((SIZE_T)frame.AddrPC.Offset); } }
noreturn snakeBoot(procedure_t *entry, int argc, char* argv[]) { setWaterMark(FRAMEPOINTER()); trap_closure = procClosure(entry); trap_argc = 0; trap_argv = NULL; setjmp(stackreset); trap_closure->procedure->proc(trap_closure, trap_argc, trap_argv); }
// getstacktrace - Traces the stack as far back as possible, or until 'maxdepth' // frames have been traced. Populates the CallStack with one entry for each // stack frame traced. // // Note: This function uses a very efficient method to walk the stack from // frame to frame, so it is quite fast. However, unconventional stack frames // (such as those created when frame pointer omission optimization is used) // will not be successfully walked by this function and will cause the // stack trace to terminate prematurely. // // - maxdepth (IN): Maximum number of frames to trace back. // // - framepointer (IN): Frame (base) pointer at which to begin the stack trace. // If NULL, then the stack trace will begin at this function. // // Return Value: // // None. // VOID FastCallStack::getstacktrace (UINT32 maxdepth, SIZE_T *framepointer) { UINT32 count = 0; if (framepointer == NULL) { // Begin the stack trace with the current frame. Obtain the current // frame pointer. FRAMEPOINTER(framepointer); } while (count < maxdepth) { if ((SIZE_T*)*framepointer < framepointer) { if ((SIZE_T*)*framepointer == NULL) { // Looks like we reached the end of the stack. break; } else { // Invalid frame pointer. Frame pointer addresses should always // increase as we move up the stack. m_status |= CALLSTACK_STATUS_INCOMPLETE; break; } } if ((SIZE_T)*framepointer & (sizeof(SIZE_T*) - 1)) { // Invalid frame pointer. Frame pointer addresses should always // be aligned to the size of a pointer. This probably means that // we've encountered a frame that was created by a module built with // frame pointer omission (FPO) optimization turned on. m_status |= CALLSTACK_STATUS_INCOMPLETE; break; } if (IsBadReadPtr((SIZE_T*)*framepointer, sizeof(SIZE_T*))) { // Bogus frame pointer. Again, this probably means that we've // encountered a frame built with FPO optimization. m_status |= CALLSTACK_STATUS_INCOMPLETE; break; } count++; push_back(*(framepointer + 1)); framepointer = (SIZE_T*)*framepointer; } }