Skip to content

Commit 6601c38

Browse files
authored
Fix getting section info in large mach-o files. (#165940)
Mach-o has 32 bit file offsets in the MachO::section_64 structs. dSYM files can contain sections whose start offset exceeds UINT32_MAX, which means the MachO::section_64.offset will get truncated. We can calculate when this happens and properly adjust the section offset to be 64 bit safe. This means tools can get the correct section contents for large dSYM files and allows tools that parse DWARF, like llvm-gsymutil, to be able to load and convert these files correctly.
1 parent 0ce03c2 commit 6601c38

File tree

2 files changed

+25
-3
lines changed

2 files changed

+25
-3
lines changed

llvm/include/llvm/Object/MachO.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ class LLVM_ABI MachOObjectFile : public ObjectFile {
447447
uint64_t getSectionAddress(DataRefImpl Sec) const override;
448448
uint64_t getSectionIndex(DataRefImpl Sec) const override;
449449
uint64_t getSectionSize(DataRefImpl Sec) const override;
450-
ArrayRef<uint8_t> getSectionContents(uint32_t Offset, uint64_t Size) const;
450+
ArrayRef<uint8_t> getSectionContents(uint64_t Offset, uint64_t Size) const;
451451
Expected<ArrayRef<uint8_t>>
452452
getSectionContents(DataRefImpl Sec) const override;
453453
uint64_t getSectionAlignment(DataRefImpl Sec) const override;

llvm/lib/Object/MachOObjectFile.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,20 +1978,42 @@ uint64_t MachOObjectFile::getSectionSize(DataRefImpl Sec) const {
19781978
return SectSize;
19791979
}
19801980

1981-
ArrayRef<uint8_t> MachOObjectFile::getSectionContents(uint32_t Offset,
1981+
ArrayRef<uint8_t> MachOObjectFile::getSectionContents(uint64_t Offset,
19821982
uint64_t Size) const {
19831983
return arrayRefFromStringRef(getData().substr(Offset, Size));
19841984
}
19851985

19861986
Expected<ArrayRef<uint8_t>>
19871987
MachOObjectFile::getSectionContents(DataRefImpl Sec) const {
1988-
uint32_t Offset;
1988+
uint64_t Offset;
19891989
uint64_t Size;
19901990

19911991
if (is64Bit()) {
19921992
MachO::section_64 Sect = getSection64(Sec);
19931993
Offset = Sect.offset;
19941994
Size = Sect.size;
1995+
// Check for large mach-o files where the section contents might exceed
1996+
// 4GB. MachO::section_64 objects only have 32 bit file offsets to the
1997+
// section contents and can overflow in dSYM files. We can track this and
1998+
// adjust the section offset to be 64 bit safe. If sections overflow then
1999+
// section ordering is enforced. If sections are not ordered, then an error
2000+
// will be returned stopping invalid section data from being returned.
2001+
uint64_t PrevTrueOffset = 0;
2002+
uint64_t SectOffsetAdjust = 0;
2003+
for (uint32_t SectIdx = 0; SectIdx < Sec.d.a; ++SectIdx) {
2004+
MachO::section_64 CurrSect =
2005+
getStruct<MachO::section_64>(*this, Sections[SectIdx]);
2006+
uint64_t CurrTrueOffset = (uint64_t)CurrSect.offset + SectOffsetAdjust;
2007+
if ((SectOffsetAdjust > 0) && (PrevTrueOffset > CurrTrueOffset))
2008+
return malformedError("section data exceeds 4GB and section file "
2009+
"offsets are not ordered");
2010+
const uint64_t EndSectFileOffset =
2011+
(uint64_t)CurrSect.offset + CurrSect.size;
2012+
if (EndSectFileOffset > UINT32_MAX)
2013+
SectOffsetAdjust += EndSectFileOffset & 0xFFFFFFFF00000000ull;
2014+
PrevTrueOffset = CurrTrueOffset;
2015+
}
2016+
Offset += SectOffsetAdjust;
19952017
} else {
19962018
MachO::section Sect = getSection(Sec);
19972019
Offset = Sect.offset;

0 commit comments

Comments
 (0)