backtrace.cpp 2.3 KB

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