asan_thread_registry.cc revision cc4e6862c6a8f8f3ead96bd32b815184a36faded
1//===-- asan_thread_registry.cc ---------------------------------*- C++ -*-===// 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 20namespace __asan { 21 22static AsanThreadRegistry asan_thread_registry(__asan::LINKER_INITIALIZED); 23 24AsanThreadRegistry &asanThreadRegistry() { 25 return asan_thread_registry; 26} 27 28AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x) 29 : main_thread_(x), 30 main_thread_summary_(x), 31 accumulated_stats_(x), 32 mu_(x) { } 33 34void AsanThreadRegistry::Init() { 35 AsanTSDInit(); 36 main_thread_.set_summary(&main_thread_summary_); 37 main_thread_summary_.set_thread(&main_thread_); 38 SetCurrent(&main_thread_); 39 thread_summaries_[0] = &main_thread_summary_; 40 n_threads_ = 1; 41} 42 43void AsanThreadRegistry::RegisterThread(AsanThread *thread, int parent_tid, 44 AsanStackTrace *stack) { 45 ScopedLock lock(&mu_); 46 CHECK(n_threads_ > 0); 47 int tid = n_threads_; 48 n_threads_++; 49 CHECK(n_threads_ < kMaxNumberOfThreads); 50 AsanThreadSummary *summary = new AsanThreadSummary(tid, parent_tid, stack); 51 summary->set_thread(thread); 52 thread_summaries_[tid] = summary; 53 thread->set_summary(summary); 54} 55 56void AsanThreadRegistry::UnregisterThread(AsanThread *thread) { 57 ScopedLock lock(&mu_); 58 FlushToAccumulatedStatsUnlocked(&thread->stats()); 59 AsanThreadSummary *summary = thread->summary(); 60 CHECK(summary); 61 summary->set_thread(NULL); 62} 63 64AsanThread *AsanThreadRegistry::GetMain() { 65 return &main_thread_; 66} 67 68AsanThread *AsanThreadRegistry::GetCurrent() { 69 AsanThreadSummary *summary = (AsanThreadSummary *)AsanTSDGet(); 70 if (!summary) return 0; 71 return summary->thread(); 72} 73 74void AsanThreadRegistry::SetCurrent(AsanThread *t) { 75 CHECK(t->summary()); 76 if (FLAG_v >= 2) { 77 Report("SetCurrent: %p for thread %p\n", t->summary(), GetThreadSelf()); 78 } 79 // Make sure we do not reset the current AsanThread. 80 CHECK(AsanTSDGet() == 0); 81 AsanTSDSet(t->summary()); 82 CHECK(AsanTSDGet() == t->summary()); 83} 84 85AsanStats &AsanThreadRegistry::GetCurrentThreadStats() { 86 AsanThread *t = GetCurrent(); 87 return (t) ? t->stats() : main_thread_.stats(); 88} 89 90AsanStats AsanThreadRegistry::GetAccumulatedStats() { 91 ScopedLock lock(&mu_); 92 UpdateAccumulatedStatsUnlocked(); 93 return accumulated_stats_; 94} 95 96size_t AsanThreadRegistry::GetCurrentAllocatedBytes() { 97 ScopedLock lock(&mu_); 98 UpdateAccumulatedStatsUnlocked(); 99 return accumulated_stats_.malloced - accumulated_stats_.freed; 100} 101 102size_t AsanThreadRegistry::GetHeapSize() { 103 ScopedLock lock(&mu_); 104 UpdateAccumulatedStatsUnlocked(); 105 return accumulated_stats_.mmaped; 106} 107 108size_t AsanThreadRegistry::GetFreeBytes() { 109 ScopedLock lock(&mu_); 110 UpdateAccumulatedStatsUnlocked(); 111 return accumulated_stats_.mmaped 112 - accumulated_stats_.malloced 113 - accumulated_stats_.malloced_redzones 114 + accumulated_stats_.really_freed 115 + accumulated_stats_.really_freed_redzones; 116} 117 118AsanThreadSummary *AsanThreadRegistry::FindByTid(int tid) { 119 CHECK(tid >= 0); 120 CHECK(tid < n_threads_); 121 CHECK(thread_summaries_[tid]); 122 return thread_summaries_[tid]; 123} 124 125AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uintptr_t addr) { 126 ScopedLock lock(&mu_); 127 for (int tid = 0; tid < n_threads_; tid++) { 128 AsanThread *t = thread_summaries_[tid]->thread(); 129 if (!t) continue; 130 if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) { 131 return t; 132 } 133 } 134 return 0; 135} 136 137void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() { 138 for (int tid = 0; tid < n_threads_; tid++) { 139 AsanThread *t = thread_summaries_[tid]->thread(); 140 if (t != NULL) { 141 FlushToAccumulatedStatsUnlocked(&t->stats()); 142 } 143 } 144} 145 146void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) { 147 // AsanStats consists of variables of type size_t only. 148 size_t *dst = (size_t*)&accumulated_stats_; 149 size_t *src = (size_t*)stats; 150 size_t num_fields = sizeof(AsanStats) / sizeof(size_t); 151 for (size_t i = 0; i < num_fields; i++) { 152 dst[i] += src[i]; 153 src[i] = 0; 154 } 155} 156 157} // namespace __asan 158