-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Replace "backward" stack trace with absl::Stacktrace. #5723
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
80a0685
5572868
9698ea7
cce16c0
e826141
08fb320
58139d5
2887f00
f3a928e
706107a
90e4908
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,8 @@ | ||
| #pragma once | ||
|
|
||
| #include <backward.hpp> | ||
|
|
||
| #include "common/common/logger.h" | ||
|
|
||
| #include "absl/debugging/stacktrace.h" | ||
| #include "absl/debugging/symbolize.h" | ||
|
|
||
| namespace Envoy { | ||
|
|
@@ -15,7 +14,7 @@ namespace Envoy { | |
| } while (0) | ||
|
|
||
| /** | ||
| * Use the Backward library ( https://github.com/bombela/backward-cpp ) to log | ||
| * Use absl::Stacktrace and absl::Symbolize to log resolved symbols | ||
| * stack traces on demand. To use this just do: | ||
| * | ||
| * BackwardsTrace tracer; | ||
|
|
@@ -29,20 +28,8 @@ namespace Envoy { | |
| * For convenience a macro is provided BACKTRACE_LOG() which performs the | ||
| * construction, capture, and log in one shot. | ||
| * | ||
| * To resolve the addresses in the backtrace output and de-interleave | ||
| * multithreaded output use the tools/stack_decode.py command and pass the | ||
| * log/stderr output to stdin of the tool. Backtrace lines will be resolved, | ||
| * other lines will be passed through and echo'd unchanged. | ||
| * | ||
| * The stack_decode.py tool can also run envoy or a test as a child process if | ||
| * you pass the command and arguments as arguments to the tool. This enables | ||
| * you to run tests containing backtrace commands added for debugging and see | ||
| * the output like this: | ||
| * | ||
| * bazel test -c dbg //test/server:backtrace_test | ||
| * --run_under=`pwd`/tools/stack_decode.py | ||
| * --strategy=TestRunner=standalone --cache_test_results=no | ||
| * --test_output=all | ||
| * If the symbols cannot be resolved by absl::Symbolize then the raw address | ||
| * will be printed instead. | ||
| */ | ||
| class BackwardsTrace : Logger::Loggable<Logger::Id::backtrace> { | ||
| public: | ||
|
|
@@ -53,80 +40,50 @@ class BackwardsTrace : Logger::Loggable<Logger::Id::backtrace> { | |
| * | ||
| * The trace will begin with the call to capture(). | ||
| */ | ||
| void capture() { stack_trace_.load_here(MAX_STACK_DEPTH); } | ||
| void capture() { | ||
| // Skip of one means we exclude the last call, which must be to capture(). | ||
| stack_depth_ = absl::GetStackTrace(stack_trace_, MAX_STACK_DEPTH, /* skip_count = */ 1); | ||
| } | ||
|
|
||
| /** | ||
| * Capture a stack trace from a particular address. | ||
| * Capture a stack trace from a particular context. | ||
| * | ||
| * This can be used to capture a useful stack trace from a fatal signal | ||
| * handler. | ||
| * handler. The context argument should be a pointer to the context passed | ||
| * to a signal handler registered via a sigaction struct. | ||
| * | ||
| * @param address The stack trace will begin from this address. | ||
| * @param context A pointer to ucontext_t obtained from a sigaction handler. | ||
| */ | ||
| void captureFrom(void* address) { stack_trace_.load_from(address, MAX_STACK_DEPTH); } | ||
| void captureFrom(const void* context) { | ||
| stack_depth_ = | ||
| absl::GetStackTraceWithContext(stack_trace_, MAX_STACK_DEPTH, /* skip_count = */ 1, context, | ||
| /* min_dropped_frames = */ nullptr); | ||
| } | ||
|
|
||
| /** | ||
| * Log the stack trace. | ||
| */ | ||
| void logTrace() { | ||
| backward::TraceResolver resolver; | ||
| resolver.load_stacktrace(stack_trace_); | ||
| // If there's nothing in the captured trace we cannot do anything. | ||
| // The size must be at least two for useful info - there is a sentinel frame | ||
| // at the end that we ignore. | ||
| if (stack_trace_.size() < 2) { | ||
| ENVOY_LOG(critical, "Back trace attempt failed"); | ||
| return; | ||
| } | ||
|
|
||
| const auto thread_id = stack_trace_.thread_id(); | ||
| backward::ResolvedTrace first_frame_trace = resolver.resolve(stack_trace_[0]); | ||
| auto obj_name = first_frame_trace.object_filename; | ||
|
|
||
| #ifdef __APPLE__ | ||
| // The stack_decode.py script uses addr2line which isn't readily available and doesn't seem to | ||
| // work when installed. | ||
| ENVOY_LOG(critical, "Backtrace thr<{}> obj<{}>:", thread_id, obj_name); | ||
| #else | ||
| char out[200]; | ||
| ENVOY_LOG(critical, | ||
| "Backtrace thr<{}> obj<{}> (If unsymbolized, use tools/stack_decode.py):", thread_id, | ||
| obj_name); | ||
| #endif | ||
|
|
||
| // Backtrace gets tagged by ASAN when we try the object name resolution for the last | ||
| // frame on stack, so skip the last one. It has no useful info anyway. | ||
|
|
||
| for (unsigned int i = 0; i < stack_trace_.size() - 1; ++i) { | ||
| backward::ResolvedTrace trace = resolver.resolve(stack_trace_[i]); | ||
| if (trace.object_filename != obj_name) { | ||
| obj_name = trace.object_filename; | ||
| ENVOY_LOG(critical, "thr<{}> obj<{}>", thread_id, obj_name); | ||
| } | ||
| ENVOY_LOG(critical, "Backtrace:"); | ||
|
|
||
| #ifdef __APPLE__ | ||
| // In the absence of stack_decode.py, print the function name. | ||
| ENVOY_LOG(critical, "thr<{}> #{} {} {}", thread_id, stack_trace_[i].idx, stack_trace_[i].addr, | ||
| trace.object_function); | ||
| #else | ||
| if (absl::Symbolize(stack_trace_[i].addr, out, sizeof(out))) { | ||
| ENVOY_LOG(critical, "thr<{}> #{} {} {}", thread_id, stack_trace_[i].idx, | ||
| stack_trace_[i].addr, out); | ||
| for (int i = 0; i < stack_depth_; ++i) { | ||
| char out[1024]; | ||
| const bool success = absl::Symbolize(stack_trace_[i], out, sizeof(out)); | ||
| if (success) { | ||
| ENVOY_LOG(critical, "#{}: {}", i, out); | ||
| } else { | ||
| ENVOY_LOG(critical, "thr<{}> #{} {} (unknown)", thread_id, stack_trace_[i].idx, | ||
| stack_trace_[i].addr); | ||
| ENVOY_LOG(critical, "#{}: {}", i, stack_trace_[i]); | ||
| } | ||
| #endif | ||
| } | ||
| ENVOY_LOG(critical, "end backtrace thread {}", stack_trace_.thread_id()); | ||
| } | ||
|
|
||
| void logFault(const char* signame, const void* addr) { | ||
| ENVOY_LOG(critical, "Caught {}, suspect faulting address {}", signame, addr); | ||
| } | ||
|
|
||
| private: | ||
| static const int MAX_STACK_DEPTH = 64; | ||
| backward::StackTrace stack_trace_; | ||
| static constexpr int MAX_STACK_DEPTH = 64; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: prefer moving to the newer Envoy convention of
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good idea, done. |
||
| void* stack_trace_[MAX_STACK_DEPTH]; | ||
| int stack_depth_; | ||
| }; | ||
| } // namespace Envoy | ||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just noticed that https://github.com/envoyproxy/envoy/blob/master/bazel/external/backward.BUILD is still in the codebase. This can be removed now I believe @dnoe