[symbolize] generalize API and implementation

This commit is contained in:
Aliaksei Kandratsenka 2024-10-05 17:53:00 -04:00
parent 03d361bff8
commit 6e4984bc1b
2 changed files with 97 additions and 42 deletions

View File

@ -45,8 +45,8 @@ namespace tcmalloc {
class SymbolizePrinter { class SymbolizePrinter {
public: public:
SymbolizePrinter(backtrace_state* state, std::string_view line_prefix) SymbolizePrinter(backtrace_state* state, FunctionRef<void(const SymbolizeOutcome& outcome)> outcome_callback)
: state_(state), line_prefix_(line_prefix) {} : state_(state), outcome_callback_{outcome_callback} {}
void OnePC(uintptr_t pc) { void OnePC(uintptr_t pc) {
if (!state_) { if (!state_) {
@ -110,63 +110,85 @@ public:
demangled = nullptr; demangled = nullptr;
} }
} }
if (demangled) {
function = demangled;
}
#endif #endif
if (filename != nullptr) { SymbolizeOutcome outcome;
// We assume that function name is not blank in this case. outcome.pc = pc;
fprintf(stderr, "%.*s%p %s %s:%d\n", outcome.function = demangled ? demangled : function;
(int)line_prefix_.size(), line_prefix_.data(), outcome.original_function = function;
reinterpret_cast<void*>(pc), outcome.filename = filename;
function, outcome.lineno = lineno;
filename, lineno); outcome.symval = symval;
} else if (function == nullptr) {
fprintf(stderr, "%.*s%p\n", outcome_callback_(outcome);
(int)line_prefix_.size(), line_prefix_.data(),
reinterpret_cast<void*>(pc));
} else if (symval != 0) {
fprintf(stderr, "%.*s%p %s + %zu\n",
(int)line_prefix_.size(), line_prefix_.data(),
reinterpret_cast<void*>(pc),
function, pc - symval);
} else {
fprintf(stderr, "%.*s%p %s\n",
(int)line_prefix_.size(), line_prefix_.data(),
reinterpret_cast<void*>(pc),
function);
}
free(demangled); free(demangled);
} }
private: private:
backtrace_state* const state_; backtrace_state* const state_;
std::string_view const line_prefix_; FunctionRef<void(const SymbolizeOutcome&)> const outcome_callback_;
uintptr_t pc_{}; uintptr_t pc_{};
bool want_syminfo_; bool want_syminfo_;
}; };
void DumpStackTraceToStderr(void * const *stack, int stack_depth, SymbolizerAPI::SymbolizerAPI(FunctionRef<void(const SymbolizeOutcome& outcome)> *callback)
bool want_symbolize, std::string_view line_prefix) { : callback_(callback),
backtrace_state* state = nullptr;
if (want_symbolize) {
// note, we create fresh un-threaded backtrace state which we // note, we create fresh un-threaded backtrace state which we
// "dispose" at the end. This is contrary to libbacktrace's normal // "dispose" at the end. This is contrary to libbacktrace's normal
// recommendations. // recommendations.
state = tcmalloc_backtrace_create_state(nullptr, /*threaded = */0, nullptr, nullptr); state_(tcmalloc_backtrace_create_state(nullptr, /*threaded = */0, nullptr, nullptr)) {}
void SymbolizerAPI::Add(uintptr_t addr) const {
SymbolizePrinter{state_, *callback_}.OnePC(addr);
}
SymbolizerAPI::~SymbolizerAPI() {
tcmalloc_backtrace_dispose_state(state_);
}
void DumpStackTraceToStderr(void * const *stack, int stack_depth,
bool want_symbolize, std::string_view line_prefix) {
if (!want_symbolize) {
for (int i = 0; i < stack_depth; i++) {
fprintf(stderr,"%.*s%p\n",
(int)line_prefix.size(), line_prefix.data(),
stack[i]);
}
return;
} }
SymbolizePrinter printer{state, line_prefix}; SymbolizerAPI::With(
for (int i = 0; i < stack_depth; i++) { [&] (const SymbolizerAPI& api) {
printer.OnePC(reinterpret_cast<uintptr_t>(stack[i]) - 1); for (int i = 0; i < stack_depth; i++) {
} api.Add(reinterpret_cast<uintptr_t>(stack[i]) - 1);
}
if (state) { },
tcmalloc_backtrace_dispose_state(state); [&] (const SymbolizeOutcome& o) {
} if (o.filename != nullptr) {
// We assume that function name is not blank in this case.
fprintf(stderr, "%.*s%p %s %s:%d\n",
(int)line_prefix.size(), line_prefix.data(),
reinterpret_cast<void*>(o.pc),
o.function,
o.filename, o.lineno);
} else if (o.function == nullptr) {
fprintf(stderr, "%.*s%p\n",
(int)line_prefix.size(), line_prefix.data(),
reinterpret_cast<void*>(o.pc));
} else if (o.symval != 0) {
fprintf(stderr, "%.*s%p %s + %zu\n",
(int)line_prefix.size(), line_prefix.data(),
reinterpret_cast<void*>(o.pc),
o.function, o.pc - o.symval);
} else {
fprintf(stderr, "%.*s%p %s\n",
(int)line_prefix.size(), line_prefix.data(),
reinterpret_cast<void*>(o.pc),
o.function);
}
});
} }
} // namespace tcmalloc } // namespace tcmalloc

View File

@ -37,12 +37,45 @@
#include <string_view> #include <string_view>
#include "base/basictypes.h"
#include "base/function_ref.h"
extern "C" {
struct backtrace_state;
}
namespace tcmalloc { namespace tcmalloc {
// ATTRIBUTE_VISIBILITY_HIDDEN ATTRIBUTE_VISIBILITY_HIDDEN
void DumpStackTraceToStderr( void DumpStackTraceToStderr(
void * const *stack, int stack_depth, bool want_symbolize, void * const *stack, int stack_depth, bool want_symbolize,
std::string_view line_prefix); std::string_view line_prefix);
struct SymbolizeOutcome {
uintptr_t pc;
const char* function;
const char* filename;
int lineno;
uintptr_t symval;
const char* original_function;
};
class ATTRIBUTE_VISIBILITY_HIDDEN SymbolizerAPI {
public:
explicit SymbolizerAPI(FunctionRef<void(const SymbolizeOutcome& outcome)> *callback);
~SymbolizerAPI();
static void With(FunctionRef<void(const SymbolizerAPI& api)> body,
FunctionRef<void(const SymbolizeOutcome&)> callback) {
body(SymbolizerAPI{&callback});
}
void Add(uintptr_t addr) const;
private:
FunctionRef<void(const SymbolizeOutcome&)> *callback_;
backtrace_state* state_;
};
} // namespace tcmalloc } // namespace tcmalloc
#endif // TCMALLOC_SYMBOLIZE_H_ #endif // TCMALLOC_SYMBOLIZE_H_