1 //===-- sanitizer_symbolizer_mac.cpp --------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is shared between various sanitizers' runtime libraries.
11 // Implementation of Mac-specific "atos" symbolizer.
12 //===----------------------------------------------------------------------===//
14 #include "sanitizer_platform.h"
17 #include "sanitizer_allocator_internal.h"
18 #include "sanitizer_mac.h"
19 #include "sanitizer_symbolizer_mac.h"
28 namespace __sanitizer
{
30 bool DlAddrSymbolizer::SymbolizePC(uptr addr
, SymbolizedStack
*stack
) {
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
);
40 bool DlAddrSymbolizer::SymbolizeData(uptr addr
, DataInfo
*datainfo
) {
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
;
50 class AtosSymbolizerProcess
: public SymbolizerProcess
{
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
);
60 bool StartSymbolizerSubprocess() override
{
61 // Configure sandbox before starting atos process.
62 return SymbolizerProcess::StartSymbolizerSubprocess();
65 bool ReachedEndOfOutput(const char *buffer
, uptr length
) const override
{
66 return (length
>= 1 && buffer
[length
- 1] == '\n');
69 void GetArgV(const char *path_to_binary
,
70 const char *(&argv
)[kArgVMax
]) const override
{
72 argv
[i
++] = path_to_binary
;
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
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.
92 ExtractTokenUpToDelimiter(str
, "\n", &trim
);
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)
103 const char *rest
= trim
;
105 rest
= ExtractTokenUpToDelimiter(rest
, " (in ", &symbol_name
);
106 if (rest
[0] == '\0') {
107 InternalFree(symbol_name
);
112 if (internal_strncmp(symbol_name
, "0x", 2) != 0)
113 *out_name
= symbol_name
;
115 InternalFree(symbol_name
);
116 rest
= ExtractTokenUpToDelimiter(rest
, ") ", out_module
);
118 if (rest
[0] == '(') {
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
);
127 } else if (rest
[0] == '+') {
129 uptr offset
= internal_atoll(rest
);
130 if (start_address
) *start_address
= addr
- offset
;
137 AtosSymbolizer::AtosSymbolizer(const char *path
, LowLevelAllocator
*allocator
)
138 : process_(new(*allocator
) AtosSymbolizerProcess(path
, getpid())) {}
140 bool AtosSymbolizer::SymbolizePC(uptr addr
, SymbolizedStack
*stack
) {
141 if (!process_
) return false;
142 if (addr
== 0) return false;
144 internal_snprintf(command
, sizeof(command
), "0x%zx\n", addr
);
145 const char *buf
= process_
->SendCommand(command
);
146 if (!buf
) return false;
148 if (!ParseCommandOutput(buf
, addr
, &stack
->info
.function
, &stack
->info
.module
,
149 &stack
->info
.file
, &line
, nullptr)) {
153 stack
->info
.line
= (int)line
;
157 bool AtosSymbolizer::SymbolizeData(uptr addr
, DataInfo
*info
) {
158 if (!process_
) return false;
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
)) {
171 } // namespace __sanitizer
173 #endif // SANITIZER_MAC