Evgeniy Stepanov | 78c56c3 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 1 | //===-- msan_linux.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 MemorySanitizer. |
| 11 | // |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 12 | // Linux- and FreeBSD-specific code. |
Evgeniy Stepanov | 78c56c3 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 13 | //===----------------------------------------------------------------------===// |
| 14 | |
Evgeniy Stepanov | 24e1372 | 2013-03-19 14:33:38 +0000 | [diff] [blame] | 15 | #include "sanitizer_common/sanitizer_platform.h" |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 16 | #if SANITIZER_FREEBSD || SANITIZER_LINUX |
Evgeniy Stepanov | 78c56c3 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 17 | |
| 18 | #include "msan.h" |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 19 | #include "msan_thread.h" |
Evgeniy Stepanov | 78c56c3 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 20 | |
Reid Kleckner | 0f92deb | 2013-03-11 18:07:42 +0000 | [diff] [blame] | 21 | #include <elf.h> |
| 22 | #include <link.h> |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 23 | #include <pthread.h> |
Evgeniy Stepanov | 78c56c3 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 24 | #include <stdio.h> |
| 25 | #include <stdlib.h> |
| 26 | #include <signal.h> |
| 27 | #include <unistd.h> |
| 28 | #include <unwind.h> |
| 29 | #include <execinfo.h> |
| 30 | #include <sys/time.h> |
| 31 | #include <sys/resource.h> |
| 32 | |
| 33 | #include "sanitizer_common/sanitizer_common.h" |
| 34 | #include "sanitizer_common/sanitizer_procmaps.h" |
| 35 | |
| 36 | namespace __msan { |
| 37 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 38 | void ReportMapRange(const char *descr, uptr beg, uptr size) { |
| 39 | if (size > 0) { |
| 40 | uptr end = beg + size - 1; |
| 41 | VPrintf(1, "%s : %p - %p\n", descr, beg, end); |
Evgeniy Stepanov | 62355e9 | 2013-11-11 09:27:20 +0000 | [diff] [blame] | 42 | } |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 43 | } |
Evgeniy Stepanov | 62355e9 | 2013-11-11 09:27:20 +0000 | [diff] [blame] | 44 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 45 | static bool CheckMemoryRangeAvailability(uptr beg, uptr size) { |
| 46 | if (size > 0) { |
| 47 | uptr end = beg + size - 1; |
| 48 | if (!MemoryRangeIsAvailable(beg, end)) { |
| 49 | Printf("FATAL: Memory range %p - %p is not available.\n", beg, end); |
| 50 | return false; |
| 51 | } |
Evgeniy Stepanov | 78c56c3 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 52 | } |
| 53 | return true; |
| 54 | } |
| 55 | |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 56 | static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) { |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 57 | if (size > 0) { |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 58 | void *addr = MmapNoAccess(beg, size, name); |
| 59 | if (beg == 0 && addr != 0) { |
| 60 | // Depending on the kernel configuration, we may not be able to protect |
| 61 | // the page at address zero. |
| 62 | uptr gap = 16 * GetPageSizeCached(); |
| 63 | beg += gap; |
| 64 | size -= gap; |
| 65 | addr = MmapNoAccess(beg, size, name); |
| 66 | } |
| 67 | if ((uptr)addr != beg) { |
| 68 | uptr end = beg + size - 1; |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 69 | Printf("FATAL: Cannot protect memory range %p - %p.\n", beg, end); |
| 70 | return false; |
| 71 | } |
| 72 | } |
| 73 | return true; |
| 74 | } |
| 75 | |
| 76 | static void CheckMemoryLayoutSanity() { |
| 77 | uptr prev_end = 0; |
| 78 | for (unsigned i = 0; i < kMemoryLayoutSize; ++i) { |
| 79 | uptr start = kMemoryLayout[i].start; |
| 80 | uptr end = kMemoryLayout[i].end; |
| 81 | MappingDesc::Type type = kMemoryLayout[i].type; |
| 82 | CHECK_LT(start, end); |
| 83 | CHECK_EQ(prev_end, start); |
| 84 | CHECK(addr_is_type(start, type)); |
| 85 | CHECK(addr_is_type((start + end) / 2, type)); |
| 86 | CHECK(addr_is_type(end - 1, type)); |
| 87 | if (type == MappingDesc::APP) { |
| 88 | uptr addr = start; |
| 89 | CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); |
| 90 | CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); |
| 91 | CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); |
| 92 | |
| 93 | addr = (start + end) / 2; |
| 94 | CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); |
| 95 | CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); |
| 96 | CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); |
| 97 | |
| 98 | addr = end - 1; |
| 99 | CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); |
| 100 | CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); |
| 101 | CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); |
| 102 | } |
| 103 | prev_end = end; |
| 104 | } |
| 105 | } |
| 106 | |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 107 | bool InitShadow(bool init_origins) { |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 108 | // Let user know mapping parameters first. |
| 109 | VPrintf(1, "__msan_init %p\n", &__msan_init); |
| 110 | for (unsigned i = 0; i < kMemoryLayoutSize; ++i) |
| 111 | VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start, |
| 112 | kMemoryLayout[i].end - 1); |
| 113 | |
| 114 | CheckMemoryLayoutSanity(); |
| 115 | |
| 116 | if (!MEM_IS_APP(&__msan_init)) { |
| 117 | Printf("FATAL: Code %p is out of application range. Non-PIE build?\n", |
| 118 | (uptr)&__msan_init); |
| 119 | return false; |
| 120 | } |
| 121 | |
| 122 | for (unsigned i = 0; i < kMemoryLayoutSize; ++i) { |
| 123 | uptr start = kMemoryLayout[i].start; |
| 124 | uptr end = kMemoryLayout[i].end; |
| 125 | uptr size= end - start; |
| 126 | MappingDesc::Type type = kMemoryLayout[i].type; |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 127 | |
| 128 | bool map = type == MappingDesc::SHADOW || |
| 129 | (init_origins && type == MappingDesc::ORIGIN); |
| 130 | bool protect = type == MappingDesc::INVALID || |
| 131 | (!init_origins && type == MappingDesc::ORIGIN); |
| 132 | CHECK(!(map && protect)); |
| 133 | if (!map && !protect) |
| 134 | CHECK(type == MappingDesc::APP); |
| 135 | if (map) { |
| 136 | if (!CheckMemoryRangeAvailability(start, size)) |
| 137 | return false; |
| 138 | if ((uptr)MmapFixedNoReserve(start, size, kMemoryLayout[i].name) != start) |
| 139 | return false; |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 140 | if (common_flags()->use_madv_dontdump) |
| 141 | DontDumpShadowMemory(start, size); |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 142 | } |
| 143 | if (protect) { |
| 144 | if (!CheckMemoryRangeAvailability(start, size)) |
| 145 | return false; |
| 146 | if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name)) |
| 147 | return false; |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 148 | } |
| 149 | } |
| 150 | |
| 151 | return true; |
| 152 | } |
| 153 | |
Evgeniy Stepanov | 78c56c3 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 154 | void MsanDie() { |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 155 | if (common_flags()->coverage) |
| 156 | __sanitizer_cov_dump(); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 157 | if (death_callback) |
| 158 | death_callback(); |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 159 | internal__exit(flags()->exit_code); |
Evgeniy Stepanov | 78c56c3 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 160 | } |
Evgeniy Stepanov | 99bf1d7 | 2013-01-10 11:17:55 +0000 | [diff] [blame] | 161 | |
| 162 | static void MsanAtExit(void) { |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 163 | if (flags()->print_stats && (flags()->atexit || msan_report_count > 0)) |
| 164 | ReportStats(); |
Evgeniy Stepanov | 99bf1d7 | 2013-01-10 11:17:55 +0000 | [diff] [blame] | 165 | if (msan_report_count > 0) { |
| 166 | ReportAtExitStatistics(); |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 167 | if (flags()->exit_code) _exit(flags()->exit_code); |
Evgeniy Stepanov | 99bf1d7 | 2013-01-10 11:17:55 +0000 | [diff] [blame] | 168 | } |
| 169 | } |
| 170 | |
| 171 | void InstallAtExitHandler() { |
| 172 | atexit(MsanAtExit); |
| 173 | } |
Reid Kleckner | 0f92deb | 2013-03-11 18:07:42 +0000 | [diff] [blame] | 174 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 175 | // ---------------------- TSD ---------------- {{{1 |
| 176 | |
| 177 | static pthread_key_t tsd_key; |
| 178 | static bool tsd_key_inited = false; |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 179 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 180 | void MsanTSDInit(void (*destructor)(void *tsd)) { |
| 181 | CHECK(!tsd_key_inited); |
| 182 | tsd_key_inited = true; |
| 183 | CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); |
| 184 | } |
| 185 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 186 | static THREADLOCAL MsanThread* msan_current_thread; |
| 187 | |
| 188 | MsanThread *GetCurrentThread() { |
| 189 | return msan_current_thread; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 190 | } |
| 191 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 192 | void SetCurrentThread(MsanThread *t) { |
| 193 | // Make sure we do not reset the current MsanThread. |
| 194 | CHECK_EQ(0, msan_current_thread); |
| 195 | msan_current_thread = t; |
| 196 | // Make sure that MsanTSDDtor gets called at the end. |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 197 | CHECK(tsd_key_inited); |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 198 | pthread_setspecific(tsd_key, (void *)t); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 199 | } |
| 200 | |
| 201 | void MsanTSDDtor(void *tsd) { |
| 202 | MsanThread *t = (MsanThread*)tsd; |
| 203 | if (t->destructor_iterations_ > 1) { |
| 204 | t->destructor_iterations_--; |
| 205 | CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); |
| 206 | return; |
| 207 | } |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 208 | msan_current_thread = nullptr; |
| 209 | // Make sure that signal handler can not see a stale current thread pointer. |
| 210 | atomic_signal_fence(memory_order_seq_cst); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 211 | MsanThread::TSDDtor(tsd); |
| 212 | } |
| 213 | |
Alexey Samsonov | ba5e996 | 2013-01-30 07:45:58 +0000 | [diff] [blame] | 214 | } // namespace __msan |
Evgeniy Stepanov | 78c56c3 | 2012-12-11 12:27:27 +0000 | [diff] [blame] | 215 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 216 | #endif // SANITIZER_FREEBSD || SANITIZER_LINUX |