asan_thread.cc revision 238901
1238901Sandrew//===-- asan_thread.cc ----------------------------------------------------===//
2229109Sed//
3229109Sed//                     The LLVM Compiler Infrastructure
4229109Sed//
5229109Sed// This file is distributed under the University of Illinois Open Source
6229109Sed// License. See LICENSE.TXT for details.
7229109Sed//
8229109Sed//===----------------------------------------------------------------------===//
9229109Sed//
10229109Sed// This file is a part of AddressSanitizer, an address sanity checker.
11229109Sed//
12229109Sed// Thread-related code.
13229109Sed//===----------------------------------------------------------------------===//
14229109Sed#include "asan_allocator.h"
15229109Sed#include "asan_interceptors.h"
16238901Sandrew#include "asan_stack.h"
17229109Sed#include "asan_thread.h"
18229109Sed#include "asan_thread_registry.h"
19229109Sed#include "asan_mapping.h"
20238901Sandrew#include "sanitizer_common/sanitizer_common.h"
21229109Sed
22229109Sednamespace __asan {
23229109Sed
24229109SedAsanThread::AsanThread(LinkerInitialized x)
25229109Sed    : fake_stack_(x),
26229109Sed      malloc_storage_(x),
27229109Sed      stats_(x) { }
28229109Sed
29238901Sandrewstatic AsanLock mu_for_thread_summary(LINKER_INITIALIZED);
30238901Sandrewstatic LowLevelAllocator allocator_for_thread_summary(LINKER_INITIALIZED);
31238901Sandrew
32238901SandrewAsanThread *AsanThread::Create(u32 parent_tid, thread_callback_t start_routine,
33238901Sandrew                               void *arg, AsanStackTrace *stack) {
34238901Sandrew  uptr size = RoundUpTo(sizeof(AsanThread), kPageSize);
35238901Sandrew  AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
36238901Sandrew  thread->start_routine_ = start_routine;
37238901Sandrew  thread->arg_ = arg;
38238901Sandrew
39238901Sandrew  const uptr kSummaryAllocSize = 1024;
40238901Sandrew  CHECK_LE(sizeof(AsanThreadSummary), kSummaryAllocSize);
41238901Sandrew  AsanThreadSummary *summary;
42238901Sandrew  {
43238901Sandrew    ScopedLock lock(&mu_for_thread_summary);
44238901Sandrew    summary = (AsanThreadSummary*)
45238901Sandrew        allocator_for_thread_summary.Allocate(kSummaryAllocSize);
46238901Sandrew  }
47238901Sandrew  summary->Init(parent_tid, stack);
48238901Sandrew  summary->set_thread(thread);
49238901Sandrew  thread->set_summary(summary);
50238901Sandrew
51238901Sandrew  return thread;
52229109Sed}
53229109Sed
54238901Sandrewvoid AsanThreadSummary::TSDDtor(void *tsd) {
55238901Sandrew  AsanThreadSummary *summary = (AsanThreadSummary*)tsd;
56238901Sandrew  if (flags()->verbosity >= 1) {
57238901Sandrew    Report("T%d TSDDtor\n", summary->tid());
58238901Sandrew  }
59238901Sandrew  if (summary->thread()) {
60238901Sandrew    summary->thread()->Destroy();
61238901Sandrew  }
62238901Sandrew}
63238901Sandrew
64238901Sandrewvoid AsanThread::Destroy() {
65238901Sandrew  if (flags()->verbosity >= 1) {
66238901Sandrew    Report("T%d exited\n", tid());
67238901Sandrew  }
68238901Sandrew
69229109Sed  asanThreadRegistry().UnregisterThread(this);
70238901Sandrew  CHECK(summary()->thread() == 0);
71229109Sed  // We also clear the shadow on thread destruction because
72229109Sed  // some code may still be executing in later TSD destructors
73229109Sed  // and we don't want it to have any poisoned stack.
74229109Sed  ClearShadowForThreadStack();
75238901Sandrew  fake_stack().Cleanup();
76238901Sandrew  uptr size = RoundUpTo(sizeof(AsanThread), kPageSize);
77238901Sandrew  UnmapOrDie(this, size);
78229109Sed}
79229109Sed
80229109Sedvoid AsanThread::Init() {
81229109Sed  SetThreadStackTopAndBottom();
82229109Sed  CHECK(AddrIsInMem(stack_bottom_));
83229109Sed  CHECK(AddrIsInMem(stack_top_));
84229109Sed  ClearShadowForThreadStack();
85238901Sandrew  if (flags()->verbosity >= 1) {
86238901Sandrew    int local = 0;
87238901Sandrew    Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
88238901Sandrew           tid(), (void*)stack_bottom_, (void*)stack_top_,
89238901Sandrew           stack_top_ - stack_bottom_, &local);
90238901Sandrew  }
91238901Sandrew  fake_stack_.Init(stack_size());
92238901Sandrew  AsanPlatformThreadInit();
93229109Sed}
94229109Sed
95238901Sandrewthread_return_t AsanThread::ThreadStart() {
96229109Sed  Init();
97238901Sandrew  if (flags()->use_sigaltstack) SetAlternateSignalStack();
98229109Sed
99229109Sed  if (!start_routine_) {
100238901Sandrew    // start_routine_ == 0 if we're on the main thread or on one of the
101229109Sed    // OS X libdispatch worker threads. But nobody is supposed to call
102229109Sed    // ThreadStart() for the worker threads.
103229109Sed    CHECK(tid() == 0);
104229109Sed    return 0;
105229109Sed  }
106229109Sed
107238901Sandrew  thread_return_t res = start_routine_(arg_);
108229109Sed  malloc_storage().CommitBack();
109238901Sandrew  if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
110229109Sed
111238901Sandrew  this->Destroy();
112229109Sed
113229109Sed  return res;
114229109Sed}
115229109Sed
116238901Sandrewvoid AsanThread::SetThreadStackTopAndBottom() {
117238901Sandrew  GetThreadStackTopAndBottom(tid() == 0, &stack_top_, &stack_bottom_);
118238901Sandrew  int local;
119238901Sandrew  CHECK(AddrIsInStack((uptr)&local));
120238901Sandrew}
121238901Sandrew
122238901Sandrewvoid AsanThread::ClearShadowForThreadStack() {
123238901Sandrew  PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
124238901Sandrew}
125238901Sandrew
126238901Sandrewconst char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
127238901Sandrew  uptr bottom = 0;
128229109Sed  bool is_fake_stack = false;
129229109Sed  if (AddrIsInStack(addr)) {
130229109Sed    bottom = stack_bottom();
131229109Sed  } else {
132229109Sed    bottom = fake_stack().AddrIsInFakeStack(addr);
133229109Sed    CHECK(bottom);
134229109Sed    is_fake_stack = true;
135229109Sed  }
136238901Sandrew  uptr aligned_addr = addr & ~(__WORDSIZE/8 - 1);  // align addr.
137238901Sandrew  u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
138238901Sandrew  u8 *shadow_bottom = (u8*)MemToShadow(bottom);
139238901Sandrew
140238901Sandrew  while (shadow_ptr >= shadow_bottom &&
141238901Sandrew      *shadow_ptr != kAsanStackLeftRedzoneMagic) {
142238901Sandrew    shadow_ptr--;
143229109Sed  }
144229109Sed
145238901Sandrew  while (shadow_ptr >= shadow_bottom &&
146238901Sandrew      *shadow_ptr == kAsanStackLeftRedzoneMagic) {
147238901Sandrew    shadow_ptr--;
148238901Sandrew  }
149229109Sed
150238901Sandrew  if (shadow_ptr < shadow_bottom) {
151238901Sandrew    *offset = 0;
152238901Sandrew    return "UNKNOWN";
153229109Sed  }
154229109Sed
155238901Sandrew  uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
156238901Sandrew  CHECK((ptr[0] == kCurrentStackFrameMagic) ||
157238901Sandrew      (is_fake_stack && ptr[0] == kRetiredStackFrameMagic));
158238901Sandrew  *offset = addr - (uptr)ptr;
159238901Sandrew  return (const char*)ptr[1];
160229109Sed}
161229109Sed
162229109Sed}  // namespace __asan
163