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

View File

@ -37,12 +37,45 @@
#include <string_view>
#include "base/basictypes.h"
#include "base/function_ref.h"
extern "C" {
struct backtrace_state;
}
namespace tcmalloc {
// ATTRIBUTE_VISIBILITY_HIDDEN
ATTRIBUTE_VISIBILITY_HIDDEN
void DumpStackTraceToStderr(
void * const *stack, int stack_depth, bool want_symbolize,
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
#endif // TCMALLOC_SYMBOLIZE_H_