[yaml2obj/obj2yaml][MachO] Allow setting custom section data

Reviewers: alexshap, jhenderson, rupprecht

Reviewed By: alexshap, jhenderson

Subscribers: abrachet, hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D65799

llvm-svn: 369348
This commit is contained in:
Seiya Nuta 2019-08-20 08:49:07 +00:00
parent 9c371309f3
commit 522377494b
9 changed files with 223 additions and 26 deletions

View File

@ -581,6 +581,11 @@ struct section_64 {
uint32_t reserved3;
};
inline bool isVirtualSection(uint8_t type) {
return (type == MachO::S_ZEROFILL || type == MachO::S_GB_ZEROFILL ||
type == MachO::S_THREAD_LOCAL_ZEROFILL);
}
struct fvmlib {
uint32_t name;
uint32_t minor_version;

View File

@ -297,6 +297,7 @@ public:
uint64_t getSectionAddress(DataRefImpl Sec) const override;
uint64_t getSectionIndex(DataRefImpl Sec) const override;
uint64_t getSectionSize(DataRefImpl Sec) const override;
ArrayRef<uint8_t> getSectionContents(uint32_t Offset, uint64_t Size) const;
Expected<ArrayRef<uint8_t>>
getSectionContents(DataRefImpl Sec) const override;
uint64_t getSectionAlignment(DataRefImpl Sec) const override;

View File

@ -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 <cstdint>
#include <string>
@ -39,6 +40,7 @@ struct Section {
llvm::yaml::Hex32 reserved1;
llvm::yaml::Hex32 reserved2;
llvm::yaml::Hex32 reserved3;
Optional<llvm::yaml::BinaryRef> content;
};
struct FileHeader {
@ -198,6 +200,7 @@ template <> struct MappingTraits<MachOYAML::ExportEntry> {
template <> struct MappingTraits<MachOYAML::Section> {
static void mapping(IO &IO, MachOYAML::Section &Section);
static StringRef validate(IO &io, MachOYAML::Section &Section);
};
template <> struct MappingTraits<MachOYAML::NListEntry> {

View File

@ -1945,6 +1945,11 @@ uint64_t MachOObjectFile::getSectionSize(DataRefImpl Sec) const {
return SectSize;
}
ArrayRef<uint8_t> MachOObjectFile::getSectionContents(uint32_t Offset,
uint64_t Size) const {
return arrayRefFromStringRef(getData().substr(Offset, Size));
}
Expected<ArrayRef<uint8_t>>
MachOObjectFile::getSectionContents(DataRefImpl Sec) const {
uint32_t Offset;
@ -1960,7 +1965,7 @@ MachOObjectFile::getSectionContents(DataRefImpl Sec) const {
Size = Sect.size;
}
return arrayRefFromStringRef(getData().substr(Offset, Size));
return getSectionContents(Offset, Size);
}
uint64_t MachOObjectFile::getSectionAlignment(DataRefImpl Sec) const {

View File

@ -262,11 +262,6 @@ Error MachOWriter::writeLoadCommands(raw_ostream &OS) {
return Error::success();
}
static bool isVirtualSection(uint8_t type) {
return (type == MachO::S_ZEROFILL || type == MachO::S_GB_ZEROFILL ||
type == MachO::S_THREAD_LOCAL_ZEROFILL);
}
Error MachOWriter::writeSectionData(raw_ostream &OS) {
bool FoundLinkEditSeg = false;
for (auto &LC : Obj.LoadCommands) {
@ -311,11 +306,17 @@ Error MachOWriter::writeSectionData(raw_ostream &OS) {
}
// Skip if it's a virtual section.
if (isVirtualSection(Sec.flags & MachO::SECTION_TYPE))
if (MachO::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;

View File

@ -287,6 +287,15 @@ void MappingTraits<MachOYAML::Section>::mapping(IO &IO,
IO.mapRequired("reserved1", Section.reserved1);
IO.mapRequired("reserved2", Section.reserved2);
IO.mapOptional("reserved3", Section.reserved3);
IO.mapOptional("content", Section.content);
}
StringRef
MappingTraits<MachOYAML::Section>::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<MachO::build_tool_version>::mapping(

View File

@ -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 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: Regular (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: Regular (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

View File

@ -163,8 +163,7 @@ LinkEditData:
- ''
...
# 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 @@ LinkEditData:
# 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 @@ LinkEditData:
# 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 @@ LinkEditData:
# CHECK-NEXT: reserved1: 0x00000000
# CHECK-NEXT: reserved2: 0x00000000
# CHECK-NEXT: reserved3: 0x00000000
# CHECK-NEXT: content: {{.*}}

View File

@ -39,6 +39,15 @@ class MachODumper {
void dumpDebugStrings(DWARFContext &DCtx,
std::unique_ptr<MachOYAML::Object> &Y);
template <typename SectionType>
MachOYAML::Section constructSectionCommon(SectionType Sec);
template <typename SectionType>
MachOYAML::Section constructSection(SectionType Sec);
template <typename SectionType, typename SegmentType>
const char *
extractSections(const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd,
std::vector<MachOYAML::Section> &Sections);
public:
MachODumper(const object::MachOObjectFile &O) : Obj(O) {}
Expected<std::unique_ptr<MachOYAML::Object>> dump();
@ -46,7 +55,7 @@ public:
#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 +63,7 @@ public:
break;
template <typename SectionType>
MachOYAML::Section constructSectionCommon(SectionType Sec) {
MachOYAML::Section MachODumper::constructSectionCommon(SectionType Sec) {
MachOYAML::Section TempSec;
memcpy(reinterpret_cast<void *>(&TempSec.sectname[0]), &Sec.sectname[0], 16);
memcpy(reinterpret_cast<void *>(&TempSec.segname[0]), &Sec.segname[0], 16);
@ -68,34 +77,35 @@ MachOYAML::Section constructSectionCommon(SectionType Sec) {
TempSec.reserved1 = Sec.reserved1;
TempSec.reserved2 = Sec.reserved2;
TempSec.reserved3 = 0;
if (!MachO::isVirtualSection(Sec.flags & MachO::SECTION_TYPE))
TempSec.content =
yaml::BinaryRef(Obj.getSectionContents(Sec.offset, Sec.size));
return TempSec;
}
template <typename SectionType>
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 <typename SectionType, typename SegmentType>
const char *
extractSections(const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd,
std::vector<MachOYAML::Section> &Sections,
bool IsLittleEndian) {
const char *MachODumper::extractSections(
const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd,
std::vector<MachOYAML::Section> &Sections) {
auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize;
const SectionType *Curr =
reinterpret_cast<const SectionType *>(LoadCmd.Ptr + sizeof(SegmentType));
for (; reinterpret_cast<const void *>(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 +128,8 @@ template <>
const char *MachODumper::processLoadCommandData<MachO::segment_command>(
MachOYAML::LoadCommand &LC,
const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) {
return extractSections<MachO::section, MachO::segment_command>(
LoadCmd, LC.Sections, Obj.isLittleEndian());
return extractSections<MachO::section, MachO::segment_command>(LoadCmd,
LC.Sections);
}
template <>
@ -127,7 +137,7 @@ const char *MachODumper::processLoadCommandData<MachO::segment_command_64>(
MachOYAML::LoadCommand &LC,
const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) {
return extractSections<MachO::section_64, MachO::segment_command_64>(
LoadCmd, LC.Sections, Obj.isLittleEndian());
LoadCmd, LC.Sections);
}
template <typename StructType>