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 
14 namespace __sanitizer {
15 
StripFunctionName(const char * function,const char * prefix)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;
23 }
24 
25 static const char kDefaultFormat[] = "    #%n %p %F %L";
26 
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)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;
36     }
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);
80       }
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>)");
97       }
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();
113     }
114   }
115 }
116 
RenderSourceLocation(InternalScopedString * buffer,const char * file,int line,int column,bool vs_style,const char * strip_path_prefix)117 void RenderSourceLocation(InternalScopedString *buffer, const char *file,
118                           int line, int column, bool vs_style,
119                           const char *strip_path_prefix) {
120   if (vs_style && line > 0) {
121     buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
122     if (column > 0)
123       buffer->append(",%d", column);
124     buffer->append(")");
125     return;
126   }
127 
128   buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
129   if (line > 0) {
130     buffer->append(":%d", line);
131     if (column > 0)
132       buffer->append(":%d", column);
133   }
134 }
135 
RenderModuleLocation(InternalScopedString * buffer,const char * module,uptr offset,const char * strip_path_prefix)136 void RenderModuleLocation(InternalScopedString *buffer, const char *module,
137                           uptr offset, const char *strip_path_prefix) {
138   buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix),
139                  offset);
140 }
141 
142 } // namespace __sanitizer
143