summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/lib/Object/MachOObjectFile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/Object/MachOObjectFile.cpp')
-rw-r--r--contrib/llvm/lib/Object/MachOObjectFile.cpp136
1 files changed, 83 insertions, 53 deletions
diff --git a/contrib/llvm/lib/Object/MachOObjectFile.cpp b/contrib/llvm/lib/Object/MachOObjectFile.cpp
index e476976..79f8100 100644
--- a/contrib/llvm/lib/Object/MachOObjectFile.cpp
+++ b/contrib/llvm/lib/Object/MachOObjectFile.cpp
@@ -38,8 +38,12 @@ namespace {
};
}
-template<typename T>
+template <typename T>
static T getStruct(const MachOObjectFile *O, const char *P) {
+ // Don't read before the beginning or past the end of the file
+ if (P < O->getData().begin() || P + sizeof(T) > O->getData().end())
+ report_fatal_error("Malformed MachO file.");
+
T Cmd;
memcpy(&Cmd, P, sizeof(T));
if (O->isLittleEndian() != sys::IsLittleEndianHost)
@@ -47,15 +51,26 @@ static T getStruct(const MachOObjectFile *O, const char *P) {
return Cmd;
}
+template <typename SegmentCmd>
+static uint32_t getSegmentLoadCommandNumSections(const SegmentCmd &S,
+ uint32_t Cmdsize) {
+ const unsigned SectionSize = sizeof(SegmentCmd);
+ if (S.nsects > std::numeric_limits<uint32_t>::max() / SectionSize ||
+ S.nsects * SectionSize > Cmdsize - sizeof(S))
+ report_fatal_error(
+ "Number of sections too large for size of load command.");
+ return S.nsects;
+}
+
static uint32_t
getSegmentLoadCommandNumSections(const MachOObjectFile *O,
const MachOObjectFile::LoadCommandInfo &L) {
- if (O->is64Bit()) {
- MachO::segment_command_64 S = O->getSegment64LoadCommand(L);
- return S.nsects;
- }
- MachO::segment_command S = O->getSegmentLoadCommand(L);
- return S.nsects;
+ if (O->is64Bit())
+ return getSegmentLoadCommandNumSections(O->getSegment64LoadCommand(L),
+ L.C.cmdsize);
+
+ return getSegmentLoadCommandNumSections(O->getSegmentLoadCommand(L),
+ L.C.cmdsize);
}
static bool isPageZeroSegment(const MachOObjectFile *O,
@@ -233,8 +248,9 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
bool Is64bits, std::error_code &EC)
: ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object),
SymtabLoadCmd(nullptr), DysymtabLoadCmd(nullptr),
- DataInCodeLoadCmd(nullptr), DyldInfoLoadCmd(nullptr),
- UuidLoadCmd(nullptr), HasPageZeroSegment(false) {
+ DataInCodeLoadCmd(nullptr), LinkOptHintsLoadCmd(nullptr),
+ DyldInfoLoadCmd(nullptr), UuidLoadCmd(nullptr),
+ HasPageZeroSegment(false) {
uint32_t LoadCommandCount = this->getHeader().ncmds;
if (LoadCommandCount == 0)
return;
@@ -265,6 +281,13 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
return;
}
DataInCodeLoadCmd = Load.Ptr;
+ } else if (Load.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT) {
+ // Multiple linker optimization hint tables
+ if (LinkOptHintsLoadCmd) {
+ EC = object_error::parse_failed;
+ return;
+ }
+ LinkOptHintsLoadCmd = Load.Ptr;
} else if (Load.C.cmd == MachO::LC_DYLD_INFO ||
Load.C.cmd == MachO::LC_DYLD_INFO_ONLY) {
// Multiple dyldinfo load commands
@@ -281,6 +304,12 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
}
UuidLoadCmd = Load.Ptr;
} else if (Load.C.cmd == SegmentLoadType) {
+ const unsigned SegmentLoadSize = this->is64Bit()
+ ? sizeof(MachO::segment_command_64)
+ : sizeof(MachO::segment_command);
+ if (Load.C.cmdsize < SegmentLoadSize)
+ report_fatal_error("Segment load command size is too small.");
+
uint32_t NumSections = getSegmentLoadCommandNumSections(this, Load);
for (unsigned J = 0; J < NumSections; ++J) {
const char *Sec = getSectionPtr(this, Load, J);
@@ -315,6 +344,9 @@ std::error_code MachOObjectFile::getSymbolName(DataRefImpl Symb,
StringRef StringTable = getStringTableData();
MachO::nlist_base Entry = getSymbolTableEntryBase(this, Symb);
const char *Start = &StringTable.data()[Entry.n_strx];
+ if (Start < getData().begin() || Start >= getData().end())
+ report_fatal_error(
+ "Symbol name entry points before beginning or past end of file.");
Res = StringRef(Start);
return object_error::success;
}
@@ -383,49 +415,13 @@ std::error_code MachOObjectFile::getSymbolAlignment(DataRefImpl DRI,
std::error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI,
uint64_t &Result) const {
- uint64_t BeginOffset;
- uint64_t EndOffset = 0;
- uint8_t SectionIndex;
-
- MachO::nlist_base Entry = getSymbolTableEntryBase(this, DRI);
uint64_t Value;
getSymbolAddress(DRI, Value);
- if (Value == UnknownAddressOrSize) {
+ uint32_t flags = getSymbolFlags(DRI);
+ if (flags & SymbolRef::SF_Common)
+ Result = Value;
+ else
Result = UnknownAddressOrSize;
- return object_error::success;
- }
-
- BeginOffset = Value;
-
- SectionIndex = Entry.n_sect;
- if (!SectionIndex) {
- uint32_t flags = getSymbolFlags(DRI);
- if (flags & SymbolRef::SF_Common)
- Result = Value;
- else
- Result = UnknownAddressOrSize;
- return object_error::success;
- }
- // Unfortunately symbols are unsorted so we need to touch all
- // symbols from load command
- for (const SymbolRef &Symbol : symbols()) {
- DataRefImpl DRI = Symbol.getRawDataRefImpl();
- Entry = getSymbolTableEntryBase(this, DRI);
- getSymbolAddress(DRI, Value);
- if (Value == UnknownAddressOrSize)
- continue;
- if (Entry.n_sect == SectionIndex && Value > BeginOffset)
- if (!EndOffset || Value < EndOffset)
- EndOffset = Value;
- }
- if (!EndOffset) {
- DataRefImpl Sec;
- Sec.d.a = SectionIndex-1;
- uint64_t Size = getSectionSize(Sec);
- EndOffset = getSectionAddress(Sec);
- EndOffset += Size;
- }
- Result = EndOffset - BeginOffset;
return object_error::success;
}
@@ -478,6 +474,9 @@ uint32_t MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const {
if (Value && Value != UnknownAddressOrSize)
Result |= SymbolRef::SF_Common;
}
+
+ if (!(MachOType & MachO::N_PEXT))
+ Result |= SymbolRef::SF_Exported;
}
if (MachOFlags & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF))
@@ -502,6 +501,8 @@ std::error_code MachOObjectFile::getSymbolSection(DataRefImpl Symb,
} else {
DataRefImpl DRI;
DRI.d.a = index - 1;
+ if (DRI.d.a >= Sections.size())
+ report_fatal_error("getSymbolSection: Invalid section index.");
Res = section_iterator(SectionRef(DRI, this));
}
@@ -675,6 +676,11 @@ MachOObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
return symbol_iterator(SymbolRef(Sym, this));
}
+section_iterator
+MachOObjectFile::getRelocationSection(DataRefImpl Rel) const {
+ return section_iterator(getAnyRelocationSection(getRelocation(Rel)));
+}
+
std::error_code MachOObjectFile::getRelocationType(DataRefImpl Rel,
uint64_t &Res) const {
MachO::any_relocation_info RE = getRelocation(Rel);
@@ -1201,7 +1207,8 @@ basic_symbol_iterator MachOObjectFile::getSymbolByIndex(unsigned Index) const {
return basic_symbol_iterator(SymbolRef(DRI, this));
MachO::symtab_command Symtab = getSymtabLoadCommand();
- assert(Index < Symtab.nsyms && "Requested symbol index is out of range.");
+ if (Index >= Symtab.nsyms)
+ report_fatal_error("Requested symbol index is out of range.");
unsigned SymbolTableEntrySize =
is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
DRI.p = reinterpret_cast<uintptr_t>(getPtr(this, Symtab.symoff));
@@ -1501,7 +1508,7 @@ bool ExportEntry::operator==(const ExportEntry &Other) const {
if (Stack.size() != Other.Stack.size())
return false;
// Not equal if different cumulative strings.
- if (!CumulativeString.str().equals(Other.CumulativeString.str()))
+ if (!CumulativeString.equals(Other.CumulativeString))
return false;
// Equal if all nodes in both stacks match.
for (unsigned i=0; i < Stack.size(); ++i) {
@@ -1523,7 +1530,7 @@ uint64_t ExportEntry::readULEB128(const uint8_t *&Ptr) {
}
StringRef ExportEntry::name() const {
- return CumulativeString.str();
+ return CumulativeString;
}
uint64_t ExportEntry::flags() const {
@@ -2105,6 +2112,7 @@ MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const {
ArrayRef<char>
MachOObjectFile::getSectionRawName(DataRefImpl Sec) const {
+ assert(Sec.d.a < Sections.size() && "Should have detected this earlier");
const section_base *Base =
reinterpret_cast<const section_base *>(Sections[Sec.d.a]);
return makeArrayRef(Base->sectname);
@@ -2112,6 +2120,7 @@ MachOObjectFile::getSectionRawName(DataRefImpl Sec) const {
ArrayRef<char>
MachOObjectFile::getSectionRawFinalSegmentName(DataRefImpl Sec) const {
+ assert(Sec.d.a < Sections.size() && "Should have detected this earlier");
const section_base *Base =
reinterpret_cast<const section_base *>(Sections[Sec.d.a]);
return makeArrayRef(Base->segname);
@@ -2184,7 +2193,7 @@ MachOObjectFile::getAnyRelocationType(
}
SectionRef
-MachOObjectFile::getRelocationSection(
+MachOObjectFile::getAnyRelocationSection(
const MachO::any_relocation_info &RE) const {
if (isRelocationScattered(RE) || getPlainRelocationExternal(RE))
return *section_end();
@@ -2202,6 +2211,8 @@ MachOObjectFile::getFirstLoadCommandInfo() const {
sizeof(MachO::mach_header);
Load.Ptr = getPtr(this, HeaderSize);
Load.C = getStruct<MachO::load_command>(this, Load.Ptr);
+ if (Load.C.cmdsize < 8)
+ report_fatal_error("Load command with size < 8 bytes.");
return Load;
}
@@ -2210,14 +2221,18 @@ MachOObjectFile::getNextLoadCommandInfo(const LoadCommandInfo &L) const {
MachOObjectFile::LoadCommandInfo Next;
Next.Ptr = L.Ptr + L.C.cmdsize;
Next.C = getStruct<MachO::load_command>(this, Next.Ptr);
+ if (Next.C.cmdsize < 8)
+ report_fatal_error("Load command with size < 8 bytes.");
return Next;
}
MachO::section MachOObjectFile::getSection(DataRefImpl DRI) const {
+ assert(DRI.d.a < Sections.size() && "Should have detected this earlier");
return getStruct<MachO::section>(this, Sections[DRI.d.a]);
}
MachO::section_64 MachOObjectFile::getSection64(DataRefImpl DRI) const {
+ assert(DRI.d.a < Sections.size() && "Should have detected this earlier");
return getStruct<MachO::section_64>(this, Sections[DRI.d.a]);
}
@@ -2455,6 +2470,21 @@ MachOObjectFile::getDataInCodeLoadCommand() const {
return Cmd;
}
+MachO::linkedit_data_command
+MachOObjectFile::getLinkOptHintsLoadCommand() const {
+ if (LinkOptHintsLoadCmd)
+ return getStruct<MachO::linkedit_data_command>(this, LinkOptHintsLoadCmd);
+
+ // If there is no LinkOptHintsLoadCmd return a load command with zero'ed
+ // fields.
+ MachO::linkedit_data_command Cmd;
+ Cmd.cmd = MachO::LC_LINKER_OPTIMIZATION_HINT;
+ Cmd.cmdsize = sizeof(MachO::linkedit_data_command);
+ Cmd.dataoff = 0;
+ Cmd.datasize = 0;
+ return Cmd;
+}
+
ArrayRef<uint8_t> MachOObjectFile::getDyldInfoRebaseOpcodes() const {
if (!DyldInfoLoadCmd)
return ArrayRef<uint8_t>();
OpenPOWER on IntegriCloud