2013-02-04 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / libsanitizer / asan / asan_thread.cc
blob02f49dd59ef9fbb19960605a1ed64e4ac8aea8a1
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"
20 namespace __asan {
22 AsanThread::AsanThread(LinkerInitialized x)
23 : fake_stack_(x),
24 malloc_storage_(x),
25 stats_(x) { }
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;
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);
43 return thread;
46 void AsanThreadSummary::TSDDtor(void *tsd) {
47 AsanThreadSummary *summary = (AsanThreadSummary*)tsd;
48 if (flags()->verbosity >= 1) {
49 Report("T%d TSDDtor\n", summary->tid());
51 if (summary->thread()) {
52 summary->thread()->Destroy();
56 void AsanThread::Destroy() {
57 if (flags()->verbosity >= 1) {
58 Report("T%d exited\n", tid());
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);
72 void AsanThread::Init() {
73 SetThreadStackTopAndBottom();
74 CHECK(AddrIsInMem(stack_bottom_));
75 CHECK(AddrIsInMem(stack_top_ - 1));
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);
83 fake_stack_.Init(stack_size());
84 AsanPlatformThreadInit();
87 thread_return_t AsanThread::ThreadStart() {
88 Init();
89 if (flags()->use_sigaltstack) SetAlternateSignalStack();
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;
99 thread_return_t res = start_routine_(arg_);
100 malloc_storage().CommitBack();
101 if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
103 this->Destroy();
105 return res;
108 void AsanThread::SetThreadStackTopAndBottom() {
109 GetThreadStackTopAndBottom(tid() == 0, &stack_top_, &stack_bottom_);
110 int local;
111 CHECK(AddrIsInStack((uptr)&local));
114 void AsanThread::ClearShadowForThreadStack() {
115 PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
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];
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);
132 while (shadow_ptr >= shadow_bottom &&
133 *shadow_ptr != kAsanStackLeftRedzoneMagic) {
134 shadow_ptr--;
137 while (shadow_ptr >= shadow_bottom &&
138 *shadow_ptr == kAsanStackLeftRedzoneMagic) {
139 shadow_ptr--;
142 if (shadow_ptr < shadow_bottom) {
143 *offset = 0;
144 return "UNKNOWN";
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];
153 } // namespace __asan