/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2016 Danny Robson */ #include "backtrace.hpp" #include "debug.hpp" #include "types.hpp" #include "win32/except.hpp" #include "win32/windows.hpp" // windows.h needs to be included here so that it defines some symbols that // dbghelp.h requires. #include #include #include using debug::backtrace; /////////////////////////////////////////////////////////////////////////////// backtrace::backtrace () { if (!SymInitialize (GetCurrentProcess (), nullptr, TRUE)) cruft::win32::error::throw_code (); CONTEXT ctx; memset (&ctx, 0, sizeof (ctx)); ctx.ContextFlags = CONTEXT_ALL; RtlCaptureContext (&ctx); auto image_type = IMAGE_FILE_MACHINE_AMD64; STACKFRAME64 frame; memset (&frame, 0, sizeof (frame)); frame.AddrPC.Offset = ctx.Rip; frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Offset = ctx.Rsp; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrStack.Offset = ctx.Rsp; frame.AddrStack.Mode = AddrModeFlat; auto process = GetCurrentProcess (); auto thread = GetCurrentThread (); SetLastError (0); while (true) { if (!StackWalk64 (image_type, process, thread, &frame, &ctx, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, nullptr)) { cruft::win32::error::throw_code (); } // we've read the bottom of the stack if (frame.AddrReturn.Offset == 0) break; // we've reached the tail of an (apparently) infinite stack. this is a common occurence. if (frame.AddrPC.Offset == frame.AddrReturn.Offset) break; m_frames.push_back (reinterpret_cast (frame.AddrPC.Offset)); } } /////////////////////////////////////////////////////////////////////////////// std::ostream& debug::operator<< (std::ostream &os, const debug::backtrace &b) { const auto self = GetCurrentProcess (); struct { IMAGEHLP_SYMBOL64 info; char name[255]; } sym; sym.info.SizeOfStruct = sizeof (sym.info); sym.info.MaxNameLength = std::size (sym.name); for (auto frame: b.frames ()) { // Find the symbol name sym.info.Name[0] = '\0'; memset (sym.name, 0, sizeof (sym.name)); SymGetSymFromAddr64 (self, reinterpret_cast (frame), nullptr, &sym.info); *std::rbegin (sym.name) = '\0'; os << self << '\t' << frame << '\t' << sym.info.Name << '\n'; } return os; }