* gcc-interface/trans.c (Subprogram_Body_to_gnu): Initialize locus.
[official-gcc.git] / libsanitizer / lsan / lsan_common_linux.cc
blob677727229b1e9632d9d95dc4ab303a39babb8177
1 //=-- lsan_common_linux.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 a part of LeakSanitizer.
9 // Implementation of common leak checking functionality. Linux-specific code.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common/sanitizer_platform.h"
14 #include "lsan_common.h"
16 #if CAN_SANITIZE_LEAKS && SANITIZER_LINUX
17 #include <link.h>
19 #include "sanitizer_common/sanitizer_common.h"
20 #include "sanitizer_common/sanitizer_flags.h"
21 #include "sanitizer_common/sanitizer_linux.h"
22 #include "sanitizer_common/sanitizer_stackdepot.h"
24 namespace __lsan {
26 static const char kLinkerName[] = "ld";
28 static char linker_placeholder[sizeof(LoadedModule)] ALIGNED(64);
29 static LoadedModule *linker = nullptr;
31 static bool IsLinker(const char* full_name) {
32 return LibraryNameIs(full_name, kLinkerName);
35 __attribute__((tls_model("initial-exec")))
36 THREADLOCAL int disable_counter;
37 bool DisabledInThisThread() { return disable_counter > 0; }
38 void DisableInThisThread() { disable_counter++; }
39 void EnableInThisThread() {
40 if (disable_counter == 0) {
41 DisableCounterUnderflow();
43 disable_counter--;
46 void InitializePlatformSpecificModules() {
47 ListOfModules modules;
48 modules.init();
49 for (LoadedModule &module : modules) {
50 if (!IsLinker(module.full_name())) continue;
51 if (linker == nullptr) {
52 linker = reinterpret_cast<LoadedModule *>(linker_placeholder);
53 *linker = module;
54 module = LoadedModule();
55 } else {
56 VReport(1, "LeakSanitizer: Multiple modules match \"%s\". "
57 "TLS will not be handled correctly.\n", kLinkerName);
58 linker->clear();
59 linker = nullptr;
60 return;
63 if (linker == nullptr) {
64 VReport(1, "LeakSanitizer: Dynamic linker not found. "
65 "TLS will not be handled correctly.\n");
69 static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
70 void *data) {
71 Frontier *frontier = reinterpret_cast<Frontier *>(data);
72 for (uptr j = 0; j < info->dlpi_phnum; j++) {
73 const ElfW(Phdr) *phdr = &(info->dlpi_phdr[j]);
74 // We're looking for .data and .bss sections, which reside in writeable,
75 // loadable segments.
76 if (!(phdr->p_flags & PF_W) || (phdr->p_type != PT_LOAD) ||
77 (phdr->p_memsz == 0))
78 continue;
79 uptr begin = info->dlpi_addr + phdr->p_vaddr;
80 uptr end = begin + phdr->p_memsz;
81 ScanGlobalRange(begin, end, frontier);
83 return 0;
86 // Scans global variables for heap pointers.
87 void ProcessGlobalRegions(Frontier *frontier) {
88 if (!flags()->use_globals) return;
89 dl_iterate_phdr(ProcessGlobalRegionsCallback, frontier);
92 LoadedModule *GetLinker() { return linker; }
94 void ProcessPlatformSpecificAllocations(Frontier *frontier) {}
96 struct DoStopTheWorldParam {
97 StopTheWorldCallback callback;
98 void *argument;
101 // While calling Die() here is undefined behavior and can potentially
102 // cause race conditions, it isn't possible to intercept exit on linux,
103 // so we have no choice but to call Die() from the atexit handler.
104 void HandleLeaks() {
105 if (common_flags()->exitcode) Die();
108 static int DoStopTheWorldCallback(struct dl_phdr_info *info, size_t size,
109 void *data) {
110 DoStopTheWorldParam *param = reinterpret_cast<DoStopTheWorldParam *>(data);
111 StopTheWorld(param->callback, param->argument);
112 return 1;
115 // LSan calls dl_iterate_phdr() from the tracer task. This may deadlock: if one
116 // of the threads is frozen while holding the libdl lock, the tracer will hang
117 // in dl_iterate_phdr() forever.
118 // Luckily, (a) the lock is reentrant and (b) libc can't distinguish between the
119 // tracer task and the thread that spawned it. Thus, if we run the tracer task
120 // while holding the libdl lock in the parent thread, we can safely reenter it
121 // in the tracer. The solution is to run stoptheworld from a dl_iterate_phdr()
122 // callback in the parent thread.
123 void DoStopTheWorld(StopTheWorldCallback callback, void *argument) {
124 DoStopTheWorldParam param = {callback, argument};
125 dl_iterate_phdr(DoStopTheWorldCallback, &param);
128 } // namespace __lsan
130 #endif // CAN_SANITIZE_LEAKS && SANITIZER_LINUX