Skip to content

Instantly share code, notes, and snippets.

@shawwn
Created May 29, 2022 22:30
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save shawwn/0839ea40a3ea4f00930177c4f1e2d2df to your computer and use it in GitHub Desktop.
Code for printing out C++ stack traces
/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#if defined(_MSC_VER)
#include <windows.h>
#include <cstring>
#else
#include <cxxabi.h>
#include <cstdlib>
#endif
#include <memory>
#include <string>
#if defined(_MSC_VER)
extern "C" char* __unDName(char* output_string, const char* name,
int max_string_length, void* (*p_alloc)(std::size_t),
void (*p_free)(void*), unsigned short disable_flags);
#endif // defined(_MSC_VER)
namespace sg {
std::string MaybeAbiDemangle(const char* name) {
#if defined(_MSC_VER)
std::unique_ptr<char> demangled{__unDName(nullptr, name, 0, std::malloc,
std::free,
static_cast<unsigned short>(0))};
return std::string(demangled.get() != nullptr ? demangled.get() : name);
#else
int status = 0;
std::unique_ptr<char, void (*)(void*)> res{
abi::__cxa_demangle(name, nullptr, nullptr, &status), std::free};
return (status == 0) ? res.get() : name;
#endif
}
} // namespace sg
#pragma once
#include <string>
namespace sg {
extern std::string MaybeAbiDemangle(const char* name);
}
#ifndef SG_HAS_STACKTRACE
#if !defined(IS_MOBILE_PLATFORM) && (defined(__clang__) || defined(__GNUC__))
#define SG_HAS_STACKTRACE 1
#endif
#endif
#if defined(SG_HAS_STACKTRACE)
#include <dlfcn.h>
#include <execinfo.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#endif
#include <sstream>
#include <string>
#include "demangle.hpp"
#include "stacktrace.hpp"
std::string sg::stacktrace(bool detailed) {
#if defined(SG_HAS_STACKTRACE)
std::stringstream ss("");
ss << "*** Begin stack trace ***" << std::endl;
// Get the mangled stack trace.
int buffer_size = 2048;
void* trace[2048];
buffer_size = backtrace(trace, buffer_size);
for (int i = 0; i < buffer_size; ++i) {
// typedef struct dl_info {
// const char *dli_fname; /* Pathname of shared object */
// void *dli_fbase; /* Base address of shared object */
// const char *dli_sname; /* Name of nearest symbol */
// void *dli_saddr; /* Address of nearest symbol */
// }
const char* exe = "(null)";
const char* symbol = "(null)";
void* base_addr = nullptr;
void* symbol_addr = nullptr;
Dl_info info;
if (dladdr(trace[i], &info)) {
if (info.dli_fname != nullptr) {
exe = info.dli_fname;
}
if (info.dli_sname != nullptr) {
symbol = info.dli_sname;
}
base_addr = info.dli_fbase;
symbol_addr = info.dli_saddr;
}
std::string demangled = sg::MaybeAbiDemangle(symbol);
std::string name(demangled.length() ? demangled : symbol);
if (detailed) {
char base[256];
sprintf(base, "%p", base_addr);
ss << "#" << i << " (" << trace[i] << "): " << exe << "\t" << base << "\t" << symbol_addr << "\t" << name << std::endl;
} else {
ss << "\t" << name << std::endl;
}
}
ss << "*** End stack trace ***" << std::endl;
return ss.str();
#else
return std::string();
#endif // defined(SG_HAS_STACKTRACE)
}
#pragma once
#include <string>
namespace sg {
std::string stacktrace(bool detailed = false);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment