]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cc
Merge compiler-rt r291274.
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / sanitizer_common / sanitizer_stacktrace_printer.cc
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
16 namespace __sanitizer {
17
18 static 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
27 static const char kDefaultFormat[] = "    #%n %p %F %L";
28
29 void 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
119 void RenderData(InternalScopedString *buffer, const char *format,
120                 const DataInfo *DI, const char *strip_path_prefix) {
121   for (const char *p = format; *p != '\0'; p++) {
122     if (*p != '%') {
123       buffer->append("%c", *p);
124       continue;
125     }
126     p++;
127     switch (*p) {
128       case '%':
129         buffer->append("%%");
130         break;
131       case 's':
132         buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix));
133         break;
134       case 'l':
135         buffer->append("%d", DI->line);
136         break;
137       case 'g':
138         buffer->append("%s", DI->name);
139         break;
140       default:
141         Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p,
142                *p);
143         Die();
144     }
145   }
146 }
147
148 void RenderSourceLocation(InternalScopedString *buffer, const char *file,
149                           int line, int column, bool vs_style,
150                           const char *strip_path_prefix) {
151   if (vs_style && line > 0) {
152     buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
153     if (column > 0)
154       buffer->append(",%d", column);
155     buffer->append(")");
156     return;
157   }
158
159   buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
160   if (line > 0) {
161     buffer->append(":%d", line);
162     if (column > 0)
163       buffer->append(":%d", column);
164   }
165 }
166
167 void RenderModuleLocation(InternalScopedString *buffer, const char *module,
168                           uptr offset, const char *strip_path_prefix) {
169   buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix),
170                  offset);
171 }
172
173 } // namespace __sanitizer