1 //===-- sanitizer_symbolizer_mac.cc ---------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is shared between various sanitizers' runtime libraries.
12 // Implementation of Mac-specific "atos" symbolizer.
13 //===----------------------------------------------------------------------===//
15 #include "sanitizer_platform.h"
18 #include "sanitizer_allocator_internal.h"
19 #include "sanitizer_mac.h"
20 #include "sanitizer_symbolizer_mac.h"
22 namespace __sanitizer {
31 bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
33 int result = dladdr((const void *)addr, &info);
34 if (!result) return false;
35 const char *demangled = DemangleCXXABI(info.dli_sname);
36 stack->info.function = demangled ? internal_strdup(demangled) : nullptr;
40 bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) {
42 int result = dladdr((const void *)addr, &info);
43 if (!result) return false;
44 const char *demangled = DemangleCXXABI(info.dli_sname);
45 datainfo->name = internal_strdup(demangled);
46 datainfo->start = (uptr)info.dli_saddr;
50 class AtosSymbolizerProcess : public SymbolizerProcess {
52 explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid)
53 : SymbolizerProcess(path, /*use_forkpty*/ true) {
54 // Put the string command line argument in the object so that it outlives
55 // the call to GetArgV.
56 internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid);
60 bool ReachedEndOfOutput(const char *buffer, uptr length) const override {
61 return (length >= 1 && buffer[length - 1] == '\n');
64 void GetArgV(const char *path_to_binary,
65 const char *(&argv)[kArgVMax]) const override {
67 argv[i++] = path_to_binary;
69 argv[i++] = &pid_str_[0];
70 if (GetMacosVersion() == MACOS_VERSION_MAVERICKS) {
71 // On Mavericks atos prints a deprecation warning which we suppress by
72 // passing -d. The warning isn't present on other OSX versions, even the
82 static const char *kAtosErrorMessages[] = {
83 "atos cannot examine process",
84 "unable to get permission to examine process",
85 "An admin user name and password is required",
86 "could not load inserted library",
87 "architecture mismatch between analysis process",
90 static bool IsAtosErrorMessage(const char *str) {
91 for (uptr i = 0; i < ARRAY_SIZE(kAtosErrorMessages); i++) {
92 if (internal_strstr(str, kAtosErrorMessages[i])) {
99 static bool ParseCommandOutput(const char *str, uptr addr, char **out_name,
100 char **out_module, char **out_file, uptr *line,
101 uptr *start_address) {
102 // Trim ending newlines.
104 ExtractTokenUpToDelimiter(str, "\n", &trim);
106 // The line from `atos` is in one of these formats:
107 // myfunction (in library.dylib) (sourcefile.c:17)
108 // myfunction (in library.dylib) + 0x1fe
109 // myfunction (in library.dylib) + 15
110 // 0xdeadbeef (in library.dylib) + 0x1fe
111 // 0xdeadbeef (in library.dylib) + 15
112 // 0xdeadbeef (in library.dylib)
115 if (IsAtosErrorMessage(trim)) {
116 Report("atos returned an error: %s\n", trim);
121 const char *rest = trim;
123 rest = ExtractTokenUpToDelimiter(rest, " (in ", &symbol_name);
124 if (rest[0] == '\0') {
125 InternalFree(symbol_name);
130 if (internal_strncmp(symbol_name, "0x", 2) != 0)
131 *out_name = symbol_name;
133 InternalFree(symbol_name);
134 rest = ExtractTokenUpToDelimiter(rest, ") ", out_module);
136 if (rest[0] == '(') {
139 rest = ExtractTokenUpToDelimiter(rest, ":", out_file);
140 char *extracted_line_number;
141 rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number);
142 if (line) *line = (uptr)internal_atoll(extracted_line_number);
143 InternalFree(extracted_line_number);
145 } else if (rest[0] == '+') {
147 uptr offset = internal_atoll(rest);
148 if (start_address) *start_address = addr - offset;
155 AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator)
156 : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {}
158 bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
159 if (!process_) return false;
161 internal_snprintf(command, sizeof(command), "0x%zx\n", addr);
162 const char *buf = process_->SendCommand(command);
163 if (!buf) return false;
165 if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module,
166 &stack->info.file, &line, nullptr)) {
170 stack->info.line = (int)line;
174 bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
175 if (!process_) return false;
177 internal_snprintf(command, sizeof(command), "0x%zx\n", addr);
178 const char *buf = process_->SendCommand(command);
179 if (!buf) return false;
180 if (!ParseCommandOutput(buf, addr, &info->name, &info->module, nullptr,
181 nullptr, &info->start)) {
188 } // namespace __sanitizer
190 #endif // SANITIZER_MAC