Clean up some minor white space issues in trans-decl.c and trans-expr.c
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_symbolizer_mac.cc
blobe65976c18d0733f62b8f9416e8dc56ac4fa0a6f9
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 //===----------------------------------------------------------------------===//
13 #include "sanitizer_platform.h"
14 #if SANITIZER_MAC
16 #include "sanitizer_allocator_internal.h"
17 #include "sanitizer_mac.h"
18 #include "sanitizer_symbolizer_mac.h"
20 namespace __sanitizer {
22 #include <dlfcn.h>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
27 #include <util.h>
29 bool 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 = DemangleCXXABI(info.dli_sname);
34 stack->info.function = internal_strdup(demangled);
35 return true;
38 bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) {
39 Dl_info info;
40 int result = dladdr((const void *)addr, &info);
41 if (!result) return false;
42 const char *demangled = DemangleCXXABI(info.dli_sname);
43 datainfo->name = internal_strdup(demangled);
44 datainfo->start = (uptr)info.dli_saddr;
45 return true;
48 class AtosSymbolizerProcess : public SymbolizerProcess {
49 public:
50 explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid)
51 : SymbolizerProcess(path, /*use_forkpty*/ true) {
52 // Put the string command line argument in the object so that it outlives
53 // the call to GetArgV.
54 internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid);
57 private:
58 bool ReachedEndOfOutput(const char *buffer, uptr length) const override {
59 return (length >= 1 && buffer[length - 1] == '\n');
62 void GetArgV(const char *path_to_binary,
63 const char *(&argv)[kArgVMax]) const override {
64 int i = 0;
65 argv[i++] = path_to_binary;
66 argv[i++] = "-p";
67 argv[i++] = &pid_str_[0];
68 if (GetMacosVersion() == MACOS_VERSION_MAVERICKS) {
69 // On Mavericks atos prints a deprecation warning which we suppress by
70 // passing -d. The warning isn't present on other OSX versions, even the
71 // newer ones.
72 argv[i++] = "-d";
74 argv[i++] = nullptr;
77 char pid_str_[16];
80 static const char *kAtosErrorMessages[] = {
81 "atos cannot examine process",
82 "unable to get permission to examine process",
83 "An admin user name and password is required",
84 "could not load inserted library",
85 "architecture mismatch between analysis process",
88 static bool IsAtosErrorMessage(const char *str) {
89 for (uptr i = 0; i < ARRAY_SIZE(kAtosErrorMessages); i++) {
90 if (internal_strstr(str, kAtosErrorMessages[i])) {
91 return true;
94 return false;
97 static bool ParseCommandOutput(const char *str, uptr addr, char **out_name,
98 char **out_module, char **out_file, uptr *line,
99 uptr *start_address) {
100 // Trim ending newlines.
101 char *trim;
102 ExtractTokenUpToDelimiter(str, "\n", &trim);
104 // The line from `atos` is in one of these formats:
105 // myfunction (in library.dylib) (sourcefile.c:17)
106 // myfunction (in library.dylib) + 0x1fe
107 // myfunction (in library.dylib) + 15
108 // 0xdeadbeef (in library.dylib) + 0x1fe
109 // 0xdeadbeef (in library.dylib) + 15
110 // 0xdeadbeef (in library.dylib)
111 // 0xdeadbeef
113 if (IsAtosErrorMessage(trim)) {
114 Report("atos returned an error: %s\n", trim);
115 InternalFree(trim);
116 return false;
119 const char *rest = trim;
120 char *symbol_name;
121 rest = ExtractTokenUpToDelimiter(rest, " (in ", &symbol_name);
122 if (internal_strncmp(symbol_name, "0x", 2) != 0)
123 *out_name = symbol_name;
124 else
125 InternalFree(symbol_name);
126 rest = ExtractTokenUpToDelimiter(rest, ") ", out_module);
128 if (rest[0] == '(') {
129 if (out_file) {
130 rest++;
131 rest = ExtractTokenUpToDelimiter(rest, ":", out_file);
132 char *extracted_line_number;
133 rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number);
134 if (line) *line = (uptr)internal_atoll(extracted_line_number);
135 InternalFree(extracted_line_number);
137 } else if (rest[0] == '+') {
138 rest += 2;
139 uptr offset = internal_atoll(rest);
140 if (start_address) *start_address = addr - offset;
143 InternalFree(trim);
144 return true;
147 AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator)
148 : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {}
150 bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
151 if (!process_) return false;
152 char command[32];
153 internal_snprintf(command, sizeof(command), "0x%zx\n", addr);
154 const char *buf = process_->SendCommand(command);
155 if (!buf) return false;
156 uptr line;
157 if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module,
158 &stack->info.file, &line, nullptr)) {
159 process_ = nullptr;
160 return false;
162 stack->info.line = (int)line;
163 return true;
166 bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
167 if (!process_) return false;
168 char command[32];
169 internal_snprintf(command, sizeof(command), "0x%zx\n", addr);
170 const char *buf = process_->SendCommand(command);
171 if (!buf) return false;
172 if (!ParseCommandOutput(buf, addr, &info->name, &info->module, nullptr,
173 nullptr, &info->start)) {
174 process_ = nullptr;
175 return false;
177 return true;
180 } // namespace __sanitizer
182 #endif // SANITIZER_MAC