Skip to content

Instantly share code, notes, and snippets.

@vikaschoudhary16
Created July 4, 2020 05:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vikaschoudhary16/d07f897c75da5b2d0f23ba1fa8ed219c to your computer and use it in GitHub Desktop.
Save vikaschoudhary16/d07f897c75da5b2d0f23ba1fa8ed219c to your computer and use it in GitHub Desktop.
envoy-debugging
vikas@ proxy ((HEAD detached at d2d90deb)) $ cat extensions/metadata_exchange/backtrace.h
#pragma once
#include <functional>
#include "absl/debugging/stacktrace.h"
#include "absl/debugging/symbolize.h"
#include "common/common/logger.h"
//#include "common/common/version.h"
namespace Plugin {
#define BACKTRACE_LOG() \
do { \
::Plugin::BackwardsTrace t; \
t.capture(); \
t.logTrace(); \
} while (0)
/**
* Use absl::Stacktrace and absl::Symbolize to log resolved symbols
* stack traces on demand. To use this just do:
*
* BackwardsTrace tracer;
* tracer.capture(); // Trace is captured as of here.
* tracer.logTrace(); // Output the captured trace to the log.
*
* The capture and log steps are separated to enable debugging in the case where
* you want to capture a stack trace from inside some logic but don't know
* whether you want to bother logging it until later.
*
* For convenience a macro is provided BACKTRACE_LOG() which performs the
* construction, capture, and log in one shot.
*
* If the symbols cannot be resolved by absl::Symbolize then the raw address
* will be printed instead.
*/
class BackwardsTrace : Envoy::Logger::Loggable<Envoy::Logger::Id::backtrace> {
public:
BackwardsTrace() = default;
/**
* Capture a stack trace.
*
* The trace will begin with the call to capture().
*/
void capture() {
// Skip of one means we exclude the last call, which must be to capture().
stack_depth_ =
absl::GetStackTrace(stack_trace_, MaxStackDepth, /* skip_count = */ 1);
}
/**
* Capture a stack trace from a particular context.
*
* This can be used to capture a useful stack trace from a fatal signal
* handler. The context argument should be a pointer to the context passed
* to a signal handler registered via a sigaction struct.
*
* @param context A pointer to ucontext_t obtained from a sigaction handler.
*/
void captureFrom(const void* context) {
stack_depth_ = absl::GetStackTraceWithContext(
stack_trace_, MaxStackDepth, /* skip_count = */ 1, context,
/* min_dropped_frames = */ nullptr);
}
/**
* Log the stack trace.
*/
void logTrace() {
ENVOY_LOG(critical,
"Backtrace (use tools/stack_decode.py to get line numbers):");
visitTrace([](int index, const char* symbol, void* address) {
if (symbol != nullptr) {
ENVOY_LOG(critical, "#{}: {} [{}]", index, symbol, address);
} else {
ENVOY_LOG(critical, "#{}: [{}]", index, address);
}
});
}
void logFault(const char* signame, const void* addr) {
ENVOY_LOG(critical, "Caught {}, suspect faulting address {}", signame,
addr);
}
void printTrace(std::ostream& os) {
visitTrace([&](int index, const char* symbol, void* address) {
if (symbol != nullptr) {
os << "#" << index << " " << symbol << " [" << address << "]\n";
} else {
os << "#" << index << " [" << address << "]\n";
}
});
}
private:
/**
* Visit the previously captured stack trace.
*
* The visitor function is called once per frame, with 3 parameters:
* 1. (int) The index of the current frame.
* 2. (const char*) The symbol name for the address of the current frame.
* nullptr means symbolization failed.
* 3. (void*) The address of the current frame.
*/
void visitTrace(const std::function<void(int, const char*, void*)>& visitor) {
for (int i = 0; i < stack_depth_; ++i) {
char out[1024];
const bool success = absl::Symbolize(stack_trace_[i], out, sizeof(out));
if (success) {
visitor(i, out, stack_trace_[i]);
} else {
visitor(i, nullptr, stack_trace_[i]);
}
}
}
static constexpr int MaxStackDepth = 64;
void* stack_trace_[MaxStackDepth];
int stack_depth_{0};
};
} // namespace Plugin
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment