13cab2bb3Spatrick //===-- sanitizer_stacktrace.cpp ------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is shared between AddressSanitizer and ThreadSanitizer
103cab2bb3Spatrick // run-time libraries.
113cab2bb3Spatrick //===----------------------------------------------------------------------===//
123cab2bb3Spatrick
13d89ec533Spatrick #include "sanitizer_stacktrace.h"
14d89ec533Spatrick
153cab2bb3Spatrick #include "sanitizer_common.h"
163cab2bb3Spatrick #include "sanitizer_flags.h"
17d89ec533Spatrick #include "sanitizer_platform.h"
18d89ec533Spatrick #include "sanitizer_ptrauth.h"
193cab2bb3Spatrick
203cab2bb3Spatrick namespace __sanitizer {
213cab2bb3Spatrick
GetNextInstructionPc(uptr pc)223cab2bb3Spatrick uptr StackTrace::GetNextInstructionPc(uptr pc) {
23*810390e3Srobert #if defined(__aarch64__)
24*810390e3Srobert return STRIP_PAC_PC((void *)pc) + 4;
25*810390e3Srobert #elif defined(__sparc__) || defined(__mips__)
263cab2bb3Spatrick return pc + 8;
27d89ec533Spatrick #elif SANITIZER_RISCV64
28d89ec533Spatrick // Current check order is 4 -> 2 -> 6 -> 8
29d89ec533Spatrick u8 InsnByte = *(u8 *)(pc);
30d89ec533Spatrick if (((InsnByte & 0x3) == 0x3) && ((InsnByte & 0x1c) != 0x1c)) {
31d89ec533Spatrick // xxxxxxxxxxxbbb11 | 32 bit | bbb != 111
32d89ec533Spatrick return pc + 4;
33d89ec533Spatrick }
34d89ec533Spatrick if ((InsnByte & 0x3) != 0x3) {
35d89ec533Spatrick // xxxxxxxxxxxxxxaa | 16 bit | aa != 11
36d89ec533Spatrick return pc + 2;
37d89ec533Spatrick }
38d89ec533Spatrick // RISC-V encoding allows instructions to be up to 8 bytes long
39d89ec533Spatrick if ((InsnByte & 0x3f) == 0x1f) {
40d89ec533Spatrick // xxxxxxxxxx011111 | 48 bit |
41d89ec533Spatrick return pc + 6;
42d89ec533Spatrick }
43d89ec533Spatrick if ((InsnByte & 0x7f) == 0x3f) {
44d89ec533Spatrick // xxxxxxxxx0111111 | 64 bit |
45d89ec533Spatrick return pc + 8;
46d89ec533Spatrick }
47d89ec533Spatrick // bail-out if could not figure out the instruction size
48d89ec533Spatrick return 0;
49*810390e3Srobert #elif SANITIZER_S390 || SANITIZER_I386 || SANITIZER_X32 || SANITIZER_X64
503cab2bb3Spatrick return pc + 1;
51*810390e3Srobert #else
52*810390e3Srobert return pc + 4;
533cab2bb3Spatrick #endif
543cab2bb3Spatrick }
553cab2bb3Spatrick
GetCurrentPc()563cab2bb3Spatrick uptr StackTrace::GetCurrentPc() {
573cab2bb3Spatrick return GET_CALLER_PC();
583cab2bb3Spatrick }
593cab2bb3Spatrick
Init(const uptr * pcs,uptr cnt,uptr extra_top_pc)603cab2bb3Spatrick void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) {
613cab2bb3Spatrick size = cnt + !!extra_top_pc;
623cab2bb3Spatrick CHECK_LE(size, kStackTraceMax);
633cab2bb3Spatrick internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0]));
643cab2bb3Spatrick if (extra_top_pc)
653cab2bb3Spatrick trace_buffer[cnt] = extra_top_pc;
663cab2bb3Spatrick top_frame_bp = 0;
673cab2bb3Spatrick }
683cab2bb3Spatrick
69*810390e3Srobert // Sparc implementation is in its own file.
703cab2bb3Spatrick #if !defined(__sparc__)
713cab2bb3Spatrick
723cab2bb3Spatrick // In GCC on ARM bp points to saved lr, not fp, so we should check the next
733cab2bb3Spatrick // cell in stack to be a saved frame pointer. GetCanonicFrame returns the
743cab2bb3Spatrick // pointer to saved frame pointer in any case.
GetCanonicFrame(uptr bp,uptr stack_top,uptr stack_bottom)753cab2bb3Spatrick static inline uhwptr *GetCanonicFrame(uptr bp,
763cab2bb3Spatrick uptr stack_top,
773cab2bb3Spatrick uptr stack_bottom) {
783cab2bb3Spatrick CHECK_GT(stack_top, stack_bottom);
793cab2bb3Spatrick #ifdef __arm__
803cab2bb3Spatrick if (!IsValidFrame(bp, stack_top, stack_bottom)) return 0;
813cab2bb3Spatrick uhwptr *bp_prev = (uhwptr *)bp;
823cab2bb3Spatrick if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) return bp_prev;
833cab2bb3Spatrick // The next frame pointer does not look right. This could be a GCC frame, step
843cab2bb3Spatrick // back by 1 word and try again.
853cab2bb3Spatrick if (IsValidFrame((uptr)bp_prev[-1], stack_top, stack_bottom))
863cab2bb3Spatrick return bp_prev - 1;
873cab2bb3Spatrick // Nope, this does not look right either. This means the frame after next does
883cab2bb3Spatrick // not have a valid frame pointer, but we can still extract the caller PC.
893cab2bb3Spatrick // Unfortunately, there is no way to decide between GCC and LLVM frame
903cab2bb3Spatrick // layouts. Assume LLVM.
913cab2bb3Spatrick return bp_prev;
923cab2bb3Spatrick #else
933cab2bb3Spatrick return (uhwptr*)bp;
943cab2bb3Spatrick #endif
953cab2bb3Spatrick }
963cab2bb3Spatrick
UnwindFast(uptr pc,uptr bp,uptr stack_top,uptr stack_bottom,u32 max_depth)973cab2bb3Spatrick void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top,
983cab2bb3Spatrick uptr stack_bottom, u32 max_depth) {
993cab2bb3Spatrick // TODO(yln): add arg sanity check for stack_top/stack_bottom
1003cab2bb3Spatrick CHECK_GE(max_depth, 2);
1013cab2bb3Spatrick const uptr kPageSize = GetPageSizeCached();
1023cab2bb3Spatrick trace_buffer[0] = pc;
1033cab2bb3Spatrick size = 1;
1043cab2bb3Spatrick if (stack_top < 4096) return; // Sanity check for stack top.
1053cab2bb3Spatrick uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom);
1063cab2bb3Spatrick // Lowest possible address that makes sense as the next frame pointer.
1073cab2bb3Spatrick // Goes up as we walk the stack.
1083cab2bb3Spatrick uptr bottom = stack_bottom;
1093cab2bb3Spatrick // Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
1103cab2bb3Spatrick while (IsValidFrame((uptr)frame, stack_top, bottom) &&
1113cab2bb3Spatrick IsAligned((uptr)frame, sizeof(*frame)) &&
1123cab2bb3Spatrick size < max_depth) {
1133cab2bb3Spatrick #ifdef __powerpc__
1143cab2bb3Spatrick // PowerPC ABIs specify that the return address is saved at offset
1153cab2bb3Spatrick // 16 of the *caller's* stack frame. Thus we must dereference the
1163cab2bb3Spatrick // back chain to find the caller frame before extracting it.
1173cab2bb3Spatrick uhwptr *caller_frame = (uhwptr*)frame[0];
1183cab2bb3Spatrick if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) ||
1193cab2bb3Spatrick !IsAligned((uptr)caller_frame, sizeof(uhwptr)))
1203cab2bb3Spatrick break;
1213cab2bb3Spatrick uhwptr pc1 = caller_frame[2];
1223cab2bb3Spatrick #elif defined(__s390__)
1233cab2bb3Spatrick uhwptr pc1 = frame[14];
124*810390e3Srobert #elif defined(__loongarch__) || defined(__riscv)
125d89ec533Spatrick // frame[-1] contains the return address
126d89ec533Spatrick uhwptr pc1 = frame[-1];
1273cab2bb3Spatrick #else
128d89ec533Spatrick uhwptr pc1 = STRIP_PAC_PC((void *)frame[1]);
1293cab2bb3Spatrick #endif
1303cab2bb3Spatrick // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and
1313cab2bb3Spatrick // x86_64) is invalid and stop unwinding here. If we're adding support for
1323cab2bb3Spatrick // a platform where this isn't true, we need to reconsider this check.
1333cab2bb3Spatrick if (pc1 < kPageSize)
1343cab2bb3Spatrick break;
1353cab2bb3Spatrick if (pc1 != pc) {
1363cab2bb3Spatrick trace_buffer[size++] = (uptr) pc1;
1373cab2bb3Spatrick }
1383cab2bb3Spatrick bottom = (uptr)frame;
139*810390e3Srobert #if defined(__loongarch__) || defined(__riscv)
140d89ec533Spatrick // frame[-2] contain fp of the previous frame
141d89ec533Spatrick uptr new_bp = (uptr)frame[-2];
142d89ec533Spatrick #else
143d89ec533Spatrick uptr new_bp = (uptr)frame[0];
144d89ec533Spatrick #endif
145d89ec533Spatrick frame = GetCanonicFrame(new_bp, stack_top, bottom);
1463cab2bb3Spatrick }
1473cab2bb3Spatrick }
1483cab2bb3Spatrick
1493cab2bb3Spatrick #endif // !defined(__sparc__)
1503cab2bb3Spatrick
PopStackFrames(uptr count)1513cab2bb3Spatrick void BufferedStackTrace::PopStackFrames(uptr count) {
1523cab2bb3Spatrick CHECK_LT(count, size);
1533cab2bb3Spatrick size -= count;
1543cab2bb3Spatrick for (uptr i = 0; i < size; ++i) {
1553cab2bb3Spatrick trace_buffer[i] = trace_buffer[i + count];
1563cab2bb3Spatrick }
1573cab2bb3Spatrick }
1583cab2bb3Spatrick
Distance(uptr a,uptr b)1593cab2bb3Spatrick static uptr Distance(uptr a, uptr b) { return a < b ? b - a : a - b; }
1603cab2bb3Spatrick
LocatePcInTrace(uptr pc)1613cab2bb3Spatrick uptr BufferedStackTrace::LocatePcInTrace(uptr pc) {
1623cab2bb3Spatrick uptr best = 0;
1633cab2bb3Spatrick for (uptr i = 1; i < size; ++i) {
1643cab2bb3Spatrick if (Distance(trace[i], pc) < Distance(trace[best], pc)) best = i;
1653cab2bb3Spatrick }
1663cab2bb3Spatrick return best;
1673cab2bb3Spatrick }
1683cab2bb3Spatrick
1693cab2bb3Spatrick } // namespace __sanitizer
170