[symbolize] generalize API and implementation
This commit is contained in:
parent
03d361bff8
commit
6e4984bc1b
104
src/symbolize.cc
104
src/symbolize.cc
|
@ -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
|
||||||
|
|
|
@ -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_
|
||||||
|
|
Loading…
Reference in New Issue