blob: c2397ef98a544cbf93241d6433c0826327da3c4d [file] [log] [blame]
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -07001//===-- sanitizer_symbolizer_mac.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 various sanitizers' runtime libraries.
11//
12// Implementation of Mac-specific "atos" symbolizer.
13//===----------------------------------------------------------------------===//
14
15#include "sanitizer_platform.h"
16#if SANITIZER_MAC
17
18#include "sanitizer_allocator_internal.h"
19#include "sanitizer_mac.h"
20#include "sanitizer_symbolizer_mac.h"
21
22namespace __sanitizer {
23
24#include <dlfcn.h>
25#include <errno.h>
26#include <stdlib.h>
27#include <sys/wait.h>
28#include <unistd.h>
29#include <util.h>
30
31bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
32 Dl_info info;
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 = internal_strdup(demangled);
37 return true;
38}
39
40bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
41 return false;
42}
43
44class AtosSymbolizerProcess : public SymbolizerProcess {
45 public:
46 explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid)
47 : SymbolizerProcess(path, /*use_forkpty*/ true),
48 parent_pid_(parent_pid) {}
49
50 private:
51 bool ReachedEndOfOutput(const char *buffer, uptr length) const override {
52 return (length >= 1 && buffer[length - 1] == '\n');
53 }
54
55 void ExecuteWithDefaultArgs(const char *path_to_binary) const override {
56 // The `atos` binary has some issues with DYLD_ROOT_PATH on i386.
57 unsetenv("DYLD_ROOT_PATH");
58
59 char pid_str[16];
60 internal_snprintf(pid_str, sizeof(pid_str), "%d", parent_pid_);
61 if (GetMacosVersion() == MACOS_VERSION_MAVERICKS) {
62 // On Mavericks atos prints a deprecation warning which we suppress by
63 // passing -d. The warning isn't present on other OSX versions, even the
64 // newer ones.
65 execl(path_to_binary, path_to_binary, "-p", pid_str, "-d", (char *)0);
66 } else {
67 execl(path_to_binary, path_to_binary, "-p", pid_str, (char *)0);
68 }
69 }
70
71 pid_t parent_pid_;
72};
73
74static const char *kAtosErrorMessages[] = {
75 "atos cannot examine process",
76 "unable to get permission to examine process",
77 "An admin user name and password is required",
78 "could not load inserted library",
79 "architecture mismatch between analysis process",
80};
81
82static bool IsAtosErrorMessage(const char *str) {
83 for (uptr i = 0; i < ARRAY_SIZE(kAtosErrorMessages); i++) {
84 if (internal_strstr(str, kAtosErrorMessages[i])) {
85 return true;
86 }
87 }
88 return false;
89}
90
91static bool ParseCommandOutput(const char *str, SymbolizedStack *res) {
92 // Trim ending newlines.
93 char *trim;
94 ExtractTokenUpToDelimiter(str, "\n", &trim);
95
96 // The line from `atos` is in one of these formats:
97 // myfunction (in library.dylib) (sourcefile.c:17)
98 // myfunction (in library.dylib) + 0x1fe
99 // 0xdeadbeef (in library.dylib) + 0x1fe
100 // 0xdeadbeef (in library.dylib)
101 // 0xdeadbeef
102
103 if (IsAtosErrorMessage(trim)) {
104 Report("atos returned an error: %s\n", trim);
105 InternalFree(trim);
106 return false;
107 }
108
109 const char *rest = trim;
110 char *function_name;
111 rest = ExtractTokenUpToDelimiter(rest, " (in ", &function_name);
112 if (internal_strncmp(function_name, "0x", 2) != 0)
113 res->info.function = function_name;
114 else
115 InternalFree(function_name);
116 rest = ExtractTokenUpToDelimiter(rest, ") ", &res->info.module);
117
118 if (rest[0] == '(') {
119 rest++;
120 rest = ExtractTokenUpToDelimiter(rest, ":", &res->info.file);
121 char *extracted_line_number;
122 rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number);
123 res->info.line = internal_atoll(extracted_line_number);
124 InternalFree(extracted_line_number);
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 char command[32];
137 internal_snprintf(command, sizeof(command), "0x%zx\n", addr);
138 const char *buf = process_->SendCommand(command);
139 if (!buf) return false;
140 if (!ParseCommandOutput(buf, stack)) {
141 process_ = nullptr;
142 return false;
143 }
144 return true;
145}
146
147bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { return false; }
148
149} // namespace __sanitizer
150
151#endif // SANITIZER_MAC