#include "backtrace.h" #include #include #include #include namespace NDwarf { namespace { struct TContext { TCallback& Callback; int Counter = 0; TMaybe Error; }; void HandleLibBacktraceError(void* data, const char* msg, int errnum) { auto* context = reinterpret_cast(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(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(context->Callback(lineInfo)); } } TMaybe ResolveBacktrace(TArrayRef 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(address) - 1, // last byte of the call instruction HandleLibBacktraceFrame, HandleLibBacktraceError, &context /* data for both callbacks */); if (0 != status) { break; } } return context.Error; } }