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 #include "sanitizer_stacktrace_printer.h"
14 
15 namespace __sanitizer {
16 
StripFunctionName(const char * function,const char * prefix)17 static const char *StripFunctionName(const char *function, const char *prefix) {
18   if (function == 0) return 0;
19   if (prefix == 0) return function;
20   uptr prefix_len = internal_strlen(prefix);
21   if (0 == internal_strncmp(function, prefix, prefix_len))
22     return function + prefix_len;
23   return function;
24 }
25 
26 static const char kDefaultFormat[] = "    #%n %p %F %L";
27 
RenderFrame(InternalScopedString * buffer,const char * format,int frame_no,const AddressInfo & info,const char * strip_path_prefix,const char * strip_func_prefix)28 void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
29                  const AddressInfo &info, const char *strip_path_prefix,
30                  const char *strip_func_prefix) {
31   if (0 == internal_strcmp(format, "DEFAULT"))
32     format = kDefaultFormat;
33   for (const char *p = format; *p != '\0'; p++) {
34     if (*p != '%') {
35       buffer->append("%c", *p);
36       continue;
37     }
38     p++;
39     switch (*p) {
40     case '%':
41       buffer->append("%%");
42       break;
43     // Frame number and all fields of AddressInfo structure.
44     case 'n':
45       buffer->append("%zu", frame_no);
46       break;
47     case 'p':
48       buffer->append("0x%zx", info.address);
49       break;
50     case 'm':
51       buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix));
52       break;
53     case 'o':
54       buffer->append("0x%zx", info.module_offset);
55       break;
56     case 'f':
57       buffer->append("%s", StripFunctionName(info.function, strip_func_prefix));
58       break;
59     case 'q':
60       buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown
61                                   ? info.function_offset
62                                   : 0x0);
63       break;
64     case 's':
65       buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix));
66       break;
67     case 'l':
68       buffer->append("%d", info.line);
69       break;
70     case 'c':
71       buffer->append("%d", info.column);
72       break;
73     // Smarter special cases.
74     case 'F':
75       // Function name and offset, if file is unknown.
76       if (info.function) {
77         buffer->append("in %s",
78                        StripFunctionName(info.function, strip_func_prefix));
79         if (!info.file && info.function_offset != AddressInfo::kUnknown)
80           buffer->append("+0x%zx", info.function_offset);
81       }
82       break;
83     case 'S':
84       // File/line information.
85       RenderSourceLocation(buffer, info.file, info.line, info.column,
86                            strip_path_prefix);
87       break;
88     case 'L':
89       // Source location, or module location.
90       if (info.file) {
91         RenderSourceLocation(buffer, info.file, info.line, info.column,
92                              strip_path_prefix);
93       } else if (info.module) {
94         RenderModuleLocation(buffer, info.module, info.module_offset,
95                              strip_path_prefix);
96       } else {
97         buffer->append("(<unknown module>)");
98       }
99       break;
100     case 'M':
101       // Module basename and offset, or PC.
102       if (info.module)
103         buffer->append("(%s+%p)", StripModuleName(info.module),
104                        (void *)info.module_offset);
105       else
106         buffer->append("(%p)", (void *)info.address);
107       break;
108     default:
109       Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n",
110              *p, *p);
111       Die();
112     }
113   }
114 }
115 
RenderSourceLocation(InternalScopedString * buffer,const char * file,int line,int column,const char * strip_path_prefix)116 void RenderSourceLocation(InternalScopedString *buffer, const char *file,
117                           int line, int column, const char *strip_path_prefix) {
118   buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
119   if (line > 0) {
120     buffer->append(":%d", line);
121     if (column > 0)
122       buffer->append(":%d", column);
123   }
124 }
125 
RenderModuleLocation(InternalScopedString * buffer,const char * module,uptr offset,const char * strip_path_prefix)126 void RenderModuleLocation(InternalScopedString *buffer, const char *module,
127                           uptr offset, const char *strip_path_prefix) {
128   buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix),
129                  offset);
130 }
131 
132 }  // namespace __sanitizer
133