OSDN Git Service

Add support for the new LC_NOTE load command.
authorKevin Enderby <enderby@apple.com>
Thu, 19 Jan 2017 17:36:31 +0000 (17:36 +0000)
committerKevin Enderby <enderby@apple.com>
Thu, 19 Jan 2017 17:36:31 +0000 (17:36 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@292500 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Object/MachO.h
include/llvm/Support/MachO.def
include/llvm/Support/MachO.h
lib/Object/MachOObjectFile.cpp
lib/ObjectYAML/MachOYAML.cpp
test/Object/Inputs/macho-invalid-note [new file with mode: 0644]
test/Object/macho-invalid.test
test/ObjectYAML/MachO/note_command.yaml [new file with mode: 0644]
test/tools/llvm-objdump/X86/Inputs/note.macho-x86 [new file with mode: 0644]
test/tools/llvm-objdump/X86/macho-private-headers.test
tools/llvm-objdump/MachODump.cpp

index 8c33ec8..b9ff2e2 100644 (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
index 5752289..f395d82 100644 (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
 
index 2b23c0f..ab037c8 100644 (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);
index 5b01867..9a1e368 100644 (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);
index a033a79..f049563 100644 (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
diff --git a/test/Object/Inputs/macho-invalid-note b/test/Object/Inputs/macho-invalid-note
new file mode 100644 (file)
index 0000000..9bc21d9
Binary files /dev/null and b/test/Object/Inputs/macho-invalid-note differ
index 6370228..4bacc55 100644 (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)
diff --git a/test/ObjectYAML/MachO/note_command.yaml b/test/ObjectYAML/MachO/note_command.yaml
new file mode 100644 (file)
index 0000000..17f1a97
--- /dev/null
@@ -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/test/tools/llvm-objdump/X86/Inputs/note.macho-x86 b/test/tools/llvm-objdump/X86/Inputs/note.macho-x86
new file mode 100644 (file)
index 0000000..588a09d
Binary files /dev/null and b/test/tools/llvm-objdump/X86/Inputs/note.macho-x86 differ
index e0c68d7..d1ea0cf 100644 (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
index 5630848..6f810f4 100644 (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);