Add support for UndefinedAtom in yaml and native format.  Add test cases with undefined atoms

llvm-svn: 149962
diff --git a/lld/lib/Core/NativeReader.cpp b/lld/lib/Core/NativeReader.cpp
index 845d6bf..033cf98 100644
--- a/lld/lib/Core/NativeReader.cpp
+++ b/lld/lib/Core/NativeReader.cpp
@@ -65,7 +65,8 @@
   }
 
   virtual DefinedAtom::ContentType contentType() const {
-    return (DefinedAtom::ContentType)(attributes().contentType);
+    const NativeAtomAttributesV1& attr = attributes();
+    return (DefinedAtom::ContentType)(attr.contentType);
   }
     
   virtual DefinedAtom::Alignment alignment() const {
@@ -113,6 +114,29 @@
 
 
 
+//
+// An object of this class is instantied for each NativeUndefinedAtomIvarsV1
+// struct in the NCS_UndefinedAtomsV1 chunk.
+//
+class NativeUndefinedAtomV1 : public UndefinedAtom {
+public:
+       NativeUndefinedAtomV1(const NativeFile& f, 
+                             const NativeUndefinedAtomIvarsV1* ivarData)
+        : _file(&f), _ivarData(ivarData) { } 
+
+  virtual const File& file() const;
+  virtual llvm::StringRef name() const;
+  
+  virtual bool weakImport() const {
+    return (_ivarData->flags & 0x1);
+  }
+  
+private:
+  const NativeFile*                 _file;
+  const NativeUndefinedAtomIvarsV1* _ivarData;
+};
+
+
 
 //
 // lld::File object for native llvm object file
@@ -122,8 +146,9 @@
 
   /// Instantiates a File object from a native object file.  Ownership
   /// of the MemoryBuffer is transfered to the resulting File object.
-  static llvm::error_code make(llvm::MemoryBuffer* mb, llvm::StringRef path, 
-                                                                File*& result) {
+  static llvm::error_code make(llvm::OwningPtr<llvm::MemoryBuffer>& mb, 
+                               llvm::StringRef path, 
+                               llvm::OwningPtr<File>& result) {
     const uint8_t* const base = 
                        reinterpret_cast<const uint8_t*>(mb->getBufferStart());
     const NativeFileHeader* const header = 
@@ -159,6 +184,9 @@
         case NCS_AttributesArrayV1:
           ec = file->processAttributesV1(base, chunk);
           break;
+        case NCS_UndefinedAtomsV1:
+          ec = file->processUndefinedAtomsV1(base, chunk);
+          break;
         case NCS_Content:
           ec = file->processContent(base, chunk);
           break;
@@ -175,7 +203,7 @@
       
       // TO DO: validate enough chunks were used
       
-      result = file;
+      result.reset(file);
     }
 
 
@@ -183,13 +211,14 @@
   }
   
   virtual ~NativeFile() {
-    // The NativeFile owns the MemoryBuffer and must not delete it.
-    delete _buffer;
+    // _buffer is automatically deleted because of OwningPtr<>
+    
     // All other ivar pointers are pointers into the MemoryBuffer, except
     // the _definedAtoms array which was allocated to contain an array
     // of Atom objects.  The atoms have empty destructors, so it is ok
     // to just delete the memory.
     delete _definedAtoms.arrayStart;
+    delete _undefinedAtoms.arrayStart;
   }
   
   // visits each atom in the file
@@ -199,6 +228,11 @@
       const DefinedAtom* atom = reinterpret_cast<const DefinedAtom*>(p);
       handler.doDefinedAtom(*atom);
     }
+    for(const uint8_t* p=_undefinedAtoms.arrayStart; p != _undefinedAtoms.arrayEnd; 
+          p += _undefinedAtoms.elementSize) {
+      const UndefinedAtom* atom = reinterpret_cast<const UndefinedAtom*>(p);
+      handler.doUndefinedAtom(*atom);
+    }
     return (_definedAtoms.arrayStart != _definedAtoms.arrayEnd);
   }
   
@@ -210,6 +244,7 @@
   
 private:
   friend class NativeDefinedAtomV1;
+  friend class NativeUndefinedAtomV1;
   
   // instantiate array of DefinedAtoms from v1 ivar data in file
   llvm::error_code processDefinedAtomsV1(const uint8_t* base, 
@@ -247,6 +282,34 @@
     return make_error_code(native_reader_error::success);
   }
   
+  llvm::error_code processUndefinedAtomsV1(const uint8_t* base, 
+                                                const NativeChunk* chunk) {
+    const size_t atomSize = sizeof(NativeUndefinedAtomV1);
+    size_t atomsArraySize = chunk->elementCount * atomSize;
+    uint8_t* atomsStart = reinterpret_cast<uint8_t*>
+                                (operator new(atomsArraySize, std::nothrow));
+    if (atomsStart == NULL )
+      return make_error_code(native_reader_error::memory_error);
+    const size_t ivarElementSize = chunk->fileSize 
+                                          / chunk->elementCount;
+    if ( ivarElementSize != sizeof(NativeUndefinedAtomIvarsV1) )
+      return make_error_code(native_reader_error::file_malformed);
+    uint8_t* atomsEnd = atomsStart + atomsArraySize;
+    const NativeUndefinedAtomIvarsV1* ivarData = 
+                            reinterpret_cast<const NativeUndefinedAtomIvarsV1*>
+                                                  (base + chunk->fileOffset);
+    for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
+      NativeUndefinedAtomV1* atomAllocSpace = 
+                  reinterpret_cast<NativeUndefinedAtomV1*>(s);
+      new (atomAllocSpace) NativeUndefinedAtomV1(*this, ivarData);
+      ++ivarData;
+    }
+    this->_undefinedAtoms.arrayStart = atomsStart;
+    this->_undefinedAtoms.arrayEnd = atomsEnd;
+    this->_undefinedAtoms.elementSize = atomSize;
+    return make_error_code(native_reader_error::success);
+  }
+  
   // set up pointers to string pool in file
   llvm::error_code processStrings(const uint8_t* base, 
                                                 const NativeChunk* chunk) {
@@ -281,12 +344,18 @@
 
 
   // private constructor, only called by make()
-  NativeFile(llvm::MemoryBuffer* mb, llvm::StringRef path) :
-    lld::File(path), _buffer(mb), _header(NULL), 
-    _strings(NULL), _stringsMaxOffset(0),
-    _contentStart(NULL), _contentEnd(NULL)
+  NativeFile(llvm::OwningPtr<llvm::MemoryBuffer>& mb, llvm::StringRef path) :
+    lld::File(path), 
+    _buffer(mb.take()),  // NativeFile now takes ownership of buffer
+    _header(NULL), 
+    _strings(NULL), 
+    _stringsMaxOffset(0),
+    _contentStart(NULL), 
+    _contentEnd(NULL)
   {
-    _header = reinterpret_cast<const NativeFileHeader*>(mb->getBufferStart());
+    _header = reinterpret_cast<const NativeFileHeader*>(_buffer->getBufferStart());
+    _definedAtoms.arrayStart = NULL;
+    _undefinedAtoms.arrayStart = NULL;
   }
 
   struct AtomArray {
@@ -297,9 +366,10 @@
     uint32_t           elementSize;
   };
 
-  llvm::MemoryBuffer*             _buffer;
+  llvm::OwningPtr<llvm::MemoryBuffer>  _buffer;
   const NativeFileHeader*         _header;
   AtomArray                       _definedAtoms;
+  AtomArray                       _undefinedAtoms;
   const uint8_t*                  _attributes;
   uint32_t                        _attributesMaxOffset;
   const char*                     _strings;
@@ -342,11 +412,24 @@
 
 
 
+
+inline const class File& NativeUndefinedAtomV1::file() const {
+  return *_file;
+}
+
+inline llvm::StringRef NativeUndefinedAtomV1::name() const {
+  return _file->string(_ivarData->nameOffset);
+}
+
+
+
+
 //
 // Instantiate an lld::File from the given native object file buffer
 //
-llvm::error_code parseNativeObjectFile(llvm::MemoryBuffer* mb, 
-                                       llvm::StringRef path, File*& result) {
+llvm::error_code parseNativeObjectFile(llvm::OwningPtr<llvm::MemoryBuffer>& mb, 
+                                       llvm::StringRef path, 
+                                       llvm::OwningPtr<File>& result) {
   return NativeFile::make(mb, path, result);
 }
 
@@ -356,13 +439,13 @@
 // Instantiate an lld::File from the given native object file path
 //
 llvm::error_code parseNativeObjectFileOrSTDIN(llvm::StringRef path, 
-                                              File*& result) {
+                                              llvm::OwningPtr<File>& result) {
   llvm::OwningPtr<llvm::MemoryBuffer> mb;
   llvm::error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, mb);
   if ( ec ) 
       return ec;
 
-  return parseNativeObjectFile(mb.take(), path, result);
+  return parseNativeObjectFile(mb, path, result);
 }