1353944Sdim//===-- sanitizer_common.cpp ----------------------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim//
9353944Sdim// This file is shared between sanitizers' run-time libraries.
10353944Sdim//
11353944Sdim//===----------------------------------------------------------------------===//
12353944Sdim
13353944Sdim#include "sanitizer_stacktrace_printer.h"
14353944Sdim#include "sanitizer_file.h"
15353944Sdim#include "sanitizer_fuchsia.h"
16353944Sdim
17353944Sdimnamespace __sanitizer {
18353944Sdim
19353944Sdim// sanitizer_symbolizer_markup.cpp implements these differently.
20353944Sdim#if !SANITIZER_SYMBOLIZER_MARKUP
21353944Sdim
22353944Sdimstatic const char *StripFunctionName(const char *function, const char *prefix) {
23353944Sdim  if (!function) return nullptr;
24353944Sdim  if (!prefix) return function;
25353944Sdim  uptr prefix_len = internal_strlen(prefix);
26353944Sdim  if (0 == internal_strncmp(function, prefix, prefix_len))
27353944Sdim    return function + prefix_len;
28353944Sdim  return function;
29353944Sdim}
30353944Sdim
31353944Sdimstatic const char *DemangleFunctionName(const char *function) {
32353944Sdim  if (!function) return nullptr;
33353944Sdim
34353944Sdim  // NetBSD uses indirection for old threading functions for historical reasons
35353944Sdim  // The mangled names are internal implementation detail and should not be
36353944Sdim  // exposed even in backtraces.
37353944Sdim#if SANITIZER_NETBSD
38353944Sdim  if (!internal_strcmp(function, "__libc_mutex_init"))
39353944Sdim    return "pthread_mutex_init";
40353944Sdim  if (!internal_strcmp(function, "__libc_mutex_lock"))
41353944Sdim    return "pthread_mutex_lock";
42353944Sdim  if (!internal_strcmp(function, "__libc_mutex_trylock"))
43353944Sdim    return "pthread_mutex_trylock";
44353944Sdim  if (!internal_strcmp(function, "__libc_mutex_unlock"))
45353944Sdim    return "pthread_mutex_unlock";
46353944Sdim  if (!internal_strcmp(function, "__libc_mutex_destroy"))
47353944Sdim    return "pthread_mutex_destroy";
48353944Sdim  if (!internal_strcmp(function, "__libc_mutexattr_init"))
49353944Sdim    return "pthread_mutexattr_init";
50353944Sdim  if (!internal_strcmp(function, "__libc_mutexattr_settype"))
51353944Sdim    return "pthread_mutexattr_settype";
52353944Sdim  if (!internal_strcmp(function, "__libc_mutexattr_destroy"))
53353944Sdim    return "pthread_mutexattr_destroy";
54353944Sdim  if (!internal_strcmp(function, "__libc_cond_init"))
55353944Sdim    return "pthread_cond_init";
56353944Sdim  if (!internal_strcmp(function, "__libc_cond_signal"))
57353944Sdim    return "pthread_cond_signal";
58353944Sdim  if (!internal_strcmp(function, "__libc_cond_broadcast"))
59353944Sdim    return "pthread_cond_broadcast";
60353944Sdim  if (!internal_strcmp(function, "__libc_cond_wait"))
61353944Sdim    return "pthread_cond_wait";
62353944Sdim  if (!internal_strcmp(function, "__libc_cond_timedwait"))
63353944Sdim    return "pthread_cond_timedwait";
64353944Sdim  if (!internal_strcmp(function, "__libc_cond_destroy"))
65353944Sdim    return "pthread_cond_destroy";
66353944Sdim  if (!internal_strcmp(function, "__libc_rwlock_init"))
67353944Sdim    return "pthread_rwlock_init";
68353944Sdim  if (!internal_strcmp(function, "__libc_rwlock_rdlock"))
69353944Sdim    return "pthread_rwlock_rdlock";
70353944Sdim  if (!internal_strcmp(function, "__libc_rwlock_wrlock"))
71353944Sdim    return "pthread_rwlock_wrlock";
72353944Sdim  if (!internal_strcmp(function, "__libc_rwlock_tryrdlock"))
73353944Sdim    return "pthread_rwlock_tryrdlock";
74353944Sdim  if (!internal_strcmp(function, "__libc_rwlock_trywrlock"))
75353944Sdim    return "pthread_rwlock_trywrlock";
76353944Sdim  if (!internal_strcmp(function, "__libc_rwlock_unlock"))
77353944Sdim    return "pthread_rwlock_unlock";
78353944Sdim  if (!internal_strcmp(function, "__libc_rwlock_destroy"))
79353944Sdim    return "pthread_rwlock_destroy";
80353944Sdim  if (!internal_strcmp(function, "__libc_thr_keycreate"))
81353944Sdim    return "pthread_key_create";
82353944Sdim  if (!internal_strcmp(function, "__libc_thr_setspecific"))
83353944Sdim    return "pthread_setspecific";
84353944Sdim  if (!internal_strcmp(function, "__libc_thr_getspecific"))
85353944Sdim    return "pthread_getspecific";
86353944Sdim  if (!internal_strcmp(function, "__libc_thr_keydelete"))
87353944Sdim    return "pthread_key_delete";
88353944Sdim  if (!internal_strcmp(function, "__libc_thr_once"))
89353944Sdim    return "pthread_once";
90353944Sdim  if (!internal_strcmp(function, "__libc_thr_self"))
91353944Sdim    return "pthread_self";
92353944Sdim  if (!internal_strcmp(function, "__libc_thr_exit"))
93353944Sdim    return "pthread_exit";
94353944Sdim  if (!internal_strcmp(function, "__libc_thr_setcancelstate"))
95353944Sdim    return "pthread_setcancelstate";
96353944Sdim  if (!internal_strcmp(function, "__libc_thr_equal"))
97353944Sdim    return "pthread_equal";
98353944Sdim  if (!internal_strcmp(function, "__libc_thr_curcpu"))
99353944Sdim    return "pthread_curcpu_np";
100353944Sdim  if (!internal_strcmp(function, "__libc_thr_sigsetmask"))
101353944Sdim    return "pthread_sigmask";
102353944Sdim#endif
103353944Sdim
104353944Sdim  return function;
105353944Sdim}
106353944Sdim
107353944Sdimstatic const char kDefaultFormat[] = "    #%n %p %F %L";
108353944Sdim
109353944Sdimvoid RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
110353944Sdim                 const AddressInfo &info, bool vs_style,
111353944Sdim                 const char *strip_path_prefix, const char *strip_func_prefix) {
112353944Sdim  if (0 == internal_strcmp(format, "DEFAULT"))
113353944Sdim    format = kDefaultFormat;
114353944Sdim  for (const char *p = format; *p != '\0'; p++) {
115353944Sdim    if (*p != '%') {
116353944Sdim      buffer->append("%c", *p);
117353944Sdim      continue;
118353944Sdim    }
119353944Sdim    p++;
120353944Sdim    switch (*p) {
121353944Sdim    case '%':
122353944Sdim      buffer->append("%%");
123353944Sdim      break;
124353944Sdim    // Frame number and all fields of AddressInfo structure.
125353944Sdim    case 'n':
126353944Sdim      buffer->append("%zu", frame_no);
127353944Sdim      break;
128353944Sdim    case 'p':
129353944Sdim      buffer->append("0x%zx", info.address);
130353944Sdim      break;
131353944Sdim    case 'm':
132353944Sdim      buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix));
133353944Sdim      break;
134353944Sdim    case 'o':
135353944Sdim      buffer->append("0x%zx", info.module_offset);
136353944Sdim      break;
137353944Sdim    case 'f':
138353944Sdim      buffer->append("%s",
139353944Sdim        DemangleFunctionName(
140353944Sdim          StripFunctionName(info.function, strip_func_prefix)));
141353944Sdim      break;
142353944Sdim    case 'q':
143353944Sdim      buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown
144353944Sdim                                  ? info.function_offset
145353944Sdim                                  : 0x0);
146353944Sdim      break;
147353944Sdim    case 's':
148353944Sdim      buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix));
149353944Sdim      break;
150353944Sdim    case 'l':
151353944Sdim      buffer->append("%d", info.line);
152353944Sdim      break;
153353944Sdim    case 'c':
154353944Sdim      buffer->append("%d", info.column);
155353944Sdim      break;
156353944Sdim    // Smarter special cases.
157353944Sdim    case 'F':
158353944Sdim      // Function name and offset, if file is unknown.
159353944Sdim      if (info.function) {
160353944Sdim        buffer->append("in %s",
161353944Sdim                       DemangleFunctionName(
162353944Sdim                         StripFunctionName(info.function, strip_func_prefix)));
163353944Sdim        if (!info.file && info.function_offset != AddressInfo::kUnknown)
164353944Sdim          buffer->append("+0x%zx", info.function_offset);
165353944Sdim      }
166353944Sdim      break;
167353944Sdim    case 'S':
168353944Sdim      // File/line information.
169353944Sdim      RenderSourceLocation(buffer, info.file, info.line, info.column, vs_style,
170353944Sdim                           strip_path_prefix);
171353944Sdim      break;
172353944Sdim    case 'L':
173353944Sdim      // Source location, or module location.
174353944Sdim      if (info.file) {
175353944Sdim        RenderSourceLocation(buffer, info.file, info.line, info.column,
176353944Sdim                             vs_style, strip_path_prefix);
177353944Sdim      } else if (info.module) {
178353944Sdim        RenderModuleLocation(buffer, info.module, info.module_offset,
179353944Sdim                             info.module_arch, strip_path_prefix);
180353944Sdim      } else {
181353944Sdim        buffer->append("(<unknown module>)");
182353944Sdim      }
183353944Sdim      break;
184353944Sdim    case 'M':
185353944Sdim      // Module basename and offset, or PC.
186353944Sdim      if (info.address & kExternalPCBit)
187353944Sdim        {} // There PCs are not meaningful.
188353944Sdim      else if (info.module)
189353944Sdim        // Always strip the module name for %M.
190353944Sdim        RenderModuleLocation(buffer, StripModuleName(info.module),
191353944Sdim                             info.module_offset, info.module_arch, "");
192353944Sdim      else
193353944Sdim        buffer->append("(%p)", (void *)info.address);
194353944Sdim      break;
195353944Sdim    default:
196353944Sdim      Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p,
197353944Sdim             *p);
198353944Sdim      Die();
199353944Sdim    }
200353944Sdim  }
201353944Sdim}
202353944Sdim
203353944Sdimvoid RenderData(InternalScopedString *buffer, const char *format,
204353944Sdim                const DataInfo *DI, const char *strip_path_prefix) {
205353944Sdim  for (const char *p = format; *p != '\0'; p++) {
206353944Sdim    if (*p != '%') {
207353944Sdim      buffer->append("%c", *p);
208353944Sdim      continue;
209353944Sdim    }
210353944Sdim    p++;
211353944Sdim    switch (*p) {
212353944Sdim      case '%':
213353944Sdim        buffer->append("%%");
214353944Sdim        break;
215353944Sdim      case 's':
216353944Sdim        buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix));
217353944Sdim        break;
218353944Sdim      case 'l':
219353944Sdim        buffer->append("%d", DI->line);
220353944Sdim        break;
221353944Sdim      case 'g':
222353944Sdim        buffer->append("%s", DI->name);
223353944Sdim        break;
224353944Sdim      default:
225353944Sdim        Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p,
226353944Sdim               *p);
227353944Sdim        Die();
228353944Sdim    }
229353944Sdim  }
230353944Sdim}
231353944Sdim
232353944Sdim#endif  // !SANITIZER_SYMBOLIZER_MARKUP
233353944Sdim
234353944Sdimvoid RenderSourceLocation(InternalScopedString *buffer, const char *file,
235353944Sdim                          int line, int column, bool vs_style,
236353944Sdim                          const char *strip_path_prefix) {
237353944Sdim  if (vs_style && line > 0) {
238353944Sdim    buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
239353944Sdim    if (column > 0)
240353944Sdim      buffer->append(",%d", column);
241353944Sdim    buffer->append(")");
242353944Sdim    return;
243353944Sdim  }
244353944Sdim
245353944Sdim  buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
246353944Sdim  if (line > 0) {
247353944Sdim    buffer->append(":%d", line);
248353944Sdim    if (column > 0)
249353944Sdim      buffer->append(":%d", column);
250353944Sdim  }
251353944Sdim}
252353944Sdim
253353944Sdimvoid RenderModuleLocation(InternalScopedString *buffer, const char *module,
254353944Sdim                          uptr offset, ModuleArch arch,
255353944Sdim                          const char *strip_path_prefix) {
256353944Sdim  buffer->append("(%s", StripPathPrefix(module, strip_path_prefix));
257353944Sdim  if (arch != kModuleArchUnknown) {
258353944Sdim    buffer->append(":%s", ModuleArchToString(arch));
259353944Sdim  }
260353944Sdim  buffer->append("+0x%zx)", offset);
261353944Sdim}
262353944Sdim
263353944Sdim} // namespace __sanitizer
264