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