From a4579c41843e1aa48d29cc837108b0a112d8ba8a Mon Sep 17 00:00:00 2001 From: Kevin Enderby Date: Thu, 19 Jan 2017 17:36:31 +0000 Subject: [PATCH] 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 --- llvm/include/llvm/Object/MachO.h | 2 + llvm/include/llvm/Support/MachO.def | 2 + llvm/include/llvm/Support/MachO.h | 15 ++++++ llvm/lib/Object/MachOObjectFile.cpp | 33 ++++++++++++ llvm/lib/ObjectYAML/MachOYAML.cpp | 8 +++ llvm/test/Object/Inputs/macho-invalid-note | Bin 0 -> 76 bytes llvm/test/Object/macho-invalid.test | 3 ++ llvm/test/ObjectYAML/MachO/note_command.yaml | 50 ++++++++++++++++++ .../llvm-objdump/X86/Inputs/note.macho-x86 | Bin 0 -> 76 bytes .../X86/macho-private-headers.test | 8 +++ llvm/tools/llvm-objdump/MachODump.cpp | 16 ++++++ 11 files changed, 137 insertions(+) create mode 100644 llvm/test/Object/Inputs/macho-invalid-note create mode 100644 llvm/test/ObjectYAML/MachO/note_command.yaml create mode 100644 llvm/test/tools/llvm-objdump/X86/Inputs/note.macho-x86 diff --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h index 8c33ec8fd603..b9ff2e264e04 100644 --- a/llvm/include/llvm/Object/MachO.h +++ b/llvm/include/llvm/Object/MachO.h @@ -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 diff --git a/llvm/include/llvm/Support/MachO.def b/llvm/include/llvm/Support/MachO.def index 57522897d0fc..f395d8241c18 100644 --- a/llvm/include/llvm/Support/MachO.def +++ b/llvm/include/llvm/Support/MachO.def @@ -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 diff --git a/llvm/include/llvm/Support/MachO.h b/llvm/include/llvm/Support/MachO.h index 2b23c0f86448..ab037c8cf015 100644 --- a/llvm/include/llvm/Support/MachO.h +++ b/llvm/include/llvm/Support/MachO.h @@ -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); diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index 5b018676eba3..9a1e368f3a7b 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -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 &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(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(*this, L.Ptr); } +MachO::note_command +MachOObjectFile::getNoteLoadCommand(const LoadCommandInfo &L) const { + return getStruct(*this, L.Ptr); +} + MachO::dylib_command MachOObjectFile::getDylibIDLoadCommand(const LoadCommandInfo &L) const { return getStruct(*this, L.Ptr); diff --git a/llvm/lib/ObjectYAML/MachOYAML.cpp b/llvm/lib/ObjectYAML/MachOYAML.cpp index a033a79189bd..f04956332e06 100644 --- a/llvm/lib/ObjectYAML/MachOYAML.cpp +++ b/llvm/lib/ObjectYAML/MachOYAML.cpp @@ -558,6 +558,14 @@ void MappingTraits::mapping( IO.mapRequired("sdk", LoadCommand.sdk); } +void MappingTraits::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 diff --git a/llvm/test/Object/Inputs/macho-invalid-note b/llvm/test/Object/Inputs/macho-invalid-note new file mode 100644 index 0000000000000000000000000000000000000000..9bc21d99323e676e7155c16859a69e3940d513de GIT binary patch literal 76 zcmX^2>+L^w1_lOZAZ7t#Mj+MzVh}I{Vi4QKF~m{9KitnX2qX&RLnsClkYXeN0Gta4 Af&c&j literal 0 HcmV?d00001 diff --git a/llvm/test/Object/macho-invalid.test b/llvm/test/Object/macho-invalid.test index 6370228e5986..4bacc55eb70c 100644 --- a/llvm/test/Object/macho-invalid.test +++ b/llvm/test/Object/macho-invalid.test @@ -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) diff --git a/llvm/test/ObjectYAML/MachO/note_command.yaml b/llvm/test/ObjectYAML/MachO/note_command.yaml new file mode 100644 index 000000000000..17f1a970bff7 --- /dev/null +++ b/llvm/test/ObjectYAML/MachO/note_command.yaml @@ -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 diff --git a/llvm/test/tools/llvm-objdump/X86/Inputs/note.macho-x86 b/llvm/test/tools/llvm-objdump/X86/Inputs/note.macho-x86 new file mode 100644 index 0000000000000000000000000000000000000000..588a09d1e3436c70f4191cf8559da94640704ef7 GIT binary patch literal 76 zcmX^2>+L^w1_lOZAZ7t#Mj+MzVh}I{Vi4QKF~m{9KitnX2qX&RLnsCgC=H_knLGzo literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-objdump/X86/macho-private-headers.test b/llvm/test/tools/llvm-objdump/X86/macho-private-headers.test index e0c68d7cd97a..d1ea0cf140b7 100644 --- a/llvm/test/tools/llvm-objdump/X86/macho-private-headers.test +++ b/llvm/test/tools/llvm-objdump/X86/macho-private-headers.test @@ -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 diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp index 563084856f6f..6f810f415345 100644 --- a/llvm/tools/llvm-objdump/MachODump.cpp +++ b/llvm/tools/llvm-objdump/MachODump.cpp @@ -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);