backtrace.cpp 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  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. #include <mutex>
  7. namespace NDwarf {
  8. namespace {
  9. struct TContext {
  10. TCallback& Callback;
  11. int Counter = 0;
  12. TMaybe<TError> Error;
  13. };
  14. void HandleLibBacktraceError(void* data, const char* msg, int errnum) {
  15. auto* context = reinterpret_cast<TContext*>(data);
  16. context->Error = TError{.Code = errnum, .Message=msg};
  17. }
  18. int HandleLibBacktraceFrame(void* data, uintptr_t pc, const char* filename, int lineno, const char* function) {
  19. auto* context = reinterpret_cast<TContext*>(data);
  20. TLineInfo lineInfo{
  21. .FileName = filename != nullptr ? filename : "???",
  22. .Line = lineno,
  23. .Col = 0, // libbacktrace doesn't provide column numbers, so fill this field with a dummy value.
  24. .FunctionName = function != nullptr ? CppDemangle(function) : "???",
  25. .Address = pc,
  26. .Index = context->Counter++,
  27. };
  28. return static_cast<int>(context->Callback(lineInfo));
  29. }
  30. auto CreateBacktraceState(TContext& context, bool threaded) {
  31. return backtrace_create_state(
  32. GetPersistentExecPath().c_str(),
  33. static_cast<int>(threaded),
  34. HandleLibBacktraceError,
  35. &context /* data for the error callback */
  36. );
  37. }
  38. TMaybe<TError> ResolveBacktraceImpl(backtrace_state* state, TArrayRef<const void* const> backtrace, TContext& context) {
  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. }
  57. TMaybe<TError> ResolveBacktrace(TArrayRef<const void* const> backtrace, TCallback callback) {
  58. TContext context{.Callback = callback};
  59. // Intentionally never freed (see the documentation to `backtrace_create_state`).
  60. static auto* state{CreateBacktraceState(context, true /* enable threading support */)};
  61. return ResolveBacktraceImpl(state, backtrace, context);
  62. }
  63. TMaybe<TError> ResolveBacktraceLocked(TArrayRef<const void* const> backtrace, TCallback callback) {
  64. TContext context{.Callback = callback};
  65. // Intentionally never freed (see the documentation to `backtrace_create_state`).
  66. static auto* state{CreateBacktraceState(context, false /* disable threading support */)};
  67. static std::mutex mutex;
  68. const std::lock_guard lock{mutex};
  69. return ResolveBacktraceImpl(state, backtrace, context);
  70. }
  71. }