1 //===-- sanitizer_symbolizer_mac.cc ---------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is shared between various sanitizers' runtime libraries.
10 // Implementation of Mac-specific "atos" symbolizer.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_platform.h"
16 #include "sanitizer_allocator_internal.h"
17 #include "sanitizer_mac.h"
18 #include "sanitizer_symbolizer_mac.h"
20 namespace __sanitizer
{
29 bool DlAddrSymbolizer::SymbolizePC(uptr addr
, SymbolizedStack
*stack
) {
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
);
38 bool DlAddrSymbolizer::SymbolizeData(uptr addr
, DataInfo
*datainfo
) {
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
;
48 class AtosSymbolizerProcess
: public SymbolizerProcess
{
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
);
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
{
65 argv
[i
++] = path_to_binary
;
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
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
])) {
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.
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)
113 if (IsAtosErrorMessage(trim
)) {
114 Report("atos returned an error: %s\n", trim
);
119 const char *rest
= trim
;
121 rest
= ExtractTokenUpToDelimiter(rest
, " (in ", &symbol_name
);
122 if (internal_strncmp(symbol_name
, "0x", 2) != 0)
123 *out_name
= symbol_name
;
125 InternalFree(symbol_name
);
126 rest
= ExtractTokenUpToDelimiter(rest
, ") ", out_module
);
128 if (rest
[0] == '(') {
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] == '+') {
139 uptr offset
= internal_atoll(rest
);
140 if (start_address
) *start_address
= addr
- offset
;
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;
153 internal_snprintf(command
, sizeof(command
), "0x%zx\n", addr
);
154 const char *buf
= process_
->SendCommand(command
);
155 if (!buf
) return false;
157 if (!ParseCommandOutput(buf
, addr
, &stack
->info
.function
, &stack
->info
.module
,
158 &stack
->info
.file
, &line
, nullptr)) {
162 stack
->info
.line
= (int)line
;
166 bool AtosSymbolizer::SymbolizeData(uptr addr
, DataInfo
*info
) {
167 if (!process_
) return false;
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
)) {
180 } // namespace __sanitizer
182 #endif // SANITIZER_MAC