blob: 459b2ef9c00463b77c7f1d7033d7681312a6c1c5 [file] [log] [blame]
Kostya Serebryany1e172b42011-11-30 01:07:02 +00001//===-- asan_thread.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// 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"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000017#include "asan_thread.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000018#include "asan_mapping.h"
19
Kostya Serebryany1e172b42011-11-30 01:07:02 +000020namespace __asan {
21
22AsanThread::AsanThread(LinkerInitialized x)
23 : fake_stack_(x),
24 malloc_storage_(x),
25 stats_(x) { }
26
Kostya Serebryanya6b52262012-01-06 19:44:11 +000027AsanThread *AsanThread::Create(int parent_tid, void *(*start_routine) (void *),
28 void *arg) {
29 size_t size = RoundUpTo(sizeof(AsanThread), kPageSize);
30 AsanThread *res = (AsanThread*)AsanMmapSomewhereOrDie(size, __FUNCTION__);
31 res->start_routine_ = start_routine;
32 res->arg_ = arg;
33 return res;
Kostya Serebryany1e172b42011-11-30 01:07:02 +000034}
35
Kostya Serebryanya6b52262012-01-06 19:44:11 +000036void AsanThread::Destroy() {
Kostya Serebryany1e172b42011-11-30 01:07:02 +000037 fake_stack().Cleanup();
38 // We also clear the shadow on thread destruction because
39 // some code may still be executing in later TSD destructors
40 // and we don't want it to have any poisoned stack.
41 ClearShadowForThreadStack();
Kostya Serebryanya6b52262012-01-06 19:44:11 +000042 size_t size = RoundUpTo(sizeof(AsanThread), kPageSize);
43 AsanUnmapOrDie(this, size);
Kostya Serebryany1e172b42011-11-30 01:07:02 +000044}
45
46void AsanThread::ClearShadowForThreadStack() {
47 uintptr_t shadow_bot = MemToShadow(stack_bottom_);
48 uintptr_t shadow_top = MemToShadow(stack_top_);
49 real_memset((void*)shadow_bot, 0, shadow_top - shadow_bot);
50}
51
Kostya Serebryany69eca732011-12-16 19:13:35 +000052void AsanThread::Init() {
Kostya Serebryany1e172b42011-11-30 01:07:02 +000053 SetThreadStackTopAndBottom();
54 fake_stack_.Init(stack_size());
55 if (FLAG_v >= 1) {
56 int local = 0;
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000057 Report("T%d: stack [%p,%p) size 0x%lx; local=%p\n",
Kostya Serebryany1e172b42011-11-30 01:07:02 +000058 tid(), stack_bottom_, stack_top_,
Kostya Serebryanya7e760a2012-01-09 19:18:27 +000059 stack_top_ - stack_bottom_, &local);
Kostya Serebryany1e172b42011-11-30 01:07:02 +000060 }
61
62 CHECK(AddrIsInMem(stack_bottom_));
63 CHECK(AddrIsInMem(stack_top_));
64
65 ClearShadowForThreadStack();
Kostya Serebryany69eca732011-12-16 19:13:35 +000066}
67
68void *AsanThread::ThreadStart() {
69 Init();
Kostya Serebryany1e172b42011-11-30 01:07:02 +000070
71 if (!start_routine_) {
72 // start_routine_ == NULL if we're on the main thread or on one of the
73 // OS X libdispatch worker threads. But nobody is supposed to call
74 // ThreadStart() for the worker threads.
75 CHECK(tid() == 0);
76 return 0;
77 }
78
79 void *res = start_routine_(arg_);
80 malloc_storage().CommitBack();
81
82 if (FLAG_v >= 1) {
83 Report("T%d exited\n", tid());
84 }
85
86 return res;
87}
88
89const char *AsanThread::GetFrameNameByAddr(uintptr_t addr, uintptr_t *offset) {
90 uintptr_t bottom = 0;
91 bool is_fake_stack = false;
92 if (AddrIsInStack(addr)) {
93 bottom = stack_bottom();
94 } else {
95 bottom = fake_stack().AddrIsInFakeStack(addr);
96 CHECK(bottom);
97 is_fake_stack = true;
98 }
99 uintptr_t aligned_addr = addr & ~(__WORDSIZE/8 - 1); // align addr.
100 uintptr_t *ptr = (uintptr_t*)aligned_addr;
101 while (ptr >= (uintptr_t*)bottom) {
102 if (ptr[0] == kCurrentStackFrameMagic ||
103 (is_fake_stack && ptr[0] == kRetiredStackFrameMagic)) {
104 *offset = addr - (uintptr_t)ptr;
105 return (const char*)ptr[1];
106 }
107 ptr--;
108 }
109 *offset = 0;
110 return "UNKNOWN";
111}
112
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000113} // namespace __asan