Add support for the new LC_NOTE load command.

It describes a region of arbitrary data included in a Mach-O file.
Its initial use is to record extra data in MH_CORE files.

rdar://30001545
rdar://30001731

llvm-svn: 292500
This commit is contained in:
Kevin Enderby 2017-01-19 17:36:31 +00:00
parent 5efa0b5fb4
commit 59a3f7063b
11 changed files with 137 additions and 0 deletions

View File

@ -351,6 +351,8 @@ public:
getLinkerOptionLoadCommand(const LoadCommandInfo &L) const;
MachO::version_min_command
getVersionMinLoadCommand(const LoadCommandInfo &L) const;
MachO::note_command
getNoteLoadCommand(const LoadCommandInfo &L) const;
MachO::dylib_command
getDylibIDLoadCommand(const LoadCommandInfo &L) const;
MachO::dyld_info_command

View File

@ -73,6 +73,7 @@ HANDLE_LOAD_COMMAND(LC_LINKER_OPTION, 0x0000002Du, linker_option_command)
HANDLE_LOAD_COMMAND(LC_LINKER_OPTIMIZATION_HINT, 0x0000002Eu, linkedit_data_command)
HANDLE_LOAD_COMMAND(LC_VERSION_MIN_TVOS, 0x0000002Fu, version_min_command)
HANDLE_LOAD_COMMAND(LC_VERSION_MIN_WATCHOS, 0x00000030u, version_min_command)
HANDLE_LOAD_COMMAND(LC_NOTE, 0x00000031u, note_command)
#endif
@ -109,6 +110,7 @@ LOAD_COMMAND_STRUCT(thread_command)
LOAD_COMMAND_STRUCT(twolevel_hints_command)
LOAD_COMMAND_STRUCT(uuid_command)
LOAD_COMMAND_STRUCT(version_min_command)
LOAD_COMMAND_STRUCT(note_command)
#endif

View File

@ -819,6 +819,14 @@ namespace llvm {
uint32_t sdk; // X.Y.Z is encoded in nibbles xxxx.yy.zz
};
struct note_command {
uint32_t cmd; // LC_NOTE
uint32_t cmdsize; // sizeof(struct note_command)
char data_owner[16]; // owner name for this LC_NOTE
uint64_t offset; // file offset of this data
uint64_t size; // length of data region
};
struct dyld_info_command {
uint32_t cmd;
uint32_t cmdsize;
@ -1266,6 +1274,13 @@ namespace llvm {
sys::swapByteOrder(C.sdk);
}
inline void swapStruct(note_command &C) {
sys::swapByteOrder(C.cmd);
sys::swapByteOrder(C.cmdsize);
sys::swapByteOrder(C.offset);
sys::swapByteOrder(C.size);
}
inline void swapStruct(data_in_code_entry &C) {
sys::swapByteOrder(C.offset);
sys::swapByteOrder(C.length);

View File

@ -784,6 +784,31 @@ static Error checkVersCommand(const MachOObjectFile &Obj,
return Error::success();
}
static Error checkNoteCommand(const MachOObjectFile &Obj,
const MachOObjectFile::LoadCommandInfo &Load,
uint32_t LoadCommandIndex,
std::list<MachOElement> &Elements) {
if (Load.C.cmdsize != sizeof(MachO::note_command))
return malformedError("load command " + Twine(LoadCommandIndex) +
" LC_NOTE has incorrect cmdsize");
MachO::note_command Nt = getStruct<MachO::note_command>(Obj, Load.Ptr);
uint64_t FileSize = Obj.getData().size();
if (Nt.offset > FileSize)
return malformedError("offset field of LC_NOTE command " +
Twine(LoadCommandIndex) + " extends "
"past the end of the file");
uint64_t BigSize = Nt.offset;
BigSize += Nt.size;
if (BigSize > FileSize)
return malformedError("size field plus offset field of LC_NOTE command " +
Twine(LoadCommandIndex) + " extends past the end of "
"the file");
if (Error Err = checkOverlappingElement(Elements, Nt.offset, Nt.size,
"LC_NOTE data"))
return Err;
return Error::success();
}
static Error checkRpathCommand(const MachOObjectFile &Obj,
const MachOObjectFile::LoadCommandInfo &Load,
uint32_t LoadCommandIndex) {
@ -1280,6 +1305,9 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,
"LC_VERSION_MIN_WATCHOS")))
return;
} else if (Load.C.cmd == MachO::LC_NOTE) {
if ((Err = checkNoteCommand(*this, Load, I, Elements)))
return;
} else if (Load.C.cmd == MachO::LC_RPATH) {
if ((Err = checkRpathCommand(*this, Load, I)))
return;
@ -3289,6 +3317,11 @@ MachOObjectFile::getVersionMinLoadCommand(const LoadCommandInfo &L) const {
return getStruct<MachO::version_min_command>(*this, L.Ptr);
}
MachO::note_command
MachOObjectFile::getNoteLoadCommand(const LoadCommandInfo &L) const {
return getStruct<MachO::note_command>(*this, L.Ptr);
}
MachO::dylib_command
MachOObjectFile::getDylibIDLoadCommand(const LoadCommandInfo &L) const {
return getStruct<MachO::dylib_command>(*this, L.Ptr);

View File

@ -558,6 +558,14 @@ void MappingTraits<MachO::version_min_command>::mapping(
IO.mapRequired("sdk", LoadCommand.sdk);
}
void MappingTraits<MachO::note_command>::mapping(
IO &IO, MachO::note_command &LoadCommand) {
IO.mapRequired("data_owner", LoadCommand.data_owner);
IO.mapRequired("offset", LoadCommand.offset);
IO.mapRequired("size", LoadCommand.size);
}
} // namespace llvm::yaml
} // namespace llvm

Binary file not shown.

View File

@ -505,3 +505,6 @@ INVALID-FAT-ARCH-OVERLAP: macho-invalid-fat-arch-overlap': truncated or malforme
RUN: not llvm-objdump -macho -universal-headers %p/Inputs/macho-invalid-fat-arch-overlapheaders 2>&1 | FileCheck -check-prefix INVALID-FAT-ARCH-OVERLAPHEADERS %s
INVALID-FAT-ARCH-OVERLAPHEADERS: macho-invalid-fat-arch-overlapheaders': truncated or malformed fat file (cputype (7) cpusubtype (3) offset 12 overlaps universal headers)
RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-note 2>&1 | FileCheck -check-prefix INVALID-NOTE-COMMAND %s
INVALID-NOTE-COMMAND: macho-invalid-note': truncated or malformed object (size field plus offset field of LC_NOTE command 0 extends past the end of the file)

View File

@ -0,0 +1,50 @@
# RUN: yaml2obj %s | obj2yaml | FileCheck %s
--- !mach-o
FileHeader:
magic: 0xFEEDFACE
cputype: 0x00000007
cpusubtype: 0x00000003
filetype: 0x00000004
ncmds: 2
sizeofcmds: 192
flags: 0x00000000
LoadCommands:
- cmd: LC_SEGMENT_64
cmdsize: 152
segname: __TEXT
vmaddr: 4294967296
vmsize: 8192
fileoff: 0
filesize: 3099
maxprot: 7
initprot: 5
nsects: 1
flags: 0
Sections:
- sectname: __text
segname: __TEXT
addr: 0x0000000100001160
size: 3099
offset: 0x00001160
align: 4
reloff: 0x00000000
nreloc: 0
flags: 0x80000400
reserved1: 0x00000000
reserved2: 0x00000000
reserved3: 0x00000000
- cmd: LC_NOTE
cmdsize: 40
data_owner: DATA OWNER
offset: 220
size: 8
...
#CHECK: LoadCommands:
#CHECK: - cmd: LC_NOTE
#CHECK_NEXT: cmdsize: 40
#CHECK_NEXT: data_owner: DATA OWNER
#CHECK_NEXT: offset: 220
#CHECK_NEXT: size: 8

Binary file not shown.

View File

@ -23,6 +23,8 @@
// RUN: | FileCheck %s -check-prefix=NON_VERBOSE
// RUN: llvm-objdump -p %p/Inputs/codesig.macho-x86_64 \
// RUN: | FileCheck %s -check-prefix=CODESIG
// RUN: llvm-objdump -p %p/Inputs/note.macho-x86 \
// RUN: | FileCheck %s -check-prefix=NOTE
CHECK: Mach header
CHECK: magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
@ -544,3 +546,9 @@ CODESIG: cmd LC_CODE_SIGNATURE
CODESIG: cmdsize 16
CODESIG: dataoff 8496
CODESIG: datasize 64
NOTE: cmd LC_NOTE
NOTE: cmdsize 40
NOTE: data_owner DATA OWNER
NOTE: offset 68
NOTE: size 8

View File

@ -8169,6 +8169,19 @@ static void PrintVersionMinLoadCommand(MachO::version_min_command vd) {
outs() << "\n";
}
static void PrintNoteLoadCommand(MachO::note_command Nt) {
outs() << " cmd LC_NOTE\n";
outs() << " cmdsize " << Nt.cmdsize;
if (Nt.cmdsize != sizeof(struct MachO::note_command))
outs() << " Incorrect size\n";
else
outs() << "\n";
const char *d = Nt.data_owner;
outs() << "data_owner " << format("%.16s\n", d);
outs() << " offset " << Nt.offset << "\n";
outs() << " size " << Nt.size << "\n";
}
static void PrintSourceVersionCommand(MachO::source_version_command sd) {
outs() << " cmd LC_SOURCE_VERSION\n";
outs() << " cmdsize " << sd.cmdsize;
@ -9014,6 +9027,9 @@ static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype,
Command.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) {
MachO::version_min_command Vd = Obj->getVersionMinLoadCommand(Command);
PrintVersionMinLoadCommand(Vd);
} else if (Command.C.cmd == MachO::LC_NOTE) {
MachO::note_command Nt = Obj->getNoteLoadCommand(Command);
PrintNoteLoadCommand(Nt);
} else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) {
MachO::source_version_command Sd = Obj->getSourceVersionCommand(Command);
PrintSourceVersionCommand(Sd);