diff options
| -rw-r--r-- | compiler-rt/lib/asan/asan_linux.cc | 65 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_mac.cc | 121 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_posix.cc | 5 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_procmaps.h | 48 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_stack.cc | 3 | ||||
| -rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_linux.cc | 63 | ||||
| -rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_mac.cc | 122 | ||||
| -rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h | 71 |
8 files changed, 263 insertions, 235 deletions
diff --git a/compiler-rt/lib/asan/asan_linux.cc b/compiler-rt/lib/asan/asan_linux.cc index b59a0a5104b..947c17f708f 100644 --- a/compiler-rt/lib/asan/asan_linux.cc +++ b/compiler-rt/lib/asan/asan_linux.cc @@ -19,6 +19,7 @@ #include "asan_procmaps.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_procmaps.h" #include <sys/time.h> #include <sys/resource.h> @@ -116,68 +117,6 @@ const char* AsanGetEnv(const char* name) { return 0; // Not found. } -AsanProcMaps::AsanProcMaps() { - proc_self_maps_buff_len_ = - ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_, - &proc_self_maps_buff_mmaped_size_, 1 << 26); - CHECK(proc_self_maps_buff_len_ > 0); - // internal_write(2, proc_self_maps_buff_, proc_self_maps_buff_len_); - Reset(); -} - -AsanProcMaps::~AsanProcMaps() { - UnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_); -} - -void AsanProcMaps::Reset() { - current_ = proc_self_maps_buff_; -} - -bool AsanProcMaps::Next(uptr *start, uptr *end, - uptr *offset, char filename[], - uptr 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; - uptr inode; - uptr dummy; - if (!start) start = &dummy; - if (!end) end = &dummy; - if (!offset) offset = &dummy; - char *next_line = (char*)internal_memchr(current_, '\n', last - current_); - if (next_line == 0) - next_line = last; - if (internal_sscanf(current_, - "%lx-%lx %4s %lx %x:%x %ld %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. - uptr 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; -} - -// Gets the object name and the offset by walking AsanProcMaps. -bool AsanProcMaps::GetObjectNameAndOffset(uptr addr, uptr *offset, - char filename[], - uptr filename_size) { - return IterateForObjectNameAndOffset(addr, offset, filename, filename_size); -} - void AsanThread::SetThreadStackTopAndBottom() { if (tid() == 0) { // This is the main thread. Libpthread may not be initialized yet. @@ -185,7 +124,7 @@ void AsanThread::SetThreadStackTopAndBottom() { CHECK(getrlimit(RLIMIT_STACK, &rl) == 0); // Find the mapping that contains a stack variable. - AsanProcMaps proc_maps; + ProcessMaps proc_maps; uptr start, end, offset; uptr prev_end = 0; while (proc_maps.Next(&start, &end, &offset, 0, 0)) { diff --git a/compiler-rt/lib/asan/asan_mac.cc b/compiler-rt/lib/asan/asan_mac.cc index 3e2c9bfa01f..644fbd9af0c 100644 --- a/compiler-rt/lib/asan/asan_mac.cc +++ b/compiler-rt/lib/asan/asan_mac.cc @@ -132,127 +132,6 @@ const char *AsanGetEnv(const char *name) { return 0; } -AsanProcMaps::AsanProcMaps() { - Reset(); -} - -AsanProcMaps::~AsanProcMaps() { -} - -// More information about Mach-O headers can be found in mach-o/loader.h -// Each Mach-O image has a header (mach_header or mach_header_64) starting with -// a magic number, and a list of linker load commands directly following the -// header. -// A load command is at least two 32-bit words: the command type and the -// command size in bytes. We're interested only in segment load commands -// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped -// into the task's address space. -// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or -// segment_command_64 correspond to the memory address, memory size and the -// file offset of the current memory segment. -// Because these fields are taken from the images as is, one needs to add -// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime. - -void AsanProcMaps::Reset() { - // Count down from the top. - // TODO(glider): as per man 3 dyld, iterating over the headers with - // _dyld_image_count is thread-unsafe. We need to register callbacks for - // adding and removing images which will invalidate the AsanProcMaps state. - current_image_ = _dyld_image_count(); - current_load_cmd_count_ = -1; - current_load_cmd_addr_ = 0; - current_magic_ = 0; -} - -// Next and NextSegmentLoad were inspired by base/sysinfo.cc in -// Google Perftools, http://code.google.com/p/google-perftools. - -// NextSegmentLoad scans the current image for the next segment load command -// and returns the start and end addresses and file offset of the corresponding -// segment. -// Note that the segment addresses are not necessarily sorted. -template<u32 kLCSegment, typename SegmentCommand> -bool AsanProcMaps::NextSegmentLoad( - uptr *start, uptr *end, uptr *offset, - char filename[], uptr filename_size) { - const char* lc = current_load_cmd_addr_; - current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize; - if (((const load_command *)lc)->cmd == kLCSegment) { - const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); - const SegmentCommand* sc = (const SegmentCommand *)lc; - if (start) *start = sc->vmaddr + dlloff; - if (end) *end = sc->vmaddr + sc->vmsize + dlloff; - if (offset) *offset = sc->fileoff; - if (filename) { - REAL(strncpy)(filename, _dyld_get_image_name(current_image_), - filename_size); - } - if (FLAG_v >= 4) - Report("LC_SEGMENT: %p--%p %s+%p\n", (void*)*start, (void*)*end, - filename, (void*)*offset); - return true; - } - return false; -} - -bool AsanProcMaps::Next(uptr *start, uptr *end, - uptr *offset, char filename[], - uptr filename_size) { - for (; current_image_ >= 0; current_image_--) { - const mach_header* hdr = _dyld_get_image_header(current_image_); - if (!hdr) continue; - if (current_load_cmd_count_ < 0) { - // Set up for this image; - current_load_cmd_count_ = hdr->ncmds; - current_magic_ = hdr->magic; - switch (current_magic_) { -#ifdef MH_MAGIC_64 - case MH_MAGIC_64: { - current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64); - break; - } -#endif - case MH_MAGIC: { - current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header); - break; - } - default: { - continue; - } - } - } - - for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) { - switch (current_magic_) { - // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64. -#ifdef MH_MAGIC_64 - case MH_MAGIC_64: { - if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>( - start, end, offset, filename, filename_size)) - return true; - break; - } -#endif - case MH_MAGIC: { - if (NextSegmentLoad<LC_SEGMENT, struct segment_command>( - start, end, offset, filename, filename_size)) - return true; - break; - } - } - } - // If we get here, no more load_cmd's in this image talk about - // segments. Go on to the next image. - } - return false; -} - -bool AsanProcMaps::GetObjectNameAndOffset(uptr addr, uptr *offset, - char filename[], - uptr filename_size) { - return IterateForObjectNameAndOffset(addr, offset, filename, filename_size); -} - void AsanThread::SetThreadStackTopAndBottom() { uptr stacksize = pthread_get_stacksize_np(pthread_self()); void *stackaddr = pthread_get_stackaddr_np(pthread_self()); diff --git a/compiler-rt/lib/asan/asan_posix.cc b/compiler-rt/lib/asan/asan_posix.cc index bae14a870ef..590a5d7640a 100644 --- a/compiler-rt/lib/asan/asan_posix.cc +++ b/compiler-rt/lib/asan/asan_posix.cc @@ -20,6 +20,7 @@ #include "asan_stack.h" #include "asan_thread_registry.h" #include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_procmaps.h" #include <pthread.h> #include <signal.h> @@ -52,7 +53,7 @@ static inline bool IntervalsAreSeparate(uptr start1, uptr end1, // several worker threads on Mac, which aren't expected to map big chunks of // memory). bool AsanShadowRangeIsAvailable() { - AsanProcMaps procmaps; + ProcessMaps procmaps; uptr start, end; uptr shadow_start = kLowShadowBeg; if (kLowShadowBeg > 0) shadow_start -= kMmapGranularity; @@ -142,7 +143,7 @@ void AsanDisableCoreDumper() { } void AsanDumpProcessMap() { - AsanProcMaps proc_maps; + ProcessMaps proc_maps; uptr start, end; const sptr kBufSize = 4095; char filename[kBufSize]; diff --git a/compiler-rt/lib/asan/asan_procmaps.h b/compiler-rt/lib/asan/asan_procmaps.h index cfb0550029b..053b6d3398e 100644 --- a/compiler-rt/lib/asan/asan_procmaps.h +++ b/compiler-rt/lib/asan/asan_procmaps.h @@ -18,54 +18,6 @@ namespace __asan { -class AsanProcMaps { - public: - AsanProcMaps(); - bool Next(uptr *start, uptr *end, uptr *offset, - char filename[], uptr filename_size); - void Reset(); - // Gets the object file name and the offset in that object for a given - // address 'addr'. Returns true on success. - bool GetObjectNameAndOffset(uptr addr, uptr *offset, - char filename[], uptr filename_size); - ~AsanProcMaps(); - private: - // Default implementation of GetObjectNameAndOffset. - // Quite slow, because it iterates through the whole process map for each - // lookup. - bool IterateForObjectNameAndOffset(uptr addr, uptr *offset, - char filename[], uptr filename_size) { - Reset(); - uptr start, end, file_offset; - for (int i = 0; Next(&start, &end, &file_offset, filename, filename_size); - i++) { - if (addr >= start && addr < end) { - // Don't subtract 'start' for the first entry. Don't ask me why. - *offset = (addr - (i ? start : 0)) + file_offset; - return true; - } - } - if (filename_size) - filename[0] = '\0'; - return false; - } - -#if defined __linux__ - char *proc_self_maps_buff_; - uptr proc_self_maps_buff_mmaped_size_; - uptr proc_self_maps_buff_len_; - char *current_; -#elif defined __APPLE__ - template<u32 kLCSegment, typename SegmentCommand> - bool NextSegmentLoad(uptr *start, uptr *end, uptr *offset, - char filename[], uptr filename_size); - int current_image_; - u32 current_magic_; - int current_load_cmd_count_; - char *current_load_cmd_addr_; -#endif -}; - } // namespace __asan #endif // ASAN_PROCMAPS_H diff --git a/compiler-rt/lib/asan/asan_stack.cc b/compiler-rt/lib/asan/asan_stack.cc index 45d30c18362..25f69d651b6 100644 --- a/compiler-rt/lib/asan/asan_stack.cc +++ b/compiler-rt/lib/asan/asan_stack.cc @@ -17,6 +17,7 @@ #include "asan_stack.h" #include "asan_thread.h" #include "asan_thread_registry.h" +#include "sanitizer_common/sanitizer_procmaps.h" #include "sanitizer_common/sanitizer_symbolizer.h" #ifdef ASAN_USE_EXTERNAL_SYMBOLIZER @@ -39,7 +40,7 @@ void AsanStackTrace::PrintStack(uptr *addr, uptr size) { #else // ASAN_USE_EXTERNAL_SYMBOLIZER void AsanStackTrace::PrintStack(uptr *addr, uptr size) { - AsanProcMaps proc_maps; + ProcessMaps proc_maps; uptr frame_num = 0; for (uptr i = 0; i < size && addr[i]; i++) { proc_maps.Reset(); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc index 1e4e628a8be..9cd336efea0 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc @@ -13,8 +13,10 @@ //===----------------------------------------------------------------------===// #ifdef __linux__ +#include "sanitizer_common.h" #include "sanitizer_internal_defs.h" #include "sanitizer_libc.h" +#include "sanitizer_procmaps.h" #include <fcntl.h> #include <sys/mman.h> @@ -66,6 +68,67 @@ int internal_dup2(int oldfd, int newfd) { return syscall(__NR_dup2, oldfd, newfd); } +// ----------------- ProcessMaps implementation. +ProcessMaps::ProcessMaps() { + proc_self_maps_buff_len_ = + ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_, + &proc_self_maps_buff_mmaped_size_, 1 << 26); + CHECK(proc_self_maps_buff_len_ > 0); + // internal_write(2, proc_self_maps_buff_, proc_self_maps_buff_len_); + Reset(); +} + +ProcessMaps::~ProcessMaps() { + UnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_); +} + +void ProcessMaps::Reset() { + current_ = proc_self_maps_buff_; +} + +bool ProcessMaps::Next(uptr *start, uptr *end, uptr *offset, + char filename[], uptr 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; + uptr inode; + uptr dummy; + if (!start) start = &dummy; + if (!end) end = &dummy; + if (!offset) offset = &dummy; + char *next_line = (char*)internal_memchr(current_, '\n', last - current_); + if (next_line == 0) + next_line = last; + if (internal_sscanf(current_, "%lx-%lx %4s %lx %x:%x %ld %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. + uptr 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; +} + +// Gets the object name and the offset by walking ProcessMaps. +bool ProcessMaps::GetObjectNameAndOffset(uptr addr, uptr *offset, + char filename[], + uptr filename_size) { + return IterateForObjectNameAndOffset(addr, offset, filename, filename_size); +} + } // namespace __sanitizer #endif // __linux__ diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc index c607838f590..6fe0b60869c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc @@ -16,7 +16,10 @@ #include "sanitizer_internal_defs.h" #include "sanitizer_libc.h" +#include "sanitizer_procmaps.h" +#include <mach-o/dyld.h> +#include <mach-o/loader.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> @@ -62,6 +65,125 @@ int internal_dup2(int oldfd, int newfd) { return dup2(oldfd, newfd); } +// ----------------- ProcessMaps implementation. + +ProcessMaps::ProcessMaps() { + Reset(); +} + +ProcessMaps::~ProcessMaps() { +} + +// More information about Mach-O headers can be found in mach-o/loader.h +// Each Mach-O image has a header (mach_header or mach_header_64) starting with +// a magic number, and a list of linker load commands directly following the +// header. +// A load command is at least two 32-bit words: the command type and the +// command size in bytes. We're interested only in segment load commands +// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped +// into the task's address space. +// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or +// segment_command_64 correspond to the memory address, memory size and the +// file offset of the current memory segment. +// Because these fields are taken from the images as is, one needs to add +// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime. + +void ProcessMaps::Reset() { + // Count down from the top. + // TODO(glider): as per man 3 dyld, iterating over the headers with + // _dyld_image_count is thread-unsafe. We need to register callbacks for + // adding and removing images which will invalidate the ProcessMaps state. + current_image_ = _dyld_image_count(); + current_load_cmd_count_ = -1; + current_load_cmd_addr_ = 0; + current_magic_ = 0; +} + +// Next and NextSegmentLoad were inspired by base/sysinfo.cc in +// Google Perftools, http://code.google.com/p/google-perftools. + +// NextSegmentLoad scans the current image for the next segment load command +// and returns the start and end addresses and file offset of the corresponding +// segment. +// Note that the segment addresses are not necessarily sorted. +template<u32 kLCSegment, typename SegmentCommand> +bool ProcessMaps::NextSegmentLoad( + uptr *start, uptr *end, uptr *offset, + char filename[], uptr filename_size) { + const char* lc = current_load_cmd_addr_; + current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize; + if (((const load_command *)lc)->cmd == kLCSegment) { + const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); + const SegmentCommand* sc = (const SegmentCommand *)lc; + if (start) *start = sc->vmaddr + dlloff; + if (end) *end = sc->vmaddr + sc->vmsize + dlloff; + if (offset) *offset = sc->fileoff; + if (filename) { + internal_strncpy(filename, _dyld_get_image_name(current_image_), + filename_size); + } + return true; + } + return false; +} + +bool ProcessMaps::Next(uptr *start, uptr *end, uptr *offset, + char filename[], uptr filename_size) { + for (; current_image_ >= 0; current_image_--) { + const mach_header* hdr = _dyld_get_image_header(current_image_); + if (!hdr) continue; + if (current_load_cmd_count_ < 0) { + // Set up for this image; + current_load_cmd_count_ = hdr->ncmds; + current_magic_ = hdr->magic; + switch (current_magic_) { +#ifdef MH_MAGIC_64 + case MH_MAGIC_64: { + current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64); + break; + } +#endif + case MH_MAGIC: { + current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header); + break; + } + default: { + continue; + } + } + } + + for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) { + switch (current_magic_) { + // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64. +#ifdef MH_MAGIC_64 + case MH_MAGIC_64: { + if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>( + start, end, offset, filename, filename_size)) + return true; + break; + } +#endif + case MH_MAGIC: { + if (NextSegmentLoad<LC_SEGMENT, struct segment_command>( + start, end, offset, filename, filename_size)) + return true; + break; + } + } + } + // If we get here, no more load_cmd's in this image talk about + // segments. Go on to the next image. + } + return false; +} + +bool ProcessMaps::GetObjectNameAndOffset(uptr addr, uptr *offset, + char filename[], + uptr filename_size) { + return IterateForObjectNameAndOffset(addr, offset, filename, filename_size); +} + } // namespace __sanitizer #endif // __APPLE__ diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h new file mode 100644 index 00000000000..2140106e2f3 --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h @@ -0,0 +1,71 @@ +//===-- sanitizer_procmaps.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer. +// +// Information about the process mappings. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_PROCMAPS_H +#define SANITIZER_PROCMAPS_H + +#include "sanitizer_internal_defs.h" + +namespace __sanitizer { + +class ProcessMaps { + public: + ProcessMaps(); + bool Next(uptr *start, uptr *end, uptr *offset, + char filename[], uptr filename_size); + void Reset(); + // Gets the object file name and the offset in that object for a given + // address 'addr'. Returns true on success. + bool GetObjectNameAndOffset(uptr addr, uptr *offset, + char filename[], uptr filename_size); + ~ProcessMaps(); + private: + // Default implementation of GetObjectNameAndOffset. + // Quite slow, because it iterates through the whole process map for each + // lookup. + bool IterateForObjectNameAndOffset(uptr addr, uptr *offset, + char filename[], uptr filename_size) { + Reset(); + uptr start, end, file_offset; + for (int i = 0; Next(&start, &end, &file_offset, filename, filename_size); + i++) { + if (addr >= start && addr < end) { + // Don't subtract 'start' for the first entry. Don't ask me why. + *offset = (addr - (i ? start : 0)) + file_offset; + return true; + } + } + if (filename_size) + filename[0] = '\0'; + return false; + } + +#if defined __linux__ + char *proc_self_maps_buff_; + uptr proc_self_maps_buff_mmaped_size_; + uptr proc_self_maps_buff_len_; + char *current_; +#elif defined __APPLE__ + template<u32 kLCSegment, typename SegmentCommand> + bool NextSegmentLoad(uptr *start, uptr *end, uptr *offset, + char filename[], uptr filename_size); + int current_image_; + u32 current_magic_; + int current_load_cmd_count_; + char *current_load_cmd_addr_; +#endif +}; + +} // namespace __sanitizer + +#endif // SANITIZER_PROCMAPS_H |

