2017-09-18 Jeff Law <law@redhat.com>
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_stacktrace_printer.cc
blobde78c7ac8d1daa046d0546ca20d911f846c551ae
1 //===-- sanitizer_common.cc -----------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is shared between sanitizers' run-time libraries.
9 //
10 //===----------------------------------------------------------------------===//
12 #include "sanitizer_stacktrace_printer.h"
14 namespace __sanitizer {
16 static const char *StripFunctionName(const char *function, const char *prefix) {
17 if (!function) return nullptr;
18 if (!prefix) return function;
19 uptr prefix_len = internal_strlen(prefix);
20 if (0 == internal_strncmp(function, prefix, prefix_len))
21 return function + prefix_len;
22 return function;
25 static const char kDefaultFormat[] = " #%n %p %F %L";
27 void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
28 const AddressInfo &info, bool vs_style,
29 const char *strip_path_prefix, const char *strip_func_prefix) {
30 if (0 == internal_strcmp(format, "DEFAULT"))
31 format = kDefaultFormat;
32 for (const char *p = format; *p != '\0'; p++) {
33 if (*p != '%') {
34 buffer->append("%c", *p);
35 continue;
37 p++;
38 switch (*p) {
39 case '%':
40 buffer->append("%%");
41 break;
42 // Frame number and all fields of AddressInfo structure.
43 case 'n':
44 buffer->append("%zu", frame_no);
45 break;
46 case 'p':
47 buffer->append("0x%zx", info.address);
48 break;
49 case 'm':
50 buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix));
51 break;
52 case 'o':
53 buffer->append("0x%zx", info.module_offset);
54 break;
55 case 'f':
56 buffer->append("%s", StripFunctionName(info.function, strip_func_prefix));
57 break;
58 case 'q':
59 buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown
60 ? info.function_offset
61 : 0x0);
62 break;
63 case 's':
64 buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix));
65 break;
66 case 'l':
67 buffer->append("%d", info.line);
68 break;
69 case 'c':
70 buffer->append("%d", info.column);
71 break;
72 // Smarter special cases.
73 case 'F':
74 // Function name and offset, if file is unknown.
75 if (info.function) {
76 buffer->append("in %s",
77 StripFunctionName(info.function, strip_func_prefix));
78 if (!info.file && info.function_offset != AddressInfo::kUnknown)
79 buffer->append("+0x%zx", info.function_offset);
81 break;
82 case 'S':
83 // File/line information.
84 RenderSourceLocation(buffer, info.file, info.line, info.column, vs_style,
85 strip_path_prefix);
86 break;
87 case 'L':
88 // Source location, or module location.
89 if (info.file) {
90 RenderSourceLocation(buffer, info.file, info.line, info.column,
91 vs_style, strip_path_prefix);
92 } else if (info.module) {
93 RenderModuleLocation(buffer, info.module, info.module_offset,
94 strip_path_prefix);
95 } else {
96 buffer->append("(<unknown module>)");
98 break;
99 case 'M':
100 // Module basename and offset, or PC.
101 if (info.address & kExternalPCBit)
102 {} // There PCs are not meaningful.
103 else if (info.module)
104 buffer->append("(%s+%p)", StripModuleName(info.module),
105 (void *)info.module_offset);
106 else
107 buffer->append("(%p)", (void *)info.address);
108 break;
109 default:
110 Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p,
111 *p);
112 Die();
117 void RenderData(InternalScopedString *buffer, const char *format,
118 const DataInfo *DI, const char *strip_path_prefix) {
119 for (const char *p = format; *p != '\0'; p++) {
120 if (*p != '%') {
121 buffer->append("%c", *p);
122 continue;
124 p++;
125 switch (*p) {
126 case '%':
127 buffer->append("%%");
128 break;
129 case 's':
130 buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix));
131 break;
132 case 'l':
133 buffer->append("%d", DI->line);
134 break;
135 case 'g':
136 buffer->append("%s", DI->name);
137 break;
138 default:
139 Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p,
140 *p);
141 Die();
146 void RenderSourceLocation(InternalScopedString *buffer, const char *file,
147 int line, int column, bool vs_style,
148 const char *strip_path_prefix) {
149 if (vs_style && line > 0) {
150 buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
151 if (column > 0)
152 buffer->append(",%d", column);
153 buffer->append(")");
154 return;
157 buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
158 if (line > 0) {
159 buffer->append(":%d", line);
160 if (column > 0)
161 buffer->append(":%d", column);
165 void RenderModuleLocation(InternalScopedString *buffer, const char *module,
166 uptr offset, const char *strip_path_prefix) {
167 buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix),
168 offset);
171 } // namespace __sanitizer