2012-10-29 Wei Mi <wmi@google.com>
[official-gcc.git] / libasan / asan_thread.cc
blob9295c1570ecf9f611daab53e91950ea9f14f7401
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 size = RoundUpTo(sizeof(AsanThread), kPageSize);
30 AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
31 thread->start_routine_ = start_routine;
32 thread->arg_ = arg;
34 const uptr kSummaryAllocSize = kPageSize;
35 CHECK_LE(sizeof(AsanThreadSummary), kSummaryAllocSize);
36 AsanThreadSummary *summary =
37 (AsanThreadSummary*)MmapOrDie(kPageSize, "AsanThreadSummary");
38 summary->Init(parent_tid, stack);
39 summary->set_thread(thread);
40 thread->set_summary(summary);
42 return thread;
45 void AsanThreadSummary::TSDDtor(void *tsd) {
46 AsanThreadSummary *summary = (AsanThreadSummary*)tsd;
47 if (flags()->verbosity >= 1) {
48 Report("T%d TSDDtor\n", summary->tid());
50 if (summary->thread()) {
51 summary->thread()->Destroy();
55 void AsanThread::Destroy() {
56 if (flags()->verbosity >= 1) {
57 Report("T%d exited\n", tid());
60 asanThreadRegistry().UnregisterThread(this);
61 CHECK(summary()->thread() == 0);
62 // We also clear the shadow on thread destruction because
63 // some code may still be executing in later TSD destructors
64 // and we don't want it to have any poisoned stack.
65 ClearShadowForThreadStack();
66 fake_stack().Cleanup();
67 uptr size = RoundUpTo(sizeof(AsanThread), kPageSize);
68 UnmapOrDie(this, size);
71 void AsanThread::Init() {
72 SetThreadStackTopAndBottom();
73 CHECK(AddrIsInMem(stack_bottom_));
74 CHECK(AddrIsInMem(stack_top_));
75 ClearShadowForThreadStack();
76 if (flags()->verbosity >= 1) {
77 int local = 0;
78 Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
79 tid(), (void*)stack_bottom_, (void*)stack_top_,
80 stack_top_ - stack_bottom_, &local);
82 fake_stack_.Init(stack_size());
83 AsanPlatformThreadInit();
86 thread_return_t AsanThread::ThreadStart() {
87 Init();
88 if (flags()->use_sigaltstack) SetAlternateSignalStack();
90 if (!start_routine_) {
91 // start_routine_ == 0 if we're on the main thread or on one of the
92 // OS X libdispatch worker threads. But nobody is supposed to call
93 // ThreadStart() for the worker threads.
94 CHECK(tid() == 0);
95 return 0;
98 thread_return_t res = start_routine_(arg_);
99 malloc_storage().CommitBack();
100 if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
102 this->Destroy();
104 return res;
107 void AsanThread::SetThreadStackTopAndBottom() {
108 GetThreadStackTopAndBottom(tid() == 0, &stack_top_, &stack_bottom_);
109 int local;
110 CHECK(AddrIsInStack((uptr)&local));
113 void AsanThread::ClearShadowForThreadStack() {
114 PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
117 const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
118 uptr bottom = 0;
119 bool is_fake_stack = false;
120 if (AddrIsInStack(addr)) {
121 bottom = stack_bottom();
122 } else {
123 bottom = fake_stack().AddrIsInFakeStack(addr);
124 CHECK(bottom);
125 is_fake_stack = true;
127 uptr aligned_addr = addr & ~(__WORDSIZE/8 - 1); // align addr.
128 u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
129 u8 *shadow_bottom = (u8*)MemToShadow(bottom);
131 while (shadow_ptr >= shadow_bottom &&
132 *shadow_ptr != kAsanStackLeftRedzoneMagic) {
133 shadow_ptr--;
136 while (shadow_ptr >= shadow_bottom &&
137 *shadow_ptr == kAsanStackLeftRedzoneMagic) {
138 shadow_ptr--;
141 if (shadow_ptr < shadow_bottom) {
142 *offset = 0;
143 return "UNKNOWN";
146 uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
147 CHECK((ptr[0] == kCurrentStackFrameMagic) ||
148 (is_fake_stack && ptr[0] == kRetiredStackFrameMagic));
149 *offset = addr - (uptr)ptr;
150 return (const char*)ptr[1];
153 } // namespace __asan