2016-04-27 16:00:00 +10:00
|
|
|
/*
|
2018-08-04 15:14:06 +10:00
|
|
|
* 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/.
|
2016-04-27 16:00:00 +10:00
|
|
|
*
|
|
|
|
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
|
|
|
|
*/
|
|
|
|
|
2017-11-22 16:49:37 +11:00
|
|
|
#include "backtrace.hpp"
|
2016-04-27 16:00:00 +10:00
|
|
|
|
2017-11-22 16:49:37 +11:00
|
|
|
#include "types.hpp"
|
2018-08-13 14:51:33 +10:00
|
|
|
#include "win32/except.hpp"
|
2018-08-27 14:16:27 +10:00
|
|
|
#include "win32/windows.hpp"
|
2016-04-27 16:00:00 +10:00
|
|
|
|
2019-01-04 17:11:53 +11:00
|
|
|
// windows.h needs to be included here so that it defines some symbols that
|
|
|
|
// dbghelp.h requires.
|
2019-07-02 16:37:43 +10:00
|
|
|
#include "win32/windows.hpp"
|
2016-04-27 16:00:00 +10:00
|
|
|
#include <dbghelp.h>
|
|
|
|
|
2024-02-21 15:52:50 +11:00
|
|
|
#include <fmt/ostream.h>
|
2016-04-27 16:00:00 +10:00
|
|
|
|
2019-07-02 16:37:43 +10:00
|
|
|
using cruft::backtrace;
|
2016-04-27 16:00:00 +10:00
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
backtrace::backtrace ()
|
|
|
|
{
|
2018-08-20 15:07:35 +10:00
|
|
|
if (!SymInitialize (GetCurrentProcess (), nullptr, TRUE))
|
|
|
|
cruft::win32::error::throw_code ();
|
2016-04-27 16:00:00 +10:00
|
|
|
|
|
|
|
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))
|
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::win32::error::throw_code ();
|
2016-04-27 16:00:00 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
2018-08-13 14:51:33 +10:00
|
|
|
m_frames.push_back (reinterpret_cast<void*> (frame.AddrPC.Offset));
|
2016-04-27 16:00:00 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
std::ostream&
|
2019-07-02 16:37:43 +10:00
|
|
|
cruft::operator<< (std::ostream &os, backtrace const &obj)
|
2016-04-27 16:00:00 +10:00
|
|
|
{
|
2024-02-21 15:52:50 +11:00
|
|
|
fmt::print (os, "{}", obj);
|
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
fmt::format_context::iterator
|
|
|
|
fmt::formatter<cruft::backtrace>::format (
|
|
|
|
cruft::backtrace const &obj,
|
|
|
|
fmt::format_context &ctx
|
|
|
|
) {
|
2019-07-02 16:37:43 +10:00
|
|
|
const auto process = GetCurrentProcess ();
|
2016-04-27 16:00:00 +10:00
|
|
|
|
2018-08-13 14:51:33 +10:00
|
|
|
struct {
|
2019-07-02 16:37:43 +10:00
|
|
|
SYMBOL_INFO info;
|
2016-04-27 16:00:00 +10:00
|
|
|
char name[255];
|
2019-07-02 16:37:43 +10:00
|
|
|
char null = '\0';
|
|
|
|
} sym {};
|
2016-04-27 16:00:00 +10:00
|
|
|
|
|
|
|
sym.info.SizeOfStruct = sizeof (sym.info);
|
2019-07-02 16:37:43 +10:00
|
|
|
sym.info.MaxNameLen = std::size (sym.name);
|
|
|
|
|
2024-02-21 15:52:50 +11:00
|
|
|
fmt::format_to (ctx.out (), "[ ");
|
2019-07-02 16:37:43 +10:00
|
|
|
|
|
|
|
for (auto const frame: obj.frames ()) {
|
2024-02-21 15:52:50 +11:00
|
|
|
fmt::format_to (ctx.out (), "{{ addr: {}, name: ", frame);
|
2016-04-27 16:00:00 +10:00
|
|
|
|
|
|
|
// Find the symbol name
|
|
|
|
sym.info.Name[0] = '\0';
|
|
|
|
memset (sym.name, 0, sizeof (sym.name));
|
2019-07-02 16:37:43 +10:00
|
|
|
if (FALSE == SymFromAddr (process, reinterpret_cast<uintptr_t> (frame), nullptr, &sym.info)) {
|
2024-02-21 15:52:50 +11:00
|
|
|
fmt::format_to (ctx.out (), "null }}, ");
|
2019-07-02 16:37:43 +10:00
|
|
|
} else {
|
2024-02-21 15:52:50 +11:00
|
|
|
fmt::format_to (ctx.out (), "'{}' }}, ", sym.info.Name);
|
2019-07-02 16:37:43 +10:00
|
|
|
}
|
2016-04-27 16:00:00 +10:00
|
|
|
}
|
|
|
|
|
2024-02-21 15:52:50 +11:00
|
|
|
return fmt::format_to (ctx.out (), " ]");
|
2016-04-27 16:00:00 +10:00
|
|
|
}
|