aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/mac/macho_reader.cc40
-rw-r--r--src/common/mac/macho_reader.h4
2 files changed, 34 insertions, 10 deletions
diff --git a/src/common/mac/macho_reader.cc b/src/common/mac/macho_reader.cc
index 52f3c411..b4e3192a 100644
--- a/src/common/mac/macho_reader.cc
+++ b/src/common/mac/macho_reader.cc
@@ -38,6 +38,8 @@
#include <stdio.h>
#include <stdlib.h>
+#include <limits>
+
// Unfortunately, CPU_TYPE_ARM is not define for 10.4.
#if !defined(CPU_TYPE_ARM)
#define CPU_TYPE_ARM 12
@@ -344,8 +346,8 @@ bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const {
cursor
.Read(word_size, false, &segment.vmaddr)
.Read(word_size, false, &segment.vmsize)
- .Read(word_size, false, &file_offset)
- .Read(word_size, false, &file_size);
+ .Read(word_size, false, &segment.fileoff)
+ .Read(word_size, false, &segment.filesize);
cursor >> segment.maxprot
>> segment.initprot
>> segment.nsects
@@ -354,8 +356,8 @@ bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const {
reporter_->LoadCommandTooShort(index, type);
return false;
}
- if (file_offset > buffer_.Size() ||
- file_size > buffer_.Size() - file_offset) {
+ if (segment.fileoff > buffer_.Size() ||
+ segment.filesize > buffer_.Size() - segment.fileoff) {
reporter_->MisplacedSegmentData(segment.name);
return false;
}
@@ -363,11 +365,11 @@ bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const {
// segments removed, and their file offsets and file sizes zeroed
// out. To help us handle this special case properly, give such
// segments' contents NULL starting and ending pointers.
- if (file_offset == 0 && file_size == 0) {
+ if (segment.fileoff == 0 && segment.filesize == 0) {
segment.contents.start = segment.contents.end = NULL;
} else {
- segment.contents.start = buffer_.start + file_offset;
- segment.contents.end = segment.contents.start + file_size;
+ segment.contents.start = buffer_.start + segment.fileoff;
+ segment.contents.end = segment.contents.start + segment.filesize;
}
// The section list occupies the remainder of this load command's space.
segment.section_list.start = cursor.here();
@@ -461,14 +463,14 @@ bool Reader::WalkSegmentSections(const Segment &segment,
for (size_t i = 0; i < segment.nsects; i++) {
Section section;
section.bits_64 = segment.bits_64;
- uint64_t size;
- uint32_t offset, dummy32;
+ uint64_t size, offset;
+ uint32_t dummy32;
cursor
.CString(&section.section_name, 16)
.CString(&section.segment_name, 16)
.Read(word_size, false, &section.address)
.Read(word_size, false, &size)
- >> offset
+ .Read(sizeof(uint32_t), false, &offset) // clears high bits of |offset|
>> section.align
>> dummy32
>> dummy32
@@ -481,6 +483,24 @@ bool Reader::WalkSegmentSections(const Segment &segment,
reporter_->SectionsMissing(segment.name);
return false;
}
+
+ // Even 64-bit Mach-O isn’t a true 64-bit format in that it doesn’t handle
+ // 64-bit file offsets gracefully. Segment load commands do contain 64-bit
+ // file offsets, but sections within do not. Because segments load
+ // contiguously, recompute each section’s file offset on the basis of its
+ // containing segment’s file offset and the difference between the section’s
+ // and segment’s load addresses. If truncation is detected, honor the
+ // recomputed offset.
+ if (segment.bits_64 &&
+ segment.fileoff + segment.filesize >
+ std::numeric_limits<uint32_t>::max()) {
+ const uint64_t section_offset_recomputed =
+ segment.fileoff + section.address - segment.vmaddr;
+ if (offset == static_cast<uint32_t>(section_offset_recomputed)) {
+ offset = section_offset_recomputed;
+ }
+ }
+
const uint32_t section_type = section.flags & SECTION_TYPE;
if (section_type == S_ZEROFILL || section_type == S_THREAD_LOCAL_ZEROFILL ||
section_type == S_GB_ZEROFILL) {
diff --git a/src/common/mac/macho_reader.h b/src/common/mac/macho_reader.h
index 30db742d..145d17d1 100644
--- a/src/common/mac/macho_reader.h
+++ b/src/common/mac/macho_reader.h
@@ -175,6 +175,10 @@ struct Segment {
// of this value are valid.
uint64_t vmsize;
+ // The file offset and size of the segment in the Mach-O image.
+ uint64_t fileoff;
+ uint64_t filesize;
+
// The maximum and initial VM protection of this segment's contents.
uint32_t maxprot;
uint32_t initprot;