diff --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h --- a/llvm/include/llvm/Object/MachO.h +++ b/llvm/include/llvm/Object/MachO.h @@ -297,6 +297,7 @@ uint64_t getSectionAddress(DataRefImpl Sec) const override; uint64_t getSectionIndex(DataRefImpl Sec) const override; uint64_t getSectionSize(DataRefImpl Sec) const override; + ArrayRef getSectionContents(uint32_t Offset, uint64_t Size) const; Expected> getSectionContents(DataRefImpl Sec) const override; uint64_t getSectionAlignment(DataRefImpl Sec) const override; diff --git a/llvm/include/llvm/ObjectYAML/MachOYAML.h b/llvm/include/llvm/ObjectYAML/MachOYAML.h --- a/llvm/include/llvm/ObjectYAML/MachOYAML.h +++ b/llvm/include/llvm/ObjectYAML/MachOYAML.h @@ -18,6 +18,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/ObjectYAML/DWARFYAML.h" +#include "llvm/ObjectYAML/YAML.h" #include "llvm/Support/YAMLTraits.h" #include #include @@ -39,6 +40,7 @@ llvm::yaml::Hex32 reserved1; llvm::yaml::Hex32 reserved2; llvm::yaml::Hex32 reserved3; + Optional content; }; struct FileHeader { @@ -198,6 +200,7 @@ template <> struct MappingTraits { static void mapping(IO &IO, MachOYAML::Section &Section); + static StringRef validate(IO &io, MachOYAML::Section &Section); }; template <> struct MappingTraits { diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -1945,6 +1945,11 @@ return SectSize; } +ArrayRef MachOObjectFile::getSectionContents(uint32_t Offset, + uint64_t Size) const { + return arrayRefFromStringRef(getData().substr(Offset, Size)); +} + Expected> MachOObjectFile::getSectionContents(DataRefImpl Sec) const { uint32_t Offset; @@ -1960,7 +1965,7 @@ Size = Sect.size; } - return arrayRefFromStringRef(getData().substr(Offset, Size)); + return getSectionContents(Offset, Size); } uint64_t MachOObjectFile::getSectionAlignment(DataRefImpl Sec) const { 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 @@ -314,8 +314,14 @@ if (isVirtualSection(Sec.flags & MachO::SECTION_TYPE)) continue; - // Fill section data with 0xDEADBEEF - Fill(OS, Sec.size, 0xDEADBEEFu); + if (Sec.content) { + yaml::BinaryRef Content = *Sec.content; + Content.writeAsBinary(OS); + ZeroFillBytes(OS, Sec.size - Content.binary_size()); + } else { + // Fill section data with 0xDEADBEEF + Fill(OS, Sec.size, 0xDEADBEEFu); + } } uint64_t segSize = is64Bit ? LC.Data.segment_command_64_data.filesize : LC.Data.segment_command_data.filesize; diff --git a/llvm/lib/ObjectYAML/MachOYAML.cpp b/llvm/lib/ObjectYAML/MachOYAML.cpp --- a/llvm/lib/ObjectYAML/MachOYAML.cpp +++ b/llvm/lib/ObjectYAML/MachOYAML.cpp @@ -287,6 +287,15 @@ IO.mapRequired("reserved1", Section.reserved1); IO.mapRequired("reserved2", Section.reserved2); IO.mapOptional("reserved3", Section.reserved3); + IO.mapOptional("content", Section.content); +} + +StringRef +MappingTraits::validate(IO &IO, + MachOYAML::Section &Section) { + if (Section.content && Section.size < Section.content->binary_size()) + return "Section size must be greater than or equal to the content size"; + return {}; } void MappingTraits::mapping( diff --git a/llvm/test/ObjectYAML/MachO/section_data.yaml b/llvm/test/ObjectYAML/MachO/section_data.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/ObjectYAML/MachO/section_data.yaml @@ -0,0 +1,161 @@ +## Show that yaml2obj supports custom section data for Mach-O YAML inputs. + +## Case 1: The size of content is greater than the section size. +# RUN: not yaml2obj --docnum=1 %s -o %t1 2>&1 | FileCheck %s --check-prefix=CASE1 +# CASE1: error: Section size must be greater than or equal to the content size + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 1 + sizeofcmds: 232 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0 + vmsize: 4 + fileoff: 392 + filesize: 4 + maxprot: 7 + initprot: 7 + nsects: 1 + flags: 0 + Sections: + - sectname: __data + segname: __DATA + addr: 0x0000000000000000 + size: 0 + offset: 0x00000188 + align: 2 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: CDAB3412 + +## Case 2: The content size content equals the section size. +# RUN: yaml2obj --docnum=2 %s > %t2 +# RUN: llvm-readobj --sections --section-data %t2 | FileCheck %s --check-prefix=CASE2 +# CASE2: Index: 0 +# CASE2-NEXT: Name: __data (5F 5F 64 61 74 61 00 00 00 00 00 00 00 00 00 00) +# CASE2-NEXT: Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00) +# CASE2-NEXT: Address: 0x0 +# CASE2-NEXT: Size: 0x4 +# CASE2-NEXT: Offset: 392 +# CASE2-NEXT: Alignment: 2 +# CASE2-NEXT: RelocationOffset: 0x0 +# CASE2-NEXT: RelocationCount: 0 +# CASE2-NEXT: Type: 0x0 +# CASE2-NEXT: Attributes [ (0x0) +# CASE2-NEXT: ] +# CASE2-NEXT: Reserved1: 0x0 +# CASE2-NEXT: Reserved2: 0x0 +# CASE2-NEXT: Reserved3: 0x0 +# CASE2-NEXT: SectionData ( +# CASE2-NEXT: 0000: CDAB3412 |..4.| +# CASE2-NEXT: ) + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 1 + sizeofcmds: 232 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0 + vmsize: 4 + fileoff: 392 + filesize: 4 + maxprot: 7 + initprot: 7 + nsects: 1 + flags: 0 + Sections: + - sectname: __data + segname: __DATA + addr: 0x0000000000000000 + size: 4 + offset: 0x00000188 + align: 2 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: CDAB3412 + +## Case 3: The content size is less than the section size. In this case, the area +## after the custom content is filled with zeroes. +# RUN: yaml2obj --docnum=3 %s > %t3 +# RUN: llvm-readobj --sections --section-data %t3 | FileCheck %s --check-prefix=CASE3 +# CASE3: Index: 0 +# CASE3-NEXT: Name: __data (5F 5F 64 61 74 61 00 00 00 00 00 00 00 00 00 00) +# CASE3-NEXT: Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00) +# CASE3-NEXT: Address: 0x0 +# CASE3-NEXT: Size: 0x4 +# CASE3-NEXT: Offset: 392 +# CASE3-NEXT: Alignment: 2 +# CASE3-NEXT: RelocationOffset: 0x0 +# CASE3-NEXT: RelocationCount: 0 +# CASE3-NEXT: Type: 0x0 +# CASE3-NEXT: Attributes [ (0x0) +# CASE3-NEXT: ] +# CASE3-NEXT: Reserved1: 0x0 +# CASE3-NEXT: Reserved2: 0x0 +# CASE3-NEXT: Reserved3: 0x0 +# CASE3-NEXT: SectionData ( +# CASE3-NEXT: 0000: AA000000 |....| +# CASE3-NEXT: ) + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 1 + sizeofcmds: 232 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0 + vmsize: 4 + fileoff: 392 + filesize: 4 + maxprot: 7 + initprot: 7 + nsects: 1 + flags: 0 + Sections: + - sectname: __data + segname: __DATA + addr: 0x0000000000000000 + size: 4 + offset: 0x00000188 + align: 2 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: AA diff --git a/llvm/test/ObjectYAML/MachO/virtual_section.yaml b/llvm/test/ObjectYAML/MachO/virtual_section.yaml --- a/llvm/test/ObjectYAML/MachO/virtual_section.yaml +++ b/llvm/test/ObjectYAML/MachO/virtual_section.yaml @@ -163,8 +163,7 @@ - '' ... -# CHECK: Sections: -# CHECK-NEXT: - sectname: __text +# CHECK: - sectname: __text # CHECK-NEXT: segname: __TEXT # CHECK-NEXT: addr: 0x0000000000000000 # CHECK-NEXT: size: 72 @@ -176,6 +175,7 @@ # CHECK-NEXT: reserved1: 0x00000000 # CHECK-NEXT: reserved2: 0x00000000 # CHECK-NEXT: reserved3: 0x00000000 +# CHECK-NEXT: content: {{(EFBEADDE){18}$}} # CHECK-NEXT: - sectname: __data # CHECK-NEXT: segname: __DATA # CHECK-NEXT: addr: 0x0000000000000048 @@ -188,6 +188,7 @@ # CHECK-NEXT: reserved1: 0x00000000 # CHECK-NEXT: reserved2: 0x00000000 # CHECK-NEXT: reserved3: 0x00000000 +# CHECK-NEXT: content: EFBEADDE{{$}} # CHECK-NEXT: - sectname: __bss # CHECK-NEXT: segname: __DATA # CHECK-NEXT: addr: 0x00000000000000A0 @@ -224,3 +225,4 @@ # CHECK-NEXT: reserved1: 0x00000000 # CHECK-NEXT: reserved2: 0x00000000 # CHECK-NEXT: reserved3: 0x00000000 +# CHECK-NEXT: content: {{.*}} diff --git a/llvm/tools/obj2yaml/macho2yaml.cpp b/llvm/tools/obj2yaml/macho2yaml.cpp --- a/llvm/tools/obj2yaml/macho2yaml.cpp +++ b/llvm/tools/obj2yaml/macho2yaml.cpp @@ -18,6 +18,11 @@ using namespace llvm; +static bool isVirtualSection(uint8_t type) { + return (type == MachO::S_ZEROFILL || type == MachO::S_GB_ZEROFILL || + type == MachO::S_THREAD_LOCAL_ZEROFILL); +} + class MachODumper { template @@ -39,6 +44,15 @@ void dumpDebugStrings(DWARFContext &DCtx, std::unique_ptr &Y); + template + MachOYAML::Section constructSectionCommon(SectionType Sec); + template + MachOYAML::Section constructSection(SectionType Sec); + template + const char * + extractSections(const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd, + std::vector &Sections); + public: MachODumper(const object::MachOObjectFile &O) : Obj(O) {} Expected> dump(); @@ -46,7 +60,7 @@ #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ case MachO::LCName: \ - memcpy((void *) & (LC.Data.LCStruct##_data), LoadCmd.Ptr, \ + memcpy((void *)&(LC.Data.LCStruct##_data), LoadCmd.Ptr, \ sizeof(MachO::LCStruct)); \ if (Obj.isLittleEndian() != sys::IsLittleEndianHost) \ MachO::swapStruct(LC.Data.LCStruct##_data); \ @@ -54,7 +68,7 @@ break; template -MachOYAML::Section constructSectionCommon(SectionType Sec) { +MachOYAML::Section MachODumper::constructSectionCommon(SectionType Sec) { MachOYAML::Section TempSec; memcpy(reinterpret_cast(&TempSec.sectname[0]), &Sec.sectname[0], 16); memcpy(reinterpret_cast(&TempSec.segname[0]), &Sec.segname[0], 16); @@ -68,34 +82,35 @@ TempSec.reserved1 = Sec.reserved1; TempSec.reserved2 = Sec.reserved2; TempSec.reserved3 = 0; + if (!isVirtualSection(Sec.flags & MachO::SECTION_TYPE)) + TempSec.content = + yaml::BinaryRef(Obj.getSectionContents(Sec.offset, Sec.size)); return TempSec; } -template -MachOYAML::Section constructSection(SectionType Sec); - -template <> MachOYAML::Section constructSection(MachO::section Sec) { +template <> +MachOYAML::Section MachODumper::constructSection(MachO::section Sec) { MachOYAML::Section TempSec = constructSectionCommon(Sec); TempSec.reserved3 = 0; return TempSec; } -template <> MachOYAML::Section constructSection(MachO::section_64 Sec) { +template <> +MachOYAML::Section MachODumper::constructSection(MachO::section_64 Sec) { MachOYAML::Section TempSec = constructSectionCommon(Sec); TempSec.reserved3 = Sec.reserved3; return TempSec; } template -const char * -extractSections(const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd, - std::vector &Sections, - bool IsLittleEndian) { +const char *MachODumper::extractSections( + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd, + std::vector &Sections) { auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize; const SectionType *Curr = reinterpret_cast(LoadCmd.Ptr + sizeof(SegmentType)); for (; reinterpret_cast(Curr) < End; Curr++) { - if (IsLittleEndian != sys::IsLittleEndianHost) { + if (Obj.isLittleEndian() != sys::IsLittleEndianHost) { SectionType Sec; memcpy((void *)&Sec, Curr, sizeof(SectionType)); MachO::swapStruct(Sec); @@ -118,8 +133,8 @@ const char *MachODumper::processLoadCommandData( MachOYAML::LoadCommand &LC, const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { - return extractSections( - LoadCmd, LC.Sections, Obj.isLittleEndian()); + return extractSections(LoadCmd, + LC.Sections); } template <> @@ -127,7 +142,7 @@ MachOYAML::LoadCommand &LC, const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { return extractSections( - LoadCmd, LC.Sections, Obj.isLittleEndian()); + LoadCmd, LC.Sections); } template