1//===-- asan_thread_registry.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// AsanThreadRegistry-related code. AsanThreadRegistry is a container 13// for summaries of all created threads. 14//===----------------------------------------------------------------------===// 15 16#include "asan_stack.h" 17#include "asan_thread.h" 18#include "asan_thread_registry.h" 19#include "sanitizer_common/sanitizer_common.h" 20 21namespace __asan { 22 23static AsanThreadRegistry asan_thread_registry(LINKER_INITIALIZED); 24 25AsanThreadRegistry &asanThreadRegistry() { 26 return asan_thread_registry; 27} 28 29AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x) 30 : main_thread_(x), 31 main_thread_summary_(x), 32 accumulated_stats_(x), 33 mu_(x) { } 34 35void AsanThreadRegistry::Init() { 36 AsanTSDInit(AsanThreadSummary::TSDDtor); 37 main_thread_.set_summary(&main_thread_summary_); 38 main_thread_summary_.set_thread(&main_thread_); 39 RegisterThread(&main_thread_); 40 SetCurrent(&main_thread_); 41 // At this point only one thread exists. 42 inited_ = true; 43} 44 45void AsanThreadRegistry::RegisterThread(AsanThread *thread) { 46 ScopedLock lock(&mu_); 47 u32 tid = n_threads_; 48 n_threads_++; 49 CHECK(n_threads_ < kMaxNumberOfThreads); 50 51 AsanThreadSummary *summary = thread->summary(); 52 CHECK(summary != 0); 53 summary->set_tid(tid); 54 thread_summaries_[tid] = summary; 55} 56 57void AsanThreadRegistry::UnregisterThread(AsanThread *thread) { 58 ScopedLock lock(&mu_); 59 FlushToAccumulatedStatsUnlocked(&thread->stats()); 60 AsanThreadSummary *summary = thread->summary(); 61 CHECK(summary); 62 summary->set_thread(0); 63} 64 65AsanThread *AsanThreadRegistry::GetMain() { 66 return &main_thread_; 67} 68 69AsanThread *AsanThreadRegistry::GetCurrent() { 70 AsanThreadSummary *summary = (AsanThreadSummary *)AsanTSDGet(); 71 if (!summary) { 72#if ASAN_ANDROID 73 // On Android, libc constructor is called _after_ asan_init, and cleans up 74 // TSD. Try to figure out if this is still the main thread by the stack 75 // address. We are not entirely sure that we have correct main thread 76 // limits, so only do this magic on Android, and only if the found thread is 77 // the main thread. 78 AsanThread* thread = FindThreadByStackAddress((uptr)&summary); 79 if (thread && thread->tid() == 0) { 80 SetCurrent(thread); 81 return thread; 82 } 83#endif 84 return 0; 85 } 86 return summary->thread(); 87} 88 89void AsanThreadRegistry::SetCurrent(AsanThread *t) { 90 CHECK(t->summary()); 91 if (flags()->verbosity >= 2) { 92 Report("SetCurrent: %p for thread %p\n", 93 t->summary(), (void*)GetThreadSelf()); 94 } 95 // Make sure we do not reset the current AsanThread. 96 CHECK(AsanTSDGet() == 0); 97 AsanTSDSet(t->summary()); 98 CHECK(AsanTSDGet() == t->summary()); 99} 100 101AsanStats &AsanThreadRegistry::GetCurrentThreadStats() { 102 AsanThread *t = GetCurrent(); 103 return (t) ? t->stats() : main_thread_.stats(); 104} 105 106AsanStats AsanThreadRegistry::GetAccumulatedStats() { 107 ScopedLock lock(&mu_); 108 UpdateAccumulatedStatsUnlocked(); 109 return accumulated_stats_; 110} 111 112uptr AsanThreadRegistry::GetCurrentAllocatedBytes() { 113 ScopedLock lock(&mu_); 114 UpdateAccumulatedStatsUnlocked(); 115 return accumulated_stats_.malloced - accumulated_stats_.freed; 116} 117 118uptr AsanThreadRegistry::GetHeapSize() { 119 ScopedLock lock(&mu_); 120 UpdateAccumulatedStatsUnlocked(); 121 return accumulated_stats_.mmaped; 122} 123 124uptr AsanThreadRegistry::GetFreeBytes() { 125 ScopedLock lock(&mu_); 126 UpdateAccumulatedStatsUnlocked(); 127 return accumulated_stats_.mmaped 128 - accumulated_stats_.malloced 129 - accumulated_stats_.malloced_redzones 130 + accumulated_stats_.really_freed 131 + accumulated_stats_.really_freed_redzones; 132} 133 134AsanThreadSummary *AsanThreadRegistry::FindByTid(u32 tid) { 135 CHECK(tid < n_threads_); 136 CHECK(thread_summaries_[tid]); 137 return thread_summaries_[tid]; 138} 139 140AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uptr addr) { 141 ScopedLock lock(&mu_); 142 for (u32 tid = 0; tid < n_threads_; tid++) { 143 AsanThread *t = thread_summaries_[tid]->thread(); 144 if (!t || !(t->fake_stack().StackSize())) continue; 145 if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) { 146 return t; 147 } 148 } 149 return 0; 150} 151 152void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() { 153 for (u32 tid = 0; tid < n_threads_; tid++) { 154 AsanThread *t = thread_summaries_[tid]->thread(); 155 if (t != 0) { 156 FlushToAccumulatedStatsUnlocked(&t->stats()); 157 } 158 } 159} 160 161void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) { 162 // AsanStats consists of variables of type uptr only. 163 uptr *dst = (uptr*)&accumulated_stats_; 164 uptr *src = (uptr*)stats; 165 uptr num_fields = sizeof(AsanStats) / sizeof(uptr); 166 for (uptr i = 0; i < num_fields; i++) { 167 dst[i] += src[i]; 168 src[i] = 0; 169 } 170} 171 172} // namespace __asan 173