diff --git a/llvm/lib/ObjectYAML/MachOEmitter.cpp b/llvm/lib/ObjectYAML/MachOEmitter.cpp --- a/llvm/lib/ObjectYAML/MachOEmitter.cpp +++ b/llvm/lib/ObjectYAML/MachOEmitter.cpp @@ -15,6 +15,8 @@ #include "llvm/ObjectYAML/DWARFEmitter.h" #include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/ObjectYAML/yaml2obj.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" @@ -33,12 +35,12 @@ memset(reinterpret_cast(&Header), 0, sizeof(MachO::mach_header_64)); } - void writeMachO(raw_ostream &OS); + Error writeMachO(raw_ostream &OS); private: void writeHeader(raw_ostream &OS); void writeLoadCommands(raw_ostream &OS); - void writeSectionData(raw_ostream &OS); + Error writeSectionData(raw_ostream &OS); void writeRelocations(raw_ostream &OS); void writeLinkEditData(raw_ostream &OS); @@ -66,14 +68,16 @@ bool FoundLinkEditSeg = false; }; -void MachOWriter::writeMachO(raw_ostream &OS) { +Error MachOWriter::writeMachO(raw_ostream &OS) { fileStart = OS.tell(); writeHeader(OS); writeLoadCommands(OS); - writeSectionData(OS); + if (Error Err = writeSectionData(OS)) + return Err; writeRelocations(OS); if (!FoundLinkEditSeg) writeLinkEditData(OS); + return Error::success(); } void MachOWriter::writeHeader(raw_ostream &OS) { @@ -261,7 +265,7 @@ } } -void MachOWriter::writeSectionData(raw_ostream &OS) { +Error MachOWriter::writeSectionData(raw_ostream &OS) { for (auto &LC : Obj.LoadCommands) { switch (LC.Data.load_command_data.cmd) { case MachO::LC_SEGMENT: @@ -277,9 +281,10 @@ ZeroToOffset(OS, Sec.offset); // Zero Fill any data between the end of the last thing we wrote and the // start of this section. - assert((OS.tell() - fileStart <= Sec.offset || - Sec.offset == (uint32_t)0) && - "Wrote too much data somewhere, section offsets don't line up."); + if (OS.tell() - fileStart > Sec.offset && Sec.offset != (uint32_t)0) + return createStringError( + errc::invalid_argument, + "wrote too much data somewhere, section offsets don't line up"); if (0 == strncmp(&Sec.segname[0], "__DWARF", 16)) { if (0 == strncmp(&Sec.sectname[0], "__debug_str", 16)) { DWARFYAML::EmitDebugStr(OS, Obj.DWARF); @@ -323,6 +328,8 @@ break; } } + + return Error::success(); } // The implementation of makeRelocationInfo and makeScatteredRelocationInfo is @@ -528,7 +535,7 @@ UniversalWriter(yaml::YamlObjectFile &ObjectFile) : ObjectFile(ObjectFile), fileStart(0) {} - void writeMachO(raw_ostream &OS); + Error writeMachO(raw_ostream &OS); private: void writeFatHeader(raw_ostream &OS); @@ -540,28 +547,33 @@ uint64_t fileStart; }; -void UniversalWriter::writeMachO(raw_ostream &OS) { +Error UniversalWriter::writeMachO(raw_ostream &OS) { fileStart = OS.tell(); if (ObjectFile.MachO) { MachOWriter Writer(*ObjectFile.MachO); - Writer.writeMachO(OS); - return; + return Writer.writeMachO(OS); } writeFatHeader(OS); writeFatArchs(OS); auto &FatFile = *ObjectFile.FatMachO; - assert(FatFile.FatArchs.size() >= FatFile.Slices.size() && - "Cannot write Slices if not decribed in FatArches"); + if (FatFile.FatArchs.size() < FatFile.Slices.size()) + return createStringError( + errc::invalid_argument, + "cannot write 'Slices' if not described in 'FatArches'"); + for (size_t i = 0; i < FatFile.Slices.size(); i++) { ZeroToOffset(OS, FatFile.FatArchs[i].offset); MachOWriter Writer(FatFile.Slices[i]); - Writer.writeMachO(OS); + if (Error Err = Writer.writeMachO(OS)) + return Err; auto SliceEnd = FatFile.FatArchs[i].offset + FatFile.FatArchs[i].size; ZeroToOffset(OS, SliceEnd); } + + return Error::success(); } void UniversalWriter::writeFatHeader(raw_ostream &OS) { @@ -629,9 +641,13 @@ namespace llvm { namespace yaml { -bool yaml2macho(YamlObjectFile &Doc, raw_ostream &Out, ErrorHandler /*EH*/) { +bool yaml2macho(YamlObjectFile &Doc, raw_ostream &Out, ErrorHandler EH) { UniversalWriter Writer(Doc); - Writer.writeMachO(Out); + if (Error Err = Writer.writeMachO(Out)) { + handleAllErrors(std::move(Err), + [&](const ErrorInfoBase &Err) { EH(Err.message()); }); + return false; + } return true; } diff --git a/llvm/test/ObjectYAML/MachO/fat_macho_i386_x86_64.yaml b/llvm/test/ObjectYAML/MachO/fat_macho_i386_x86_64.yaml --- a/llvm/test/ObjectYAML/MachO/fat_macho_i386_x86_64.yaml +++ b/llvm/test/ObjectYAML/MachO/fat_macho_i386_x86_64.yaml @@ -1,4 +1,9 @@ -# RUN: yaml2obj %s | obj2yaml | FileCheck %s +## This file contains test cases for generating Fat Mach-O binaries. + +## a) Test that yaml2obj emits Fat Mach-O binary and obj2yaml converts it +## back to YAML file. + +# RUN: yaml2obj --docnum=1 %s | obj2yaml | FileCheck %s --- !fat-mach-o FatHeader: @@ -72,3 +77,39 @@ #CHECK: flags: 0x00218085 #CHECK: reserved: 0x00000000 #CHECK: ... + +## b) Test that yaml2obj emits an error message if the number of 'FatArchs' is less than +## the number of 'Slices'. + +# RUN: not yaml2obj --docnum=2 %s -o %t2.fat-macho 2>&1 | FileCheck %s --check-prefix=ERROR + +# ERROR: yaml2obj: error: cannot write 'Slices' if not described in 'FatArches' + +--- !fat-mach-o +FatHeader: + magic: 0xCAFEBABE + nfat_arch: 2 +FatArchs: + ## 2 FatArchs are expected. + - cputype: 0x00000007 + cpusubtype: 0x00000003 + offset: 0x0000000000001000 + size: 0 + align: 0 +Slices: + - FileHeader: + magic: 0xFEEDFACE + cputype: 0x00000007 + cpusubtype: 0x00000003 + filetype: 0x00000002 + ncmds: 0 + sizeofcmds: 0 + flags: 0x00000000 + - FileHeader: + magic: 0xFEEDFACE + cputype: 0x00000007 + cpusubtype: 0x00000003 + filetype: 0x00000002 + ncmds: 0 + sizeofcmds: 0 + flags: 0x00000000 diff --git a/llvm/test/ObjectYAML/MachO/sections.yaml b/llvm/test/ObjectYAML/MachO/sections.yaml --- a/llvm/test/ObjectYAML/MachO/sections.yaml +++ b/llvm/test/ObjectYAML/MachO/sections.yaml @@ -1,4 +1,8 @@ -# RUN: yaml2obj %s | obj2yaml | FileCheck %s +## This file contains test cases for generating sections in Mach-O object files. + +## a) Test that yaml2obj emits sections and obj2yaml converts them back. + +# RUN: yaml2obj --docnum=1 %s | obj2yaml | FileCheck %s --- !mach-o FileHeader: @@ -281,3 +285,58 @@ #CHECK: segname: __DATA #CHECK: - sectname: __la_symbol_ptr #CHECK: segname: __DATA + +## b) Test that yaml2obj emits an error message if we specify an offset that +## makes the current section and the previous one overlap. + +# RUN: not yaml2obj --docnum=2 %s -o %t2.macho 2>&1 | FileCheck %s --check-prefix=OVERLAP + +# OVERLAP: yaml2obj: error: wrote too much data somewhere, section offsets don't line up + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x80000003 + filetype: 0x00000002 + ncmds: 1 + sizeofcmds: 1024 + flags: 0x00000000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 0xff + segname: __SEC + vmaddr: 0 + vmsize: 0 + fileoff: 0 + filesize: 0 + maxprot: 0 + initprot: 0 + nsects: 2 + flags: 0 + Sections: + - sectname: __sec1 + segname: __SEC + addr: 0x0000000000000000 + size: 2 + offset: 0x00000000 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __sec2 + segname: __SEC + addr: 0x0000000000000000 + size: 2 + offset: 0x00000001 ## Specify an offset that makes __sec1 and __sec2 overlap. + align: 1 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000