Index: llvm/include/llvm/Object/MachO.h =================================================================== --- llvm/include/llvm/Object/MachO.h +++ llvm/include/llvm/Object/MachO.h @@ -311,6 +311,9 @@ bool isSectionBitcode(DataRefImpl Sec) const override; bool isDebugSection(DataRefImpl Sec) const override; + /// Return the raw contents of an entire segment. + ArrayRef getSegmentContents(StringRef SegmentName) const; + /// When dsymutil generates the companion file, it strips all unnecessary /// sections (e.g. everything in the _TEXT segment) by omitting their body /// and setting the offset in their corresponding load command to zero. Index: llvm/include/llvm/ObjectYAML/MachOYAML.h =================================================================== --- llvm/include/llvm/ObjectYAML/MachOYAML.h +++ llvm/include/llvm/ObjectYAML/MachOYAML.h @@ -131,6 +131,7 @@ std::vector LoadCommands; std::vector
Sections; LinkEditData LinkEdit; + Optional RawLinkEditSegment; DWARFYAML::Data DWARF; }; Index: llvm/lib/Object/MachOObjectFile.cpp =================================================================== --- llvm/lib/Object/MachOObjectFile.cpp +++ llvm/lib/Object/MachOObjectFile.cpp @@ -2048,6 +2048,45 @@ SectionName == "__swift_ast"; } +namespace { +template +ArrayRef getSegmentContents(const MachOObjectFile &Obj, + MachOObjectFile::LoadCommandInfo LoadCmd, + StringRef SegmentName) { + auto SegmentOrErr = getStructOrErr(Obj, LoadCmd.Ptr); + if (!SegmentOrErr) { + consumeError(SegmentOrErr.takeError()); + return {}; + } + auto &Segment = SegmentOrErr.get(); + if (StringRef(Segment.segname, 16).startswith(SegmentName)) + return arrayRefFromStringRef(Obj.getData().slice( + Segment.fileoff, Segment.fileoff + Segment.filesize)); + return {}; +} +} + +ArrayRef MachOObjectFile::getSegmentContents(StringRef SegmentName) const { + for (auto LoadCmd : load_commands()) { + ArrayRef Contents; + switch (LoadCmd.C.cmd) { + case MachO::LC_SEGMENT: + Contents = ::getSegmentContents(*this, LoadCmd, + SegmentName); + break; + case MachO::LC_SEGMENT_64: + Contents = ::getSegmentContents(*this, LoadCmd, + SegmentName); + break; + default: + continue; + } + if (!Contents.empty()) + return Contents; + } + return {}; +} + unsigned MachOObjectFile::getSectionID(SectionRef Sec) const { return Sec.getRawDataRefImpl().d.a; } Index: llvm/lib/ObjectYAML/MachOEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/MachOEmitter.cpp +++ llvm/lib/ObjectYAML/MachOEmitter.cpp @@ -288,6 +288,7 @@ } Error MachOWriter::writeSectionData(raw_ostream &OS) { + uint64_t LinkEditOff = 0; for (auto &LC : Obj.LoadCommands) { switch (LC.Data.load_command_data.cmd) { case MachO::LC_SEGMENT: @@ -297,6 +298,9 @@ if (0 == strncmp(&LC.Data.segment_command_data.segname[0], "__LINKEDIT", 16)) { FoundLinkEditSeg = true; + LinkEditOff = segOff; + if (Obj.RawLinkEditSegment) + continue; writeLinkEditData(OS); } for (auto &Sec : LC.Sections) { @@ -344,6 +348,13 @@ } } + if (Obj.RawLinkEditSegment) { + ZeroToOffset(OS, LinkEditOff); + if (OS.tell() - fileStart > LinkEditOff || !LinkEditOff) + return createStringError(errc::invalid_argument, + "section offsets don't line up"); + Obj.RawLinkEditSegment->writeAsBinary(OS); + } return Error::success(); } Index: llvm/lib/ObjectYAML/MachOYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/MachOYAML.cpp +++ llvm/lib/ObjectYAML/MachOYAML.cpp @@ -110,9 +110,12 @@ Object.DWARF.Is64BitAddrSize = Object.Header.magic == MachO::MH_MAGIC_64 || Object.Header.magic == MachO::MH_CIGAM_64; IO.mapOptional("LoadCommands", Object.LoadCommands); + + if(Object.RawLinkEditSegment || !IO.outputting()) + IO.mapOptional("__LINKEDIT", Object.RawLinkEditSegment); if(!Object.LinkEdit.isEmpty() || !IO.outputting()) IO.mapOptional("LinkEditData", Object.LinkEdit); - + if(!Object.DWARF.isEmpty() || !IO.outputting()) IO.mapOptional("DWARF", Object.DWARF); Index: llvm/tools/obj2yaml/macho2yaml.cpp =================================================================== --- llvm/tools/obj2yaml/macho2yaml.cpp +++ llvm/tools/obj2yaml/macho2yaml.cpp @@ -29,6 +29,8 @@ const object::MachOObjectFile &Obj; std::unique_ptr DWARFCtx; + bool RawDataSegment; + bool RawLinkEditSegment; void dumpHeader(std::unique_ptr &Y); Error dumpLoadCommands(std::unique_ptr &Y); void dumpLinkEdit(std::unique_ptr &Y); @@ -52,8 +54,10 @@ public: MachODumper(const object::MachOObjectFile &O, - std::unique_ptr DCtx) - : Obj(O), DWARFCtx(std::move(DCtx)) {} + std::unique_ptr DCtx, bool RawDataSegment, + bool RawLinkEditSegment) + : Obj(O), DWARFCtx(std::move(DCtx)), RawDataSegment(RawDataSegment), + RawLinkEditSegment(RawLinkEditSegment) {} Expected> dump(); }; @@ -176,6 +180,11 @@ if (Expected S = constructSection(Sec, Sections.size() + 1)) { StringRef SecName(S->sectname); + + // Copy data sections if requested. + if (RawDataSegment && StringRef(S->segname).startswith("__DATA")) + S->content = yaml::BinaryRef(Obj.getSectionContents(Sec.offset, Sec.size)); + if (SecName.startswith("__debug_")) { // If the DWARF section cannot be successfully parsed, emit raw content // instead of an entry in the DWARF section of the YAML. @@ -282,7 +291,11 @@ dumpHeader(Y); if (Error Err = dumpLoadCommands(Y)) return std::move(Err); - dumpLinkEdit(Y); + if (RawLinkEditSegment) + Y->RawLinkEditSegment = + yaml::BinaryRef(Obj.getSegmentContents("__LINKEDIT")); + else + dumpLinkEdit(Y); return std::move(Y); } @@ -587,9 +600,10 @@ } } -Error macho2yaml(raw_ostream &Out, const object::MachOObjectFile &Obj) { +Error macho2yaml(raw_ostream &Out, const object::MachOObjectFile &Obj, + bool RawDataSegment, bool RawLinkEditSegment) { std::unique_ptr DCtx = DWARFContext::create(Obj); - MachODumper Dumper(Obj, std::move(DCtx)); + MachODumper Dumper(Obj, std::move(DCtx), RawDataSegment, RawLinkEditSegment); Expected> YAML = Dumper.dump(); if (!YAML) return YAML.takeError(); @@ -602,7 +616,8 @@ return Error::success(); } -Error macho2yaml(raw_ostream &Out, const object::MachOUniversalBinary &Obj) { +Error macho2yaml(raw_ostream &Out, const object::MachOUniversalBinary &Obj, + bool RawDataSegment, bool RawLinkEditSegment) { yaml::YamlObjectFile YAMLFile; YAMLFile.FatMachO.reset(new MachOYAML::UniversalBinary()); MachOYAML::UniversalBinary &YAML = *YAMLFile.FatMachO; @@ -624,7 +639,8 @@ return SliceObj.takeError(); std::unique_ptr DCtx = DWARFContext::create(*SliceObj.get()); - MachODumper Dumper(*SliceObj.get(), std::move(DCtx)); + MachODumper Dumper(*SliceObj.get(), std::move(DCtx), RawDataSegment, + RawLinkEditSegment); Expected> YAMLObj = Dumper.dump(); if (!YAMLObj) return YAMLObj.takeError(); @@ -636,12 +652,13 @@ return Error::success(); } -Error macho2yaml(raw_ostream &Out, const object::Binary &Binary) { +Error macho2yaml(raw_ostream &Out, const object::Binary &Binary, + bool RawDataSegment, bool RawLinkEditSegment) { if (const auto *MachOObj = dyn_cast(&Binary)) - return macho2yaml(Out, *MachOObj); + return macho2yaml(Out, *MachOObj, RawDataSegment, RawLinkEditSegment); if (const auto *MachOObj = dyn_cast(&Binary)) - return macho2yaml(Out, *MachOObj); + return macho2yaml(Out, *MachOObj, RawDataSegment, RawLinkEditSegment); llvm_unreachable("unexpected Mach-O file format"); } Index: llvm/tools/obj2yaml/obj2yaml.h =================================================================== --- llvm/tools/obj2yaml/obj2yaml.h +++ llvm/tools/obj2yaml/obj2yaml.h @@ -24,8 +24,8 @@ const llvm::object::COFFObjectFile &Obj); llvm::Error elf2yaml(llvm::raw_ostream &Out, const llvm::object::ObjectFile &Obj); -llvm::Error macho2yaml(llvm::raw_ostream &Out, - const llvm::object::Binary &Obj); +llvm::Error macho2yaml(llvm::raw_ostream &Out, const llvm::object::Binary &Obj, + bool RawDataSegment, bool RawLinkeditSegment); llvm::Error minidump2yaml(llvm::raw_ostream &Out, const llvm::object::MinidumpFile &Obj); llvm::Error xcoff2yaml(llvm::raw_ostream &Out, Index: llvm/tools/obj2yaml/obj2yaml.cpp =================================================================== --- llvm/tools/obj2yaml/obj2yaml.cpp +++ llvm/tools/obj2yaml/obj2yaml.cpp @@ -18,6 +18,19 @@ using namespace llvm; using namespace llvm::object; +static cl::opt + InputFilename(cl::Positional, cl::desc(""), cl::init("-")); +static cl::opt + RawDataSegment("raw-data-segment", + cl::desc("Mach-O: dump the raw contents of the __DATA " + "segment instead of parsing it"), + cl::init(false)); +static cl::opt RawLinkeditSegment( + "raw-linkedit-segment", + cl::desc("Mach-O: dump the raw contents of the __LINKEDIT " + "segment instead of parsing it"), + cl::init(false)); + static Error dumpObject(const ObjectFile &Obj) { if (Obj.isCOFF()) return errorCodeToError(coff2yaml(outs(), cast(Obj))); @@ -54,7 +67,7 @@ // Universal MachO is not a subclass of ObjectFile, so it needs to be handled // here with the other binary types. if (Binary.isMachO() || Binary.isMachOUniversalBinary()) - return macho2yaml(outs(), Binary); + return macho2yaml(outs(), Binary, RawDataSegment, RawLinkeditSegment); if (ObjectFile *Obj = dyn_cast(&Binary)) return dumpObject(*Obj); if (MinidumpFile *Minidump = dyn_cast(&Binary)) @@ -74,9 +87,6 @@ errs().flush(); } -cl::opt InputFilename(cl::Positional, cl::desc(""), - cl::init("-")); - int main(int argc, char *argv[]) { InitLLVM X(argc, argv); cl::ParseCommandLineOptions(argc, argv);