// Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Produce stack trace #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_ #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_ #if defined(__linux__) && (defined(__i386__) || defined(__x86_64__)) #include <ucontext.h> // for ucontext_t #endif #if !defined(_WIN32) #include <unistd.h> #endif #include <cassert> #include <cstdint> #include <limits> #include "absl/base/attributes.h" #include "absl/base/macros.h" #include "absl/base/port.h" #include "absl/debugging/internal/address_is_readable.h" #include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems #include "absl/debugging/stacktrace.h" AddressIsReadable; #if defined(__linux__) && defined(__i386__) // Count "push %reg" instructions in VDSO __kernel_vsyscall(), // preceding "syscall" or "sysenter". // If __kernel_vsyscall uses frame pointer, answer 0. // // kMaxBytes tells how many instruction bytes of __kernel_vsyscall // to analyze before giving up. Up to kMaxBytes+1 bytes of // instructions could be accessed. // // Here are known __kernel_vsyscall instruction sequences: // // SYSENTER (linux-2.6.26/arch/x86/vdso/vdso32/sysenter.S). // Used on Intel. // 0xffffe400 <__kernel_vsyscall+0>: push %ecx // 0xffffe401 <__kernel_vsyscall+1>: push %edx // 0xffffe402 <__kernel_vsyscall+2>: push %ebp // 0xffffe403 <__kernel_vsyscall+3>: mov %esp,%ebp // 0xffffe405 <__kernel_vsyscall+5>: sysenter // // SYSCALL (see linux-2.6.26/arch/x86/vdso/vdso32/syscall.S). // Used on AMD. // 0xffffe400 <__kernel_vsyscall+0>: push %ebp // 0xffffe401 <__kernel_vsyscall+1>: mov %ecx,%ebp // 0xffffe403 <__kernel_vsyscall+3>: syscall // // The sequence below isn't actually expected in Google fleet, // here only for completeness. Remove this comment from OSS release. // i386 (see linux-2.6.26/arch/x86/vdso/vdso32/int80.S) // 0xffffe400 <__kernel_vsyscall+0>: int $0x80 // 0xffffe401 <__kernel_vsyscall+1>: ret // static const int kMaxBytes = 10; // We use assert()s instead of DCHECK()s -- this is too low level // for DCHECK(). static int CountPushInstructions(const unsigned char *const addr) { int result = 0; for (int i = 0; i < kMaxBytes; ++i) { if (addr[i] == 0x89) { // "mov reg,reg" if (addr[i + 1] == 0xE5) { // Found "mov %esp,%ebp". return 0; } ++i; // Skip register encoding byte. } else if (addr[i] == 0x0F && (addr[i + 1] == 0x34 || addr[i + 1] == 0x05)) { // Found "sysenter" or "syscall". return result; } else if ((addr[i] & 0xF0) == 0x50) { // Found "push %reg". ++result; } else if (addr[i] == 0xCD && addr[i + 1] == 0x80) { // Found "int $0x80" assert(result == 0); return 0; } else { // Unexpected instruction. assert(false && "unexpected instruction in __kernel_vsyscall"); return 0; } } // Unexpected: didn't find SYSENTER or SYSCALL in // [__kernel_vsyscall, __kernel_vsyscall + kMaxBytes) interval. assert(false && "did not find SYSENTER or SYSCALL in __kernel_vsyscall"); return 0; } #endif // Assume stack frames larger than 100,000 bytes are bogus. static const int kMaxFrameBytes = …; // Stack end to use when we don't know the actual stack end // (effectively just the end of address space). constexpr uintptr_t kUnknownStackEnd = …; // Returns the stack frame pointer from signal context, 0 if unknown. // vuc is a ucontext_t *. We use void* to avoid the use // of ucontext_t on non-POSIX systems. static uintptr_t GetFP(const void *vuc) { … } // Given a pointer to a stack frame, locate and return the calling // stackframe, or return null if no stackframe can be found. Perform sanity // checks (the strictness of which is controlled by the boolean parameter // "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. template <bool STRICT_UNWINDING, bool WITH_CONTEXT> ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. static void **NextStackFrame(void **old_fp, const void *uc, size_t stack_low, size_t stack_high) { … } template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. ABSL_ATTRIBUTE_NOINLINE static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, const void *ucp, int *min_dropped_frames) { … } namespace absl { ABSL_NAMESPACE_BEGIN namespace debugging_internal { bool StackTraceWorksForTest() { … } } // namespace debugging_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_