diff options
author | Ed Schouten <ed@FreeBSD.org> | 2013-05-27 18:27:12 +0000 |
---|---|---|
committer | Ed Schouten <ed@FreeBSD.org> | 2013-05-27 18:27:12 +0000 |
commit | 11023dc647fd8f41418da90d59db138400d0f334 (patch) | |
tree | 50f0ab80515576749ef638dd0766b70a65904bfa /lib/tsan/rtl/tsan_platform_linux.cc | |
parent | 58aabf08b77d221489f10e274812ec60917c21a8 (diff) | |
download | src-test2-11023dc647fd8f41418da90d59db138400d0f334.tar.gz src-test2-11023dc647fd8f41418da90d59db138400d0f334.zip |
Notes
Diffstat (limited to 'lib/tsan/rtl/tsan_platform_linux.cc')
-rw-r--r-- | lib/tsan/rtl/tsan_platform_linux.cc | 227 |
1 files changed, 156 insertions, 71 deletions
diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc index 6cc424975125..a0d71e8589d6 100644 --- a/lib/tsan/rtl/tsan_platform_linux.cc +++ b/lib/tsan/rtl/tsan_platform_linux.cc @@ -12,7 +12,9 @@ // Linux-specific code. //===----------------------------------------------------------------------===// -#ifdef __linux__ + +#include "sanitizer_common/sanitizer_platform.h" +#if SANITIZER_LINUX #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" @@ -21,7 +23,6 @@ #include "tsan_rtl.h" #include "tsan_flags.h" -#include <asm/prctl.h> #include <fcntl.h> #include <pthread.h> #include <signal.h> @@ -40,11 +41,16 @@ #include <errno.h> #include <sched.h> #include <dlfcn.h> +#define __need_res_state +#include <resolv.h> +#include <malloc.h> -extern "C" int arch_prctl(int code, __sanitizer::uptr *addr); +extern "C" struct mallinfo __libc_mallinfo(); namespace __tsan { +const uptr kPageSize = 4096; + #ifndef TSAN_GO ScopedInRtl::ScopedInRtl() : thr_(cur_thread()) { @@ -66,8 +72,75 @@ ScopedInRtl::~ScopedInRtl() { } #endif -uptr GetShadowMemoryConsumption() { - return 0; +static bool ishex(char c) { + return (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'f'); +} + +static uptr readhex(const char *p) { + uptr v = 0; + for (; ishex(p[0]); p++) { + if (p[0] >= '0' && p[0] <= '9') + v = v * 16 + p[0] - '0'; + else + v = v * 16 + p[0] - 'a' + 10; + } + return v; +} + +static uptr readdec(const char *p) { + uptr v = 0; + for (; p[0] >= '0' && p[0] <= '9' ; p++) + v = v * 10 + p[0] - '0'; + return v; +} + +void WriteMemoryProfile(char *buf, uptr buf_size) { + char *smaps = 0; + uptr smaps_cap = 0; + uptr smaps_len = ReadFileToBuffer("/proc/self/smaps", + &smaps, &smaps_cap, 64<<20); + uptr mem[6] = {}; + uptr total = 0; + uptr start = 0; + bool file = false; + const char *pos = smaps; + while (pos < smaps + smaps_len) { + if (ishex(pos[0])) { + start = readhex(pos); + for (; *pos != '/' && *pos > '\n'; pos++) {} + file = *pos == '/'; + } else if (internal_strncmp(pos, "Rss:", 4) == 0) { + for (; *pos < '0' || *pos > '9'; pos++) {} + uptr rss = readdec(pos) * 1024; + total += rss; + start >>= 40; + if (start < 0x10) // shadow + mem[0] += rss; + else if (start >= 0x20 && start < 0x30) // compat modules + mem[file ? 1 : 2] += rss; + else if (start >= 0x7e) // modules + mem[file ? 1 : 2] += rss; + else if (start >= 0x60 && start < 0x62) // traces + mem[3] += rss; + else if (start >= 0x7d && start < 0x7e) // heap + mem[4] += rss; + else // other + mem[5] += rss; + } + while (*pos++ != '\n') {} + } + UnmapOrDie(smaps, smaps_cap); + char *buf_pos = buf; + char *buf_end = buf + buf_size; + buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos, + "RSS %zd MB: shadow:%zd file:%zd mmap:%zd trace:%zd heap:%zd other:%zd\n", + total >> 20, mem[0] >> 20, mem[1] >> 20, mem[2] >> 20, + mem[3] >> 20, mem[4] >> 20, mem[5] >> 20); + struct mallinfo mi = __libc_mallinfo(); + buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos, + "mallinfo: arena=%d mmap=%d fordblks=%d keepcost=%d\n", + mi.arena >> 20, mi.hblkhd >> 20, mi.fordblks >> 20, mi.keepcost >> 20); } void FlushShadowMemory() { @@ -89,6 +162,63 @@ static void ProtectRange(uptr beg, uptr end) { #endif #ifndef TSAN_GO +// Mark shadow for .rodata sections with the special kShadowRodata marker. +// Accesses to .rodata can't race, so this saves time, memory and trace space. +static void MapRodata() { + // First create temp file. + const char *tmpdir = GetEnv("TMPDIR"); + if (tmpdir == 0) + tmpdir = GetEnv("TEST_TMPDIR"); +#ifdef P_tmpdir + if (tmpdir == 0) + tmpdir = P_tmpdir; +#endif + if (tmpdir == 0) + return; + char filename[256]; + internal_snprintf(filename, sizeof(filename), "%s/tsan.rodata.%d", + tmpdir, (int)internal_getpid()); + uptr openrv = internal_open(filename, O_RDWR | O_CREAT | O_EXCL, 0600); + if (internal_iserror(openrv)) + return; + fd_t fd = openrv; + // Fill the file with kShadowRodata. + const uptr kMarkerSize = 512 * 1024 / sizeof(u64); + InternalScopedBuffer<u64> marker(kMarkerSize); + for (u64 *p = marker.data(); p < marker.data() + kMarkerSize; p++) + *p = kShadowRodata; + internal_write(fd, marker.data(), marker.size()); + // Map the file into memory. + uptr page = internal_mmap(0, kPageSize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, fd, 0); + if (internal_iserror(page)) { + internal_close(fd); + internal_unlink(filename); + return; + } + // Map the file into shadow of .rodata sections. + MemoryMappingLayout proc_maps(/*cache_enabled*/true); + uptr start, end, offset, prot; + char name[128]; + while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), &prot)) { + if (name[0] != 0 && name[0] != '[' + && (prot & MemoryMappingLayout::kProtectionRead) + && (prot & MemoryMappingLayout::kProtectionExecute) + && !(prot & MemoryMappingLayout::kProtectionWrite) + && IsAppMem(start)) { + // Assume it's .rodata + char *shadow_start = (char*)MemToShadow(start); + char *shadow_end = (char*)MemToShadow(end); + for (char *p = shadow_start; p < shadow_end; p += marker.size()) { + internal_mmap(p, Min<uptr>(marker.size(), shadow_end - p), + PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0); + } + } + } + internal_close(fd); + internal_unlink(filename); +} + void InitializeShadowMemory() { uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg, kLinuxShadowEnd - kLinuxShadowBeg); @@ -115,6 +245,8 @@ void InitializeShadowMemory() { kLinuxAppMemBeg, kLinuxAppMemEnd, (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30); DPrintf("stack %zx\n", (uptr)&shadow); + + MapRodata(); } #endif @@ -124,10 +256,11 @@ static uptr g_data_end; #ifndef TSAN_GO static void CheckPIE() { // Ensure that the binary is indeed compiled with -pie. - MemoryMappingLayout proc_maps; + MemoryMappingLayout proc_maps(true); uptr start, end; if (proc_maps.Next(&start, &end, - /*offset*/0, /*filename*/0, /*filename_size*/0)) { + /*offset*/0, /*filename*/0, /*filename_size*/0, + /*protection*/0)) { if ((u64)start < kLinuxAppMemBeg) { Printf("FATAL: ThreadSanitizer can not mmap the shadow memory (" "something is mapped at 0x%zx < 0x%zx)\n", @@ -140,11 +273,12 @@ static void CheckPIE() { } static void InitDataSeg() { - MemoryMappingLayout proc_maps; + MemoryMappingLayout proc_maps(true); uptr start, end, offset; char name[128]; bool prev_is_data = false; - while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name))) { + while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), + /*protection*/ 0)) { DPrintf("%p-%p %p %s\n", start, end, offset, name); bool is_data = offset != 0 && name[0] != 0; // BSS may get merged with [heap] in /proc/self/maps. This is not very @@ -163,27 +297,6 @@ static void InitDataSeg() { CHECK_LT((uptr)&g_data_start, g_data_end); } -static uptr g_tls_size; - -#ifdef __i386__ -# define INTERNAL_FUNCTION __attribute__((regparm(3), stdcall)) -#else -# define INTERNAL_FUNCTION -#endif - -static int InitTlsSize() { - typedef void (*get_tls_func)(size_t*, size_t*) INTERNAL_FUNCTION; - get_tls_func get_tls; - void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info"); - CHECK_EQ(sizeof(get_tls), sizeof(get_tls_static_info_ptr)); - internal_memcpy(&get_tls, &get_tls_static_info_ptr, - sizeof(get_tls_static_info_ptr)); - CHECK_NE(get_tls, 0); - size_t tls_size = 0; - size_t tls_align = 0; - get_tls(&tls_size, &tls_align); - return tls_size; -} #endif // #ifndef TSAN_GO static rlim_t getlim(int res) { @@ -238,57 +351,29 @@ const char *InitializePlatform() { #ifndef TSAN_GO CheckPIE(); - g_tls_size = (uptr)InitTlsSize(); + InitTlsSize(); InitDataSeg(); #endif - return getenv(kTsanOptionsEnv); -} - -void FinalizePlatform() { - fflush(0); + return GetEnv(kTsanOptionsEnv); } -uptr GetTlsSize() { -#ifndef TSAN_GO - return g_tls_size; -#else - return 0; -#endif +bool IsGlobalVar(uptr addr) { + return g_data_start && addr >= g_data_start && addr < g_data_end; } -void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, - uptr *tls_addr, uptr *tls_size) { #ifndef TSAN_GO - arch_prctl(ARCH_GET_FS, tls_addr); - *tls_addr -= g_tls_size; - *tls_size = g_tls_size; - - uptr stack_top, stack_bottom; - GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); - *stk_addr = stack_bottom; - *stk_size = stack_top - stack_bottom; - - if (!main) { - // If stack and tls intersect, make them non-intersecting. - if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) { - CHECK_GT(*tls_addr + *tls_size, *stk_addr); - CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size); - *stk_size -= *tls_size; - *tls_addr = *stk_addr + *stk_size; - } +int ExtractResolvFDs(void *state, int *fds, int nfd) { + int cnt = 0; + __res_state *statp = (__res_state*)state; + for (int i = 0; i < MAXNS && cnt < nfd; i++) { + if (statp->_u._ext.nsaddrs[i] && statp->_u._ext.nssocks[i] != -1) + fds[cnt++] = statp->_u._ext.nssocks[i]; } -#else - *stk_addr = 0; - *stk_size = 0; - *tls_addr = 0; - *tls_size = 0; -#endif + return cnt; } +#endif -bool IsGlobalVar(uptr addr) { - return g_data_start && addr >= g_data_start && addr < g_data_end; -} } // namespace __tsan -#endif // #ifdef __linux__ +#endif // SANITIZER_LINUX |