[clang][extract-api] Emit "navigator" property of "name" in SymbolGraph
[llvm-project.git] / compiler-rt / lib / sanitizer_common / sanitizer_stacktrace_printer.cpp
blob2d0eccc1602ab3f398fced45f1329515161c02dd
1 //===-- sanitizer_common.cpp ----------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is shared between sanitizers' run-time libraries.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_stacktrace_printer.h"
14 #include "sanitizer_file.h"
15 #include "sanitizer_fuchsia.h"
17 namespace __sanitizer {
19 // sanitizer_symbolizer_markup.cpp implements these differently.
20 #if !SANITIZER_SYMBOLIZER_MARKUP
22 static const char *StripFunctionName(const char *function, const char *prefix) {
23 if (!function) return nullptr;
24 if (!prefix) return function;
25 uptr prefix_len = internal_strlen(prefix);
26 if (0 == internal_strncmp(function, prefix, prefix_len))
27 return function + prefix_len;
28 return function;
31 static const char *DemangleFunctionName(const char *function) {
32 if (!function) return nullptr;
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";
100 if (!internal_strcmp(function, "__libc_thr_sigsetmask"))
101 return "pthread_sigmask";
102 #endif
104 return function;
107 static void MaybeBuildIdToBuffer(const AddressInfo &info, bool PrefixSpace,
108 InternalScopedString *buffer) {
109 if (info.uuid_size) {
110 if (PrefixSpace)
111 buffer->append(" ");
112 buffer->append("(BuildId: ");
113 for (uptr i = 0; i < info.uuid_size; ++i) {
114 buffer->append("%02x", info.uuid[i]);
116 buffer->append(")");
120 static const char kDefaultFormat[] = " #%n %p %F %L";
122 void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
123 uptr address, const AddressInfo *info, bool vs_style,
124 const char *strip_path_prefix, const char *strip_func_prefix) {
125 // info will be null in the case where symbolization is not needed for the
126 // given format. This ensures that the code below will get a hard failure
127 // rather than print incorrect information in case RenderNeedsSymbolization
128 // ever ends up out of sync with this function. If non-null, the addresses
129 // should match.
130 CHECK(!info || address == info->address);
131 if (0 == internal_strcmp(format, "DEFAULT"))
132 format = kDefaultFormat;
133 for (const char *p = format; *p != '\0'; p++) {
134 if (*p != '%') {
135 buffer->append("%c", *p);
136 continue;
138 p++;
139 switch (*p) {
140 case '%':
141 buffer->append("%%");
142 break;
143 // Frame number and all fields of AddressInfo structure.
144 case 'n':
145 buffer->append("%u", frame_no);
146 break;
147 case 'p':
148 buffer->append("0x%zx", address);
149 break;
150 case 'm':
151 buffer->append("%s", StripPathPrefix(info->module, strip_path_prefix));
152 break;
153 case 'o':
154 buffer->append("0x%zx", info->module_offset);
155 break;
156 case 'b':
157 MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/false, buffer);
158 break;
159 case 'f':
160 buffer->append("%s", DemangleFunctionName(StripFunctionName(
161 info->function, strip_func_prefix)));
162 break;
163 case 'q':
164 buffer->append("0x%zx", info->function_offset != AddressInfo::kUnknown
165 ? info->function_offset
166 : 0x0);
167 break;
168 case 's':
169 buffer->append("%s", StripPathPrefix(info->file, strip_path_prefix));
170 break;
171 case 'l':
172 buffer->append("%d", info->line);
173 break;
174 case 'c':
175 buffer->append("%d", info->column);
176 break;
177 // Smarter special cases.
178 case 'F':
179 // Function name and offset, if file is unknown.
180 if (info->function) {
181 buffer->append("in %s", DemangleFunctionName(StripFunctionName(
182 info->function, strip_func_prefix)));
183 if (!info->file && info->function_offset != AddressInfo::kUnknown)
184 buffer->append("+0x%zx", info->function_offset);
186 break;
187 case 'S':
188 // File/line information.
189 RenderSourceLocation(buffer, info->file, info->line, info->column,
190 vs_style, strip_path_prefix);
191 break;
192 case 'L':
193 // Source location, or module location.
194 if (info->file) {
195 RenderSourceLocation(buffer, info->file, info->line, info->column,
196 vs_style, strip_path_prefix);
197 } else if (info->module) {
198 RenderModuleLocation(buffer, info->module, info->module_offset,
199 info->module_arch, strip_path_prefix);
201 MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/true, buffer);
202 } else {
203 buffer->append("(<unknown module>)");
205 break;
206 case 'M':
207 // Module basename and offset, or PC.
208 if (address & kExternalPCBit) {
209 // There PCs are not meaningful.
210 } else if (info->module) {
211 // Always strip the module name for %M.
212 RenderModuleLocation(buffer, StripModuleName(info->module),
213 info->module_offset, info->module_arch, "");
214 MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/true, buffer);
215 } else {
216 buffer->append("(%p)", (void *)address);
218 break;
219 default:
220 Report("Unsupported specifier in stack frame format: %c (%p)!\n", *p,
221 (void *)p);
222 Die();
227 bool RenderNeedsSymbolization(const char *format) {
228 if (0 == internal_strcmp(format, "DEFAULT"))
229 format = kDefaultFormat;
230 for (const char *p = format; *p != '\0'; p++) {
231 if (*p != '%')
232 continue;
233 p++;
234 switch (*p) {
235 case '%':
236 break;
237 case 'n':
238 // frame_no
239 break;
240 case 'p':
241 // address
242 break;
243 default:
244 return true;
247 return false;
250 void RenderData(InternalScopedString *buffer, const char *format,
251 const DataInfo *DI, const char *strip_path_prefix) {
252 for (const char *p = format; *p != '\0'; p++) {
253 if (*p != '%') {
254 buffer->append("%c", *p);
255 continue;
257 p++;
258 switch (*p) {
259 case '%':
260 buffer->append("%%");
261 break;
262 case 's':
263 buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix));
264 break;
265 case 'l':
266 buffer->append("%zu", DI->line);
267 break;
268 case 'g':
269 buffer->append("%s", DI->name);
270 break;
271 default:
272 Report("Unsupported specifier in stack frame format: %c (%p)!\n", *p,
273 (void *)p);
274 Die();
279 #endif // !SANITIZER_SYMBOLIZER_MARKUP
281 void RenderSourceLocation(InternalScopedString *buffer, const char *file,
282 int line, int column, bool vs_style,
283 const char *strip_path_prefix) {
284 if (vs_style && line > 0) {
285 buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
286 if (column > 0)
287 buffer->append(",%d", column);
288 buffer->append(")");
289 return;
292 buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
293 if (line > 0) {
294 buffer->append(":%d", line);
295 if (column > 0)
296 buffer->append(":%d", column);
300 void RenderModuleLocation(InternalScopedString *buffer, const char *module,
301 uptr offset, ModuleArch arch,
302 const char *strip_path_prefix) {
303 buffer->append("(%s", StripPathPrefix(module, strip_path_prefix));
304 if (arch != kModuleArchUnknown) {
305 buffer->append(":%s", ModuleArchToString(arch));
307 buffer->append("+0x%zx)", offset);
310 } // namespace __sanitizer