Add libstdc++-raw-cxx.m4 and use it in libsanitizer
[gcc.git] / libsanitizer / asan / asan_thread.cc
1 //===-- asan_thread.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 AddressSanitizer, an address sanity checker.
9 //
10 // Thread-related code.
11 //===----------------------------------------------------------------------===//
12 #include "asan_allocator.h"
13 #include "asan_interceptors.h"
14 #include "asan_stack.h"
15 #include "asan_thread.h"
16 #include "asan_thread_registry.h"
17 #include "asan_mapping.h"
18 #include "sanitizer_common/sanitizer_common.h"
19
20 namespace __asan {
21
22 AsanThread::AsanThread(LinkerInitialized x)
23 : fake_stack_(x),
24 malloc_storage_(x),
25 stats_(x) { }
26
27 AsanThread *AsanThread::Create(u32 parent_tid, thread_callback_t start_routine,
28 void *arg, StackTrace *stack) {
29 uptr PageSize = GetPageSizeCached();
30 uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
31 AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
32 thread->start_routine_ = start_routine;
33 thread->arg_ = arg;
34
35 const uptr kSummaryAllocSize = PageSize;
36 CHECK_LE(sizeof(AsanThreadSummary), kSummaryAllocSize);
37 AsanThreadSummary *summary =
38 (AsanThreadSummary*)MmapOrDie(PageSize, "AsanThreadSummary");
39 summary->Init(parent_tid, stack);
40 summary->set_thread(thread);
41 thread->set_summary(summary);
42
43 return thread;
44 }
45
46 void AsanThreadSummary::TSDDtor(void *tsd) {
47 AsanThreadSummary *summary = (AsanThreadSummary*)tsd;
48 if (flags()->verbosity >= 1) {
49 Report("T%d TSDDtor\n", summary->tid());
50 }
51 if (summary->thread()) {
52 summary->thread()->Destroy();
53 }
54 }
55
56 void AsanThread::Destroy() {
57 if (flags()->verbosity >= 1) {
58 Report("T%d exited\n", tid());
59 }
60
61 asanThreadRegistry().UnregisterThread(this);
62 CHECK(summary()->thread() == 0);
63 // We also clear the shadow on thread destruction because
64 // some code may still be executing in later TSD destructors
65 // and we don't want it to have any poisoned stack.
66 ClearShadowForThreadStack();
67 fake_stack().Cleanup();
68 uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
69 UnmapOrDie(this, size);
70 }
71
72 void AsanThread::Init() {
73 SetThreadStackTopAndBottom();
74 CHECK(AddrIsInMem(stack_bottom_));
75 CHECK(AddrIsInMem(stack_top_));
76 ClearShadowForThreadStack();
77 if (flags()->verbosity >= 1) {
78 int local = 0;
79 Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
80 tid(), (void*)stack_bottom_, (void*)stack_top_,
81 stack_top_ - stack_bottom_, &local);
82 }
83 fake_stack_.Init(stack_size());
84 AsanPlatformThreadInit();
85 }
86
87 thread_return_t AsanThread::ThreadStart() {
88 Init();
89 if (flags()->use_sigaltstack) SetAlternateSignalStack();
90
91 if (!start_routine_) {
92 // start_routine_ == 0 if we're on the main thread or on one of the
93 // OS X libdispatch worker threads. But nobody is supposed to call
94 // ThreadStart() for the worker threads.
95 CHECK(tid() == 0);
96 return 0;
97 }
98
99 thread_return_t res = start_routine_(arg_);
100 malloc_storage().CommitBack();
101 if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
102
103 this->Destroy();
104
105 return res;
106 }
107
108 void AsanThread::SetThreadStackTopAndBottom() {
109 GetThreadStackTopAndBottom(tid() == 0, &stack_top_, &stack_bottom_);
110 int local;
111 CHECK(AddrIsInStack((uptr)&local));
112 }
113
114 void AsanThread::ClearShadowForThreadStack() {
115 PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
116 }
117
118 const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
119 uptr bottom = 0;
120 if (AddrIsInStack(addr)) {
121 bottom = stack_bottom();
122 } else {
123 bottom = fake_stack().AddrIsInFakeStack(addr);
124 CHECK(bottom);
125 *offset = addr - bottom;
126 return (const char *)((uptr*)bottom)[1];
127 }
128 uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr.
129 u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
130 u8 *shadow_bottom = (u8*)MemToShadow(bottom);
131
132 while (shadow_ptr >= shadow_bottom &&
133 *shadow_ptr != kAsanStackLeftRedzoneMagic) {
134 shadow_ptr--;
135 }
136
137 while (shadow_ptr >= shadow_bottom &&
138 *shadow_ptr == kAsanStackLeftRedzoneMagic) {
139 shadow_ptr--;
140 }
141
142 if (shadow_ptr < shadow_bottom) {
143 *offset = 0;
144 return "UNKNOWN";
145 }
146
147 uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
148 CHECK(ptr[0] == kCurrentStackFrameMagic);
149 *offset = addr - (uptr)ptr;
150 return (const char*)ptr[1];
151 }
152
153 } // namespace __asan