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 
StripFunctionName(const char * function,const char * prefix)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 
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)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 
RenderSourceLocation(InternalScopedString * buffer,const char * file,int line,int column,bool vs_style,const char * strip_path_prefix)119 void RenderSourceLocation(InternalScopedString *buffer, const char *file,
120                           int line, int column, bool vs_style,
121                           const char *strip_path_prefix) {
122   if (vs_style && line > 0) {
123     buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
124     if (column > 0)
125       buffer->append(",%d", column);
126     buffer->append(")");
127     return;
128   }
129 
130   buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
131   if (line > 0) {
132     buffer->append(":%d", line);
133     if (column > 0)
134       buffer->append(":%d", column);
135   }
136 }
137 
RenderModuleLocation(InternalScopedString * buffer,const char * module,uptr offset,const char * strip_path_prefix)138 void RenderModuleLocation(InternalScopedString *buffer, const char *module,
139                           uptr offset, const char *strip_path_prefix) {
140   buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix),
141                  offset);
142 }
143 
144 } // namespace __sanitizer
145