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"
27 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
= DemangleSwiftAndCXX(info
.dli_sname
);
34 if (!demangled
) return false;
35 stack
->info
.function
= internal_strdup(demangled
);
39 bool DlAddrSymbolizer::SymbolizeData(uptr addr
, DataInfo
*datainfo
) {
41 int result
= dladdr((const void *)addr
, &info
);
42 if (!result
) return false;
43 const char *demangled
= DemangleSwiftAndCXX(info
.dli_sname
);
44 datainfo
->name
= internal_strdup(demangled
);
45 datainfo
->start
= (uptr
)info
.dli_saddr
;
49 class AtosSymbolizerProcess
: public SymbolizerProcess
{
51 explicit AtosSymbolizerProcess(const char *path
, pid_t parent_pid
)
52 : SymbolizerProcess(path
, /*use_forkpty*/ true) {
53 // Put the string command line argument in the object so that it outlives
54 // the call to GetArgV.
55 internal_snprintf(pid_str_
, sizeof(pid_str_
), "%d", parent_pid
);
59 bool ReachedEndOfOutput(const char *buffer
, uptr length
) const override
{
60 return (length
>= 1 && buffer
[length
- 1] == '\n');
63 void GetArgV(const char *path_to_binary
,
64 const char *(&argv
)[kArgVMax
]) const override
{
66 argv
[i
++] = path_to_binary
;
68 argv
[i
++] = &pid_str_
[0];
69 if (GetMacosVersion() == MACOS_VERSION_MAVERICKS
) {
70 // On Mavericks atos prints a deprecation warning which we suppress by
71 // passing -d. The warning isn't present on other OSX versions, even the
81 static bool ParseCommandOutput(const char *str
, uptr addr
, char **out_name
,
82 char **out_module
, char **out_file
, uptr
*line
,
83 uptr
*start_address
) {
84 // Trim ending newlines.
86 ExtractTokenUpToDelimiter(str
, "\n", &trim
);
88 // The line from `atos` is in one of these formats:
89 // myfunction (in library.dylib) (sourcefile.c:17)
90 // myfunction (in library.dylib) + 0x1fe
91 // myfunction (in library.dylib) + 15
92 // 0xdeadbeef (in library.dylib) + 0x1fe
93 // 0xdeadbeef (in library.dylib) + 15
94 // 0xdeadbeef (in library.dylib)
97 const char *rest
= trim
;
99 rest
= ExtractTokenUpToDelimiter(rest
, " (in ", &symbol_name
);
100 if (rest
[0] == '\0') {
101 InternalFree(symbol_name
);
106 if (internal_strncmp(symbol_name
, "0x", 2) != 0)
107 *out_name
= symbol_name
;
109 InternalFree(symbol_name
);
110 rest
= ExtractTokenUpToDelimiter(rest
, ") ", out_module
);
112 if (rest
[0] == '(') {
115 rest
= ExtractTokenUpToDelimiter(rest
, ":", out_file
);
116 char *extracted_line_number
;
117 rest
= ExtractTokenUpToDelimiter(rest
, ")", &extracted_line_number
);
118 if (line
) *line
= (uptr
)internal_atoll(extracted_line_number
);
119 InternalFree(extracted_line_number
);
121 } else if (rest
[0] == '+') {
123 uptr offset
= internal_atoll(rest
);
124 if (start_address
) *start_address
= addr
- offset
;
131 AtosSymbolizer::AtosSymbolizer(const char *path
, LowLevelAllocator
*allocator
)
132 : process_(new(*allocator
) AtosSymbolizerProcess(path
, getpid())) {}
134 bool AtosSymbolizer::SymbolizePC(uptr addr
, SymbolizedStack
*stack
) {
135 if (!process_
) return false;
136 if (addr
== 0) return false;
138 internal_snprintf(command
, sizeof(command
), "0x%zx\n", addr
);
139 const char *buf
= process_
->SendCommand(command
);
140 if (!buf
) return false;
142 if (!ParseCommandOutput(buf
, addr
, &stack
->info
.function
, &stack
->info
.module
,
143 &stack
->info
.file
, &line
, nullptr)) {
147 stack
->info
.line
= (int)line
;
151 bool AtosSymbolizer::SymbolizeData(uptr addr
, DataInfo
*info
) {
152 if (!process_
) return false;
154 internal_snprintf(command
, sizeof(command
), "0x%zx\n", addr
);
155 const char *buf
= process_
->SendCommand(command
);
156 if (!buf
) return false;
157 if (!ParseCommandOutput(buf
, addr
, &info
->name
, &info
->module
, nullptr,
158 nullptr, &info
->start
)) {
165 } // namespace __sanitizer
167 #endif // SANITIZER_MAC