]> git.proxmox.com Git - rustc.git/blob - src/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cc
Imported Upstream version 1.6.0+dfsg1
[rustc.git] / src / compiler-rt / lib / sanitizer_common / sanitizer_symbolizer_mac.cc
1 //===-- 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
22 namespace __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
31 bool 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
40 bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
41 return false;
42 }
43
44 class AtosSymbolizerProcess : public SymbolizerProcess {
45 public:
46 explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid)
47 : SymbolizerProcess(path, /*use_forkpty*/ true) {
48 // Put the string command line argument in the object so that it outlives
49 // the call to GetArgV.
50 internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid);
51 }
52
53 private:
54 bool ReachedEndOfOutput(const char *buffer, uptr length) const override {
55 return (length >= 1 && buffer[length - 1] == '\n');
56 }
57
58 void GetArgV(const char *path_to_binary,
59 const char *(&argv)[kArgVMax]) const override {
60 int i = 0;
61 argv[i++] = path_to_binary;
62 argv[i++] = "-p";
63 argv[i++] = &pid_str_[0];
64 if (GetMacosVersion() == MACOS_VERSION_MAVERICKS) {
65 // On Mavericks atos prints a deprecation warning which we suppress by
66 // passing -d. The warning isn't present on other OSX versions, even the
67 // newer ones.
68 argv[i++] = "-d";
69 }
70 argv[i++] = nullptr;
71 }
72
73 char pid_str_[16];
74 };
75
76 static const char *kAtosErrorMessages[] = {
77 "atos cannot examine process",
78 "unable to get permission to examine process",
79 "An admin user name and password is required",
80 "could not load inserted library",
81 "architecture mismatch between analysis process",
82 };
83
84 static bool IsAtosErrorMessage(const char *str) {
85 for (uptr i = 0; i < ARRAY_SIZE(kAtosErrorMessages); i++) {
86 if (internal_strstr(str, kAtosErrorMessages[i])) {
87 return true;
88 }
89 }
90 return false;
91 }
92
93 static bool ParseCommandOutput(const char *str, SymbolizedStack *res) {
94 // Trim ending newlines.
95 char *trim;
96 ExtractTokenUpToDelimiter(str, "\n", &trim);
97
98 // The line from `atos` is in one of these formats:
99 // myfunction (in library.dylib) (sourcefile.c:17)
100 // myfunction (in library.dylib) + 0x1fe
101 // 0xdeadbeef (in library.dylib) + 0x1fe
102 // 0xdeadbeef (in library.dylib)
103 // 0xdeadbeef
104
105 if (IsAtosErrorMessage(trim)) {
106 Report("atos returned an error: %s\n", trim);
107 InternalFree(trim);
108 return false;
109 }
110
111 const char *rest = trim;
112 char *function_name;
113 rest = ExtractTokenUpToDelimiter(rest, " (in ", &function_name);
114 if (internal_strncmp(function_name, "0x", 2) != 0)
115 res->info.function = function_name;
116 else
117 InternalFree(function_name);
118 rest = ExtractTokenUpToDelimiter(rest, ") ", &res->info.module);
119
120 if (rest[0] == '(') {
121 rest++;
122 rest = ExtractTokenUpToDelimiter(rest, ":", &res->info.file);
123 char *extracted_line_number;
124 rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number);
125 res->info.line = internal_atoll(extracted_line_number);
126 InternalFree(extracted_line_number);
127 }
128
129 InternalFree(trim);
130 return true;
131 }
132
133 AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator)
134 : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {}
135
136 bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
137 if (!process_) return false;
138 char command[32];
139 internal_snprintf(command, sizeof(command), "0x%zx\n", addr);
140 const char *buf = process_->SendCommand(command);
141 if (!buf) return false;
142 if (!ParseCommandOutput(buf, stack)) {
143 process_ = nullptr;
144 return false;
145 }
146 return true;
147 }
148
149 bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { return false; }
150
151 } // namespace __sanitizer
152
153 #endif // SANITIZER_MAC