Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 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 | |
| 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 | |
| 28 | void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 29 | const AddressInfo &info, bool vs_style, |
| 30 | const char *strip_path_prefix, const char *strip_func_prefix) { |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 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. |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 85 | RenderSourceLocation(buffer, info.file, info.line, info.column, vs_style, |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 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, |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 92 | vs_style, strip_path_prefix); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 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: |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 109 | Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p, |
| 110 | *p); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 111 | Die(); |
| 112 | } |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | void RenderSourceLocation(InternalScopedString *buffer, const char *file, |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 117 | int line, int column, bool vs_style, |
| 118 | const char *strip_path_prefix) { |
| 119 | if (vs_style && line > 0) { |
| 120 | buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line); |
| 121 | if (column > 0) |
| 122 | buffer->append(",%d", column); |
| 123 | buffer->append(")"); |
| 124 | return; |
| 125 | } |
| 126 | |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 127 | buffer->append("%s", StripPathPrefix(file, strip_path_prefix)); |
| 128 | if (line > 0) { |
| 129 | buffer->append(":%d", line); |
| 130 | if (column > 0) |
| 131 | buffer->append(":%d", column); |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | void RenderModuleLocation(InternalScopedString *buffer, const char *module, |
| 136 | uptr offset, const char *strip_path_prefix) { |
| 137 | buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix), |
| 138 | offset); |
| 139 | } |
| 140 | |
| 141 | } // namespace __sanitizer |