]> git.ipfire.org Git - thirdparty/gcc.git/blame - libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cpp
Libsanitizer merge from trunk r368656.
[thirdparty/gcc.git] / libsanitizer / sanitizer_common / sanitizer_stacktrace_printer.cpp
CommitLineData
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
17namespace __sanitizer {
18
2fc4da48 19// sanitizer_symbolizer_markup.cpp implements these differently.
d2ef4bee 20#if !SANITIZER_SYMBOLIZER_MARKUP
36093749 21
0328398d 22static 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 31static 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 107static const char kDefaultFormat[] = " #%n %p %F %L";
108
109void 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 203void 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 234void 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
253void 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