From 928cdb4e8bb995cce6f861d8f783422617122e02 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 2 Jul 2019 16:37:43 +1000 Subject: [PATCH] backtrace: give consistent outputs for backtrace --- backtrace.hpp | 22 ++++++---------- backtrace_execinfo.cpp | 56 ++++++++++++++++++++++++----------------- backtrace_stackwalk.cpp | 31 ++++++++++++++--------- backtrace_win32.cpp | 25 +++++++++++------- debug/assert.cpp | 2 +- debug/system.cpp | 6 ++--- test/backtrace.cpp | 2 +- 7 files changed, 81 insertions(+), 63 deletions(-) diff --git a/backtrace.hpp b/backtrace.hpp index 9d2a8230..3fc6bd4f 100644 --- a/backtrace.hpp +++ b/backtrace.hpp @@ -3,33 +3,27 @@ * 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 2010-2014 Danny Robson + * Copyright 2019, Danny Robson */ -#ifndef __UTIL_BACKTRACE_HPP -#define __UTIL_BACKTRACE_HPP +#pragma once -#include #include #include -//----------------------------------------------------------------------------- -namespace debug { +/////////////////////////////////////////////////////////////////////////////// +namespace cruft { class backtrace { - protected: - static const unsigned int DEFAULT_DEPTH = 16; - std::vector m_frames; - public: backtrace (void); const auto& frames(void) const { return m_frames; } + + private: + std::vector m_frames; }; std::ostream& - operator<< (std::ostream&, const debug::backtrace&); + operator<< (std::ostream&, backtrace const&); } - - -#endif diff --git a/backtrace_execinfo.cpp b/backtrace_execinfo.cpp index b3247197..13a19959 100644 --- a/backtrace_execinfo.cpp +++ b/backtrace_execinfo.cpp @@ -3,47 +3,53 @@ * 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 2010-2014 Danny Robson + * Copyright 2019, Danny Robson */ - #include "backtrace.hpp" -#include "debug/assert.hpp" -#include "exe.hpp" -#include "io.hpp" #include "cast.hpp" +#include "iterator/zip.hpp" -#include -#include -#include -#include +#include #include +#include + +using cruft::backtrace; + +static constexpr std::size_t DEFAULT_DEPTH = 16; + /////////////////////////////////////////////////////////////////////////////// -debug::backtrace::backtrace (void): - m_frames (DEFAULT_DEPTH) +backtrace::backtrace (void) + : m_frames (DEFAULT_DEPTH) { - size_t last; - size_t size = m_frames.size (); + do { + int const target = static_cast (m_frames.size ()); + int const last = ::backtrace ( + m_frames.data (), target + ); - while ((last = ::backtrace (&m_frames[0], cruft::cast::lossless (m_frames.size ()))) == size) - m_frames.resize (size = m_frames.size () * 2); + if (last < target) { + m_frames.resize (last); + break; + } - CHECK_GT (last, 0u); - m_frames.resize (last); + m_frames.resize (m_frames.size () * 2); + } while (1); } /////////////////////////////////////////////////////////////////////////////// std::ostream& -debug::operator <<(std::ostream &os, const debug::backtrace &rhs) { +cruft::operator <<(std::ostream &os, backtrace const &rhs) { + os << "[ "; + auto const &frames = rhs.frames (); - // We don't use the array form of unique_ptr as clang fails on ambigious constructors - using str_t = std::unique_ptr; - str_t names ( + using strings_t = std::unique_ptr; + strings_t const names ( backtrace_symbols ( frames.data (), cruft::cast::lossless (frames.size ()) @@ -51,8 +57,12 @@ debug::operator <<(std::ostream &os, const debug::backtrace &rhs) { ::free ); - for (unsigned int i = 0; i < frames.size (); ++i) - os << frames[i] << '\t' << names.get()[i] << '\n'; + for (auto const [idx,addr]: cruft::iterator::izip (frames)) { + os << "{ addr: " << frames[idx] + << ", name: '" << names.get()[idx] << '\'' + << " }, "; + } + os << " ]"; return os; } diff --git a/backtrace_stackwalk.cpp b/backtrace_stackwalk.cpp index de906098..134e98cf 100644 --- a/backtrace_stackwalk.cpp +++ b/backtrace_stackwalk.cpp @@ -14,12 +14,12 @@ // windows.h needs to be included here so that it defines some symbols that // dbghelp.h requires. -#include +#include "win32/windows.hpp" #include #include -using debug::backtrace; +using cruft::backtrace; /////////////////////////////////////////////////////////////////////////////// @@ -78,27 +78,34 @@ backtrace::backtrace () /////////////////////////////////////////////////////////////////////////////// std::ostream& -debug::operator<< (std::ostream &os, const debug::backtrace &b) +cruft::operator<< (std::ostream &os, backtrace const &obj) { - const auto self = GetCurrentProcess (); + const auto process = GetCurrentProcess (); struct { - IMAGEHLP_SYMBOL64 info; + SYMBOL_INFO info; char name[255]; - } sym; + char null = '\0'; + } sym {}; sym.info.SizeOfStruct = sizeof (sym.info); - sym.info.MaxNameLength = std::size (sym.name); + sym.info.MaxNameLen = std::size (sym.name); + + os << "[ "; + + for (auto const frame: obj.frames ()) { + os << "{ addr: " << frame << ", 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'; + if (FALSE == SymFromAddr (process, reinterpret_cast (frame), nullptr, &sym.info)) { + os << "null }, "; + } else { + os << '\'' << sym.info.Name << "' }, "; + } } + os << " ]"; return os; } diff --git a/backtrace_win32.cpp b/backtrace_win32.cpp index 7e04a702..c7b7f231 100644 --- a/backtrace_win32.cpp +++ b/backtrace_win32.cpp @@ -4,7 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright: - * 2012-2016, Danny Robson + * 2012-2019, Danny Robson */ #include "backtrace.hpp" @@ -18,9 +18,13 @@ #include #include +using cruft::backtrace; + +static constexpr std::size_t DEFAULT_DEPTH = 16; + /////////////////////////////////////////////////////////////////////////////// -debug::backtrace::backtrace (void) +backtrace::backtrace (void) { m_frames.resize (DEFAULT_DEPTH); @@ -29,8 +33,8 @@ debug::backtrace::backtrace (void) cruft::win32::error::throw_code (); while (true) { - auto res = CaptureStackBackTrace (1, m_frames.size (), m_frames.data (), NULL); - if (res != m_frames.size ()) { + auto const res = CaptureStackBackTrace (1, m_frames.size (), m_frames.data (), NULL); + if (res < m_frames.size ()) { m_frames.resize (res); break; } @@ -42,9 +46,8 @@ debug::backtrace::backtrace (void) /////////////////////////////////////////////////////////////////////////////// std::ostream& -debug::operator <<(std::ostream &os, const debug::backtrace &rhs) { - static auto self = GetCurrentProcess (); - static auto ready = SymInitialize (self, nullptr, TRUE); +debug::operator <<(std::ostream &os, ::cruft::backtrace const &rhs) { + static auto process = GetCurrentProcess (); CHECK (ready); static constexpr size_t MAX_LENGTH = 255; @@ -56,13 +59,17 @@ debug::operator <<(std::ostream &os, const debug::backtrace &rhs) { symbol.info.MaxNameLen = MAX_LENGTH; symbol.info.SizeOfStruct = sizeof (SYMBOL_INFO); + os << "[ "; for (void *frame: rhs.frames ()) { symbol.name[0] = '\0'; - SymFromAddr (self, (DWORD64)frame, 0, &symbol.info); + SymFromAddr (process, (DWORD64)frame, 0, &symbol.info); symbol.name[MAX_LENGTH] = '\0'; - os << self << "\t" << frame << "\t" << symbol.name << "\n"; + os << "{ addr: " << frame + << ", name: '" << symbol.name '\'' + << " }, "; } + os << " ]"; return os; } diff --git a/debug/assert.cpp b/debug/assert.cpp index dce89af3..b381f132 100644 --- a/debug/assert.cpp +++ b/debug/assert.cpp @@ -18,7 +18,7 @@ void cruft::debug::detail::panic (const char *msg) { - std::cerr << "PANIC: " << msg << "\n" << ::debug::backtrace () << std::endl; + std::cerr << "PANIC: " << msg << "\n" << ::cruft::backtrace () << std::endl; breakpoint (); abort (); } diff --git a/debug/system.cpp b/debug/system.cpp index dc7bc0b1..0f16a929 100644 --- a/debug/system.cpp +++ b/debug/system.cpp @@ -33,12 +33,12 @@ static void abort_with_trace (void) try { std::rethrow_exception (ptr); } catch (std::exception const &x) { - LOG_EMERGENCY ("unhandled exception: %!\n%!", x.what (), debug::backtrace {}); + LOG_EMERGENCY ("unhandled exception: %!\n%!", x.what (), ::cruft::backtrace {}); } catch (...) { - LOG_EMERGENCY ("unhandled exception: %!\n", debug::backtrace {}); + LOG_EMERGENCY ("unhandled exception: %!\n", ::cruft::backtrace {}); } } else { - LOG_EMERGENCY ("aborting: %!", debug::backtrace {}); + LOG_EMERGENCY ("aborting: %!", ::cruft::backtrace {}); } std::abort (); diff --git a/test/backtrace.cpp b/test/backtrace.cpp index da050732..1238c403 100644 --- a/test/backtrace.cpp +++ b/test/backtrace.cpp @@ -11,7 +11,7 @@ main (int, char **) { cruft::TAP::logger tap; // Instantiate a backtrace just so we know that linking has worked. - debug::backtrace foo; + ::cruft::backtrace foo; (void)foo; tap.noop ();