Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/absl/debugging/internal/stacktrace_riscv-inl.inc is written in an unsupported language. File is not indexed.

0001 // Copyright 2021 The Abseil Authors
0002 //
0003 // Licensed under the Apache License, Version 2.0 (the "License");
0004 // you may not use this file except in compliance with the License.
0005 // You may obtain a copy of the License at
0006 //
0007 //     https://www.apache.org/licenses/LICENSE-2.0
0008 //
0009 // Unless required by applicable law or agreed to in writing, software
0010 // distributed under the License is distributed on an "AS IS" BASIS,
0011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012 // See the License for the specific language governing permissions and
0013 // limitations under the License.
0014 
0015 #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_RISCV_INL_H_
0016 #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_RISCV_INL_H_
0017 
0018 // Generate stack trace for riscv
0019 
0020 #include <sys/ucontext.h>
0021 
0022 #include "absl/base/config.h"
0023 #if defined(__linux__)
0024 #include <sys/mman.h>
0025 #include <ucontext.h>
0026 #include <unistd.h>
0027 #endif
0028 
0029 #include <atomic>
0030 #include <cassert>
0031 #include <cstdint>
0032 #include <iostream>
0033 #include <limits>
0034 #include <utility>
0035 
0036 #include "absl/base/attributes.h"
0037 #include "absl/debugging/stacktrace.h"
0038 
0039 static const uintptr_t kUnknownFrameSize = 0;
0040 
0041 // Compute the size of a stack frame in [low..high).  We assume that low < high.
0042 // Return size of kUnknownFrameSize.
0043 template <typename T>
0044 static inline uintptr_t ComputeStackFrameSize(const T *low, const T *high) {
0045   const char *low_char_ptr = reinterpret_cast<const char *>(low);
0046   const char *high_char_ptr = reinterpret_cast<const char *>(high);
0047   return low < high ? high_char_ptr - low_char_ptr : kUnknownFrameSize;
0048 }
0049 
0050 // Given a pointer to a stack frame, locate and return the calling stackframe,
0051 // or return null if no stackframe can be found. Perform sanity checks (the
0052 // strictness of which is controlled by the boolean parameter
0053 // "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
0054 template <bool STRICT_UNWINDING, bool WITH_CONTEXT>
0055 ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS  // May read random elements from stack.
0056 ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY   // May read random elements from stack.
0057 static void ** NextStackFrame(void **old_frame_pointer, const void *uc,
0058                               const std::pair<size_t, size_t> range) {
0059   //               .
0060   //               .
0061   //               .
0062   //   +-> +----------------+
0063   //   |   | return address |
0064   //   |   |   previous fp  |
0065   //   |   |      ...       |
0066   //   |   +----------------+ <-+
0067   //   |   | return address |   |
0068   //   +---|-  previous fp  |   |
0069   //       |      ...       |   |
0070   // $fp ->|----------------+   |
0071   //       | return address |   |
0072   //       |   previous fp -|---+
0073   // $sp ->|      ...       |
0074   //       +----------------+
0075   void **new_frame_pointer = reinterpret_cast<void **>(old_frame_pointer[-2]);
0076   uintptr_t frame_pointer = reinterpret_cast<uintptr_t>(new_frame_pointer);
0077 
0078   // The RISCV ELF psABI mandates that the stack pointer is always 16-byte
0079   // aligned.
0080   // TODO(#1236) this doesn't hold for ILP32E which only mandates a 4-byte
0081   // alignment.
0082   if (frame_pointer & 15)
0083     return nullptr;
0084 
0085   // If the new frame pointer matches the signal context, avoid terminating
0086   // early to deal with alternate signal stacks.
0087   if (WITH_CONTEXT)
0088     if (const ucontext_t *ucv = static_cast<const ucontext_t *>(uc))
0089       // RISCV ELF psABI has the frame pointer at x8/fp/s0.
0090       // -- RISCV psABI Table 18.2
0091       if (ucv->uc_mcontext.__gregs[8] == frame_pointer)
0092         return new_frame_pointer;
0093 
0094   // Check frame size.  In strict mode, we assume frames to be under 100,000
0095   // bytes.  In non-strict mode, we relax the limit to 1MB.
0096   const uintptr_t max_size = STRICT_UNWINDING ? 100000 : 1000000;
0097   const uintptr_t frame_size =
0098       ComputeStackFrameSize(old_frame_pointer, new_frame_pointer);
0099   if (frame_size == kUnknownFrameSize) {
0100     if (STRICT_UNWINDING)
0101       return nullptr;
0102 
0103     // In non-strict mode permit non-contiguous stacks (e.g. alternate signal
0104     // frame handling).
0105     if (reinterpret_cast<uintptr_t>(new_frame_pointer) < range.first ||
0106         reinterpret_cast<uintptr_t>(new_frame_pointer) > range.second)
0107       return nullptr;
0108   }
0109 
0110   if (frame_size > max_size)
0111     return nullptr;
0112 
0113   return new_frame_pointer;
0114 }
0115 
0116 template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
0117 ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS  // May read random elements from stack.
0118 ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY   // May read random elements from stack.
0119 static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count,
0120                       const void *ucp, int *min_dropped_frames) {
0121   // The `frame_pointer` that is computed here points to the top of the frame.
0122   // The two words preceding the address are the return address and the previous
0123   // frame pointer.
0124 #if defined(__GNUC__)
0125   void **frame_pointer = reinterpret_cast<void **>(__builtin_frame_address(0));
0126 #else
0127 #error reading stack pointer not yet supported on this platform
0128 #endif
0129 
0130   std::pair<size_t, size_t> stack = {
0131       // assume that the first page is not the stack.
0132       static_cast<size_t>(sysconf(_SC_PAGESIZE)),
0133       std::numeric_limits<size_t>::max() - sizeof(void *)
0134   };
0135 
0136   int n = 0;
0137   void *return_address = nullptr;
0138   while (frame_pointer && n < max_depth) {
0139     return_address = frame_pointer[-1];
0140 
0141     // The absl::GetStackFrames routine is called when we are in some
0142     // informational context (the failure signal handler for example).  Use the
0143     // non-strict unwinding rules to produce a stack trace that is as complete
0144     // as possible (even if it contains a few bogus entries in some rare cases).
0145     void **next_frame_pointer =
0146         NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(frame_pointer, ucp,
0147                                                           stack);
0148 
0149     if (skip_count > 0) {
0150       skip_count--;
0151     } else {
0152       result[n] = return_address;
0153       if (IS_STACK_FRAMES) {
0154         sizes[n] = ComputeStackFrameSize(frame_pointer, next_frame_pointer);
0155       }
0156       n++;
0157     }
0158 
0159     frame_pointer = next_frame_pointer;
0160   }
0161 
0162   if (min_dropped_frames != nullptr) {
0163     // Implementation detail: we clamp the max of frames we are willing to
0164     // count, so as not to spend too much time in the loop below.
0165     const int kMaxUnwind = 200;
0166     int num_dropped_frames = 0;
0167     for (int j = 0; frame_pointer != nullptr && j < kMaxUnwind; j++) {
0168       if (skip_count > 0) {
0169         skip_count--;
0170       } else {
0171         num_dropped_frames++;
0172       }
0173       frame_pointer =
0174           NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(frame_pointer, ucp,
0175                                                             stack);
0176     }
0177     *min_dropped_frames = num_dropped_frames;
0178   }
0179 
0180   return n;
0181 }
0182 
0183 namespace absl {
0184 ABSL_NAMESPACE_BEGIN
0185 namespace debugging_internal {
0186 bool StackTraceWorksForTest() { return true; }
0187 }  // namespace debugging_internal
0188 ABSL_NAMESPACE_END
0189 }  // namespace absl
0190 
0191 #endif