Alexey Samsonov | ff0ce7f | 2013-06-11 08:14:24 +0000 | [diff] [blame] | 1 | //===-- sanitizer_symbolizer_posix_libcdep.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 AddressSanitizer and ThreadSanitizer |
| 11 | // run-time libraries. |
| 12 | // POSIX-specific implementation of symbolizer parts. |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #include "sanitizer_platform.h" |
| 16 | #if SANITIZER_POSIX |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 17 | #include "sanitizer_allocator_internal.h" |
Alexey Samsonov | ff0ce7f | 2013-06-11 08:14:24 +0000 | [diff] [blame] | 18 | #include "sanitizer_common.h" |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 19 | #include "sanitizer_flags.h" |
Alexey Samsonov | ff0ce7f | 2013-06-11 08:14:24 +0000 | [diff] [blame] | 20 | #include "sanitizer_internal_defs.h" |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 21 | #include "sanitizer_linux.h" |
| 22 | #include "sanitizer_placement_new.h" |
| 23 | #include "sanitizer_procmaps.h" |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 24 | #include "sanitizer_symbolizer_internal.h" |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 25 | #include "sanitizer_symbolizer_libbacktrace.h" |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 26 | #include "sanitizer_symbolizer_mac.h" |
Alexey Samsonov | ff0ce7f | 2013-06-11 08:14:24 +0000 | [diff] [blame] | 27 | |
Alexey Samsonov | ff0ce7f | 2013-06-11 08:14:24 +0000 | [diff] [blame] | 28 | #include <unistd.h> |
| 29 | |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 30 | // C++ demangling function, as required by Itanium C++ ABI. This is weak, |
| 31 | // because we do not require a C++ ABI library to be linked to a program |
| 32 | // using sanitizers; if it's not present, we'll just use the mangled name. |
| 33 | namespace __cxxabiv1 { |
| 34 | extern "C" SANITIZER_WEAK_ATTRIBUTE |
| 35 | char *__cxa_demangle(const char *mangled, char *buffer, |
| 36 | size_t *length, int *status); |
| 37 | } |
| 38 | |
Alexey Samsonov | ff0ce7f | 2013-06-11 08:14:24 +0000 | [diff] [blame] | 39 | namespace __sanitizer { |
| 40 | |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 41 | // Attempts to demangle the name via __cxa_demangle from __cxxabiv1. |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 42 | const char *DemangleCXXABI(const char *name) { |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 43 | // FIXME: __cxa_demangle aggressively insists on allocating memory. |
| 44 | // There's not much we can do about that, short of providing our |
| 45 | // own demangler (libc++abi's implementation could be adapted so that |
| 46 | // it does not allocate). For now, we just call it anyway, and we leak |
| 47 | // the returned value. |
| 48 | if (__cxxabiv1::__cxa_demangle) |
| 49 | if (const char *demangled_name = |
| 50 | __cxxabiv1::__cxa_demangle(name, 0, 0, 0)) |
| 51 | return demangled_name; |
| 52 | |
| 53 | return name; |
| 54 | } |
| 55 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 56 | // Parses one or more two-line strings in the following format: |
| 57 | // <function_name> |
| 58 | // <file_name>:<line_number>[:<column_number>] |
| 59 | // Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of |
| 60 | // them use the same output format. |
| 61 | static void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) { |
| 62 | bool top_frame = true; |
| 63 | SymbolizedStack *last = res; |
| 64 | while (true) { |
| 65 | char *function_name = 0; |
| 66 | str = ExtractToken(str, "\n", &function_name); |
| 67 | CHECK(function_name); |
| 68 | if (function_name[0] == '\0') { |
| 69 | // There are no more frames. |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 70 | InternalFree(function_name); |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 71 | break; |
| 72 | } |
| 73 | SymbolizedStack *cur; |
| 74 | if (top_frame) { |
| 75 | cur = res; |
| 76 | top_frame = false; |
| 77 | } else { |
| 78 | cur = SymbolizedStack::New(res->info.address); |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 79 | cur->info.FillModuleInfo(res->info.module, res->info.module_offset); |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 80 | last->next = cur; |
| 81 | last = cur; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 82 | } |
| 83 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 84 | AddressInfo *info = &cur->info; |
| 85 | info->function = function_name; |
| 86 | // Parse <file>:<line>:<column> buffer. |
| 87 | char *file_line_info = 0; |
| 88 | str = ExtractToken(str, "\n", &file_line_info); |
| 89 | CHECK(file_line_info); |
| 90 | const char *line_info = ExtractToken(file_line_info, ":", &info->file); |
| 91 | line_info = ExtractInt(line_info, ":", &info->line); |
| 92 | line_info = ExtractInt(line_info, "", &info->column); |
| 93 | InternalFree(file_line_info); |
| 94 | |
| 95 | // Functions and filenames can be "??", in which case we write 0 |
| 96 | // to address info to mark that names are unknown. |
| 97 | if (0 == internal_strcmp(info->function, "??")) { |
| 98 | InternalFree(info->function); |
| 99 | info->function = 0; |
| 100 | } |
| 101 | if (0 == internal_strcmp(info->file, "??")) { |
| 102 | InternalFree(info->file); |
| 103 | info->file = 0; |
| 104 | } |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 105 | } |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 106 | } |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 107 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 108 | // Parses a two-line string in the following format: |
| 109 | // <symbol_name> |
| 110 | // <start_address> <size> |
| 111 | // Used by LLVMSymbolizer and InternalSymbolizer. |
| 112 | static void ParseSymbolizeDataOutput(const char *str, DataInfo *info) { |
| 113 | str = ExtractToken(str, "\n", &info->name); |
| 114 | str = ExtractUptr(str, " ", &info->start); |
| 115 | str = ExtractUptr(str, "\n", &info->size); |
| 116 | } |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 117 | |
| 118 | // For now we assume the following protocol: |
| 119 | // For each request of the form |
| 120 | // <module_name> <module_offset> |
| 121 | // passed to STDIN, external symbolizer prints to STDOUT response: |
| 122 | // <function_name> |
| 123 | // <file_name>:<line_number>:<column_number> |
| 124 | // <function_name> |
| 125 | // <file_name>:<line_number>:<column_number> |
| 126 | // ... |
| 127 | // <empty line> |
| 128 | class LLVMSymbolizerProcess : public SymbolizerProcess { |
| 129 | public: |
| 130 | explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {} |
| 131 | |
| 132 | private: |
Pirama Arumuga Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 133 | bool ReachedEndOfOutput(const char *buffer, uptr length) const override { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 134 | // Empty line marks the end of llvm-symbolizer output. |
| 135 | return length >= 2 && buffer[length - 1] == '\n' && |
| 136 | buffer[length - 2] == '\n'; |
| 137 | } |
| 138 | |
Pirama Arumuga Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 139 | void ExecuteWithDefaultArgs(const char *path_to_binary) const override { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 140 | #if defined(__x86_64__) |
| 141 | const char* const kSymbolizerArch = "--default-arch=x86_64"; |
| 142 | #elif defined(__i386__) |
| 143 | const char* const kSymbolizerArch = "--default-arch=i386"; |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 144 | #elif defined(__powerpc64__) && defined(__BIG_ENDIAN__) |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 145 | const char* const kSymbolizerArch = "--default-arch=powerpc64"; |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 146 | #elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__) |
| 147 | const char* const kSymbolizerArch = "--default-arch=powerpc64le"; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 148 | #else |
| 149 | const char* const kSymbolizerArch = "--default-arch=unknown"; |
| 150 | #endif |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 151 | |
| 152 | const char *const inline_flag = common_flags()->symbolize_inline_frames |
| 153 | ? "--inlining=true" |
| 154 | : "--inlining=false"; |
| 155 | execl(path_to_binary, path_to_binary, inline_flag, kSymbolizerArch, |
| 156 | (char *)0); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 157 | } |
| 158 | }; |
| 159 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 160 | class LLVMSymbolizer : public SymbolizerTool { |
| 161 | public: |
| 162 | explicit LLVMSymbolizer(const char *path, LowLevelAllocator *allocator) |
| 163 | : symbolizer_process_(new(*allocator) LLVMSymbolizerProcess(path)) {} |
| 164 | |
| 165 | bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { |
| 166 | if (const char *buf = SendCommand(/*is_data*/ false, stack->info.module, |
| 167 | stack->info.module_offset)) { |
| 168 | ParseSymbolizePCOutput(buf, stack); |
| 169 | return true; |
| 170 | } |
| 171 | return false; |
| 172 | } |
| 173 | |
| 174 | bool SymbolizeData(uptr addr, DataInfo *info) override { |
| 175 | if (const char *buf = |
| 176 | SendCommand(/*is_data*/ true, info->module, info->module_offset)) { |
| 177 | ParseSymbolizeDataOutput(buf, info); |
| 178 | info->start += (addr - info->module_offset); // Add the base address. |
| 179 | return true; |
| 180 | } |
| 181 | return false; |
| 182 | } |
| 183 | |
| 184 | private: |
| 185 | const char *SendCommand(bool is_data, const char *module_name, |
| 186 | uptr module_offset) { |
| 187 | CHECK(module_name); |
| 188 | internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n", |
| 189 | is_data ? "DATA " : "", module_name, module_offset); |
| 190 | return symbolizer_process_->SendCommand(buffer_); |
| 191 | } |
| 192 | |
| 193 | LLVMSymbolizerProcess *symbolizer_process_; |
| 194 | static const uptr kBufferSize = 16 * 1024; |
| 195 | char buffer_[kBufferSize]; |
| 196 | }; |
| 197 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 198 | class Addr2LineProcess : public SymbolizerProcess { |
| 199 | public: |
| 200 | Addr2LineProcess(const char *path, const char *module_name) |
| 201 | : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {} |
| 202 | |
| 203 | const char *module_name() const { return module_name_; } |
| 204 | |
| 205 | private: |
Pirama Arumuga Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 206 | bool ReachedEndOfOutput(const char *buffer, uptr length) const override { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 207 | // Output should consist of two lines. |
| 208 | int num_lines = 0; |
| 209 | for (uptr i = 0; i < length; ++i) { |
| 210 | if (buffer[i] == '\n') |
| 211 | num_lines++; |
| 212 | if (num_lines >= 2) |
| 213 | return true; |
| 214 | } |
| 215 | return false; |
| 216 | } |
| 217 | |
Pirama Arumuga Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 218 | void ExecuteWithDefaultArgs(const char *path_to_binary) const override { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 219 | execl(path_to_binary, path_to_binary, "-Cfe", module_name_, (char *)0); |
| 220 | } |
| 221 | |
| 222 | const char *module_name_; // Owned, leaked. |
| 223 | }; |
| 224 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 225 | class Addr2LinePool : public SymbolizerTool { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 226 | public: |
| 227 | explicit Addr2LinePool(const char *addr2line_path, |
| 228 | LowLevelAllocator *allocator) |
| 229 | : addr2line_path_(addr2line_path), allocator_(allocator), |
| 230 | addr2line_pool_(16) {} |
| 231 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 232 | bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { |
| 233 | if (const char *buf = |
| 234 | SendCommand(stack->info.module, stack->info.module_offset)) { |
| 235 | ParseSymbolizePCOutput(buf, stack); |
| 236 | return true; |
| 237 | } |
| 238 | return false; |
| 239 | } |
| 240 | |
| 241 | bool SymbolizeData(uptr addr, DataInfo *info) override { |
| 242 | return false; |
| 243 | } |
| 244 | |
| 245 | private: |
| 246 | const char *SendCommand(const char *module_name, uptr module_offset) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 247 | Addr2LineProcess *addr2line = 0; |
| 248 | for (uptr i = 0; i < addr2line_pool_.size(); ++i) { |
| 249 | if (0 == |
| 250 | internal_strcmp(module_name, addr2line_pool_[i]->module_name())) { |
| 251 | addr2line = addr2line_pool_[i]; |
| 252 | break; |
| 253 | } |
| 254 | } |
| 255 | if (!addr2line) { |
| 256 | addr2line = |
| 257 | new(*allocator_) Addr2LineProcess(addr2line_path_, module_name); |
| 258 | addr2line_pool_.push_back(addr2line); |
| 259 | } |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 260 | CHECK_EQ(0, internal_strcmp(module_name, addr2line->module_name())); |
| 261 | char buffer_[kBufferSize]; |
| 262 | internal_snprintf(buffer_, kBufferSize, "0x%zx\n", module_offset); |
| 263 | return addr2line->SendCommand(buffer_); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 264 | } |
| 265 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 266 | static const uptr kBufferSize = 32; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 267 | const char *addr2line_path_; |
| 268 | LowLevelAllocator *allocator_; |
| 269 | InternalMmapVector<Addr2LineProcess*> addr2line_pool_; |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 270 | }; |
| 271 | |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 272 | #if SANITIZER_SUPPORTS_WEAK_HOOKS |
| 273 | extern "C" { |
| 274 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE |
| 275 | bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset, |
| 276 | char *Buffer, int MaxLength); |
| 277 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE |
| 278 | bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset, |
| 279 | char *Buffer, int MaxLength); |
| 280 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE |
| 281 | void __sanitizer_symbolize_flush(); |
| 282 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE |
| 283 | int __sanitizer_symbolize_demangle(const char *Name, char *Buffer, |
| 284 | int MaxLength); |
| 285 | } // extern "C" |
| 286 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 287 | class InternalSymbolizer : public SymbolizerTool { |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 288 | public: |
Peter Collingbourne | c1a1ed6 | 2013-10-25 23:03:29 +0000 | [diff] [blame] | 289 | static InternalSymbolizer *get(LowLevelAllocator *alloc) { |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 290 | if (__sanitizer_symbolize_code != 0 && |
| 291 | __sanitizer_symbolize_data != 0) { |
Peter Collingbourne | c1a1ed6 | 2013-10-25 23:03:29 +0000 | [diff] [blame] | 292 | return new(*alloc) InternalSymbolizer(); |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 293 | } |
| 294 | return 0; |
| 295 | } |
| 296 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 297 | bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { |
| 298 | bool result = __sanitizer_symbolize_code( |
| 299 | stack->info.module, stack->info.module_offset, buffer_, kBufferSize); |
| 300 | if (result) ParseSymbolizePCOutput(buffer_, stack); |
| 301 | return result; |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 302 | } |
| 303 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 304 | bool SymbolizeData(uptr addr, DataInfo *info) override { |
| 305 | bool result = __sanitizer_symbolize_data(info->module, info->module_offset, |
| 306 | buffer_, kBufferSize); |
| 307 | if (result) { |
| 308 | ParseSymbolizeDataOutput(buffer_, info); |
| 309 | info->start += (addr - info->module_offset); // Add the base address. |
| 310 | } |
| 311 | return result; |
| 312 | } |
| 313 | |
| 314 | void Flush() override { |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 315 | if (__sanitizer_symbolize_flush) |
| 316 | __sanitizer_symbolize_flush(); |
| 317 | } |
| 318 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 319 | const char *Demangle(const char *name) override { |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 320 | if (__sanitizer_symbolize_demangle) { |
| 321 | for (uptr res_length = 1024; |
| 322 | res_length <= InternalSizeClassMap::kMaxSize;) { |
| 323 | char *res_buff = static_cast<char*>(InternalAlloc(res_length)); |
| 324 | uptr req_length = |
| 325 | __sanitizer_symbolize_demangle(name, res_buff, res_length); |
| 326 | if (req_length > res_length) { |
| 327 | res_length = req_length + 1; |
| 328 | InternalFree(res_buff); |
| 329 | continue; |
| 330 | } |
| 331 | return res_buff; |
| 332 | } |
| 333 | } |
| 334 | return name; |
| 335 | } |
| 336 | |
| 337 | private: |
| 338 | InternalSymbolizer() { } |
| 339 | |
| 340 | static const int kBufferSize = 16 * 1024; |
| 341 | static const int kMaxDemangledNameSize = 1024; |
| 342 | char buffer_[kBufferSize]; |
| 343 | }; |
| 344 | #else // SANITIZER_SUPPORTS_WEAK_HOOKS |
| 345 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 346 | class InternalSymbolizer : public SymbolizerTool { |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 347 | public: |
Peter Collingbourne | c1a1ed6 | 2013-10-25 23:03:29 +0000 | [diff] [blame] | 348 | static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; } |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 349 | }; |
| 350 | |
| 351 | #endif // SANITIZER_SUPPORTS_WEAK_HOOKS |
| 352 | |
Pirama Arumuga Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 353 | const char *Symbolizer::PlatformDemangle(const char *name) { |
| 354 | return DemangleCXXABI(name); |
| 355 | } |
Peter Collingbourne | c1a1ed6 | 2013-10-25 23:03:29 +0000 | [diff] [blame] | 356 | |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 357 | void Symbolizer::PlatformPrepareForSandboxing() {} |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 358 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 359 | static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) { |
| 360 | const char *path = common_flags()->external_symbolizer_path; |
| 361 | const char *binary_name = path ? StripModuleName(path) : ""; |
| 362 | if (path && path[0] == '\0') { |
| 363 | VReport(2, "External symbolizer is explicitly disabled.\n"); |
| 364 | return nullptr; |
| 365 | } else if (!internal_strcmp(binary_name, "llvm-symbolizer")) { |
| 366 | VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path); |
| 367 | return new(*allocator) LLVMSymbolizer(path, allocator); |
| 368 | } else if (!internal_strcmp(binary_name, "atos")) { |
| 369 | #if SANITIZER_MAC |
| 370 | VReport(2, "Using atos at user-specified path: %s\n", path); |
| 371 | return new(*allocator) AtosSymbolizer(path, allocator); |
| 372 | #else // SANITIZER_MAC |
| 373 | Report("ERROR: Using `atos` is only supported on Darwin.\n"); |
| 374 | Die(); |
| 375 | #endif // SANITIZER_MAC |
| 376 | } else if (!internal_strcmp(binary_name, "addr2line")) { |
| 377 | VReport(2, "Using addr2line at user-specified path: %s\n", path); |
| 378 | return new(*allocator) Addr2LinePool(path, allocator); |
| 379 | } else if (path) { |
| 380 | Report("ERROR: External symbolizer path is set to '%s' which isn't " |
| 381 | "a known symbolizer. Please set the path to the llvm-symbolizer " |
| 382 | "binary or other known tool.\n", path); |
| 383 | Die(); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 384 | } |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 385 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 386 | // Otherwise symbolizer program is unknown, let's search $PATH |
| 387 | CHECK(path == nullptr); |
| 388 | if (const char *found_path = FindPathToBinary("llvm-symbolizer")) { |
| 389 | VReport(2, "Using llvm-symbolizer found at: %s\n", found_path); |
| 390 | return new(*allocator) LLVMSymbolizer(found_path, allocator); |
| 391 | } |
| 392 | #if SANITIZER_MAC |
| 393 | if (const char *found_path = FindPathToBinary("atos")) { |
| 394 | VReport(2, "Using atos found at: %s\n", found_path); |
| 395 | return new(*allocator) AtosSymbolizer(found_path, allocator); |
| 396 | } |
| 397 | #endif // SANITIZER_MAC |
| 398 | if (common_flags()->allow_addr2line) { |
| 399 | if (const char *found_path = FindPathToBinary("addr2line")) { |
| 400 | VReport(2, "Using addr2line found at: %s\n", found_path); |
| 401 | return new(*allocator) Addr2LinePool(found_path, allocator); |
Alexey Samsonov | e059bd3 | 2013-09-10 16:16:27 +0000 | [diff] [blame] | 402 | } |
| 403 | } |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 404 | return nullptr; |
| 405 | } |
Peter Collingbourne | c1a1ed6 | 2013-10-25 23:03:29 +0000 | [diff] [blame] | 406 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 407 | static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list, |
| 408 | LowLevelAllocator *allocator) { |
| 409 | if (!common_flags()->symbolize) { |
| 410 | VReport(2, "Symbolizer is disabled.\n"); |
| 411 | return; |
| 412 | } |
| 413 | if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) { |
| 414 | VReport(2, "Using internal symbolizer.\n"); |
| 415 | list->push_back(tool); |
| 416 | return; |
| 417 | } |
| 418 | if (SymbolizerTool *tool = LibbacktraceSymbolizer::get(allocator)) { |
| 419 | VReport(2, "Using libbacktrace symbolizer.\n"); |
| 420 | list->push_back(tool); |
| 421 | return; |
| 422 | } |
| 423 | |
| 424 | if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) { |
| 425 | list->push_back(tool); |
| 426 | } else { |
| 427 | VReport(2, "No internal or external symbolizer found.\n"); |
| 428 | } |
| 429 | |
| 430 | #if SANITIZER_MAC |
| 431 | VReport(2, "Using dladdr symbolizer.\n"); |
| 432 | list->push_back(new(*allocator) DlAddrSymbolizer()); |
| 433 | #endif // SANITIZER_MAC |
| 434 | } |
| 435 | |
| 436 | Symbolizer *Symbolizer::PlatformInit() { |
| 437 | IntrusiveList<SymbolizerTool> list; |
| 438 | list.clear(); |
| 439 | ChooseSymbolizerTools(&list, &symbolizer_allocator_); |
Pirama Arumuga Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 440 | return new(symbolizer_allocator_) Symbolizer(list); |
Alexey Samsonov | 7847d77 | 2013-09-10 14:36:16 +0000 | [diff] [blame] | 441 | } |
Alexey Samsonov | ff0ce7f | 2013-06-11 08:14:24 +0000 | [diff] [blame] | 442 | |
| 443 | } // namespace __sanitizer |
| 444 | |
| 445 | #endif // SANITIZER_POSIX |