[lld] r209858 - [mach-o] Add support for parsing __eh_frame section. Generalize support for whether symbols in a section are ignored or illegal

Nick Kledzik kledzik at apple.com
Thu May 29 16:07:20 PDT 2014


Author: kledzik
Date: Thu May 29 18:07:20 2014
New Revision: 209858

URL: http://llvm.org/viewvc/llvm-project?rev=209858&view=rev
Log:
[mach-o] Add support for parsing __eh_frame section. Generalize support for whether symbols in a section are ignored or illegal

Added:
    lld/trunk/test/mach-o/parse-eh-frame.yaml
Modified:
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp?rev=209858&r1=209857&r2=209858&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp Thu May 29 18:07:20 2014
@@ -200,6 +200,9 @@ SectionInfo *Util::makeSection(DefinedAt
   case DefinedAtom::typeCFString:
      return new (_allocator) SectionInfo("__DATA", "__cfstring",
                             S_REGULAR);
+  case DefinedAtom::typeCFI:
+     return new (_allocator) SectionInfo("__TEXT", "__eh_frame",
+                            S_COALESCED);
   default:
     llvm_unreachable("TO DO: add support for more sections");
     break;

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp?rev=209858&r1=209857&r2=209858&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp Thu May 29 18:07:20 2014
@@ -21,6 +21,7 @@
 ///                    +-------+
 
 #include "MachONormalizedFile.h"
+#include "MachONormalizedFileBinaryUtils.h"
 #include "File.h"
 #include "Atoms.h"
 
@@ -35,8 +36,14 @@ namespace lld {
 namespace mach_o {
 namespace normalized {
 
+enum SymbolsInSection {
+  symbolsOk,
+  symbolsIgnored,
+  symbolsIllegal
+};
+
 static uint64_t nextSymbolAddress(const NormalizedFile &normalizedFile,
-                                const Symbol &symbol) {
+                                  const Symbol &symbol) {
   uint64_t symbolAddr = symbol.value;
   uint8_t symbolSectionIndex = symbol.sect;
   const Section &section = normalizedFile.sections[symbolSectionIndex - 1];
@@ -80,19 +87,38 @@ static DefinedAtom::ContentType atomType
   return DefinedAtom::typeCode;
 }
 
-static void processSymbol(const NormalizedFile &normalizedFile, MachOFile &file,
-                          const Symbol &sym, bool copyRefs) {
-  // Mach-O symbol table does have size in it, so need to scan ahead
-  // to find symbol with next highest address.
+static error_code
+processSymbol(const NormalizedFile &normalizedFile, MachOFile &file,
+              const Symbol &sym, bool copyRefs,
+              const SmallVector<SymbolsInSection, 32> symbolsInSect) {
+  if (sym.sect > normalizedFile.sections.size()) {
+    int sectionIndex = sym.sect;
+    return make_dynamic_error_code(Twine("Symbol '") + sym.name
+                                 + "' has n_sect ("
+                                 + Twine(sectionIndex)
+                                 + ") which is too large");
+  }
   const Section &section = normalizedFile.sections[sym.sect - 1];
+  switch (symbolsInSect[sym.sect-1]) {
+  case symbolsOk:
+    break;
+  case symbolsIgnored:
+    return error_code::success();
+    break;
+  case symbolsIllegal:
+    return make_dynamic_error_code(Twine("Symbol '") + sym.name
+                                 + "' is not legal in section "
+                                 + section.segmentName + "/"
+                                 + section.sectionName);
+    break;
+  }
+
   uint64_t offset = sym.value - section.address;
+  // Mach-O symbol table does have size in it, so need to scan ahead
+  // to find symbol with next highest address.
   uint64_t size = nextSymbolAddress(normalizedFile, sym) - sym.value;
   if (section.type == llvm::MachO::S_ZEROFILL) {
     file.addZeroFillDefinedAtom(sym.name, atomScope(sym.scope), size, copyRefs);
-  }
-  else if ((section.type == llvm::MachO::S_CSTRING_LITERALS) &&
-          (sym.name[0] == 'L')) {
-    // Ignore L labels on cstrings.
   } else {
     ArrayRef<uint8_t> atomContent = section.content.slice(offset, size);
     DefinedAtom::Merge m = DefinedAtom::mergeNo;
@@ -101,6 +127,7 @@ static void processSymbol(const Normaliz
     file.addDefinedAtom(sym.name, atomScope(sym.scope),
                         atomTypeFromSection(section), m, atomContent, copyRefs);
   }
+  return error_code::success();
 }
 
 
@@ -168,22 +195,63 @@ static error_code processCFStringSection
   return error_code::success();
 }
 
+
+// A __TEXT/__eh_frame section contains dwarf unwind CFIs (either CIE or FDE).
+// Atom boundaries are determined by looking at the length content header
+// in each CFI.
+static error_code processCFISection(MachOFile &file, const Section &section,
+                                      bool is64, bool swap, bool copyRefs) {
+  const unsigned char* buffer = section.content.data();
+  for (size_t offset = 0, end = section.content.size(); offset < end; ) {
+    size_t remaining = end - offset;
+    if (remaining < 16) {
+      return make_dynamic_error_code(Twine("Section __TEXT/__eh_frame is "
+                                     "malformed.  Not enough room left for "
+                                     "a CFI starting at offset ("
+                                     + Twine(offset)
+                                     + ")"));
+    }
+    const uint32_t *cfi = reinterpret_cast<const uint32_t *>(&buffer[offset]);
+    uint32_t len = read32(swap, *cfi) + 4;
+    if (offset+len > end) {
+      return make_dynamic_error_code(Twine("Section __TEXT/__eh_frame is "
+                                     "malformed.  Size of CFI starting at "
+                                     "at offset ("
+                                     + Twine(offset)
+                                     + ") is past end of section."));
+    }
+    ArrayRef<uint8_t> bytes = section.content.slice(offset, len);
+    file.addDefinedAtom(StringRef(), DefinedAtom::scopeTranslationUnit,
+                        DefinedAtom::typeCFI, DefinedAtom::mergeNo,
+                        bytes, copyRefs);
+    offset += len;
+  }
+  return error_code::success();
+}
+
 static error_code processSection(MachOFile &file, const Section &section,
-                                 bool is64, bool copyRefs) {
+                                 bool is64, bool swap, bool copyRefs,
+                                 SymbolsInSection &symbolsInSect) {
   unsigned offset = 0;
   const unsigned pointerSize = (is64 ? 8 : 4);
   switch (section.type) {
   case llvm::MachO::S_REGULAR:
     if (section.segmentName.equals("__TEXT") &&
         section.sectionName.equals("__ustring")) {
+      symbolsInSect = symbolsIgnored;
       return processUTF16Section(file, section, is64, copyRefs);
-    }
-    else if (section.segmentName.equals("__DATA") &&
+    } else if (section.segmentName.equals("__DATA") &&
              section.sectionName.equals("__cfstring")) {
+      symbolsInSect = symbolsIllegal;
       return processCFStringSection(file, section, is64, copyRefs);
     }
     break;
   case llvm::MachO::S_COALESCED:
+    if (section.segmentName.equals("__TEXT") &&
+        section.sectionName.equals("__eh_frame")) {
+      symbolsInSect = symbolsIgnored;
+      return processCFISection(file, section, is64, swap, copyRefs);
+    }
   case llvm::MachO::S_ZEROFILL:
     // These sections are broken into atoms based on symbols.
     break;
@@ -204,6 +272,7 @@ static error_code processSection(MachOFi
                           bytes, copyRefs);
       offset += pointerSize;
     }
+    symbolsInSect = symbolsIllegal;
     break;
   case S_MOD_TERM_FUNC_POINTERS:
     if ((section.content.size() % pointerSize) != 0) {
@@ -222,6 +291,7 @@ static error_code processSection(MachOFi
                           bytes, copyRefs);
       offset += pointerSize;
     }
+    symbolsInSect = symbolsIllegal;
     break;
   case S_NON_LAZY_SYMBOL_POINTERS:
     if ((section.content.size() % pointerSize) != 0) {
@@ -240,6 +310,7 @@ static error_code processSection(MachOFi
                           bytes, copyRefs);
       offset += pointerSize;
     }
+    symbolsInSect = symbolsIllegal;
     break;
   case llvm::MachO::S_CSTRING_LITERALS:
     for (size_t i = 0, e = section.content.size(); i != e; ++i) {
@@ -259,6 +330,7 @@ static error_code processSection(MachOFi
                                      "last string in the section is not zero "
                                      "terminated."); 
     }
+    symbolsInSect = symbolsIgnored;
     break;
   case llvm::MachO::S_4BYTE_LITERALS:
     if ((section.content.size() % 4) != 0)
@@ -274,6 +346,7 @@ static error_code processSection(MachOFi
                           DefinedAtom::mergeByContent, byteContent, copyRefs);
       offset += 4;
     }
+    symbolsInSect = symbolsIllegal;
     break;
   case llvm::MachO::S_8BYTE_LITERALS:
     if ((section.content.size() % 8) != 0)
@@ -289,6 +362,7 @@ static error_code processSection(MachOFi
                           DefinedAtom::mergeByContent, byteContent, copyRefs);
       offset += 8;
     }
+    symbolsInSect = symbolsIllegal;
     break;
   case llvm::MachO::S_16BYTE_LITERALS:
     if ((section.content.size() % 16) != 0)
@@ -304,6 +378,7 @@ static error_code processSection(MachOFi
                           DefinedAtom::mergeByContent, byteContent, copyRefs);
       offset += 16;
     }
+    symbolsInSect = symbolsIllegal;
     break;
   default:
     llvm_unreachable("mach-o section type not supported yet");
@@ -317,24 +392,32 @@ normalizedObjectToAtoms(const Normalized
                         bool copyRefs) {
   std::unique_ptr<MachOFile> file(new MachOFile(path));
 
+  // Create atoms from sections that don't have symbols.
+  bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+  bool swap = !MachOLinkingContext::isHostEndian(normalizedFile.arch);
+  SmallVector<SymbolsInSection, 32> symbolsInSect;
+  for (auto &sect : normalizedFile.sections) {
+    symbolsInSect.push_back(symbolsOk);
+    if (error_code ec = processSection(*file, sect, is64, swap, copyRefs,
+                                       symbolsInSect.back()))
+      return ec;
+  }
   // Create atoms from global symbols.
   for (const Symbol &sym : normalizedFile.globalSymbols) {
-    processSymbol(normalizedFile, *file, sym, copyRefs);
+    if (error_code ec = processSymbol(normalizedFile, *file, sym, copyRefs,
+                                      symbolsInSect))
+      return ec;
   }
   // Create atoms from local symbols.
   for (const Symbol &sym : normalizedFile.localSymbols) {
-    processSymbol(normalizedFile, *file, sym, copyRefs);
+    if (error_code ec = processSymbol(normalizedFile, *file, sym, copyRefs,
+                                      symbolsInSect))
+      return ec;
   }
-  // Create atoms from undefinded symbols.
+  // Create atoms from undefined symbols.
   for (auto &sym : normalizedFile.undefinedSymbols) {
     processUndefindeSymbol(*file, sym, copyRefs);
   }
-  // Create atoms from sections that don't have symbols.
-  bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
-  for (auto &sect : normalizedFile.sections) {
-    if (error_code ec = processSection(*file, sect, is64, copyRefs))
-      return ec;
-  }
 
   return std::unique_ptr<File>(std::move(file));
 }

Added: lld/trunk/test/mach-o/parse-eh-frame.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/parse-eh-frame.yaml?rev=209858&view=auto
==============================================================================
--- lld/trunk/test/mach-o/parse-eh-frame.yaml (added)
+++ lld/trunk/test/mach-o/parse-eh-frame.yaml Thu May 29 18:07:20 2014
@@ -0,0 +1,73 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t  | FileCheck %s
+#
+# Test parsing of __eh_frame (dwarf unwind) section.
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0xB8, 0x09, 0x00, 0x00,
+                       0x00, 0x5D, 0xC3, 0x55, 0x48, 0x89, 0xE5, 0xB8,
+                       0x0A, 0x00, 0x00, 0x00, 0x5D, 0xC3 ]
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    alignment:       3
+    address:         0x0000000000000058
+    content:         [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01,
+                       0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
+                       0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+                       0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x24, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
+                       0x6B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+  - name:            __Z3barv
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            __Z3foov
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x000000000000000B
+...
+
+# CHECK: defined-atoms:
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:         [ 14, 00, 00, 00, 00, 00, 00, 00, 01, 7A, 52, 00,
+# CHECK:                        01, 78, 10, 01, 10, 0C, 07, 08, 90, 01, 00, 00 ]
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:         [ 24, 00, 00, 00, 1C, 00, 00, 00, 88, FF, FF, FF,
+# CHECK:                        FF, FF, FF, FF, 0B, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00 ]
+# CHECK:   - type:            unwind-cfi
+# CHECK:     content:         [ 24, 00, 00, 00, 44, 00, 00, 00, 6B, FF, FF, FF,
+# CHECK:                        FF, FF, FF, FF, 0B, 00, 00, 00, 00, 00, 00, 00,
+# CHECK:                        00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+# CHECK:                        00, 00, 00, 00 ]
+# CHECK:   - name:            __Z3barv
+# CHECK:     scope:           global
+# CHECK:     content:         [ 55, 48, 89, E5, B8, 09, 00, 00, 00, 5D, C3 ]
+# CHECK:   - name:            __Z3foov
+# CHECK:     scope:           global
+# CHECK:     content:         [ 55, 48, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
+





More information about the llvm-commits mailing list