Program Listing for File backtrace.inl¶
↰ Return to documentation for file (umpire/util/backtrace.inl
)
//////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016-20, Lawrence Livermore National Security, LLC and Umpire
// project contributors. See the COPYRIGHT file for details.
//
// SPDX-License-Identifier: (MIT)
//////////////////////////////////////////////////////////////////////////////
#ifndef UMPIRE_Backtrace_INL
#define UMPIRE_Backtrace_INL
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>
#include "umpire/config.hpp"
#include "umpire/util/backtrace.hpp"
#if !defined(_MSC_VER) && !defined(_LIBCPP_VERSION)
#include <cxxabi.h> // for __cxa_demangle
#endif // !defined(_MSC_VER) && !defined(_LIBCPP_VERSION)
#if !defined(_MSC_VER)
#if defined(UMPIRE_ENABLE_BACKTRACE_SYMBOLS)
#include <dlfcn.h> // for dladdr
#endif // defined(UMPIRE_ENABLE_BACKTRACE_SYMBOLS)
#include <execinfo.h> // for backtrace
#endif // !defined(_MSC_VER)
namespace umpire {
namespace util {
namespace {
bool backtrace_enabled()
{
static bool enabled{false};
#if !defined(_WIN32)
static bool initialized{false};
if (!initialized) {
const char* enval{getenv("UMPIRE_BACKTRACE")};
if (enval) {
std::string env_str{enval};
std::transform(env_str.begin(), env_str.end(), env_str.begin(),
::toupper);
if (env_str.find("ON") != std::string::npos) {
enabled = true;
}
}
initialized = true;
}
#endif
return enabled;
}
std::vector<void*> build_backtrace()
{
std::vector<void*> frames;
#if !defined(_MSC_VER)
void* callstack[128];
const int nMaxFrames = sizeof(callstack) / sizeof(callstack[0]);
for (int i = 0; i < ::backtrace(callstack, nMaxFrames); ++i)
frames.push_back(callstack[i]);
#endif // !defined(_MSC_VER)
return frames;
}
std::string stringify(const std::vector<void*>& frames)
{
std::ostringstream backtrace_stream;
#if !defined(_MSC_VER)
int num_frames = frames.size();
char** symbols = ::backtrace_symbols(&frames[0], num_frames);
backtrace_stream << " Backtrace: " << num_frames << " frames" << std::endl;
int index{0};
for (const auto& it : frames) {
backtrace_stream << " " << index << " " << it << " ";
#if defined(UMPIRE_ENABLE_BACKTRACE_SYMBOLS)
Dl_info info;
if (dladdr(it, &info) && info.dli_sname) {
char* demangled = NULL;
int status = -1;
#if !defined(_LIBCPP_VERSION)
if (info.dli_sname[0] == '_')
demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status);
#endif // !defined(_MSC_VER) && !defined(_LIBCPP_VERSION)
backtrace_stream << (status == 0 ? demangled
: (info.dli_sname == 0 ? symbols[index]
: info.dli_sname))
<< "+0x" << std::hex
<< static_cast<int>(static_cast<char*>(it) -
static_cast<char*>(info.dli_saddr));
#if !defined(_LIBCPP_VERSION)
free(demangled);
#endif // !defined(_MSC_VER) && !defined(_LIBCPP_VERSION)
} else
#endif // defined(UMPIRE_ENABLE_BACKTRACE_SYMBOLS)
{
backtrace_stream << "No dladdr: " << symbols[index];
}
backtrace_stream << std::endl;
++index;
}
free(symbols);
#else
static_cast<void>(frames);
backtrace_stream << " Backtrace not supported on Windows" << std::endl;
#endif
return backtrace_stream.str();
}
} // namespace
template <>
struct backtracer<trace_optional> {
static void get_backtrace(backtrace& bt)
{
if (backtrace_enabled())
bt.frames = build_backtrace();
}
static std::string print(const backtrace& bt)
{
if (backtrace_enabled()) {
return stringify(bt.frames);
} else {
return "[UMPIRE_BACKTRACE=Off]";
}
}
};
template <>
struct backtracer<trace_always> {
static void get_backtrace(backtrace& bt)
{
bt.frames = build_backtrace();
}
static std::string print(const backtrace& bt)
{
return stringify(bt.frames);
}
};
} // end of namespace util
} // end of namespace umpire
#endif // UMPIRE_Backtrace_INL