]>
Commit | Line | Data |
---|---|---|
d2ef4bee | 1 | //===-- sanitizer_stacktrace_sparc.cc -------------------------------------===// |
2 | // | |
3 | // This file is distributed under the University of Illinois Open Source | |
4 | // License. See LICENSE.TXT for details. | |
5 | // | |
6 | //===----------------------------------------------------------------------===// | |
7 | // | |
8 | // This file is shared between AddressSanitizer and ThreadSanitizer | |
9 | // run-time libraries. | |
10 | // | |
11 | // Implemention of fast stack unwinding for Sparc. | |
12 | //===----------------------------------------------------------------------===// | |
13 | ||
0e7a25e4 | 14 | #if defined(__sparc__) |
15 | ||
16 | #if defined(__arch64__) || defined(__sparcv9) | |
17 | #define STACK_BIAS 2047 | |
18 | #else | |
19 | #define STACK_BIAS 0 | |
20 | #endif | |
d2ef4bee | 21 | |
22 | #include "sanitizer_common.h" | |
23 | #include "sanitizer_stacktrace.h" | |
24 | ||
25 | namespace __sanitizer { | |
26 | ||
27 | void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top, | |
28 | uptr stack_bottom, u32 max_depth) { | |
29 | const uptr kPageSize = GetPageSizeCached(); | |
30 | CHECK_GE(max_depth, 2); | |
0e7a25e4 | 31 | #if defined(__GNUC__) |
32 | // __builtin_return_address returns the address of the call instruction | |
33 | // on the SPARC and not the return address, so we need to compensate. | |
34 | trace_buffer[0] = GetNextInstructionPc(pc); | |
35 | #else | |
d2ef4bee | 36 | trace_buffer[0] = pc; |
0e7a25e4 | 37 | #endif |
d2ef4bee | 38 | size = 1; |
39 | if (stack_top < 4096) return; // Sanity check for stack top. | |
40 | // Flush register windows to memory | |
0e7a25e4 | 41 | #if defined(__sparc_v9__) || defined(__sparcv9__) || defined(__sparcv9) |
42 | asm volatile("flushw" ::: "memory"); | |
43 | #else | |
d2ef4bee | 44 | asm volatile("ta 3" ::: "memory"); |
0e7a25e4 | 45 | #endif |
46 | // On the SPARC, the return address is not in the frame, it is in a | |
47 | // register. There is no way to access it off of the current frame | |
48 | // pointer, but it can be accessed off the previous frame pointer by | |
49 | // reading the value from the register window save area. | |
50 | uptr prev_bp = GET_CURRENT_FRAME(); | |
51 | uptr next_bp = prev_bp; | |
52 | unsigned int i = 0; | |
53 | while (next_bp != bp && | |
54 | IsAligned(next_bp, sizeof(uhwptr)) && | |
55 | i++ < 8) { | |
56 | prev_bp = next_bp; | |
57 | next_bp = (uptr) ((uhwptr *) next_bp)[14] + STACK_BIAS; | |
58 | } | |
59 | if (next_bp == bp) | |
60 | bp = prev_bp; | |
d2ef4bee | 61 | // Lowest possible address that makes sense as the next frame pointer. |
62 | // Goes up as we walk the stack. | |
63 | uptr bottom = stack_bottom; | |
64 | // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. | |
0e7a25e4 | 65 | while (IsValidFrame(bp, stack_top, bottom) && |
66 | IsAligned(bp, sizeof(uhwptr)) && | |
d2ef4bee | 67 | size < max_depth) { |
0e7a25e4 | 68 | uhwptr pc1 = ((uhwptr *)bp)[15]; |
d2ef4bee | 69 | // Let's assume that any pointer in the 0th page is invalid and |
70 | // stop unwinding here. If we're adding support for a platform | |
71 | // where this isn't true, we need to reconsider this check. | |
72 | if (pc1 < kPageSize) | |
73 | break; | |
74 | if (pc1 != pc) { | |
0e7a25e4 | 75 | // %o7 contains the address of the call instruction and not the |
76 | // return address, so we need to compensate. | |
77 | trace_buffer[size++] = GetNextInstructionPc((uptr) pc1); | |
d2ef4bee | 78 | } |
0e7a25e4 | 79 | bottom = bp; |
80 | bp = (uptr) ((uhwptr *) bp)[14] + STACK_BIAS; | |
d2ef4bee | 81 | } |
82 | } | |
83 | ||
84 | } // namespace __sanitizer | |
85 | ||
0e7a25e4 | 86 | #endif // !defined(__sparc__) |