[SFN] sync up debug-only stmt list's side effects with empty stmts too
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_stacktrace_printer.cc
blob3c5bed3d75a694dd1ca07d4d8669cf04d26b8c3a
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"
13 #include "sanitizer_file.h"
14 #include "sanitizer_fuchsia.h"
16 namespace __sanitizer {
18 // sanitizer_symbolizer_fuchsia.cc implements these differently for Fuchsia.
19 #if !SANITIZER_FUCHSIA
21 static const char *StripFunctionName(const char *function, const char *prefix) {
22 if (!function) return nullptr;
23 if (!prefix) return function;
24 uptr prefix_len = internal_strlen(prefix);
25 if (0 == internal_strncmp(function, prefix, prefix_len))
26 return function + prefix_len;
27 return function;
30 static const char kDefaultFormat[] = " #%n %p %F %L";
32 void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
33 const AddressInfo &info, bool vs_style,
34 const char *strip_path_prefix, const char *strip_func_prefix) {
35 if (0 == internal_strcmp(format, "DEFAULT"))
36 format = kDefaultFormat;
37 for (const char *p = format; *p != '\0'; p++) {
38 if (*p != '%') {
39 buffer->append("%c", *p);
40 continue;
42 p++;
43 switch (*p) {
44 case '%':
45 buffer->append("%%");
46 break;
47 // Frame number and all fields of AddressInfo structure.
48 case 'n':
49 buffer->append("%zu", frame_no);
50 break;
51 case 'p':
52 buffer->append("0x%zx", info.address);
53 break;
54 case 'm':
55 buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix));
56 break;
57 case 'o':
58 buffer->append("0x%zx", info.module_offset);
59 break;
60 case 'f':
61 buffer->append("%s", StripFunctionName(info.function, strip_func_prefix));
62 break;
63 case 'q':
64 buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown
65 ? info.function_offset
66 : 0x0);
67 break;
68 case 's':
69 buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix));
70 break;
71 case 'l':
72 buffer->append("%d", info.line);
73 break;
74 case 'c':
75 buffer->append("%d", info.column);
76 break;
77 // Smarter special cases.
78 case 'F':
79 // Function name and offset, if file is unknown.
80 if (info.function) {
81 buffer->append("in %s",
82 StripFunctionName(info.function, strip_func_prefix));
83 if (!info.file && info.function_offset != AddressInfo::kUnknown)
84 buffer->append("+0x%zx", info.function_offset);
86 break;
87 case 'S':
88 // File/line information.
89 RenderSourceLocation(buffer, info.file, info.line, info.column, vs_style,
90 strip_path_prefix);
91 break;
92 case 'L':
93 // Source location, or module location.
94 if (info.file) {
95 RenderSourceLocation(buffer, info.file, info.line, info.column,
96 vs_style, strip_path_prefix);
97 } else if (info.module) {
98 RenderModuleLocation(buffer, info.module, info.module_offset,
99 info.module_arch, strip_path_prefix);
100 } else {
101 buffer->append("(<unknown module>)");
103 break;
104 case 'M':
105 // Module basename and offset, or PC.
106 if (info.address & kExternalPCBit)
107 {} // There PCs are not meaningful.
108 else if (info.module)
109 // Always strip the module name for %M.
110 RenderModuleLocation(buffer, StripModuleName(info.module),
111 info.module_offset, info.module_arch, "");
112 else
113 buffer->append("(%p)", (void *)info.address);
114 break;
115 default:
116 Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p,
117 *p);
118 Die();
123 void RenderData(InternalScopedString *buffer, const char *format,
124 const DataInfo *DI, const char *strip_path_prefix) {
125 for (const char *p = format; *p != '\0'; p++) {
126 if (*p != '%') {
127 buffer->append("%c", *p);
128 continue;
130 p++;
131 switch (*p) {
132 case '%':
133 buffer->append("%%");
134 break;
135 case 's':
136 buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix));
137 break;
138 case 'l':
139 buffer->append("%d", DI->line);
140 break;
141 case 'g':
142 buffer->append("%s", DI->name);
143 break;
144 default:
145 Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p,
146 *p);
147 Die();
152 #endif // !SANITIZER_FUCHSIA
154 void RenderSourceLocation(InternalScopedString *buffer, const char *file,
155 int line, int column, bool vs_style,
156 const char *strip_path_prefix) {
157 if (vs_style && line > 0) {
158 buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
159 if (column > 0)
160 buffer->append(",%d", column);
161 buffer->append(")");
162 return;
165 buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
166 if (line > 0) {
167 buffer->append(":%d", line);
168 if (column > 0)
169 buffer->append(":%d", column);
173 void RenderModuleLocation(InternalScopedString *buffer, const char *module,
174 uptr offset, ModuleArch arch,
175 const char *strip_path_prefix) {
176 buffer->append("(%s", StripPathPrefix(module, strip_path_prefix));
177 if (arch != kModuleArchUnknown) {
178 buffer->append(":%s", ModuleArchToString(arch));
180 buffer->append("+0x%zx)", offset);
183 } // namespace __sanitizer