From cd271f5440df3016e7f8a339358c57e5ae8468a8 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 5 Jan 2012 00:44:33 +0000 Subject: [PATCH] [asan] implement our own /proc/self/maps reader and use it on linux instead of sysinfo.h llvm-svn: 147581 --- compiler-rt/lib/asan/Makefile.old | 2 -- compiler-rt/lib/asan/asan_internal.h | 12 +++++++ compiler-rt/lib/asan/asan_linux.cc | 54 ++++++++++++++++++++++++++++ compiler-rt/lib/asan/asan_printf.cc | 9 +++++ compiler-rt/lib/asan/asan_rtl.cc | 18 +++++----- compiler-rt/lib/asan/asan_stack.cc | 21 ++++++++++- compiler-rt/lib/asan/asan_thread.cc | 13 +++---- 7 files changed, 108 insertions(+), 21 deletions(-) diff --git a/compiler-rt/lib/asan/Makefile.old b/compiler-rt/lib/asan/Makefile.old index a96ff424fa0d..c68b329cff00 100644 --- a/compiler-rt/lib/asan/Makefile.old +++ b/compiler-rt/lib/asan/Makefile.old @@ -264,7 +264,6 @@ $(BIN)/%_test$(SUFF).o: tests/%_test.mm $(RTL_HDR) $(MAKEFILE) $(BIN)/%$(SUFF).o: %.cc $(RTL_HDR) $(MAKEFILE) $(CXX) $(PIE) $(CFLAGS) -fPIC -c -O2 -fno-exceptions -funwind-tables \ -o $@ -g $< -Ithird_party \ - -DASAN_USE_SYSINFO=1 \ -DASAN_NEEDS_SEGV=$(ASAN_NEEDS_SEGV) \ -DASAN_HAS_EXCEPTIONS=$(ASAN_HAS_EXCEPTIONS) \ -DASAN_FLEXIBLE_MAPPING_AND_OFFSET=$(ASAN_FLEXIBLE_MAPPING_AND_OFFSET) \ @@ -272,7 +271,6 @@ $(BIN)/%$(SUFF).o: %.cc $(RTL_HDR) $(MAKEFILE) $(BIN)/%$(SUFF).o: %.c $(RTL_HDR) $(MAKEFILE) $(CC) $(PIE) $(CFLAGS) -fPIC -c -O2 -o $@ -g $< -Ithird_party \ - -DASAN_USE_SYSINFO=1 \ $(ASAN_FLAGS) ifeq ($(OS),darwin) diff --git a/compiler-rt/lib/asan/asan_internal.h b/compiler-rt/lib/asan/asan_internal.h index d0790a7c8b7b..4207c003e633 100644 --- a/compiler-rt/lib/asan/asan_internal.h +++ b/compiler-rt/lib/asan/asan_internal.h @@ -45,8 +45,12 @@ // If set, sysinfo/sysinfo.h will be used to iterate over /proc/maps. #ifndef ASAN_USE_SYSINFO +#ifdef __linux__ +# define ASAN_USE_SYSINFO 0 +#else # define ASAN_USE_SYSINFO 1 #endif +#endif // If set, asan will install its own SEGV signal handler. #ifndef ASAN_NEEDS_SEGV @@ -99,10 +103,18 @@ ssize_t AsanRead(int fd, void *buf, size_t count); ssize_t AsanWrite(int fd, const void *buf, size_t count); int AsanClose(int fd); +// Opens the file 'file_name" and reads up to 'max_len' bytes. +// The resulting buffer is mmaped and stored in '*buff'. +// The size of the mmaped region is stored in '*buff_size', +// Returns the number of read bytes or -1 if file can not be opened. +ssize_t ReadFileToBuffer(const char *file_name, char **buff, + size_t *buff_size, size_t max_len); + // asan_printf.cc void RawWrite(const char *buffer); int SNPrint(char *buffer, size_t length, const char *format, ...); void Printf(const char *format, ...); +int SScanf(const char *str, const char *format, ...); void Report(const char *format, ...); // Don't use std::min and std::max, to minimize dependency on libstdc++. diff --git a/compiler-rt/lib/asan/asan_linux.cc b/compiler-rt/lib/asan/asan_linux.cc index 26a08ae8f5b6..2a529167d45f 100644 --- a/compiler-rt/lib/asan/asan_linux.cc +++ b/compiler-rt/lib/asan/asan_linux.cc @@ -13,12 +13,15 @@ //===----------------------------------------------------------------------===// #ifdef __linux__ +#include "asan_interceptors.h" #include "asan_internal.h" +#include "asan_procmaps.h" #include #include #include #include +#include #include extern char _DYNAMIC[]; @@ -96,6 +99,57 @@ int AsanClose(int fd) { return close(fd); } +AsanProcMaps::AsanProcMaps() { + proc_self_maps_buff_len_ = + ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_, + &proc_self_maps_buff_mmaped_size_, 1 << 20); + CHECK(proc_self_maps_buff_len_ > 0); + // AsanWrite(2, proc_self_maps_buff_, proc_self_maps_buff_len_); + Reset(); +} + +AsanProcMaps::~AsanProcMaps() { + AsanUnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_); +} + +void AsanProcMaps::Reset() { + current_ = proc_self_maps_buff_; +} + +bool AsanProcMaps::Next(uint64_t *start, uint64_t *end, + uint64_t *offset, char filename[], + size_t filename_size) { + char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_; + if (current_ >= last) return false; + int consumed = 0; + char flags[10]; + int major, minor; + uint64_t inode; + char *next_line = (char*)internal_memchr(current_, '\n', last - current_); + if (next_line == NULL) + next_line = last; + if (SScanf(current_, + "%llx-%llx %4s %llx %x:%x %lld %n", + start, end, flags, offset, &major, &minor, + &inode, &consumed) != 7) + return false; + current_ += consumed; + // Skip spaces. + while (current_ < next_line && *current_ == ' ') + current_++; + // Fill in the filename. + size_t i = 0; + while (current_ < next_line) { + if (filename && i < filename_size - 1) + filename[i++] = *current_; + current_++; + } + if (filename && i < filename_size) + filename[i] = 0; + current_ = next_line + 1; + return true; +} + } // namespace __asan #endif // __linux__ diff --git a/compiler-rt/lib/asan/asan_printf.cc b/compiler-rt/lib/asan/asan_printf.cc index a3d06ff67ad2..b9ef42678409 100644 --- a/compiler-rt/lib/asan/asan_printf.cc +++ b/compiler-rt/lib/asan/asan_printf.cc @@ -18,6 +18,7 @@ #include "asan_interceptors.h" #include +#include namespace __asan { @@ -178,4 +179,12 @@ void Report(const char *format, ...) { RawWrite(buffer); } +int SScanf(const char *str, const char *format, ...) { + va_list args; + va_start(args, format); + int res = vsscanf(str, format, args); + va_end(args); + return res; +} + } // namespace __asan diff --git a/compiler-rt/lib/asan/asan_rtl.cc b/compiler-rt/lib/asan/asan_rtl.cc index c876f6d97f73..583a971850eb 100644 --- a/compiler-rt/lib/asan/asan_rtl.cc +++ b/compiler-rt/lib/asan/asan_rtl.cc @@ -18,6 +18,7 @@ #include "asan_lock.h" #include "asan_mac.h" #include "asan_mapping.h" +#include "asan_procmaps.h" #include "asan_stack.h" #include "asan_stats.h" #include "asan_thread.h" @@ -119,22 +120,19 @@ static void PrintBytes(const char *before, uintptr_t *a) { Printf("\n"); } -// Opens the file 'file_name" and reads up to 'max_len' bytes. -// The resulting buffer is mmaped and stored in '*buff'. -// Returns the number of read bytes or -1 if file can not be opened. -static ssize_t ReadFileToBuffer(const char *file_name, char **buff, - size_t max_len) { +ssize_t ReadFileToBuffer(const char *file_name, char **buff, + size_t *buff_size, size_t max_len) { const size_t kMinFileLen = kPageSize; ssize_t read_len = -1; *buff = 0; - size_t maped_size = 0; + *buff_size = 0; // The files we usually open are not seekable, so try different buffer sizes. for (size_t size = kMinFileLen; size <= max_len; size *= 2) { int fd = AsanOpenReadonly(file_name); if (fd < 0) return -1; - AsanUnmapOrDie(*buff, maped_size); - maped_size = size; + AsanUnmapOrDie(*buff, *buff_size); *buff = (char*)AsanMmapSomewhereOrDie(size, __FUNCTION__); + *buff_size = size; read_len = AsanRead(fd, *buff, size); AsanClose(fd); if (read_len < size) // We've read the whole file. @@ -151,7 +149,9 @@ static const char* GetEnvFromProcSelfEnviron(const char* name) { static bool inited; if (!inited) { inited = true; - len = ReadFileToBuffer("/proc/self/environ", &environ, 1 << 20); + size_t environ_size; + len = ReadFileToBuffer("/proc/self/environ", + &environ, &environ_size, 1 << 20); } if (!environ || len <= 0) return NULL; size_t namelen = internal_strlen(name); diff --git a/compiler-rt/lib/asan/asan_stack.cc b/compiler-rt/lib/asan/asan_stack.cc index 8163983bce7d..24d008104d2d 100644 --- a/compiler-rt/lib/asan/asan_stack.cc +++ b/compiler-rt/lib/asan/asan_stack.cc @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "asan_interceptors.h" #include "asan_lock.h" +#include "asan_procmaps.h" #include "asan_stack.h" #include "asan_thread.h" #include "asan_thread_registry.h" @@ -128,9 +129,27 @@ void AsanStackTrace::PrintStack(uintptr_t *addr, size_t size) { #else // ASAN_USE_SYSINFO void AsanStackTrace::PrintStack(uintptr_t *addr, size_t size) { + AsanProcMaps proc_maps; for (size_t i = 0; i < size && addr[i]; i++) { + proc_maps.Reset(); uintptr_t pc = addr[i]; - Printf(" #%ld 0x%lx\n", i, pc); + uint64_t start, end, offset; + char filename[4096]; + bool found = 0; + int map_idx = 0; + while (proc_maps.Next(&start, &end, &offset, + filename, sizeof(filename))) { + if (pc >= start && pc <= end) { + found = true; + uintptr_t relative_pc = (map_idx == 0) ? pc : (pc - start); + Printf(" #%ld 0x%lx (%s+0x%lx)\n", i, pc, filename, relative_pc); + break; + } + map_idx++; + } + if (!found) { + Printf(" #%ld 0x%lx\n", i, pc); + } } } #endif // ASAN_USE_SYSINFO diff --git a/compiler-rt/lib/asan/asan_thread.cc b/compiler-rt/lib/asan/asan_thread.cc index 329197dd4e25..420c34273d92 100644 --- a/compiler-rt/lib/asan/asan_thread.cc +++ b/compiler-rt/lib/asan/asan_thread.cc @@ -13,14 +13,11 @@ //===----------------------------------------------------------------------===// #include "asan_allocator.h" #include "asan_interceptors.h" +#include "asan_procmaps.h" #include "asan_thread.h" #include "asan_thread_registry.h" #include "asan_mapping.h" -#if ASAN_USE_SYSINFO == 1 -#include "sysinfo/sysinfo.h" -#endif - #include #include #include @@ -126,17 +123,16 @@ void AsanThread::SetThreadStackTopAndBottom() { int local; CHECK(AddrIsInStack((uintptr_t)&local)); #else -#if ASAN_USE_SYSINFO == 1 if (tid() == 0) { // This is the main thread. Libpthread may not be initialized yet. struct rlimit rl; CHECK(getrlimit(RLIMIT_STACK, &rl) == 0); // Find the mapping that contains a stack variable. - ProcMapsIterator it(0); - uint64_t start, end; + AsanProcMaps proc_maps; + uint64_t start, end, offset; uint64_t prev_end = 0; - while (it.Next(&start, &end, NULL, NULL, NULL, NULL)) { + while (proc_maps.Next(&start, &end, &offset, NULL, 0)) { if ((uintptr_t)&rl < end) break; prev_end = end; @@ -155,7 +151,6 @@ void AsanThread::SetThreadStackTopAndBottom() { CHECK(AddrIsInStack((uintptr_t)&rl)); return; } -#endif pthread_attr_t attr; CHECK(pthread_getattr_np(pthread_self(), &attr) == 0); size_t stacksize = 0;