sanitizer_symbolizer_mac.cc revision 1.5
1//===-- sanitizer_symbolizer_mac.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 various sanitizers' runtime libraries. 9// 10// Implementation of Mac-specific "atos" symbolizer. 11//===----------------------------------------------------------------------===// 12 13#include "sanitizer_platform.h" 14#if SANITIZER_MAC 15 16#include "sanitizer_allocator_internal.h" 17#include "sanitizer_mac.h" 18#include "sanitizer_symbolizer_mac.h" 19 20#include <dlfcn.h> 21#include <errno.h> 22#include <stdlib.h> 23#include <sys/wait.h> 24#include <unistd.h> 25#include <util.h> 26 27namespace __sanitizer { 28 29bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { 30 Dl_info info; 31 int result = dladdr((const void *)addr, &info); 32 if (!result) return false; 33 const char *demangled = DemangleSwiftAndCXX(info.dli_sname); 34 if (!demangled) return false; 35 stack->info.function = internal_strdup(demangled); 36 return true; 37} 38 39bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) { 40 Dl_info info; 41 int result = dladdr((const void *)addr, &info); 42 if (!result) return false; 43 const char *demangled = DemangleSwiftAndCXX(info.dli_sname); 44 datainfo->name = internal_strdup(demangled); 45 datainfo->start = (uptr)info.dli_saddr; 46 return true; 47} 48 49class AtosSymbolizerProcess : public SymbolizerProcess { 50 public: 51 explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid) 52 : SymbolizerProcess(path, /*use_forkpty*/ true) { 53 // Put the string command line argument in the object so that it outlives 54 // the call to GetArgV. 55 internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid); 56 } 57 58 private: 59 bool ReachedEndOfOutput(const char *buffer, uptr length) const override { 60 return (length >= 1 && buffer[length - 1] == '\n'); 61 } 62 63 void GetArgV(const char *path_to_binary, 64 const char *(&argv)[kArgVMax]) const override { 65 int i = 0; 66 argv[i++] = path_to_binary; 67 argv[i++] = "-p"; 68 argv[i++] = &pid_str_[0]; 69 if (GetMacosVersion() == MACOS_VERSION_MAVERICKS) { 70 // On Mavericks atos prints a deprecation warning which we suppress by 71 // passing -d. The warning isn't present on other OSX versions, even the 72 // newer ones. 73 argv[i++] = "-d"; 74 } 75 argv[i++] = nullptr; 76 } 77 78 char pid_str_[16]; 79}; 80 81static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, 82 char **out_module, char **out_file, uptr *line, 83 uptr *start_address) { 84 // Trim ending newlines. 85 char *trim; 86 ExtractTokenUpToDelimiter(str, "\n", &trim); 87 88 // The line from `atos` is in one of these formats: 89 // myfunction (in library.dylib) (sourcefile.c:17) 90 // myfunction (in library.dylib) + 0x1fe 91 // myfunction (in library.dylib) + 15 92 // 0xdeadbeef (in library.dylib) + 0x1fe 93 // 0xdeadbeef (in library.dylib) + 15 94 // 0xdeadbeef (in library.dylib) 95 // 0xdeadbeef 96 97 const char *rest = trim; 98 char *symbol_name; 99 rest = ExtractTokenUpToDelimiter(rest, " (in ", &symbol_name); 100 if (rest[0] == '\0') { 101 InternalFree(symbol_name); 102 InternalFree(trim); 103 return false; 104 } 105 106 if (internal_strncmp(symbol_name, "0x", 2) != 0) 107 *out_name = symbol_name; 108 else 109 InternalFree(symbol_name); 110 rest = ExtractTokenUpToDelimiter(rest, ") ", out_module); 111 112 if (rest[0] == '(') { 113 if (out_file) { 114 rest++; 115 rest = ExtractTokenUpToDelimiter(rest, ":", out_file); 116 char *extracted_line_number; 117 rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number); 118 if (line) *line = (uptr)internal_atoll(extracted_line_number); 119 InternalFree(extracted_line_number); 120 } 121 } else if (rest[0] == '+') { 122 rest += 2; 123 uptr offset = internal_atoll(rest); 124 if (start_address) *start_address = addr - offset; 125 } 126 127 InternalFree(trim); 128 return true; 129} 130 131AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator) 132 : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {} 133 134bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { 135 if (!process_) return false; 136 if (addr == 0) return false; 137 char command[32]; 138 internal_snprintf(command, sizeof(command), "0x%zx\n", addr); 139 const char *buf = process_->SendCommand(command); 140 if (!buf) return false; 141 uptr line; 142 if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module, 143 &stack->info.file, &line, nullptr)) { 144 process_ = nullptr; 145 return false; 146 } 147 stack->info.line = (int)line; 148 return true; 149} 150 151bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { 152 if (!process_) return false; 153 char command[32]; 154 internal_snprintf(command, sizeof(command), "0x%zx\n", addr); 155 const char *buf = process_->SendCommand(command); 156 if (!buf) return false; 157 if (!ParseCommandOutput(buf, addr, &info->name, &info->module, nullptr, 158 nullptr, &info->start)) { 159 process_ = nullptr; 160 return false; 161 } 162 return true; 163} 164 165} // namespace __sanitizer 166 167#endif // SANITIZER_MAC 168