1//===-- sanitizer_common.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 shared between sanitizers' run-time libraries.
11//
12//===----------------------------------------------------------------------===//
13
14#include "sanitizer_stacktrace_printer.h"
15
16namespace __sanitizer {
17
18static const char *StripFunctionName(const char *function, const char *prefix) {
19  if (!function) return nullptr;
20  if (!prefix) return function;
21  uptr prefix_len = internal_strlen(prefix);
22  if (0 == internal_strncmp(function, prefix, prefix_len))
23    return function + prefix_len;
24  return function;
25}
26
27static const char kDefaultFormat[] = "    #%n %p %F %L";
28
29void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
30                 const AddressInfo &info, bool vs_style,
31                 const char *strip_path_prefix, const char *strip_func_prefix) {
32  if (0 == internal_strcmp(format, "DEFAULT"))
33    format = kDefaultFormat;
34  for (const char *p = format; *p != '\0'; p++) {
35    if (*p != '%') {
36      buffer->append("%c", *p);
37      continue;
38    }
39    p++;
40    switch (*p) {
41    case '%':
42      buffer->append("%%");
43      break;
44    // Frame number and all fields of AddressInfo structure.
45    case 'n':
46      buffer->append("%zu", frame_no);
47      break;
48    case 'p':
49      buffer->append("0x%zx", info.address);
50      break;
51    case 'm':
52      buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix));
53      break;
54    case 'o':
55      buffer->append("0x%zx", info.module_offset);
56      break;
57    case 'f':
58      buffer->append("%s", StripFunctionName(info.function, strip_func_prefix));
59      break;
60    case 'q':
61      buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown
62                                  ? info.function_offset
63                                  : 0x0);
64      break;
65    case 's':
66      buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix));
67      break;
68    case 'l':
69      buffer->append("%d", info.line);
70      break;
71    case 'c':
72      buffer->append("%d", info.column);
73      break;
74    // Smarter special cases.
75    case 'F':
76      // Function name and offset, if file is unknown.
77      if (info.function) {
78        buffer->append("in %s",
79                       StripFunctionName(info.function, strip_func_prefix));
80        if (!info.file && info.function_offset != AddressInfo::kUnknown)
81          buffer->append("+0x%zx", info.function_offset);
82      }
83      break;
84    case 'S':
85      // File/line information.
86      RenderSourceLocation(buffer, info.file, info.line, info.column, vs_style,
87                           strip_path_prefix);
88      break;
89    case 'L':
90      // Source location, or module location.
91      if (info.file) {
92        RenderSourceLocation(buffer, info.file, info.line, info.column,
93                             vs_style, strip_path_prefix);
94      } else if (info.module) {
95        RenderModuleLocation(buffer, info.module, info.module_offset,
96                             strip_path_prefix);
97      } else {
98        buffer->append("(<unknown module>)");
99      }
100      break;
101    case 'M':
102      // Module basename and offset, or PC.
103      if (info.address & kExternalPCBit)
104        {} // There PCs are not meaningful.
105      else if (info.module)
106        buffer->append("(%s+%p)", StripModuleName(info.module),
107                       (void *)info.module_offset);
108      else
109        buffer->append("(%p)", (void *)info.address);
110      break;
111    default:
112      Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p,
113             *p);
114      Die();
115    }
116  }
117}
118
119void RenderSourceLocation(InternalScopedString *buffer, const char *file,
120                          int line, int column, bool vs_style,
121                          const char *strip_path_prefix) {
122  if (vs_style && line > 0) {
123    buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
124    if (column > 0)
125      buffer->append(",%d", column);
126    buffer->append(")");
127    return;
128  }
129
130  buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
131  if (line > 0) {
132    buffer->append(":%d", line);
133    if (column > 0)
134      buffer->append(":%d", column);
135  }
136}
137
138void RenderModuleLocation(InternalScopedString *buffer, const char *module,
139                          uptr offset, const char *strip_path_prefix) {
140  buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix),
141                 offset);
142}
143
144} // namespace __sanitizer
145