1 //===-- sanitizer_symbolizer_posix_libcdep.cc -----------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is shared between AddressSanitizer and ThreadSanitizer
11 // run-time libraries.
12 // POSIX-specific implementation of symbolizer parts.
13 //===----------------------------------------------------------------------===//
15 #include "sanitizer_platform.h"
17 #include "sanitizer_allocator_internal.h"
18 #include "sanitizer_common.h"
19 #include "sanitizer_flags.h"
20 #include "sanitizer_internal_defs.h"
21 #include "sanitizer_linux.h"
22 #include "sanitizer_placement_new.h"
23 #include "sanitizer_posix.h"
24 #include "sanitizer_procmaps.h"
25 #include "sanitizer_symbolizer_internal.h"
26 #include "sanitizer_symbolizer_libbacktrace.h"
27 #include "sanitizer_symbolizer_mac.h"
35 #include <util.h> // for forkpty()
36 #endif // SANITIZER_MAC
38 // C++ demangling function, as required by Itanium C++ ABI. This is weak,
39 // because we do not require a C++ ABI library to be linked to a program
40 // using sanitizers; if it's not present, we'll just use the mangled name.
41 namespace __cxxabiv1 {
42 extern "C" SANITIZER_WEAK_ATTRIBUTE
43 char *__cxa_demangle(const char *mangled, char *buffer,
44 size_t *length, int *status);
47 namespace __sanitizer {
49 // Attempts to demangle the name via __cxa_demangle from __cxxabiv1.
50 const char *DemangleCXXABI(const char *name) {
51 // FIXME: __cxa_demangle aggressively insists on allocating memory.
52 // There's not much we can do about that, short of providing our
53 // own demangler (libc++abi's implementation could be adapted so that
54 // it does not allocate). For now, we just call it anyway, and we leak
55 // the returned value.
56 if (__cxxabiv1::__cxa_demangle)
57 if (const char *demangled_name =
58 __cxxabiv1::__cxa_demangle(name, 0, 0, 0))
59 return demangled_name;
64 bool SymbolizerProcess::StartSymbolizerSubprocess() {
65 if (!FileExists(path_)) {
66 if (!reported_invalid_path_) {
67 Report("WARNING: invalid path to external symbolizer!\n");
68 reported_invalid_path_ = true;
77 // Use forkpty to disable buffering in the new terminal.
78 pid = internal_forkpty(&fd);
81 Report("WARNING: failed to fork external symbolizer (errno: %d)\n",
84 } else if (pid == 0) {
86 const char *argv[kArgVMax];
88 execv(path_, const_cast<char **>(&argv[0]));
92 // Continue execution in parent process.
93 input_fd_ = output_fd_ = fd;
95 // Disable echo in the new terminal, disable CR.
96 struct termios termflags;
97 tcgetattr(fd, &termflags);
98 termflags.c_oflag &= ~ONLCR;
99 termflags.c_lflag &= ~ECHO;
100 tcsetattr(fd, TCSANOW, &termflags);
101 #else // SANITIZER_MAC
103 #endif // SANITIZER_MAC
107 // The client program may close its stdin and/or stdout and/or stderr
108 // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
109 // In this case the communication between the forked processes may be
110 // broken if either the parent or the child tries to close or duplicate
111 // these descriptors. The loop below produces two pairs of file
112 // descriptors, each greater than 2 (stderr).
114 for (int i = 0; i < 5; i++) {
115 if (pipe(sock_pair[i]) == -1) {
116 for (int j = 0; j < i; j++) {
117 internal_close(sock_pair[j][0]);
118 internal_close(sock_pair[j][1]);
120 Report("WARNING: Can't create a socket pair to start "
121 "external symbolizer (errno: %d)\n", errno);
123 } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
127 outfd = sock_pair[i];
128 for (int j = 0; j < i; j++) {
129 if (sock_pair[j] == infd) continue;
130 internal_close(sock_pair[j][0]);
131 internal_close(sock_pair[j][1]);
140 // Real fork() may call user callbacks registered with pthread_atfork().
141 pid = internal_fork();
144 internal_close(infd[0]);
145 internal_close(infd[1]);
146 internal_close(outfd[0]);
147 internal_close(outfd[1]);
148 Report("WARNING: failed to fork external symbolizer "
149 " (errno: %d)\n", errno);
151 } else if (pid == 0) {
153 internal_close(STDOUT_FILENO);
154 internal_close(STDIN_FILENO);
155 internal_dup2(outfd[0], STDIN_FILENO);
156 internal_dup2(infd[1], STDOUT_FILENO);
157 internal_close(outfd[0]);
158 internal_close(outfd[1]);
159 internal_close(infd[0]);
160 internal_close(infd[1]);
161 for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--)
163 const char *argv[kArgVMax];
164 GetArgV(path_, argv);
165 execv(path_, const_cast<char **>(&argv[0]));
169 // Continue execution in parent process.
170 internal_close(outfd[0]);
171 internal_close(infd[1]);
173 output_fd_ = outfd[1];
176 // Check that symbolizer subprocess started successfully.
178 SleepForMillis(kSymbolizerStartupTimeMillis);
179 int exited_pid = waitpid(pid, &pid_status, WNOHANG);
180 if (exited_pid != 0) {
181 // Either waitpid failed, or child has already exited.
182 Report("WARNING: external symbolizer didn't start up correctly!\n");
189 class Addr2LineProcess : public SymbolizerProcess {
191 Addr2LineProcess(const char *path, const char *module_name)
192 : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {}
194 const char *module_name() const { return module_name_; }
197 void GetArgV(const char *path_to_binary,
198 const char *(&argv)[kArgVMax]) const override {
200 argv[i++] = path_to_binary;
202 argv[i++] = module_name_;
206 bool ReachedEndOfOutput(const char *buffer, uptr length) const override;
208 bool ReadFromSymbolizer(char *buffer, uptr max_length) override {
209 if (!SymbolizerProcess::ReadFromSymbolizer(buffer, max_length))
211 // We should cut out output_terminator_ at the end of given buffer,
212 // appended by addr2line to mark the end of its meaningful output.
213 // We cannot scan buffer from it's beginning, because it is legal for it
214 // to start with output_terminator_ in case given offset is invalid. So,
215 // scanning from second character.
216 char *garbage = internal_strstr(buffer + 1, output_terminator_);
217 // This should never be NULL since buffer must end up with
218 // output_terminator_.
225 const char *module_name_; // Owned, leaked.
226 static const char output_terminator_[];
229 const char Addr2LineProcess::output_terminator_[] = "??\n??:0\n";
231 bool Addr2LineProcess::ReachedEndOfOutput(const char *buffer,
233 const size_t kTerminatorLen = sizeof(output_terminator_) - 1;
234 // Skip, if we read just kTerminatorLen bytes, because Addr2Line output
235 // should consist at least of two pairs of lines:
236 // 1. First one, corresponding to given offset to be symbolized
237 // (may be equal to output_terminator_, if offset is not valid).
238 // 2. Second one for output_terminator_, itself to mark the end of output.
239 if (length <= kTerminatorLen) return false;
240 // Addr2Line output should end up with output_terminator_.
241 return !internal_memcmp(buffer + length - kTerminatorLen,
242 output_terminator_, kTerminatorLen);
245 class Addr2LinePool : public SymbolizerTool {
247 explicit Addr2LinePool(const char *addr2line_path,
248 LowLevelAllocator *allocator)
249 : addr2line_path_(addr2line_path), allocator_(allocator),
250 addr2line_pool_(16) {}
252 bool SymbolizePC(uptr addr, SymbolizedStack *stack) override {
253 if (const char *buf =
254 SendCommand(stack->info.module, stack->info.module_offset)) {
255 ParseSymbolizePCOutput(buf, stack);
261 bool SymbolizeData(uptr addr, DataInfo *info) override {
266 const char *SendCommand(const char *module_name, uptr module_offset) {
267 Addr2LineProcess *addr2line = 0;
268 for (uptr i = 0; i < addr2line_pool_.size(); ++i) {
270 internal_strcmp(module_name, addr2line_pool_[i]->module_name())) {
271 addr2line = addr2line_pool_[i];
277 new(*allocator_) Addr2LineProcess(addr2line_path_, module_name);
278 addr2line_pool_.push_back(addr2line);
280 CHECK_EQ(0, internal_strcmp(module_name, addr2line->module_name()));
281 char buffer[kBufferSize];
282 internal_snprintf(buffer, kBufferSize, "0x%zx\n0x%zx\n",
283 module_offset, dummy_address_);
284 return addr2line->SendCommand(buffer);
287 static const uptr kBufferSize = 64;
288 const char *addr2line_path_;
289 LowLevelAllocator *allocator_;
290 InternalMmapVector<Addr2LineProcess*> addr2line_pool_;
291 static const uptr dummy_address_ =
292 FIRST_32_SECOND_64(UINT32_MAX, UINT64_MAX);
295 #if SANITIZER_SUPPORTS_WEAK_HOOKS
297 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
298 bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
299 char *Buffer, int MaxLength);
300 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
301 bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset,
302 char *Buffer, int MaxLength);
303 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
304 void __sanitizer_symbolize_flush();
305 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
306 int __sanitizer_symbolize_demangle(const char *Name, char *Buffer,
310 class InternalSymbolizer : public SymbolizerTool {
312 static InternalSymbolizer *get(LowLevelAllocator *alloc) {
313 if (__sanitizer_symbolize_code != 0 &&
314 __sanitizer_symbolize_data != 0) {
315 return new(*alloc) InternalSymbolizer();
320 bool SymbolizePC(uptr addr, SymbolizedStack *stack) override {
321 bool result = __sanitizer_symbolize_code(
322 stack->info.module, stack->info.module_offset, buffer_, kBufferSize);
323 if (result) ParseSymbolizePCOutput(buffer_, stack);
327 bool SymbolizeData(uptr addr, DataInfo *info) override {
328 bool result = __sanitizer_symbolize_data(info->module, info->module_offset,
329 buffer_, kBufferSize);
331 ParseSymbolizeDataOutput(buffer_, info);
332 info->start += (addr - info->module_offset); // Add the base address.
337 void Flush() override {
338 if (__sanitizer_symbolize_flush)
339 __sanitizer_symbolize_flush();
342 const char *Demangle(const char *name) override {
343 if (__sanitizer_symbolize_demangle) {
344 for (uptr res_length = 1024;
345 res_length <= InternalSizeClassMap::kMaxSize;) {
346 char *res_buff = static_cast<char*>(InternalAlloc(res_length));
348 __sanitizer_symbolize_demangle(name, res_buff, res_length);
349 if (req_length > res_length) {
350 res_length = req_length + 1;
351 InternalFree(res_buff);
361 InternalSymbolizer() { }
363 static const int kBufferSize = 16 * 1024;
364 static const int kMaxDemangledNameSize = 1024;
365 char buffer_[kBufferSize];
367 #else // SANITIZER_SUPPORTS_WEAK_HOOKS
369 class InternalSymbolizer : public SymbolizerTool {
371 static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; }
374 #endif // SANITIZER_SUPPORTS_WEAK_HOOKS
376 const char *Symbolizer::PlatformDemangle(const char *name) {
377 return DemangleCXXABI(name);
380 void Symbolizer::PlatformPrepareForSandboxing() {}
382 static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
383 const char *path = common_flags()->external_symbolizer_path;
384 const char *binary_name = path ? StripModuleName(path) : "";
385 if (path && path[0] == '\0') {
386 VReport(2, "External symbolizer is explicitly disabled.\n");
388 } else if (!internal_strcmp(binary_name, "llvm-symbolizer")) {
389 VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path);
390 return new(*allocator) LLVMSymbolizer(path, allocator);
391 } else if (!internal_strcmp(binary_name, "atos")) {
393 VReport(2, "Using atos at user-specified path: %s\n", path);
394 return new(*allocator) AtosSymbolizer(path, allocator);
395 #else // SANITIZER_MAC
396 Report("ERROR: Using `atos` is only supported on Darwin.\n");
398 #endif // SANITIZER_MAC
399 } else if (!internal_strcmp(binary_name, "addr2line")) {
400 VReport(2, "Using addr2line at user-specified path: %s\n", path);
401 return new(*allocator) Addr2LinePool(path, allocator);
403 Report("ERROR: External symbolizer path is set to '%s' which isn't "
404 "a known symbolizer. Please set the path to the llvm-symbolizer "
405 "binary or other known tool.\n", path);
409 // Otherwise symbolizer program is unknown, let's search $PATH
410 CHECK(path == nullptr);
411 if (const char *found_path = FindPathToBinary("llvm-symbolizer")) {
412 VReport(2, "Using llvm-symbolizer found at: %s\n", found_path);
413 return new(*allocator) LLVMSymbolizer(found_path, allocator);
416 if (const char *found_path = FindPathToBinary("atos")) {
417 VReport(2, "Using atos found at: %s\n", found_path);
418 return new(*allocator) AtosSymbolizer(found_path, allocator);
420 #endif // SANITIZER_MAC
421 if (common_flags()->allow_addr2line) {
422 if (const char *found_path = FindPathToBinary("addr2line")) {
423 VReport(2, "Using addr2line found at: %s\n", found_path);
424 return new(*allocator) Addr2LinePool(found_path, allocator);
430 static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
431 LowLevelAllocator *allocator) {
432 if (!common_flags()->symbolize) {
433 VReport(2, "Symbolizer is disabled.\n");
436 if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) {
437 VReport(2, "Using internal symbolizer.\n");
438 list->push_back(tool);
441 if (SymbolizerTool *tool = LibbacktraceSymbolizer::get(allocator)) {
442 VReport(2, "Using libbacktrace symbolizer.\n");
443 list->push_back(tool);
447 if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) {
448 list->push_back(tool);
452 VReport(2, "Using dladdr symbolizer.\n");
453 list->push_back(new(*allocator) DlAddrSymbolizer());
454 #endif // SANITIZER_MAC
457 Symbolizer *Symbolizer::PlatformInit() {
458 IntrusiveList<SymbolizerTool> list;
460 ChooseSymbolizerTools(&list, &symbolizer_allocator_);
461 return new(symbolizer_allocator_) Symbolizer(list);
464 } // namespace __sanitizer
466 #endif // SANITIZER_POSIX