1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
#include "backtrace.h"
#include <contrib/libs/backtrace/backtrace.h>
#include <util/generic/yexception.h>
#include <util/system/type_name.h>
#include <util/system/execpath.h>
namespace NDwarf {
namespace {
struct TContext {
TCallback& Callback;
int Counter = 0;
TMaybe<TError> Error;
};
void HandleLibBacktraceError(void* data, const char* msg, int errnum) {
auto* context = reinterpret_cast<TContext*>(data);
context->Error = TError{.Code = errnum, .Message=msg};
}
int HandleLibBacktraceFrame(void* data, uintptr_t pc, const char* filename, int lineno, const char* function) {
auto* context = reinterpret_cast<TContext*>(data);
TLineInfo lineInfo{
.FileName = filename != nullptr ? filename : "???",
.Line = lineno,
.Col = 0, // libbacktrace doesn't provide column numbers, so fill this field with a dummy value.
.FunctionName = function != nullptr ? CppDemangle(function) : "???",
.Address = pc,
.Index = context->Counter++,
};
return static_cast<int>(context->Callback(lineInfo));
}
}
TMaybe<TError> ResolveBacktrace(TArrayRef<const void* const> backtrace, TCallback callback) {
TContext context{.Callback = callback};
// Intentionally never freed (see https://a.yandex-team.ru/arc/trunk/arcadia/contrib/libs/backtrace/backtrace.h?rev=6789902#L80).
static auto* state = backtrace_create_state(
GetPersistentExecPath().c_str(),
1 /* threaded */,
HandleLibBacktraceError,
&context /* data for the error callback */
);
if (nullptr == state) {
static const auto initError = context.Error;
return initError;
}
for (const void* address : backtrace) {
int status = backtrace_pcinfo(
state,
reinterpret_cast<uintptr_t>(address) - 1, // last byte of the call instruction
HandleLibBacktraceFrame,
HandleLibBacktraceError,
&context /* data for both callbacks */);
if (0 != status) {
break;
}
}
return context.Error;
}
}
|