LCOV - code coverage report
Current view: top level - source/server - backtrace.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 0 49 0.0 %
Date: 2024-01-05 06:35:25 Functions: 0 10 0.0 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <functional>
       4             : 
       5             : #include "source/common/common/logger.h"
       6             : #include "source/common/version/version.h"
       7             : 
       8             : #include "absl/debugging/stacktrace.h"
       9             : #include "absl/debugging/symbolize.h"
      10             : 
      11             : namespace Envoy {
      12             : #define BACKTRACE_LOG()                                                                            \
      13             :   do {                                                                                             \
      14             :     BackwardsTrace t;                                                                              \
      15             :     t.capture();                                                                                   \
      16             :     t.logTrace();                                                                                  \
      17             :   } while (0)
      18             : 
      19             : /**
      20             :  * Use absl::Stacktrace and absl::Symbolize to log resolved symbols
      21             :  * stack traces on demand. To use this just do:
      22             :  *
      23             :  * BackwardsTrace tracer;
      24             :  * tracer.capture(); // Trace is captured as of here.
      25             :  * tracer.logTrace(); // Output the captured trace to the log.
      26             :  *
      27             :  * The capture and log steps are separated to enable debugging in the case where
      28             :  * you want to capture a stack trace from inside some logic but don't know whether
      29             :  * you want to bother logging it until later.
      30             :  *
      31             :  * For convenience a macro is provided BACKTRACE_LOG() which performs the
      32             :  * construction, capture, and log in one shot.
      33             :  *
      34             :  * If the symbols cannot be resolved by absl::Symbolize then the raw address
      35             :  * will be printed instead.
      36             :  */
      37             : class BackwardsTrace : Logger::Loggable<Logger::Id::backtrace> {
      38             : public:
      39           0 :   BackwardsTrace() = default;
      40             : 
      41             :   /**
      42             :    * Directs the output of logTrace() to directly stderr rather than the
      43             :    * logging infrastructure.
      44             :    *
      45             :    * This is intended for coverage tests, where we enable trace logs, but send
      46             :    * them to /dev/null to avoid accumulating too much data in CI.
      47             :    *
      48             :    * @param log_to_stderr Whether to log to stderr or the logging system.
      49             :    */
      50             :   static void setLogToStderr(bool log_to_stderr);
      51             : 
      52             :   /**
      53             :    * @return whether the system directing backtraces directly to stderr.
      54             :    */
      55           0 :   static bool logToStderr() { return log_to_stderr_; }
      56             : 
      57             :   /**
      58             :    * Capture a stack trace.
      59             :    *
      60             :    * The trace will begin with the call to capture().
      61             :    */
      62           0 :   void capture() {
      63           0 :     // Skip of one means we exclude the last call, which must be to capture().
      64           0 :     stack_depth_ = absl::GetStackTrace(stack_trace_, MaxStackDepth, /* skip_count = */ 1);
      65           0 :   }
      66             : 
      67             :   /**
      68             :    * Capture a stack trace from a particular context.
      69             :    *
      70             :    * This can be used to capture a useful stack trace from a fatal signal
      71             :    * handler. The context argument should be a pointer to the context passed
      72             :    * to a signal handler registered via a sigaction struct.
      73             :    *
      74             :    * @param context A pointer to ucontext_t obtained from a sigaction handler.
      75             :    */
      76           0 :   void captureFrom(const void* context) {
      77           0 :     stack_depth_ =
      78           0 :         absl::GetStackTraceWithContext(stack_trace_, MaxStackDepth, /* skip_count = */ 1, context,
      79           0 :                                        /* min_dropped_frames = */ nullptr);
      80           0 :   }
      81             : 
      82             :   /**
      83             :    * Log the stack trace.
      84             :    */
      85           0 :   void logTrace() {
      86           0 :     if (log_to_stderr_) {
      87           0 :       printTrace(std::cerr);
      88           0 :       return;
      89           0 :     }
      90             : 
      91           0 :     ENVOY_LOG(critical, "Backtrace (use tools/stack_decode.py to get line numbers):");
      92           0 :     ENVOY_LOG(critical, "Envoy version: {}", VersionInfo::version());
      93             : 
      94           0 :     visitTrace([](int index, const char* symbol, void* address) {
      95           0 :       if (symbol != nullptr) {
      96           0 :         ENVOY_LOG(critical, "#{}: {} [{}]", index, symbol, address);
      97           0 :       } else {
      98           0 :         ENVOY_LOG(critical, "#{}: [{}]", index, address);
      99           0 :       }
     100           0 :     });
     101           0 :   }
     102             : 
     103           0 :   void logFault(const char* signame, const void* addr) {
     104           0 :     ENVOY_LOG(critical, "Caught {}, suspect faulting address {}", signame, addr);
     105           0 :   }
     106             : 
     107           0 :   void printTrace(std::ostream& os) {
     108           0 :     visitTrace([&](int index, const char* symbol, void* address) {
     109           0 :       if (symbol != nullptr) {
     110           0 :         os << "#" << index << " " << symbol << " [" << address << "]\n";
     111           0 :       } else {
     112           0 :         os << "#" << index << " [" << address << "]\n";
     113           0 :       }
     114           0 :     });
     115           0 :   }
     116             : 
     117             : private:
     118             :   static bool log_to_stderr_;
     119             : 
     120             :   /**
     121             :    * Visit the previously captured stack trace.
     122             :    *
     123             :    * The visitor function is called once per frame, with 3 parameters:
     124             :    * 1. (int) The index of the current frame.
     125             :    * 2. (const char*) The symbol name for the address of the current frame. nullptr means
     126             :    * symbolization failed.
     127             :    * 3. (void*) The address of the current frame.
     128             :    */
     129           0 :   void visitTrace(const std::function<void(int, const char*, void*)>& visitor) {
     130           0 :     for (int i = 0; i < stack_depth_; ++i) {
     131           0 :       char out[1024];
     132           0 :       const bool success = absl::Symbolize(stack_trace_[i], out, sizeof(out));
     133           0 :       if (success) {
     134           0 :         visitor(i, out, stack_trace_[i]);
     135           0 :       } else {
     136           0 :         visitor(i, nullptr, stack_trace_[i]);
     137           0 :       }
     138           0 :     }
     139           0 :   }
     140             : 
     141             :   static constexpr int MaxStackDepth = 64;
     142             :   void* stack_trace_[MaxStackDepth];
     143             :   int stack_depth_{0};
     144             : };
     145             : } // namespace Envoy

Generated by: LCOV version 1.15