Add address ranges for individual macho sections on darwin
Summary: This is a re-upload of the reverted commit r308644. It has changed quite a bit to reflect post-commit comments by kcc, so I'm re-uploading as a new review. Reviewers: kubamracek, alekseyshl, kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D35799 llvm-svn: 308977
This commit is contained in:
parent
85cc5687df
commit
ec4ac0f0c6
|
|
@ -37,9 +37,12 @@ static const uptr kProtectionWrite = 2;
|
|||
static const uptr kProtectionExecute = 4;
|
||||
static const uptr kProtectionShared = 8;
|
||||
|
||||
struct MemoryMappedSegment {
|
||||
struct MemoryMappedSegmentData;
|
||||
|
||||
class MemoryMappedSegment {
|
||||
public:
|
||||
MemoryMappedSegment(char *buff = nullptr, uptr size = 0)
|
||||
: filename(buff), filename_size(size) {}
|
||||
: filename(buff), filename_size(size), data_(nullptr) {}
|
||||
~MemoryMappedSegment() {}
|
||||
|
||||
bool IsReadable() const { return protection & kProtectionRead; }
|
||||
|
|
@ -47,6 +50,8 @@ struct MemoryMappedSegment {
|
|||
bool IsExecutable() const { return protection & kProtectionExecute; }
|
||||
bool IsShared() const { return protection & kProtectionShared; }
|
||||
|
||||
void AddAddressRanges(LoadedModule *module);
|
||||
|
||||
uptr start;
|
||||
uptr end;
|
||||
uptr offset;
|
||||
|
|
@ -55,6 +60,12 @@ struct MemoryMappedSegment {
|
|||
uptr protection;
|
||||
ModuleArch arch;
|
||||
u8 uuid[kModuleUUIDSize];
|
||||
|
||||
private:
|
||||
friend class MemoryMappingLayout;
|
||||
|
||||
// This field is assigned and owned by MemoryMappingLayout if needed
|
||||
MemoryMappedSegmentData *data_;
|
||||
};
|
||||
|
||||
class MemoryMappingLayout {
|
||||
|
|
|
|||
|
|
@ -64,6 +64,10 @@ uptr ParseHex(const char **p) {
|
|||
return ParseNumber(p, 16);
|
||||
}
|
||||
|
||||
void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) {
|
||||
module->addAddressRange(start, end, IsExecutable(), IsWritable());
|
||||
}
|
||||
|
||||
MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
|
||||
ReadProcMaps(&proc_self_maps_);
|
||||
if (cache_enabled) {
|
||||
|
|
@ -139,8 +143,7 @@ void MemoryMappingLayout::DumpListOfModules(
|
|||
uptr base_address = (i ? segment.start : 0) - segment.offset;
|
||||
LoadedModule cur_module;
|
||||
cur_module.set(cur_name, base_address);
|
||||
cur_module.addAddressRange(segment.start, segment.end,
|
||||
segment.IsExecutable(), segment.IsWritable());
|
||||
segment.AddAddressRanges(&cur_module);
|
||||
modules->push_back(cur_module);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,48 @@
|
|||
|
||||
namespace __sanitizer {
|
||||
|
||||
// Contains information used to iterate through sections.
|
||||
struct MemoryMappedSegmentData {
|
||||
uptr nsects;
|
||||
char *current_load_cmd_addr;
|
||||
u32 lc_type;
|
||||
uptr base_virt_addr;
|
||||
uptr addr_mask;
|
||||
};
|
||||
|
||||
template <typename Section>
|
||||
static void NextSectionLoad(LoadedModule *module, MemoryMappedSegmentData *data,
|
||||
bool isWritable) {
|
||||
const Section *sc = (const Section *)data->current_load_cmd_addr;
|
||||
data->current_load_cmd_addr += sizeof(Section);
|
||||
|
||||
uptr sec_start = (sc->addr & data->addr_mask) + data->base_virt_addr;
|
||||
uptr sec_end = sec_start + sc->size;
|
||||
module->addAddressRange(sec_start, sec_end, /*executable=*/false, isWritable);
|
||||
}
|
||||
|
||||
void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) {
|
||||
// Don't iterate over sections when the caller hasn't set up the
|
||||
// data pointer, when there are no sections, or when the segment
|
||||
// is executable. Avoid iterating over executable sections because
|
||||
// it will confuse libignore, and because the extra granularity
|
||||
// of information is not needed by any sanitizers.
|
||||
if (!data_ || !data_->nsects || IsExecutable()) {
|
||||
module->addAddressRange(start, end, IsExecutable(), IsWritable());
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (data_->lc_type == LC_SEGMENT) {
|
||||
NextSectionLoad<struct section>(module, data_, IsWritable());
|
||||
#ifdef MH_MAGIC_64
|
||||
} else if (data_->lc_type == LC_SEGMENT_64) {
|
||||
NextSectionLoad<struct section_64>(module, data_, IsWritable());
|
||||
#endif
|
||||
}
|
||||
} while (--data_->nsects);
|
||||
}
|
||||
|
||||
MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
|
||||
Reset();
|
||||
}
|
||||
|
|
@ -144,19 +186,32 @@ bool MemoryMappingLayout::NextSegmentLoad(MemoryMappedSegment *segment) {
|
|||
if (((const load_command *)lc)->cmd == kLCSegment) {
|
||||
const SegmentCommand* sc = (const SegmentCommand *)lc;
|
||||
|
||||
uptr base_virt_addr, addr_mask;
|
||||
if (current_image_ == kDyldImageIdx) {
|
||||
base_virt_addr = (uptr)get_dyld_hdr();
|
||||
// vmaddr is masked with 0xfffff because on macOS versions < 10.12,
|
||||
// it contains an absolute address rather than an offset for dyld.
|
||||
// To make matters even more complicated, this absolute address
|
||||
// isn't actually the absolute segment address, but the offset portion
|
||||
// of the address is accurate when combined with the dyld base address,
|
||||
// and the mask will give just this offset.
|
||||
segment->start = (sc->vmaddr & 0xfffff) + (uptr)get_dyld_hdr();
|
||||
segment->end = (sc->vmaddr & 0xfffff) + sc->vmsize + (uptr)get_dyld_hdr();
|
||||
addr_mask = 0xfffff;
|
||||
} else {
|
||||
const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
|
||||
segment->start = sc->vmaddr + dlloff;
|
||||
segment->end = sc->vmaddr + sc->vmsize + dlloff;
|
||||
base_virt_addr = (uptr)_dyld_get_image_vmaddr_slide(current_image_);
|
||||
addr_mask = ~0;
|
||||
}
|
||||
segment->start = (sc->vmaddr & addr_mask) + base_virt_addr;
|
||||
segment->end = segment->start + sc->vmsize;
|
||||
|
||||
// Most callers don't need section information, so only fill this struct
|
||||
// when required.
|
||||
if (segment->data_) {
|
||||
segment->data_->nsects = sc->nsects;
|
||||
segment->data_->current_load_cmd_addr =
|
||||
(char *)lc + sizeof(SegmentCommand);
|
||||
segment->data_->lc_type = kLCSegment;
|
||||
segment->data_->base_virt_addr = base_virt_addr;
|
||||
segment->data_->addr_mask = addr_mask;
|
||||
}
|
||||
|
||||
// Return the initial protection.
|
||||
|
|
@ -292,7 +347,9 @@ void MemoryMappingLayout::DumpListOfModules(
|
|||
Reset();
|
||||
InternalScopedString module_name(kMaxPathLength);
|
||||
MemoryMappedSegment segment(module_name.data(), kMaxPathLength);
|
||||
for (uptr i = 0; Next(&segment); i++) {
|
||||
MemoryMappedSegmentData data;
|
||||
segment.data_ = &data;
|
||||
while (Next(&segment)) {
|
||||
if (segment.filename[0] == '\0') continue;
|
||||
LoadedModule *cur_module = nullptr;
|
||||
if (!modules->empty() &&
|
||||
|
|
@ -304,8 +361,7 @@ void MemoryMappingLayout::DumpListOfModules(
|
|||
cur_module->set(segment.filename, segment.start, segment.arch,
|
||||
segment.uuid, current_instrumented_);
|
||||
}
|
||||
cur_module->addAddressRange(segment.start, segment.end,
|
||||
segment.IsExecutable(), segment.IsWritable());
|
||||
segment.AddAddressRanges(cur_module);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue