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