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 //===----------------------------------------------------------------------===//
11 
12 #include "sanitizer_stacktrace_printer.h"
13 #include "sanitizer_file.h"
14 #include "sanitizer_fuchsia.h"
15 
16 namespace __sanitizer {
17 
18 // sanitizer_symbolizer_fuchsia.cc implements these differently for Fuchsia.
19 #if !SANITIZER_FUCHSIA
20 
StripFunctionName(const char * function,const char * prefix)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;
28 }
29 
30 static const char kDefaultFormat[] = "    #%n %p %F %L";
31 
RenderFrame(InternalScopedString * buffer,const char * format,int frame_no,const AddressInfo & info,bool vs_style,const char * strip_path_prefix,const char * strip_func_prefix)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;
41     }
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);
85       }
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>)");
102       }
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();
119     }
120   }
121 }
122 
RenderData(InternalScopedString * buffer,const char * format,const DataInfo * DI,const char * strip_path_prefix)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;
129     }
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();
148     }
149   }
150 }
151 
152 #endif  // !SANITIZER_FUCHSIA
153 
RenderSourceLocation(InternalScopedString * buffer,const char * file,int line,int column,bool vs_style,const char * strip_path_prefix)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;
163   }
164 
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);
170   }
171 }
172 
RenderModuleLocation(InternalScopedString * buffer,const char * module,uptr offset,ModuleArch arch,const char * strip_path_prefix)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));
179   }
180   buffer->append("+0x%zx)", offset);
181 }
182 
183 } // namespace __sanitizer
184