libcruft-util/backtrace_execinfo.cpp

84 lines
2.0 KiB
C++

/*
* 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 2019, Danny Robson <danny@nerdcruft.net>
*/
#include "backtrace.hpp"
#include "cast.hpp"
#include "iterator/zip.hpp"
#include <fmt/ostream.h>
#include <ostream>
#include <memory>
#include <execinfo.h>
using cruft::backtrace;
static constexpr std::size_t DEFAULT_DEPTH = 16;
///////////////////////////////////////////////////////////////////////////////
backtrace::backtrace (void)
: m_frames (DEFAULT_DEPTH)
{
do {
int const target = static_cast<int> (m_frames.size ());
int const last = ::backtrace (
m_frames.data (), target
);
if (last < target) {
m_frames.resize (last);
break;
}
m_frames.resize (m_frames.size () * 2);
} while (1);
}
///////////////////////////////////////////////////////////////////////////////
std::ostream&
cruft::operator <<(std::ostream &os, backtrace const &rhs) {
fmt::print (os, "{}", rhs);
return os;
}
///////////////////////////////////////////////////////////////////////////////
fmt::format_context::iterator
fmt::formatter<cruft::backtrace>::format (
cruft::backtrace const &obj,
fmt::format_context &ctx
) {
fmt::format_to (ctx.out (), "[ ");
auto const &frames = obj.frames ();
using strings_t = std::unique_ptr<char *, decltype(&std::free)>;
strings_t const names (
backtrace_symbols (
frames.data (),
cruft::cast::lossless <int> (frames.size ())
),
::free
);
for (auto const [idx,addr]: cruft::iterator::izip (frames)) {
fmt::format_to (
ctx.out (),
"{{ addr: {}, name: '{}', }}, ",
frames[idx],
names.get()[idx]
);
}
return fmt::format_to (ctx.out (), " ]");
}