]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //===-- asan_posix.cc -----------------------------------------------------===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | // | |
10 | // This file is a part of AddressSanitizer, an address sanity checker. | |
11 | // | |
12 | // Posix-specific details. | |
13 | //===----------------------------------------------------------------------===// | |
14 | ||
15 | #include "sanitizer_common/sanitizer_platform.h" | |
16 | #if SANITIZER_POSIX | |
17 | ||
18 | #include "asan_internal.h" | |
19 | #include "asan_interceptors.h" | |
20 | #include "asan_mapping.h" | |
21 | #include "asan_report.h" | |
22 | #include "asan_stack.h" | |
23 | #include "sanitizer_common/sanitizer_libc.h" | |
92a42be0 | 24 | #include "sanitizer_common/sanitizer_posix.h" |
1a4d82fc JJ |
25 | #include "sanitizer_common/sanitizer_procmaps.h" |
26 | ||
27 | #include <pthread.h> | |
28 | #include <signal.h> | |
29 | #include <stdlib.h> | |
30 | #include <sys/time.h> | |
31 | #include <sys/resource.h> | |
32 | #include <unistd.h> | |
33 | ||
34 | namespace __asan { | |
35 | ||
7cac9316 XL |
36 | const char *DescribeSignalOrException(int signo) { |
37 | switch (signo) { | |
38 | case SIGFPE: | |
39 | return "FPE"; | |
40 | case SIGILL: | |
41 | return "ILL"; | |
42 | case SIGABRT: | |
43 | return "ABRT"; | |
44 | default: | |
45 | return "SEGV"; | |
46 | } | |
47 | } | |
48 | ||
92a42be0 SL |
49 | void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { |
50 | ScopedDeadlySignal signal_scope(GetCurrentThread()); | |
1a4d82fc | 51 | int code = (int)((siginfo_t*)siginfo)->si_code; |
5bcae85e SL |
52 | // Write the first message using fd=2, just in case. |
53 | // It may actually fail to write in case stderr is closed. | |
54 | internal_write(2, "ASAN:DEADLYSIGNAL\n", 18); | |
92a42be0 | 55 | SignalContext sig = SignalContext::Create(siginfo, context); |
1a4d82fc JJ |
56 | |
57 | // Access at a reasonable offset above SP, or slightly below it (to account | |
92a42be0 SL |
58 | // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is |
59 | // probably a stack overflow. | |
5bcae85e SL |
60 | #ifdef __s390__ |
61 | // On s390, the fault address in siginfo points to start of the page, not | |
62 | // to the precise word that was accessed. Mask off the low bits of sp to | |
63 | // take it into account. | |
64 | bool IsStackAccess = sig.addr >= (sig.sp & ~0xFFF) && | |
65 | sig.addr < sig.sp + 0xFFFF; | |
66 | #else | |
92a42be0 | 67 | bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF; |
5bcae85e | 68 | #endif |
92a42be0 SL |
69 | |
70 | #if __powerpc__ | |
71 | // Large stack frames can be allocated with e.g. | |
72 | // lis r0,-10000 | |
73 | // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000 | |
74 | // If the store faults then sp will not have been updated, so test above | |
75 | // will not work, becase the fault address will be more than just "slightly" | |
76 | // below sp. | |
77 | if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) { | |
78 | u32 inst = *(unsigned *)sig.pc; | |
79 | u32 ra = (inst >> 16) & 0x1F; | |
80 | u32 opcd = inst >> 26; | |
81 | u32 xo = (inst >> 1) & 0x3FF; | |
82 | // Check for store-with-update to sp. The instructions we accept are: | |
83 | // stbu rs,d(ra) stbux rs,ra,rb | |
84 | // sthu rs,d(ra) sthux rs,ra,rb | |
85 | // stwu rs,d(ra) stwux rs,ra,rb | |
86 | // stdu rs,ds(ra) stdux rs,ra,rb | |
87 | // where ra is r1 (the stack pointer). | |
88 | if (ra == 1 && | |
89 | (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 || | |
90 | (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181)))) | |
91 | IsStackAccess = true; | |
92 | } | |
93 | #endif // __powerpc__ | |
94 | ||
1a4d82fc JJ |
95 | // We also check si_code to filter out SEGV caused by something else other |
96 | // then hitting the guard page or unmapped memory, like, for example, | |
97 | // unaligned memory access. | |
92a42be0 SL |
98 | if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR)) |
99 | ReportStackOverflow(sig); | |
1a4d82fc | 100 | else |
7cac9316 | 101 | ReportDeadlySignal(signo, sig); |
1a4d82fc JJ |
102 | } |
103 | ||
104 | // ---------------------- TSD ---------------- {{{1 | |
105 | ||
106 | static pthread_key_t tsd_key; | |
107 | static bool tsd_key_inited = false; | |
108 | void AsanTSDInit(void (*destructor)(void *tsd)) { | |
109 | CHECK(!tsd_key_inited); | |
110 | tsd_key_inited = true; | |
111 | CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); | |
112 | } | |
113 | ||
114 | void *AsanTSDGet() { | |
115 | CHECK(tsd_key_inited); | |
116 | return pthread_getspecific(tsd_key); | |
117 | } | |
118 | ||
119 | void AsanTSDSet(void *tsd) { | |
120 | CHECK(tsd_key_inited); | |
121 | pthread_setspecific(tsd_key, tsd); | |
122 | } | |
123 | ||
124 | void PlatformTSDDtor(void *tsd) { | |
125 | AsanThreadContext *context = (AsanThreadContext*)tsd; | |
126 | if (context->destructor_iterations > 1) { | |
127 | context->destructor_iterations--; | |
128 | CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); | |
129 | return; | |
130 | } | |
131 | AsanThread::TSDDtor(tsd); | |
132 | } | |
133 | } // namespace __asan | |
134 | ||
135 | #endif // SANITIZER_POSIX |