summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Object/MachOObjectFile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Object/MachOObjectFile.cpp')
-rw-r--r--llvm/lib/Object/MachOObjectFile.cpp228
1 files changed, 136 insertions, 92 deletions
diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp
index 340faa44a31..26aa5164710 100644
--- a/llvm/lib/Object/MachOObjectFile.cpp
+++ b/llvm/lib/Object/MachOObjectFile.cpp
@@ -38,6 +38,22 @@ namespace {
};
}
+// FIXME: Remove ECOverride once Error has been plumbed down to obj tool code.
+static Error
+malformedError(std::string FileName, std::string Msg,
+ object_error ECOverride = object_error::parse_failed) {
+ return make_error<GenericBinaryError>(std::move(FileName), std::move(Msg),
+ ECOverride);
+}
+
+
+// FIXME: Remove ECOverride once Error has been plumbed down to obj tool code.
+static Error
+malformedError(const MachOObjectFile &Obj, std::string Msg,
+ object_error ECOverride = object_error::parse_failed) {
+ return malformedError(Obj.getFileName(), std::move(Msg), ECOverride);
+}
+
// FIXME: Replace all uses of this function with getStructOrErr.
template <typename T>
static T getStruct(const MachOObjectFile *O, const char *P) {
@@ -53,10 +69,10 @@ static T getStruct(const MachOObjectFile *O, const char *P) {
}
template <typename T>
-static ErrorOr<T> getStructOrErr(const MachOObjectFile *O, const char *P) {
+static Expected<T> getStructOrErr(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())
- return object_error::parse_failed;
+ return malformedError(*O, "Structure read out-of-range");
T Cmd;
memcpy(&Cmd, P, sizeof(T));
@@ -161,27 +177,25 @@ static uint32_t getSectionFlags(const MachOObjectFile *O,
return Sect.flags;
}
-static ErrorOr<MachOObjectFile::LoadCommandInfo>
+static Expected<MachOObjectFile::LoadCommandInfo>
getLoadCommandInfo(const MachOObjectFile *Obj, const char *Ptr) {
- auto CmdOrErr = getStructOrErr<MachO::load_command>(Obj, Ptr);
- if (!CmdOrErr)
- return CmdOrErr.getError();
- if (CmdOrErr->cmdsize < 8)
- return object_error::macho_small_load_command;
- MachOObjectFile::LoadCommandInfo Load;
- Load.Ptr = Ptr;
- Load.C = CmdOrErr.get();
- return Load;
-}
-
-static ErrorOr<MachOObjectFile::LoadCommandInfo>
+ if (auto CmdOrErr = getStructOrErr<MachO::load_command>(Obj, Ptr)) {
+ if (CmdOrErr->cmdsize < 8)
+ return malformedError(*Obj, "Mach-O load command with size < 8 bytes",
+ object_error::macho_small_load_command);
+ return MachOObjectFile::LoadCommandInfo({Ptr, *CmdOrErr});
+ } else
+ return CmdOrErr.takeError();
+}
+
+static Expected<MachOObjectFile::LoadCommandInfo>
getFirstLoadCommandInfo(const MachOObjectFile *Obj) {
unsigned HeaderSize = Obj->is64Bit() ? sizeof(MachO::mach_header_64)
: sizeof(MachO::mach_header);
return getLoadCommandInfo(Obj, getPtr(Obj, HeaderSize));
}
-static ErrorOr<MachOObjectFile::LoadCommandInfo>
+static Expected<MachOObjectFile::LoadCommandInfo>
getNextLoadCommandInfo(const MachOObjectFile *Obj,
const MachOObjectFile::LoadCommandInfo &L) {
return getLoadCommandInfo(Obj, L.Ptr + L.C.cmdsize);
@@ -189,92 +203,104 @@ getNextLoadCommandInfo(const MachOObjectFile *Obj,
template <typename T>
static void parseHeader(const MachOObjectFile *Obj, T &Header,
- std::error_code &EC) {
- auto HeaderOrErr = getStructOrErr<T>(Obj, getPtr(Obj, 0));
- if (HeaderOrErr)
- Header = HeaderOrErr.get();
+ Error &Err) {
+ if (auto HeaderOrErr = getStructOrErr<T>(Obj, getPtr(Obj, 0)))
+ Header = *HeaderOrErr;
else
- EC = HeaderOrErr.getError();
+ Err = HeaderOrErr.takeError();
}
// Parses LC_SEGMENT or LC_SEGMENT_64 load command, adds addresses of all
// sections to \param Sections, and optionally sets
// \param IsPageZeroSegment to true.
template <typename SegmentCmd>
-static std::error_code parseSegmentLoadCommand(
+static Error parseSegmentLoadCommand(
const MachOObjectFile *Obj, const MachOObjectFile::LoadCommandInfo &Load,
SmallVectorImpl<const char *> &Sections, bool &IsPageZeroSegment) {
const unsigned SegmentLoadSize = sizeof(SegmentCmd);
if (Load.C.cmdsize < SegmentLoadSize)
- return object_error::macho_load_segment_too_small;
- auto SegOrErr = getStructOrErr<SegmentCmd>(Obj, Load.Ptr);
- if (!SegOrErr)
- return SegOrErr.getError();
- SegmentCmd S = SegOrErr.get();
- const unsigned SectionSize =
+ return malformedError(*Obj,
+ "Mach-O segment load command size is too small",
+ object_error::macho_load_segment_too_small);
+ if (auto SegOrErr = getStructOrErr<SegmentCmd>(Obj, Load.Ptr)) {
+ SegmentCmd S = SegOrErr.get();
+ const unsigned SectionSize =
Obj->is64Bit() ? sizeof(MachO::section_64) : sizeof(MachO::section);
- if (S.nsects > std::numeric_limits<uint32_t>::max() / SectionSize ||
- S.nsects * SectionSize > Load.C.cmdsize - SegmentLoadSize)
- return object_error::macho_load_segment_too_many_sections;
- for (unsigned J = 0; J < S.nsects; ++J) {
- const char *Sec = getSectionPtr(Obj, Load, J);
- Sections.push_back(Sec);
- }
- IsPageZeroSegment |= StringRef("__PAGEZERO").equals(S.segname);
- return std::error_code();
+ if (S.nsects > std::numeric_limits<uint32_t>::max() / SectionSize ||
+ S.nsects * SectionSize > Load.C.cmdsize - SegmentLoadSize)
+ return malformedError(*Obj,
+ "Mach-O segment load command contains too many "
+ "sections",
+ object_error::macho_load_segment_too_many_sections);
+ for (unsigned J = 0; J < S.nsects; ++J) {
+ const char *Sec = getSectionPtr(Obj, Load, J);
+ Sections.push_back(Sec);
+ }
+ IsPageZeroSegment |= StringRef("__PAGEZERO").equals(S.segname);
+ } else
+ return SegOrErr.takeError();
+
+ return Error::success();
}
MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
- bool Is64bits, std::error_code &EC)
+ bool Is64bits, Error &Err)
: ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object),
SymtabLoadCmd(nullptr), DysymtabLoadCmd(nullptr),
DataInCodeLoadCmd(nullptr), LinkOptHintsLoadCmd(nullptr),
DyldInfoLoadCmd(nullptr), UuidLoadCmd(nullptr),
HasPageZeroSegment(false) {
+
+ // We have to check Err before it's assigned to.
+ if (Err)
+ llvm_unreachable("Err should be in success state at entry to constructor.");
+
if (is64Bit())
- parseHeader(this, Header64, EC);
+ parseHeader(this, Header64, Err);
else
- parseHeader(this, Header, EC);
- if (EC)
+ parseHeader(this, Header, Err);
+ if (Err)
return;
uint32_t LoadCommandCount = getHeader().ncmds;
if (LoadCommandCount == 0)
return;
- auto LoadOrErr = getFirstLoadCommandInfo(this);
- if (!LoadOrErr) {
- EC = LoadOrErr.getError();
+ LoadCommandInfo Load;
+ if (auto LoadOrErr = getFirstLoadCommandInfo(this))
+ Load = *LoadOrErr;
+ else {
+ Err = LoadOrErr.takeError();
return;
}
- LoadCommandInfo Load = LoadOrErr.get();
+
for (unsigned I = 0; I < LoadCommandCount; ++I) {
LoadCommands.push_back(Load);
if (Load.C.cmd == MachO::LC_SYMTAB) {
// Multiple symbol tables
if (SymtabLoadCmd) {
- EC = object_error::parse_failed;
+ Err = malformedError(*this, "Multiple symbol tables");
return;
}
SymtabLoadCmd = Load.Ptr;
} else if (Load.C.cmd == MachO::LC_DYSYMTAB) {
// Multiple dynamic symbol tables
if (DysymtabLoadCmd) {
- EC = object_error::parse_failed;
+ Err = malformedError(*this, "Multiple dynamic symbol tables");
return;
}
DysymtabLoadCmd = Load.Ptr;
} else if (Load.C.cmd == MachO::LC_DATA_IN_CODE) {
// Multiple data in code tables
if (DataInCodeLoadCmd) {
- EC = object_error::parse_failed;
+ Err = malformedError(*this, "Multiple data-in-code tables");
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;
+ Err = malformedError(*this, "Multiple linker optimization hint tables");
return;
}
LinkOptHintsLoadCmd = Load.Ptr;
@@ -282,24 +308,24 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
Load.C.cmd == MachO::LC_DYLD_INFO_ONLY) {
// Multiple dyldinfo load commands
if (DyldInfoLoadCmd) {
- EC = object_error::parse_failed;
+ Err = malformedError(*this, "Multiple dyldinfo load commands");
return;
}
DyldInfoLoadCmd = Load.Ptr;
} else if (Load.C.cmd == MachO::LC_UUID) {
// Multiple UUID load commands
if (UuidLoadCmd) {
- EC = object_error::parse_failed;
+ Err = malformedError(*this, "Multiple UUID load commands");
return;
}
UuidLoadCmd = Load.Ptr;
} else if (Load.C.cmd == MachO::LC_SEGMENT_64) {
- if ((EC = parseSegmentLoadCommand<MachO::segment_command_64>(
- this, Load, Sections, HasPageZeroSegment)))
+ if ((Err = parseSegmentLoadCommand<MachO::segment_command_64>(
+ this, Load, Sections, HasPageZeroSegment)))
return;
} else if (Load.C.cmd == MachO::LC_SEGMENT) {
- if ((EC = parseSegmentLoadCommand<MachO::segment_command>(
- this, Load, Sections, HasPageZeroSegment)))
+ if ((Err = parseSegmentLoadCommand<MachO::segment_command>(
+ this, Load, Sections, HasPageZeroSegment)))
return;
} else if (Load.C.cmd == MachO::LC_LOAD_DYLIB ||
Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
@@ -309,19 +335,20 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
Libraries.push_back(Load.Ptr);
}
if (I < LoadCommandCount - 1) {
- auto LoadOrErr = getNextLoadCommandInfo(this, Load);
- if (!LoadOrErr) {
- EC = LoadOrErr.getError();
+ if (auto LoadOrErr = getNextLoadCommandInfo(this, Load))
+ Load = *LoadOrErr;
+ else {
+ Err = LoadOrErr.takeError();
return;
}
- Load = LoadOrErr.get();
}
}
if (!SymtabLoadCmd) {
if (DysymtabLoadCmd) {
- // Diagnostic("truncated or malformed object (contains LC_DYSYMTAB load "
- // "command without a LC_SYMTAB load command)");
- EC = object_error::parse_failed;
+ Err = malformedError(*this,
+ "truncated or malformed object (contains "
+ "LC_DYSYMTAB load command without a LC_SYMTAB load "
+ "command)");
return;
}
} else if (DysymtabLoadCmd) {
@@ -330,49 +357,57 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
MachO::dysymtab_command Dysymtab =
getStruct<MachO::dysymtab_command>(this, DysymtabLoadCmd);
if (Dysymtab.nlocalsym != 0 && Dysymtab.ilocalsym > Symtab.nsyms) {
- // Diagnostic("truncated or malformed object (ilocalsym in LC_DYSYMTAB "
- // "load command extends past the end of the symbol table)"
- EC = object_error::parse_failed;
+ Err = malformedError(*this,
+ "truncated or malformed object (iolocalsym in "
+ "LC_DYSYMTAB load command extends past the end of "
+ "the symbol table)");
return;
}
uint64_t big_size = Dysymtab.ilocalsym;
big_size += Dysymtab.nlocalsym;
if (Dysymtab.nlocalsym != 0 && big_size > Symtab.nsyms) {
- // Diagnostic("truncated or malformed object (ilocalsym plus nlocalsym "
- // "in LC_DYSYMTAB load command extends past the end of the symbol table)"
- EC = object_error::parse_failed;
+ Err = malformedError(*this,
+ "truncated or malformed object (ilocalsym plus "
+ "nlocalsym in LC_DYSYMTAB load command extends past "
+ "the end of the symbol table)");
return;
}
if (Dysymtab.nextdefsym != 0 && Dysymtab.ilocalsym > Symtab.nsyms) {
- // Diagnostic("truncated or malformed object (nextdefsym in LC_DYSYMTAB "
- // "load command extends past the end of the symbol table)"
- EC = object_error::parse_failed;
+ Err = malformedError(*this,
+ "truncated or malformed object (nextdefsym in "
+ "LC_DYSYMTAB load command extends past the end of "
+ "the symbol table)");
return;
}
big_size = Dysymtab.iextdefsym;
big_size += Dysymtab.nextdefsym;
if (Dysymtab.nextdefsym != 0 && big_size > Symtab.nsyms) {
- // Diagnostic("truncated or malformed object (iextdefsym plus nextdefsym "
- // "in LC_DYSYMTAB load command extends past the end of the symbol table)"
- EC = object_error::parse_failed;
+ Err = malformedError(*this,
+ "truncated or malformed object (iextdefsym plus "
+ "nextdefsym in LC_DYSYMTAB load command extends "
+ "past the end of the symbol table)");
return;
}
if (Dysymtab.nundefsym != 0 && Dysymtab.iundefsym > Symtab.nsyms) {
- // Diagnostic("truncated or malformed object (nundefsym in LC_DYSYMTAB "
- // "load command extends past the end of the symbol table)"
- EC = object_error::parse_failed;
+ Err = malformedError(*this,
+ "truncated or malformed object (nundefsym in "
+ "LC_DYSYMTAB load command extends past the end of "
+ "the symbol table)");
return;
}
big_size = Dysymtab.iundefsym;
big_size += Dysymtab.nundefsym;
if (Dysymtab.nundefsym != 0 && big_size > Symtab.nsyms) {
- // Diagnostic("truncated or malformed object (iundefsym plus nundefsym "
- // "in LC_DYSYMTAB load command extends past the end of the symbol table)"
- EC = object_error::parse_failed;
+ Err = malformedError(*this,
+ "truncated or malformed object (iundefsym plus "
+ "nundefsym in LC_DYSYMTAB load command extends past "
+ "the end of the symbol table");
return;
}
}
assert(LoadCommands.size() == LoadCommandCount);
+
+ Err = Error::success();
}
void MachOObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
@@ -2381,20 +2416,29 @@ bool MachOObjectFile::isRelocatableObject() const {
ErrorOr<std::unique_ptr<MachOObjectFile>>
ObjectFile::createMachOObjectFile(MemoryBufferRef Buffer) {
StringRef Magic = Buffer.getBuffer().slice(0, 4);
- std::error_code EC;
std::unique_ptr<MachOObjectFile> Ret;
- if (Magic == "\xFE\xED\xFA\xCE")
- Ret.reset(new MachOObjectFile(Buffer, false, false, EC));
- else if (Magic == "\xCE\xFA\xED\xFE")
- Ret.reset(new MachOObjectFile(Buffer, true, false, EC));
- else if (Magic == "\xFE\xED\xFA\xCF")
- Ret.reset(new MachOObjectFile(Buffer, false, true, EC));
- else if (Magic == "\xCF\xFA\xED\xFE")
- Ret.reset(new MachOObjectFile(Buffer, true, true, EC));
- else
+ if (Magic == "\xFE\xED\xFA\xCE") {
+ Error Err;
+ Ret.reset(new MachOObjectFile(Buffer, false, false, Err));
+ if (Err)
+ return errorToErrorCode(std::move(Err));
+ } else if (Magic == "\xCE\xFA\xED\xFE") {
+ Error Err;
+ Ret.reset(new MachOObjectFile(Buffer, true, false, Err));
+ if (Err)
+ return errorToErrorCode(std::move(Err));
+ } else if (Magic == "\xFE\xED\xFA\xCF") {
+ Error Err;
+ Ret.reset(new MachOObjectFile(Buffer, false, true, Err));
+ if (Err)
+ return errorToErrorCode(std::move(Err));
+ } else if (Magic == "\xCF\xFA\xED\xFE") {
+ Error Err;
+ Ret.reset(new MachOObjectFile(Buffer, true, true, Err));
+ if (Err)
+ return errorToErrorCode(std::move(Err));
+ } else
return object_error::parse_failed;
- if (EC)
- return EC;
return std::move(Ret);
}
OpenPOWER on IntegriCloud