168d75effSDimitry Andric //===-- sanitizer_stacktrace_sparc.cpp ------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer 1068d75effSDimitry Andric // run-time libraries. 1168d75effSDimitry Andric // 12349cc55cSDimitry Andric // Implementation of fast stack unwinding for Sparc. 1368d75effSDimitry Andric //===----------------------------------------------------------------------===// 1468d75effSDimitry Andric 1568d75effSDimitry Andric #if defined(__sparc__) 1668d75effSDimitry Andric 1768d75effSDimitry Andric #if defined(__arch64__) || defined(__sparcv9) 1868d75effSDimitry Andric #define STACK_BIAS 2047 1968d75effSDimitry Andric #else 2068d75effSDimitry Andric #define STACK_BIAS 0 2168d75effSDimitry Andric #endif 2268d75effSDimitry Andric 2368d75effSDimitry Andric #include "sanitizer_common.h" 2468d75effSDimitry Andric #include "sanitizer_stacktrace.h" 2568d75effSDimitry Andric 2668d75effSDimitry Andric namespace __sanitizer { 2768d75effSDimitry Andric 2868d75effSDimitry Andric void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top, 2968d75effSDimitry Andric uptr stack_bottom, u32 max_depth) { 3068d75effSDimitry Andric // TODO(yln): add arg sanity check for stack_top/stack_bottom 3168d75effSDimitry Andric CHECK_GE(max_depth, 2); 3268d75effSDimitry Andric const uptr kPageSize = GetPageSizeCached(); 3368d75effSDimitry Andric trace_buffer[0] = pc; 3468d75effSDimitry Andric size = 1; 3568d75effSDimitry Andric if (stack_top < 4096) return; // Sanity check for stack top. 3668d75effSDimitry Andric // Flush register windows to memory 3768d75effSDimitry Andric #if defined(__sparc_v9__) || defined(__sparcv9__) || defined(__sparcv9) 3868d75effSDimitry Andric asm volatile("flushw" ::: "memory"); 3968d75effSDimitry Andric #else 4068d75effSDimitry Andric asm volatile("ta 3" ::: "memory"); 4168d75effSDimitry Andric #endif 4268d75effSDimitry Andric // On the SPARC, the return address is not in the frame, it is in a 4368d75effSDimitry Andric // register. There is no way to access it off of the current frame 4468d75effSDimitry Andric // pointer, but it can be accessed off the previous frame pointer by 4568d75effSDimitry Andric // reading the value from the register window save area. 4668d75effSDimitry Andric uptr prev_bp = GET_CURRENT_FRAME(); 4768d75effSDimitry Andric uptr next_bp = prev_bp; 4868d75effSDimitry Andric unsigned int i = 0; 4968d75effSDimitry Andric while (next_bp != bp && IsAligned(next_bp, sizeof(uhwptr)) && i++ < 8) { 5068d75effSDimitry Andric prev_bp = next_bp; 5168d75effSDimitry Andric next_bp = (uptr)((uhwptr *)next_bp)[14] + STACK_BIAS; 5268d75effSDimitry Andric } 5368d75effSDimitry Andric if (next_bp == bp) 5468d75effSDimitry Andric bp = prev_bp; 5568d75effSDimitry Andric // Lowest possible address that makes sense as the next frame pointer. 5668d75effSDimitry Andric // Goes up as we walk the stack. 5768d75effSDimitry Andric uptr bottom = stack_bottom; 5868d75effSDimitry Andric // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. 5968d75effSDimitry Andric while (IsValidFrame(bp, stack_top, bottom) && IsAligned(bp, sizeof(uhwptr)) && 6068d75effSDimitry Andric size < max_depth) { 61*52418fc2SDimitry Andric // %o7 contains the address of the call instruction and not the 62*52418fc2SDimitry Andric // return address, so we need to compensate. 63*52418fc2SDimitry Andric uhwptr pc1 = GetNextInstructionPc(((uhwptr *)bp)[15]); 6468d75effSDimitry Andric // Let's assume that any pointer in the 0th page is invalid and 6568d75effSDimitry Andric // stop unwinding here. If we're adding support for a platform 6668d75effSDimitry Andric // where this isn't true, we need to reconsider this check. 6768d75effSDimitry Andric if (pc1 < kPageSize) 6868d75effSDimitry Andric break; 69*52418fc2SDimitry Andric if (pc1 != pc) 70*52418fc2SDimitry Andric trace_buffer[size++] = pc1; 7168d75effSDimitry Andric bottom = bp; 7268d75effSDimitry Andric bp = (uptr)((uhwptr *)bp)[14] + STACK_BIAS; 7368d75effSDimitry Andric } 7468d75effSDimitry Andric } 7568d75effSDimitry Andric 7668d75effSDimitry Andric } // namespace __sanitizer 7768d75effSDimitry Andric 7868d75effSDimitry Andric #endif // !defined(__sparc__) 79