blob: d301a4b87c4f3c2257af2ff19027c6add4519990 [file] [log] [blame]
Alexey Samsonove5f58952012-06-04 13:50:10 +00001//===-- asan_thread.cc ----------------------------------------------------===//
Kostya Serebryany1e172b42011-11-30 01:07:02 +00002//
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"
Kostya Serebryanydf499b42012-01-05 00:44:33 +000016#include "asan_procmaps.h"
Alexey Samsonov55cdfc62012-01-17 06:35:31 +000017#include "asan_stack.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000018#include "asan_thread.h"
Kostya Serebryanyaf344152012-01-11 02:03:16 +000019#include "asan_thread_registry.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000020#include "asan_mapping.h"
Alexey Samsonove5931fd2012-06-07 07:13:46 +000021#include "sanitizer_common/sanitizer_common.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000022
Kostya Serebryany1e172b42011-11-30 01:07:02 +000023namespace __asan {
24
25AsanThread::AsanThread(LinkerInitialized x)
26 : fake_stack_(x),
27 malloc_storage_(x),
28 stats_(x) { }
29
Kostya Serebryanye0cff0b2012-06-06 15:06:58 +000030AsanThread *AsanThread::Create(u32 parent_tid, thread_callback_t start_routine,
Alexey Samsonov55cdfc62012-01-17 06:35:31 +000031 void *arg, AsanStackTrace *stack) {
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000032 uptr size = RoundUpTo(sizeof(AsanThread), kPageSize);
Alexey Samsonova25b3462012-06-06 16:15:07 +000033 AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
Alexey Samsonov55cdfc62012-01-17 06:35:31 +000034 thread->start_routine_ = start_routine;
35 thread->arg_ = arg;
36
37 AsanThreadSummary *summary = new AsanThreadSummary(parent_tid, stack);
38 summary->set_thread(thread);
39 thread->set_summary(summary);
40
41 return thread;
Kostya Serebryany1e172b42011-11-30 01:07:02 +000042}
43
Kostya Serebryanyf58f9982012-02-07 00:27:15 +000044void AsanThreadSummary::TSDDtor(void *tsd) {
45 AsanThreadSummary *summary = (AsanThreadSummary*)tsd;
46 if (FLAG_v >= 1) {
47 Report("T%d TSDDtor\n", summary->tid());
48 }
49 if (summary->thread()) {
50 summary->thread()->Destroy();
51 }
52}
53
Kostya Serebryanya6b52262012-01-06 19:44:11 +000054void AsanThread::Destroy() {
Kostya Serebryanyf58f9982012-02-07 00:27:15 +000055 if (FLAG_v >= 1) {
56 Report("T%d exited\n", tid());
57 }
58
59 asanThreadRegistry().UnregisterThread(this);
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000060 CHECK(summary()->thread() == 0);
Kostya Serebryany1e172b42011-11-30 01:07:02 +000061 // We also clear the shadow on thread destruction because
62 // some code may still be executing in later TSD destructors
63 // and we don't want it to have any poisoned stack.
64 ClearShadowForThreadStack();
Alexey Samsonov55cdfc62012-01-17 06:35:31 +000065 fake_stack().Cleanup();
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000066 uptr size = RoundUpTo(sizeof(AsanThread), kPageSize);
Alexey Samsonova25b3462012-06-06 16:15:07 +000067 UnmapOrDie(this, size);
Kostya Serebryany1e172b42011-11-30 01:07:02 +000068}
69
Kostya Serebryany69eca732011-12-16 19:13:35 +000070void AsanThread::Init() {
Kostya Serebryany1e172b42011-11-30 01:07:02 +000071 SetThreadStackTopAndBottom();
Alexey Samsonov55cdfc62012-01-17 06:35:31 +000072 CHECK(AddrIsInMem(stack_bottom_));
73 CHECK(AddrIsInMem(stack_top_));
74 ClearShadowForThreadStack();
Kostya Serebryany1e172b42011-11-30 01:07:02 +000075 if (FLAG_v >= 1) {
76 int local = 0;
Evgeniy Stepanov739eb792012-03-21 11:32:46 +000077 Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
Alexey Samsonov5bcca4e2012-06-06 10:46:00 +000078 tid(), (void*)stack_bottom_, (void*)stack_top_,
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000079 stack_top_ - stack_bottom_, &local);
Kostya Serebryany1e172b42011-11-30 01:07:02 +000080 }
Alexey Samsonov55cdfc62012-01-17 06:35:31 +000081 fake_stack_.Init(stack_size());
Kostya Serebryany69eca732011-12-16 19:13:35 +000082}
83
Timur Iskhodzhanov600972e2012-02-24 15:28:43 +000084thread_return_t AsanThread::ThreadStart() {
Kostya Serebryany69eca732011-12-16 19:13:35 +000085 Init();
Alexander Potapenkof03d8af2012-04-05 10:54:52 +000086 if (FLAG_use_sigaltstack) SetAlternateSignalStack();
Kostya Serebryany1e172b42011-11-30 01:07:02 +000087
88 if (!start_routine_) {
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000089 // start_routine_ == 0 if we're on the main thread or on one of the
Kostya Serebryany1e172b42011-11-30 01:07:02 +000090 // OS X libdispatch worker threads. But nobody is supposed to call
91 // ThreadStart() for the worker threads.
92 CHECK(tid() == 0);
93 return 0;
94 }
95
Timur Iskhodzhanov600972e2012-02-24 15:28:43 +000096 thread_return_t res = start_routine_(arg_);
Kostya Serebryany1e172b42011-11-30 01:07:02 +000097 malloc_storage().CommitBack();
Alexander Potapenkof03d8af2012-04-05 10:54:52 +000098 if (FLAG_use_sigaltstack) UnsetAlternateSignalStack();
Kostya Serebryany1e172b42011-11-30 01:07:02 +000099
Kostya Serebryanyaf344152012-01-11 02:03:16 +0000100 this->Destroy();
101
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000102 return res;
103}
104
Alexey Samsonove5931fd2012-06-07 07:13:46 +0000105void AsanThread::SetThreadStackTopAndBottom() {
106 GetThreadStackTopAndBottom(tid() == 0, &stack_top_, &stack_bottom_);
107 int local;
108 CHECK(AddrIsInStack((uptr)&local));
109}
110
Alexey Samsonov55cdfc62012-01-17 06:35:31 +0000111void AsanThread::ClearShadowForThreadStack() {
112 PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
113}
114
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000115const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
116 uptr bottom = 0;
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000117 bool is_fake_stack = false;
118 if (AddrIsInStack(addr)) {
119 bottom = stack_bottom();
120 } else {
121 bottom = fake_stack().AddrIsInFakeStack(addr);
122 CHECK(bottom);
123 is_fake_stack = true;
124 }
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000125 uptr aligned_addr = addr & ~(__WORDSIZE/8 - 1); // align addr.
Kostya Serebryanyee392552012-05-31 15:02:07 +0000126 u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
127 u8 *shadow_bottom = (u8*)MemToShadow(bottom);
Evgeniy Stepanov3972ea02012-05-12 12:33:10 +0000128
129 while (shadow_ptr >= shadow_bottom &&
130 *shadow_ptr != kAsanStackLeftRedzoneMagic) {
131 shadow_ptr--;
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000132 }
Evgeniy Stepanov3972ea02012-05-12 12:33:10 +0000133
134 while (shadow_ptr >= shadow_bottom &&
135 *shadow_ptr == kAsanStackLeftRedzoneMagic) {
136 shadow_ptr--;
137 }
138
139 if (shadow_ptr < shadow_bottom) {
140 *offset = 0;
141 return "UNKNOWN";
142 }
143
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000144 uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
Evgeniy Stepanov3972ea02012-05-12 12:33:10 +0000145 CHECK((ptr[0] == kCurrentStackFrameMagic) ||
146 (is_fake_stack && ptr[0] == kRetiredStackFrameMagic));
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000147 *offset = addr - (uptr)ptr;
Evgeniy Stepanov3972ea02012-05-12 12:33:10 +0000148 return (const char*)ptr[1];
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000149}
150
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000151} // namespace __asan