Fix fast stack unwind on ARM to support code generated with GCC.
http://reviews.llvm.org/D4692 Patch by Maxim Ostapenko! llvm-svn: 217079
This commit is contained in:
parent
0e3e6155fe
commit
c8d8ca0bd6
|
@ -36,19 +36,39 @@ uptr StackTrace::GetCurrentPc() {
|
||||||
return GET_CALLER_PC();
|
return GET_CALLER_PC();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if given pointer points into allocated stack area.
|
||||||
|
static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) {
|
||||||
|
return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// In GCC on ARM bp points to saved lr, not fp, so we should check the next
|
||||||
|
// cell in stack to be a saved frame pointer. GetCanonicFrame returns the
|
||||||
|
// pointer to saved frame pointer in any case.
|
||||||
|
static inline uhwptr *GetCanonicFrame(uptr bp,
|
||||||
|
uptr stack_top,
|
||||||
|
uptr stack_bottom) {
|
||||||
|
#ifdef __arm__
|
||||||
|
if (!IsValidFrame(bp, stack_top, stack_bottom)) return 0;
|
||||||
|
uhwptr *bp_prev = (uhwptr *)bp;
|
||||||
|
if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) return bp_prev;
|
||||||
|
return bp_prev - 1;
|
||||||
|
#else
|
||||||
|
return (uhwptr*)bp;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void StackTrace::FastUnwindStack(uptr pc, uptr bp,
|
void StackTrace::FastUnwindStack(uptr pc, uptr bp,
|
||||||
uptr stack_top, uptr stack_bottom,
|
uptr stack_top, uptr stack_bottom,
|
||||||
uptr max_depth) {
|
uptr max_depth) {
|
||||||
CHECK_GE(max_depth, 2);
|
CHECK_GE(max_depth, 2);
|
||||||
trace[0] = pc;
|
trace[0] = pc;
|
||||||
size = 1;
|
size = 1;
|
||||||
uhwptr *frame = (uhwptr *)bp;
|
|
||||||
uhwptr *prev_frame = frame - 1;
|
|
||||||
if (stack_top < 4096) return; // Sanity check for stack top.
|
if (stack_top < 4096) return; // Sanity check for stack top.
|
||||||
|
uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom);
|
||||||
|
uhwptr *prev_frame = 0;
|
||||||
// Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
|
// Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
|
||||||
while (frame > prev_frame &&
|
while (frame > prev_frame &&
|
||||||
frame < (uhwptr *)stack_top - 2 &&
|
IsValidFrame((uptr)frame, stack_top, stack_bottom) &&
|
||||||
frame > (uhwptr *)stack_bottom &&
|
|
||||||
IsAligned((uptr)frame, sizeof(*frame)) &&
|
IsAligned((uptr)frame, sizeof(*frame)) &&
|
||||||
size < max_depth) {
|
size < max_depth) {
|
||||||
uhwptr pc1 = frame[1];
|
uhwptr pc1 = frame[1];
|
||||||
|
@ -56,7 +76,7 @@ void StackTrace::FastUnwindStack(uptr pc, uptr bp,
|
||||||
trace[size++] = (uptr) pc1;
|
trace[size++] = (uptr) pc1;
|
||||||
}
|
}
|
||||||
prev_frame = frame;
|
prev_frame = frame;
|
||||||
frame = (uhwptr *)frame[0];
|
frame = GetCanonicFrame((uptr)frame[0], stack_top, stack_bottom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
// RUN: %clangxx_asan -O0 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||||
|
// RUN: %clangxx_asan -O1 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||||
|
// RUN: %clangxx_asan -O2 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||||
|
// RUN: %clangxx_asan -O3 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
// REQUIRES: arm-supported-target
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int boom() {
|
||||||
|
volatile int three = 3;
|
||||||
|
char *s = (char *)malloc(three);
|
||||||
|
// CHECK: #1 0x{{.*}} in boom {{.*}}clang_gcc_abi.cc:[[@LINE-1]]
|
||||||
|
return s[three]; //BOOM
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((naked, noinline)) void gcc_abi() {
|
||||||
|
// CHECK: #2 0x{{.*}} in gcc_abi {{.*}}clang_gcc_abi.cc:[[@LINE+1]]
|
||||||
|
asm volatile("str fp, [sp, #-8]!\n\t"
|
||||||
|
"str lr, [sp, #4]\n\t"
|
||||||
|
"add fp, sp, #4\n\t"
|
||||||
|
"bl boom\n\t"
|
||||||
|
"sub sp, fp, #4\n\t"
|
||||||
|
"ldr fp, [sp]\n\t"
|
||||||
|
"add sp, sp, #4\n\t"
|
||||||
|
"ldr pc, [sp], #4\n\t"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((naked, noinline)) void clang_abi() {
|
||||||
|
// CHECK: #3 0x{{.*}} in clang_abi {{.*}}clang_gcc_abi.cc:[[@LINE+1]]
|
||||||
|
asm volatile("push {r11, lr}\n\t"
|
||||||
|
"mov r11, sp\n\t"
|
||||||
|
"bl gcc_abi\n\t"
|
||||||
|
"add r0, r0, #1\n\t"
|
||||||
|
"pop {r11, pc}\n\t"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
clang_abi();
|
||||||
|
// CHECK: #4 0x{{.*}} in main {{.*}}clang_gcc_abi.cc:[[@LINE-1]]
|
||||||
|
}
|
Loading…
Reference in New Issue