[Sanitizer] Move OS-specific code for MemoryMappingLayout into separate source files.

llvm-svn: 198003
This commit is contained in:
Alexey Samsonov 2013-12-25 08:01:16 +00:00
parent 3c849f6a06
commit 2f392d237c
7 changed files with 449 additions and 377 deletions

View File

@ -14,6 +14,9 @@ set(SANITIZER_SOURCES
sanitizer_platform_limits_posix.cc
sanitizer_posix.cc
sanitizer_printf.cc
sanitizer_procmaps_linux.cc
sanitizer_procmaps_mac.cc
sanitizer_procmaps_posix.cc
sanitizer_stackdepot.cc
sanitizer_stacktrace.cc
sanitizer_suppressions.cc

View File

@ -318,213 +318,6 @@ void PrepareForSandboxing() {
#endif
}
// ----------------- sanitizer_procmaps.h
// Linker initialized.
ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_;
StaticSpinMutex MemoryMappingLayout::cache_lock_; // Linker initialized.
MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
proc_self_maps_.len =
ReadFileToBuffer("/proc/self/maps", &proc_self_maps_.data,
&proc_self_maps_.mmaped_size, 1 << 26);
if (cache_enabled) {
if (proc_self_maps_.mmaped_size == 0) {
LoadFromCache();
CHECK_GT(proc_self_maps_.len, 0);
}
} else {
CHECK_GT(proc_self_maps_.mmaped_size, 0);
}
Reset();
// FIXME: in the future we may want to cache the mappings on demand only.
if (cache_enabled)
CacheMemoryMappings();
}
MemoryMappingLayout::~MemoryMappingLayout() {
// Only unmap the buffer if it is different from the cached one. Otherwise
// it will be unmapped when the cache is refreshed.
if (proc_self_maps_.data != cached_proc_self_maps_.data) {
UnmapOrDie(proc_self_maps_.data, proc_self_maps_.mmaped_size);
}
}
void MemoryMappingLayout::Reset() {
current_ = proc_self_maps_.data;
}
// static
void MemoryMappingLayout::CacheMemoryMappings() {
SpinMutexLock l(&cache_lock_);
// Don't invalidate the cache if the mappings are unavailable.
ProcSelfMapsBuff old_proc_self_maps;
old_proc_self_maps = cached_proc_self_maps_;
cached_proc_self_maps_.len =
ReadFileToBuffer("/proc/self/maps", &cached_proc_self_maps_.data,
&cached_proc_self_maps_.mmaped_size, 1 << 26);
if (cached_proc_self_maps_.mmaped_size == 0) {
cached_proc_self_maps_ = old_proc_self_maps;
} else {
if (old_proc_self_maps.mmaped_size) {
UnmapOrDie(old_proc_self_maps.data,
old_proc_self_maps.mmaped_size);
}
}
}
void MemoryMappingLayout::LoadFromCache() {
SpinMutexLock l(&cache_lock_);
if (cached_proc_self_maps_.data) {
proc_self_maps_ = cached_proc_self_maps_;
}
}
// Parse a hex value in str and update str.
static uptr ParseHex(char **str) {
uptr x = 0;
char *s;
for (s = *str; ; s++) {
char c = *s;
uptr v = 0;
if (c >= '0' && c <= '9')
v = c - '0';
else if (c >= 'a' && c <= 'f')
v = c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
v = c - 'A' + 10;
else
break;
x = x * 16 + v;
}
*str = s;
return x;
}
static bool IsOneOf(char c, char c1, char c2) {
return c == c1 || c == c2;
}
static bool IsDecimal(char c) {
return c >= '0' && c <= '9';
}
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 ReadDecimal(const char *p) {
uptr v = 0;
for (; IsDecimal(p[0]); p++)
v = v * 10 + p[0] - '0';
return v;
}
bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
char filename[], uptr filename_size,
uptr *protection) {
char *last = proc_self_maps_.data + proc_self_maps_.len;
if (current_ >= last) return false;
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;
// Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar
*start = ParseHex(&current_);
CHECK_EQ(*current_++, '-');
*end = ParseHex(&current_);
CHECK_EQ(*current_++, ' ');
uptr local_protection = 0;
CHECK(IsOneOf(*current_, '-', 'r'));
if (*current_++ == 'r')
local_protection |= kProtectionRead;
CHECK(IsOneOf(*current_, '-', 'w'));
if (*current_++ == 'w')
local_protection |= kProtectionWrite;
CHECK(IsOneOf(*current_, '-', 'x'));
if (*current_++ == 'x')
local_protection |= kProtectionExecute;
CHECK(IsOneOf(*current_, 's', 'p'));
if (*current_++ == 's')
local_protection |= kProtectionShared;
if (protection) {
*protection = local_protection;
}
CHECK_EQ(*current_++, ' ');
*offset = ParseHex(&current_);
CHECK_EQ(*current_++, ' ');
ParseHex(&current_);
CHECK_EQ(*current_++, ':');
ParseHex(&current_);
CHECK_EQ(*current_++, ' ');
while (IsDecimal(*current_))
current_++;
// Qemu may lack the trailing space.
// http://code.google.com/p/address-sanitizer/issues/detail?id=160
// CHECK_EQ(*current_++, ' ');
// 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 MemoryMappingLayout.
bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
char filename[],
uptr filename_size,
uptr *protection) {
return IterateForObjectNameAndOffset(addr, offset, filename, filename_size,
protection);
}
void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {
char *smaps = 0;
uptr smaps_cap = 0;
uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
&smaps, &smaps_cap, 64<<20);
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 = ReadDecimal(pos) * 1024;
cb(start, rss, file, stats, stats_size);
}
while (*pos++ != '\n') {}
}
UnmapOrDie(smaps, smaps_cap);
}
enum MutexState {
MtxUnlocked = 0,
MtxLocked = 1,

View File

@ -30,8 +30,6 @@
#include <crt_externs.h> // for _NSGetEnviron
#include <fcntl.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
#include <pthread.h>
#include <sched.h>
#include <sys/mman.h>
@ -179,148 +177,6 @@ uptr GetPageSize() {
return sysconf(_SC_PAGESIZE);
}
// ----------------- sanitizer_procmaps.h
MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
Reset();
}
MemoryMappingLayout::~MemoryMappingLayout() {
}
// 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 MemoryMappingLayout::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 MemoryMappingLayout
// state.
current_image_ = _dyld_image_count();
current_load_cmd_count_ = -1;
current_load_cmd_addr_ = 0;
current_magic_ = 0;
current_filetype_ = 0;
}
// static
void MemoryMappingLayout::CacheMemoryMappings() {
// No-op on Mac for now.
}
void MemoryMappingLayout::LoadFromCache() {
// No-op on Mac for now.
}
// 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 MemoryMappingLayout::NextSegmentLoad(
uptr *start, uptr *end, uptr *offset,
char filename[], uptr filename_size, uptr *protection) {
if (protection)
UNIMPLEMENTED();
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) {
if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
*offset = sc->vmaddr;
} else {
*offset = sc->fileoff;
}
}
if (filename) {
internal_strncpy(filename, _dyld_get_image_name(current_image_),
filename_size);
}
return true;
}
return false;
}
bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
char filename[], uptr filename_size,
uptr *protection) {
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;
current_filetype_ = hdr->filetype;
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, protection))
return true;
break;
}
#endif
case MH_MAGIC: {
if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
start, end, offset, filename, filename_size, protection))
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 MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
char filename[],
uptr filename_size,
uptr *protection) {
return IterateForObjectNameAndOffset(addr, offset, filename, filename_size,
protection);
}
BlockingMutex::BlockingMutex(LinkerInitialized) {
// We assume that OS_SPINLOCK_INIT is zero
}

View File

@ -71,33 +71,10 @@ class MemoryMappingLayout {
// lookup.
bool IterateForObjectNameAndOffset(uptr addr, uptr *offset,
char filename[], uptr filename_size,
uptr *protection) {
Reset();
uptr start, end, file_offset;
for (int i = 0; Next(&start, &end, &file_offset, filename, filename_size,
protection);
i++) {
if (addr >= start && addr < end) {
// Don't subtract 'start' for the first entry:
// * If a binary is compiled w/o -pie, then the first entry in
// process maps is likely the binary itself (all dynamic libs
// are mapped higher in address space). For such a binary,
// instruction offset in binary coincides with the actual
// instruction address in virtual memory (as code section
// is mapped to a fixed memory range).
// * If a binary is compiled with -pie, all the modules are
// mapped high at address space (in particular, higher than
// shadow memory of the tool), so the module can't be the
// first entry.
*offset = (addr - (i ? start : 0)) + file_offset;
return true;
}
}
if (filename_size)
filename[0] = '\0';
return false;
}
uptr *protection);
// FIXME: Hide implementation details for different platforms in
// platform-specific files.
# if SANITIZER_LINUX
ProcSelfMapsBuff proc_self_maps_;
char *current_;

View File

@ -0,0 +1,227 @@
//===-- sanitizer_procmaps_linux.cc ---------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Information about the process mappings (Linux-specific parts).
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
#if SANITIZER_LINUX
#include "sanitizer_common.h"
#include "sanitizer_procmaps.h"
namespace __sanitizer {
// Linker initialized.
ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_;
StaticSpinMutex MemoryMappingLayout::cache_lock_; // Linker initialized.
MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
proc_self_maps_.len =
ReadFileToBuffer("/proc/self/maps", &proc_self_maps_.data,
&proc_self_maps_.mmaped_size, 1 << 26);
if (cache_enabled) {
if (proc_self_maps_.mmaped_size == 0) {
LoadFromCache();
CHECK_GT(proc_self_maps_.len, 0);
}
} else {
CHECK_GT(proc_self_maps_.mmaped_size, 0);
}
Reset();
// FIXME: in the future we may want to cache the mappings on demand only.
if (cache_enabled)
CacheMemoryMappings();
}
MemoryMappingLayout::~MemoryMappingLayout() {
// Only unmap the buffer if it is different from the cached one. Otherwise
// it will be unmapped when the cache is refreshed.
if (proc_self_maps_.data != cached_proc_self_maps_.data) {
UnmapOrDie(proc_self_maps_.data, proc_self_maps_.mmaped_size);
}
}
void MemoryMappingLayout::Reset() {
current_ = proc_self_maps_.data;
}
// static
void MemoryMappingLayout::CacheMemoryMappings() {
SpinMutexLock l(&cache_lock_);
// Don't invalidate the cache if the mappings are unavailable.
ProcSelfMapsBuff old_proc_self_maps;
old_proc_self_maps = cached_proc_self_maps_;
cached_proc_self_maps_.len =
ReadFileToBuffer("/proc/self/maps", &cached_proc_self_maps_.data,
&cached_proc_self_maps_.mmaped_size, 1 << 26);
if (cached_proc_self_maps_.mmaped_size == 0) {
cached_proc_self_maps_ = old_proc_self_maps;
} else {
if (old_proc_self_maps.mmaped_size) {
UnmapOrDie(old_proc_self_maps.data,
old_proc_self_maps.mmaped_size);
}
}
}
void MemoryMappingLayout::LoadFromCache() {
SpinMutexLock l(&cache_lock_);
if (cached_proc_self_maps_.data) {
proc_self_maps_ = cached_proc_self_maps_;
}
}
// Parse a hex value in str and update str.
static uptr ParseHex(char **str) {
uptr x = 0;
char *s;
for (s = *str; ; s++) {
char c = *s;
uptr v = 0;
if (c >= '0' && c <= '9')
v = c - '0';
else if (c >= 'a' && c <= 'f')
v = c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
v = c - 'A' + 10;
else
break;
x = x * 16 + v;
}
*str = s;
return x;
}
static bool IsOneOf(char c, char c1, char c2) {
return c == c1 || c == c2;
}
static bool IsDecimal(char c) {
return c >= '0' && c <= '9';
}
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 ReadDecimal(const char *p) {
uptr v = 0;
for (; IsDecimal(p[0]); p++)
v = v * 10 + p[0] - '0';
return v;
}
bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
char filename[], uptr filename_size,
uptr *protection) {
char *last = proc_self_maps_.data + proc_self_maps_.len;
if (current_ >= last) return false;
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;
// Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar
*start = ParseHex(&current_);
CHECK_EQ(*current_++, '-');
*end = ParseHex(&current_);
CHECK_EQ(*current_++, ' ');
uptr local_protection = 0;
CHECK(IsOneOf(*current_, '-', 'r'));
if (*current_++ == 'r')
local_protection |= kProtectionRead;
CHECK(IsOneOf(*current_, '-', 'w'));
if (*current_++ == 'w')
local_protection |= kProtectionWrite;
CHECK(IsOneOf(*current_, '-', 'x'));
if (*current_++ == 'x')
local_protection |= kProtectionExecute;
CHECK(IsOneOf(*current_, 's', 'p'));
if (*current_++ == 's')
local_protection |= kProtectionShared;
if (protection) {
*protection = local_protection;
}
CHECK_EQ(*current_++, ' ');
*offset = ParseHex(&current_);
CHECK_EQ(*current_++, ' ');
ParseHex(&current_);
CHECK_EQ(*current_++, ':');
ParseHex(&current_);
CHECK_EQ(*current_++, ' ');
while (IsDecimal(*current_))
current_++;
// Qemu may lack the trailing space.
// http://code.google.com/p/address-sanitizer/issues/detail?id=160
// CHECK_EQ(*current_++, ' ');
// 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 MemoryMappingLayout.
bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
char filename[],
uptr filename_size,
uptr *protection) {
return IterateForObjectNameAndOffset(addr, offset, filename, filename_size,
protection);
}
void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {
char *smaps = 0;
uptr smaps_cap = 0;
uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
&smaps, &smaps_cap, 64<<20);
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 = ReadDecimal(pos) * 1024;
cb(start, rss, file, stats, stats_size);
}
while (*pos++ != '\n') {}
}
UnmapOrDie(smaps, smaps_cap);
}
} // namespace __sanitizer
#endif // SANITIZER_LINUX

View File

@ -0,0 +1,165 @@
//===-- sanitizer_procmaps_mac.cc -----------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Information about the process mappings (Mac-specific parts).
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
#if SANITIZER_MAC
#include "sanitizer_common.h"
#include "sanitizer_procmaps.h"
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
namespace __sanitizer {
MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
Reset();
}
MemoryMappingLayout::~MemoryMappingLayout() {
}
// 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 MemoryMappingLayout::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 MemoryMappingLayout
// state.
current_image_ = _dyld_image_count();
current_load_cmd_count_ = -1;
current_load_cmd_addr_ = 0;
current_magic_ = 0;
current_filetype_ = 0;
}
// static
void MemoryMappingLayout::CacheMemoryMappings() {
// No-op on Mac for now.
}
void MemoryMappingLayout::LoadFromCache() {
// No-op on Mac for now.
}
// 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 MemoryMappingLayout::NextSegmentLoad(
uptr *start, uptr *end, uptr *offset,
char filename[], uptr filename_size, uptr *protection) {
if (protection)
UNIMPLEMENTED();
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) {
if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
*offset = sc->vmaddr;
} else {
*offset = sc->fileoff;
}
}
if (filename) {
internal_strncpy(filename, _dyld_get_image_name(current_image_),
filename_size);
}
return true;
}
return false;
}
bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
char filename[], uptr filename_size,
uptr *protection) {
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;
current_filetype_ = hdr->filetype;
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, protection))
return true;
break;
}
#endif
case MH_MAGIC: {
if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
start, end, offset, filename, filename_size, protection))
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 MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
char filename[],
uptr filename_size,
uptr *protection) {
return IterateForObjectNameAndOffset(addr, offset, filename, filename_size,
protection);
}
} // namespace __sanitizer
#endif // SANITIZER_MAC

View File

@ -0,0 +1,51 @@
//===-- sanitizer_procmaps_posix.cc ---------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Information about the process mappings.
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
#if SANITIZER_POSIX
#include "sanitizer_procmaps.h"
namespace __sanitizer {
bool MemoryMappingLayout::IterateForObjectNameAndOffset(uptr addr, uptr *offset,
char filename[],
uptr filename_size,
uptr *protection) {
Reset();
uptr start, end, file_offset;
for (int i = 0; Next(&start, &end, &file_offset, filename, filename_size,
protection);
i++) {
if (addr >= start && addr < end) {
// Don't subtract 'start' for the first entry:
// * If a binary is compiled w/o -pie, then the first entry in
// process maps is likely the binary itself (all dynamic libs
// are mapped higher in address space). For such a binary,
// instruction offset in binary coincides with the actual
// instruction address in virtual memory (as code section
// is mapped to a fixed memory range).
// * If a binary is compiled with -pie, all the modules are
// mapped high at address space (in particular, higher than
// shadow memory of the tool), so the module can't be the
// first entry.
*offset = (addr - (i ? start : 0)) + file_offset;
return true;
}
}
if (filename_size)
filename[0] = '\0';
return false;
}
} // namespace __sanitizer
#endif // SANITIZER_POSIX