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