Peter Collingbourne | c1a1ed6 | 2013-10-25 23:03:29 +0000 | [diff] [blame] | 1 | //===-- sanitizer_symbolizer_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 | //===----------------------------------------------------------------------===// |
| 13 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 14 | #include "sanitizer_allocator_internal.h" |
Peter Collingbourne | c1a1ed6 | 2013-10-25 23:03:29 +0000 | [diff] [blame] | 15 | #include "sanitizer_internal_defs.h" |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 16 | #include "sanitizer_symbolizer_internal.h" |
Peter Collingbourne | c1a1ed6 | 2013-10-25 23:03:29 +0000 | [diff] [blame] | 17 | |
| 18 | namespace __sanitizer { |
| 19 | |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 20 | const char *ExtractToken(const char *str, const char *delims, char **result) { |
| 21 | uptr prefix_len = internal_strcspn(str, delims); |
| 22 | *result = (char*)InternalAlloc(prefix_len + 1); |
| 23 | internal_memcpy(*result, str, prefix_len); |
| 24 | (*result)[prefix_len] = '\0'; |
| 25 | const char *prefix_end = str + prefix_len; |
| 26 | if (*prefix_end != '\0') prefix_end++; |
| 27 | return prefix_end; |
| 28 | } |
| 29 | |
| 30 | const char *ExtractInt(const char *str, const char *delims, int *result) { |
| 31 | char *buff; |
| 32 | const char *ret = ExtractToken(str, delims, &buff); |
| 33 | if (buff != 0) { |
| 34 | *result = (int)internal_atoll(buff); |
| 35 | } |
| 36 | InternalFree(buff); |
| 37 | return ret; |
| 38 | } |
| 39 | |
| 40 | const char *ExtractUptr(const char *str, const char *delims, uptr *result) { |
| 41 | char *buff; |
| 42 | const char *ret = ExtractToken(str, delims, &buff); |
| 43 | if (buff != 0) { |
| 44 | *result = (uptr)internal_atoll(buff); |
| 45 | } |
| 46 | InternalFree(buff); |
| 47 | return ret; |
| 48 | } |
| 49 | |
| 50 | const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter, |
| 51 | char **result) { |
| 52 | const char *found_delimiter = internal_strstr(str, delimiter); |
| 53 | uptr prefix_len = |
| 54 | found_delimiter ? found_delimiter - str : internal_strlen(str); |
| 55 | *result = (char *)InternalAlloc(prefix_len + 1); |
| 56 | internal_memcpy(*result, str, prefix_len); |
| 57 | (*result)[prefix_len] = '\0'; |
| 58 | const char *prefix_end = str + prefix_len; |
| 59 | if (*prefix_end != '\0') prefix_end += internal_strlen(delimiter); |
| 60 | return prefix_end; |
| 61 | } |
| 62 | |
Pirama Arumuga Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 63 | SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { |
| 64 | BlockingMutexLock l(&mu_); |
| 65 | const char *module_name; |
| 66 | uptr module_offset; |
| 67 | SymbolizedStack *res = SymbolizedStack::New(addr); |
| 68 | if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset)) |
| 69 | return res; |
| 70 | // Always fill data about module name and offset. |
| 71 | res->info.FillModuleInfo(module_name, module_offset); |
| 72 | for (auto iter = Iterator(&tools_); iter.hasNext();) { |
| 73 | auto *tool = iter.next(); |
| 74 | SymbolizerScope sym_scope(this); |
| 75 | if (tool->SymbolizePC(addr, res)) { |
| 76 | return res; |
| 77 | } |
| 78 | } |
| 79 | return res; |
| 80 | } |
| 81 | |
| 82 | bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { |
| 83 | BlockingMutexLock l(&mu_); |
| 84 | const char *module_name; |
| 85 | uptr module_offset; |
| 86 | if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset)) |
| 87 | return false; |
| 88 | info->Clear(); |
| 89 | info->module = internal_strdup(module_name); |
| 90 | info->module_offset = module_offset; |
| 91 | for (auto iter = Iterator(&tools_); iter.hasNext();) { |
| 92 | auto *tool = iter.next(); |
| 93 | SymbolizerScope sym_scope(this); |
| 94 | if (tool->SymbolizeData(addr, info)) { |
| 95 | return true; |
| 96 | } |
| 97 | } |
| 98 | return true; |
| 99 | } |
| 100 | |
| 101 | bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, |
| 102 | uptr *module_address) { |
| 103 | BlockingMutexLock l(&mu_); |
| 104 | const char *internal_module_name = nullptr; |
| 105 | if (!FindModuleNameAndOffsetForAddress(pc, &internal_module_name, |
| 106 | module_address)) |
| 107 | return false; |
| 108 | |
| 109 | if (module_name) |
| 110 | *module_name = module_names_.GetOwnedCopy(internal_module_name); |
| 111 | return true; |
| 112 | } |
| 113 | |
| 114 | void Symbolizer::Flush() { |
| 115 | BlockingMutexLock l(&mu_); |
| 116 | for (auto iter = Iterator(&tools_); iter.hasNext();) { |
| 117 | auto *tool = iter.next(); |
| 118 | SymbolizerScope sym_scope(this); |
| 119 | tool->Flush(); |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | const char *Symbolizer::Demangle(const char *name) { |
| 124 | BlockingMutexLock l(&mu_); |
| 125 | for (auto iter = Iterator(&tools_); iter.hasNext();) { |
| 126 | auto *tool = iter.next(); |
| 127 | SymbolizerScope sym_scope(this); |
| 128 | if (const char *demangled = tool->Demangle(name)) |
| 129 | return demangled; |
| 130 | } |
| 131 | return PlatformDemangle(name); |
| 132 | } |
| 133 | |
| 134 | void Symbolizer::PrepareForSandboxing() { |
| 135 | BlockingMutexLock l(&mu_); |
| 136 | PlatformPrepareForSandboxing(); |
| 137 | } |
| 138 | |
| 139 | bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, |
| 140 | const char **module_name, |
| 141 | uptr *module_offset) { |
| 142 | LoadedModule *module = FindModuleForAddress(address); |
| 143 | if (module == 0) |
| 144 | return false; |
| 145 | *module_name = module->full_name(); |
| 146 | *module_offset = address - module->base_address(); |
| 147 | return true; |
| 148 | } |
| 149 | |
| 150 | LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { |
| 151 | bool modules_were_reloaded = false; |
| 152 | if (!modules_fresh_) { |
| 153 | for (uptr i = 0; i < n_modules_; i++) |
| 154 | modules_[i].clear(); |
| 155 | n_modules_ = |
| 156 | GetListOfModules(modules_, kMaxNumberOfModules, /* filter */ nullptr); |
| 157 | CHECK_GT(n_modules_, 0); |
| 158 | CHECK_LT(n_modules_, kMaxNumberOfModules); |
| 159 | modules_fresh_ = true; |
| 160 | modules_were_reloaded = true; |
| 161 | } |
| 162 | for (uptr i = 0; i < n_modules_; i++) { |
| 163 | if (modules_[i].containsAddress(address)) { |
| 164 | return &modules_[i]; |
| 165 | } |
| 166 | } |
| 167 | // Reload the modules and look up again, if we haven't tried it yet. |
| 168 | if (!modules_were_reloaded) { |
| 169 | // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors. |
| 170 | // It's too aggressive to reload the list of modules each time we fail |
| 171 | // to find a module for a given address. |
| 172 | modules_fresh_ = false; |
| 173 | return FindModuleForAddress(address); |
| 174 | } |
| 175 | return 0; |
| 176 | } |
| 177 | |
Peter Collingbourne | c1a1ed6 | 2013-10-25 23:03:29 +0000 | [diff] [blame] | 178 | Symbolizer *Symbolizer::GetOrInit() { |
Alexey Samsonov | e00495a | 2013-10-30 17:05:37 +0000 | [diff] [blame] | 179 | SpinMutexLock l(&init_mu_); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 180 | if (symbolizer_) |
| 181 | return symbolizer_; |
Pirama Arumuga Nainar | 7c91505 | 2015-04-08 08:58:29 -0700 | [diff] [blame] | 182 | symbolizer_ = PlatformInit(); |
| 183 | CHECK(symbolizer_); |
| 184 | return symbolizer_; |
Peter Collingbourne | c1a1ed6 | 2013-10-25 23:03:29 +0000 | [diff] [blame] | 185 | } |
| 186 | |
| 187 | } // namespace __sanitizer |