Mercurial > hg > CbC > CbC_gcc
comparison libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
131:84e7813d76e9 | 145:1830386684a0 |
---|---|
1 //===-- sanitizer_symbolizer_mac.cpp --------------------------------------===// | |
2 // | |
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
4 // See https://llvm.org/LICENSE.txt for license information. | |
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
6 // | |
7 //===----------------------------------------------------------------------===// | |
8 // | |
9 // This file is shared between various sanitizers' runtime libraries. | |
10 // | |
11 // Implementation of Mac-specific "atos" symbolizer. | |
12 //===----------------------------------------------------------------------===// | |
13 | |
14 #include "sanitizer_platform.h" | |
15 #if SANITIZER_MAC | |
16 | |
17 #include "sanitizer_allocator_internal.h" | |
18 #include "sanitizer_mac.h" | |
19 #include "sanitizer_symbolizer_mac.h" | |
20 | |
21 #include <dlfcn.h> | |
22 #include <errno.h> | |
23 #include <stdlib.h> | |
24 #include <sys/wait.h> | |
25 #include <unistd.h> | |
26 #include <util.h> | |
27 | |
28 namespace __sanitizer { | |
29 | |
30 bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { | |
31 Dl_info info; | |
32 int result = dladdr((const void *)addr, &info); | |
33 if (!result) return false; | |
34 const char *demangled = DemangleSwiftAndCXX(info.dli_sname); | |
35 if (!demangled) return false; | |
36 stack->info.function = internal_strdup(demangled); | |
37 return true; | |
38 } | |
39 | |
40 bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) { | |
41 Dl_info info; | |
42 int result = dladdr((const void *)addr, &info); | |
43 if (!result) return false; | |
44 const char *demangled = DemangleSwiftAndCXX(info.dli_sname); | |
45 datainfo->name = internal_strdup(demangled); | |
46 datainfo->start = (uptr)info.dli_saddr; | |
47 return true; | |
48 } | |
49 | |
50 class AtosSymbolizerProcess : public SymbolizerProcess { | |
51 public: | |
52 explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid) | |
53 : SymbolizerProcess(path, /*use_posix_spawn*/ 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); | |
57 } | |
58 | |
59 private: | |
60 bool StartSymbolizerSubprocess() override { | |
61 // Configure sandbox before starting atos process. | |
62 return SymbolizerProcess::StartSymbolizerSubprocess(); | |
63 } | |
64 | |
65 bool ReachedEndOfOutput(const char *buffer, uptr length) const override { | |
66 return (length >= 1 && buffer[length - 1] == '\n'); | |
67 } | |
68 | |
69 void GetArgV(const char *path_to_binary, | |
70 const char *(&argv)[kArgVMax]) const override { | |
71 int i = 0; | |
72 argv[i++] = path_to_binary; | |
73 argv[i++] = "-p"; | |
74 argv[i++] = &pid_str_[0]; | |
75 if (GetMacosVersion() == MACOS_VERSION_MAVERICKS) { | |
76 // On Mavericks atos prints a deprecation warning which we suppress by | |
77 // passing -d. The warning isn't present on other OSX versions, even the | |
78 // newer ones. | |
79 argv[i++] = "-d"; | |
80 } | |
81 argv[i++] = nullptr; | |
82 } | |
83 | |
84 char pid_str_[16]; | |
85 }; | |
86 | |
87 static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, | |
88 char **out_module, char **out_file, uptr *line, | |
89 uptr *start_address) { | |
90 // Trim ending newlines. | |
91 char *trim; | |
92 ExtractTokenUpToDelimiter(str, "\n", &trim); | |
93 | |
94 // The line from `atos` is in one of these formats: | |
95 // myfunction (in library.dylib) (sourcefile.c:17) | |
96 // myfunction (in library.dylib) + 0x1fe | |
97 // myfunction (in library.dylib) + 15 | |
98 // 0xdeadbeef (in library.dylib) + 0x1fe | |
99 // 0xdeadbeef (in library.dylib) + 15 | |
100 // 0xdeadbeef (in library.dylib) | |
101 // 0xdeadbeef | |
102 | |
103 const char *rest = trim; | |
104 char *symbol_name; | |
105 rest = ExtractTokenUpToDelimiter(rest, " (in ", &symbol_name); | |
106 if (rest[0] == '\0') { | |
107 InternalFree(symbol_name); | |
108 InternalFree(trim); | |
109 return false; | |
110 } | |
111 | |
112 if (internal_strncmp(symbol_name, "0x", 2) != 0) | |
113 *out_name = symbol_name; | |
114 else | |
115 InternalFree(symbol_name); | |
116 rest = ExtractTokenUpToDelimiter(rest, ") ", out_module); | |
117 | |
118 if (rest[0] == '(') { | |
119 if (out_file) { | |
120 rest++; | |
121 rest = ExtractTokenUpToDelimiter(rest, ":", out_file); | |
122 char *extracted_line_number; | |
123 rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number); | |
124 if (line) *line = (uptr)internal_atoll(extracted_line_number); | |
125 InternalFree(extracted_line_number); | |
126 } | |
127 } else if (rest[0] == '+') { | |
128 rest += 2; | |
129 uptr offset = internal_atoll(rest); | |
130 if (start_address) *start_address = addr - offset; | |
131 } | |
132 | |
133 InternalFree(trim); | |
134 return true; | |
135 } | |
136 | |
137 AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator) | |
138 : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {} | |
139 | |
140 bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { | |
141 if (!process_) return false; | |
142 if (addr == 0) return false; | |
143 char command[32]; | |
144 internal_snprintf(command, sizeof(command), "0x%zx\n", addr); | |
145 const char *buf = process_->SendCommand(command); | |
146 if (!buf) return false; | |
147 uptr line; | |
148 if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module, | |
149 &stack->info.file, &line, nullptr)) { | |
150 process_ = nullptr; | |
151 return false; | |
152 } | |
153 stack->info.line = (int)line; | |
154 return true; | |
155 } | |
156 | |
157 bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { | |
158 if (!process_) return false; | |
159 char command[32]; | |
160 internal_snprintf(command, sizeof(command), "0x%zx\n", addr); | |
161 const char *buf = process_->SendCommand(command); | |
162 if (!buf) return false; | |
163 if (!ParseCommandOutput(buf, addr, &info->name, &info->module, nullptr, | |
164 nullptr, &info->start)) { | |
165 process_ = nullptr; | |
166 return false; | |
167 } | |
168 return true; | |
169 } | |
170 | |
171 } // namespace __sanitizer | |
172 | |
173 #endif // SANITIZER_MAC |