]>
Commit | Line | Data |
---|---|---|
2fc4da48 | 1 | //===-- sanitizer_common.cpp ----------------------------------------------===// |
0328398d | 2 | // |
2fc4da48 | 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. | |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
0328398d | 6 | // |
7 | //===----------------------------------------------------------------------===// | |
8 | // | |
9 | // This file is shared between sanitizers' run-time libraries. | |
10 | // | |
11 | //===----------------------------------------------------------------------===// | |
5645a48f | 12 | |
0328398d | 13 | #include "sanitizer_stacktrace_printer.h" |
36093749 | 14 | #include "sanitizer_file.h" |
15 | #include "sanitizer_fuchsia.h" | |
0328398d | 16 | |
17 | namespace __sanitizer { | |
18 | ||
2fc4da48 | 19 | // sanitizer_symbolizer_markup.cpp implements these differently. |
d2ef4bee | 20 | #if !SANITIZER_SYMBOLIZER_MARKUP |
36093749 | 21 | |
0328398d | 22 | static const char *StripFunctionName(const char *function, const char *prefix) { |
5645a48f | 23 | if (!function) return nullptr; |
24 | if (!prefix) return function; | |
0328398d | 25 | uptr prefix_len = internal_strlen(prefix); |
26 | if (0 == internal_strncmp(function, prefix, prefix_len)) | |
27 | return function + prefix_len; | |
28 | return function; | |
29 | } | |
30 | ||
d2ef4bee | 31 | static const char *DemangleFunctionName(const char *function) { |
32 | if (!function) return nullptr; | |
33 | ||
34 | // NetBSD uses indirection for old threading functions for historical reasons | |
35 | // The mangled names are internal implementation detail and should not be | |
36 | // exposed even in backtraces. | |
37 | #if SANITIZER_NETBSD | |
38 | if (!internal_strcmp(function, "__libc_mutex_init")) | |
39 | return "pthread_mutex_init"; | |
40 | if (!internal_strcmp(function, "__libc_mutex_lock")) | |
41 | return "pthread_mutex_lock"; | |
42 | if (!internal_strcmp(function, "__libc_mutex_trylock")) | |
43 | return "pthread_mutex_trylock"; | |
44 | if (!internal_strcmp(function, "__libc_mutex_unlock")) | |
45 | return "pthread_mutex_unlock"; | |
46 | if (!internal_strcmp(function, "__libc_mutex_destroy")) | |
47 | return "pthread_mutex_destroy"; | |
48 | if (!internal_strcmp(function, "__libc_mutexattr_init")) | |
49 | return "pthread_mutexattr_init"; | |
50 | if (!internal_strcmp(function, "__libc_mutexattr_settype")) | |
51 | return "pthread_mutexattr_settype"; | |
52 | if (!internal_strcmp(function, "__libc_mutexattr_destroy")) | |
53 | return "pthread_mutexattr_destroy"; | |
54 | if (!internal_strcmp(function, "__libc_cond_init")) | |
55 | return "pthread_cond_init"; | |
56 | if (!internal_strcmp(function, "__libc_cond_signal")) | |
57 | return "pthread_cond_signal"; | |
58 | if (!internal_strcmp(function, "__libc_cond_broadcast")) | |
59 | return "pthread_cond_broadcast"; | |
60 | if (!internal_strcmp(function, "__libc_cond_wait")) | |
61 | return "pthread_cond_wait"; | |
62 | if (!internal_strcmp(function, "__libc_cond_timedwait")) | |
63 | return "pthread_cond_timedwait"; | |
64 | if (!internal_strcmp(function, "__libc_cond_destroy")) | |
65 | return "pthread_cond_destroy"; | |
66 | if (!internal_strcmp(function, "__libc_rwlock_init")) | |
67 | return "pthread_rwlock_init"; | |
68 | if (!internal_strcmp(function, "__libc_rwlock_rdlock")) | |
69 | return "pthread_rwlock_rdlock"; | |
70 | if (!internal_strcmp(function, "__libc_rwlock_wrlock")) | |
71 | return "pthread_rwlock_wrlock"; | |
72 | if (!internal_strcmp(function, "__libc_rwlock_tryrdlock")) | |
73 | return "pthread_rwlock_tryrdlock"; | |
74 | if (!internal_strcmp(function, "__libc_rwlock_trywrlock")) | |
75 | return "pthread_rwlock_trywrlock"; | |
76 | if (!internal_strcmp(function, "__libc_rwlock_unlock")) | |
77 | return "pthread_rwlock_unlock"; | |
78 | if (!internal_strcmp(function, "__libc_rwlock_destroy")) | |
79 | return "pthread_rwlock_destroy"; | |
80 | if (!internal_strcmp(function, "__libc_thr_keycreate")) | |
81 | return "pthread_key_create"; | |
82 | if (!internal_strcmp(function, "__libc_thr_setspecific")) | |
83 | return "pthread_setspecific"; | |
84 | if (!internal_strcmp(function, "__libc_thr_getspecific")) | |
85 | return "pthread_getspecific"; | |
86 | if (!internal_strcmp(function, "__libc_thr_keydelete")) | |
87 | return "pthread_key_delete"; | |
88 | if (!internal_strcmp(function, "__libc_thr_once")) | |
89 | return "pthread_once"; | |
90 | if (!internal_strcmp(function, "__libc_thr_self")) | |
91 | return "pthread_self"; | |
92 | if (!internal_strcmp(function, "__libc_thr_exit")) | |
93 | return "pthread_exit"; | |
94 | if (!internal_strcmp(function, "__libc_thr_setcancelstate")) | |
95 | return "pthread_setcancelstate"; | |
96 | if (!internal_strcmp(function, "__libc_thr_equal")) | |
97 | return "pthread_equal"; | |
98 | if (!internal_strcmp(function, "__libc_thr_curcpu")) | |
99 | return "pthread_curcpu_np"; | |
2fc4da48 | 100 | if (!internal_strcmp(function, "__libc_thr_sigsetmask")) |
101 | return "pthread_sigmask"; | |
d2ef4bee | 102 | #endif |
103 | ||
104 | return function; | |
105 | } | |
106 | ||
0328398d | 107 | static const char kDefaultFormat[] = " #%n %p %F %L"; |
108 | ||
109 | void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, | |
5645a48f | 110 | const AddressInfo &info, bool vs_style, |
111 | const char *strip_path_prefix, const char *strip_func_prefix) { | |
0328398d | 112 | if (0 == internal_strcmp(format, "DEFAULT")) |
113 | format = kDefaultFormat; | |
114 | for (const char *p = format; *p != '\0'; p++) { | |
115 | if (*p != '%') { | |
116 | buffer->append("%c", *p); | |
117 | continue; | |
118 | } | |
119 | p++; | |
120 | switch (*p) { | |
121 | case '%': | |
122 | buffer->append("%%"); | |
123 | break; | |
124 | // Frame number and all fields of AddressInfo structure. | |
125 | case 'n': | |
126 | buffer->append("%zu", frame_no); | |
127 | break; | |
128 | case 'p': | |
129 | buffer->append("0x%zx", info.address); | |
130 | break; | |
131 | case 'm': | |
132 | buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix)); | |
133 | break; | |
134 | case 'o': | |
135 | buffer->append("0x%zx", info.module_offset); | |
136 | break; | |
137 | case 'f': | |
d2ef4bee | 138 | buffer->append("%s", |
139 | DemangleFunctionName( | |
140 | StripFunctionName(info.function, strip_func_prefix))); | |
0328398d | 141 | break; |
142 | case 'q': | |
143 | buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown | |
144 | ? info.function_offset | |
145 | : 0x0); | |
146 | break; | |
147 | case 's': | |
148 | buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix)); | |
149 | break; | |
150 | case 'l': | |
151 | buffer->append("%d", info.line); | |
152 | break; | |
153 | case 'c': | |
154 | buffer->append("%d", info.column); | |
155 | break; | |
156 | // Smarter special cases. | |
157 | case 'F': | |
158 | // Function name and offset, if file is unknown. | |
159 | if (info.function) { | |
160 | buffer->append("in %s", | |
d2ef4bee | 161 | DemangleFunctionName( |
162 | StripFunctionName(info.function, strip_func_prefix))); | |
0328398d | 163 | if (!info.file && info.function_offset != AddressInfo::kUnknown) |
164 | buffer->append("+0x%zx", info.function_offset); | |
165 | } | |
166 | break; | |
167 | case 'S': | |
168 | // File/line information. | |
5645a48f | 169 | RenderSourceLocation(buffer, info.file, info.line, info.column, vs_style, |
0328398d | 170 | strip_path_prefix); |
171 | break; | |
172 | case 'L': | |
173 | // Source location, or module location. | |
174 | if (info.file) { | |
175 | RenderSourceLocation(buffer, info.file, info.line, info.column, | |
5645a48f | 176 | vs_style, strip_path_prefix); |
0328398d | 177 | } else if (info.module) { |
178 | RenderModuleLocation(buffer, info.module, info.module_offset, | |
36093749 | 179 | info.module_arch, strip_path_prefix); |
0328398d | 180 | } else { |
181 | buffer->append("(<unknown module>)"); | |
182 | } | |
183 | break; | |
184 | case 'M': | |
185 | // Module basename and offset, or PC. | |
5645a48f | 186 | if (info.address & kExternalPCBit) |
187 | {} // There PCs are not meaningful. | |
188 | else if (info.module) | |
36093749 | 189 | // Always strip the module name for %M. |
190 | RenderModuleLocation(buffer, StripModuleName(info.module), | |
191 | info.module_offset, info.module_arch, ""); | |
0328398d | 192 | else |
193 | buffer->append("(%p)", (void *)info.address); | |
194 | break; | |
195 | default: | |
5645a48f | 196 | Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p, |
197 | *p); | |
0328398d | 198 | Die(); |
199 | } | |
200 | } | |
201 | } | |
202 | ||
23e39437 | 203 | void RenderData(InternalScopedString *buffer, const char *format, |
204 | const DataInfo *DI, const char *strip_path_prefix) { | |
205 | for (const char *p = format; *p != '\0'; p++) { | |
206 | if (*p != '%') { | |
207 | buffer->append("%c", *p); | |
208 | continue; | |
209 | } | |
210 | p++; | |
211 | switch (*p) { | |
212 | case '%': | |
213 | buffer->append("%%"); | |
214 | break; | |
215 | case 's': | |
216 | buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix)); | |
217 | break; | |
218 | case 'l': | |
219 | buffer->append("%d", DI->line); | |
220 | break; | |
221 | case 'g': | |
222 | buffer->append("%s", DI->name); | |
223 | break; | |
224 | default: | |
225 | Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p, | |
226 | *p); | |
227 | Die(); | |
228 | } | |
229 | } | |
230 | } | |
231 | ||
d2ef4bee | 232 | #endif // !SANITIZER_SYMBOLIZER_MARKUP |
36093749 | 233 | |
0328398d | 234 | void RenderSourceLocation(InternalScopedString *buffer, const char *file, |
5645a48f | 235 | int line, int column, bool vs_style, |
236 | const char *strip_path_prefix) { | |
237 | if (vs_style && line > 0) { | |
238 | buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line); | |
239 | if (column > 0) | |
240 | buffer->append(",%d", column); | |
241 | buffer->append(")"); | |
242 | return; | |
243 | } | |
244 | ||
0328398d | 245 | buffer->append("%s", StripPathPrefix(file, strip_path_prefix)); |
246 | if (line > 0) { | |
247 | buffer->append(":%d", line); | |
248 | if (column > 0) | |
249 | buffer->append(":%d", column); | |
250 | } | |
251 | } | |
252 | ||
253 | void RenderModuleLocation(InternalScopedString *buffer, const char *module, | |
36093749 | 254 | uptr offset, ModuleArch arch, |
255 | const char *strip_path_prefix) { | |
256 | buffer->append("(%s", StripPathPrefix(module, strip_path_prefix)); | |
257 | if (arch != kModuleArchUnknown) { | |
258 | buffer->append(":%s", ModuleArchToString(arch)); | |
259 | } | |
260 | buffer->append("+0x%zx)", offset); | |
0328398d | 261 | } |
262 | ||
5645a48f | 263 | } // namespace __sanitizer |