Move more self-contained functionality away from tools/opt/opt.cpp
[oota-llvm.git] / tools / llvm-readobj / COFFDumper.cpp
index 14f8b72ac79c3a64b66d7f23a8f5c7dbaa217394..120794280d24e3451daa669674809d6ea5aec5fc 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "llvm-readobj.h"
-#include "ObjDumper.h"
-
 #include "Error.h"
+#include "ObjDumper.h"
 #include "StreamWriter.h"
-
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Object/COFF.h"
 #include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/COFF.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/Compiler.h"
+#include "llvm/Support/DataExtractor.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Support/Win64EH.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/system_error.h"
-
 #include <algorithm>
 #include <cstring>
 #include <time.h>
@@ -57,11 +56,14 @@ public:
 
 private:
   void printSymbol(symbol_iterator SymI);
-
   void printRelocation(section_iterator SecI, relocation_iterator RelI);
-
+  void printDataDirectory(uint32_t Index, const std::string &FieldName);
   void printX64UnwindInfo();
 
+  template <class PEHeader> void printPEHeader(const PEHeader *Hdr);
+  void printBaseOfDataField(const pe32_header *Hdr);
+  void printBaseOfDataField(const pe32plus_header *Hdr);
+
   void printRuntimeFunction(
     const RuntimeFunction& RTF,
     uint64_t OffsetInSection,
@@ -74,6 +76,8 @@ private:
 
   void printUnwindCode(const Win64EH::UnwindInfo& UI, ArrayRef<UnwindCode> UCs);
 
+  void printCodeViewLineTables(section_iterator SecI);
+
   void cacheRelocations();
 
   error_code getSectionContents(
@@ -181,7 +185,7 @@ static error_code resolveSectionAndAddress(const COFFObjectFile *Obj,
   if (error_code EC = Sym.getAddress(ResolvedAddr))
     return EC;
 
-  section_iterator iter(Obj->begin_sections());
+  section_iterator iter(Obj->section_begin());
   if (error_code EC = Sym.getSection(iter))
     return EC;
 
@@ -201,8 +205,7 @@ static error_code resolveSymbol(const std::vector<RelocationRef> &Rels,
       return EC;
 
     if (Ofs == Offset) {
-      if (error_code EC = RelI->getSymbol(Sym))
-        return EC;
+      Sym = *RelI->getSymbol();
       return readobj_error::success;
     }
   }
@@ -263,6 +266,32 @@ static const EnumEntry<COFF::Characteristics> ImageFileCharacteristics[] = {
   LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_HI      )
 };
 
+static const EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = {
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_UNKNOWN                ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_NATIVE                 ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_GUI            ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CUI            ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_POSIX_CUI              ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI         ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_APPLICATION        ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER     ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_ROM                ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_XBOX                   ),
+};
+
+static const EnumEntry<COFF::DLLCharacteristics> PEDLLCharacteristics[] = {
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA      ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE         ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY      ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT            ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION         ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_SEH               ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_BIND              ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER           ),
+  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE),
+};
+
 static const EnumEntry<COFF::SectionCharacteristics>
 ImageSectionCharacteristics[] = {
   LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD           ),
@@ -455,15 +484,15 @@ static std::string formatSymbol(const std::vector<RelocationRef> &Rels,
 
   StringRef Sym;
   if (resolveSymbolName(Rels, Offset, Sym)) {
-    Str << format(" (0x%X)", Offset);
+    Str << format(" (0x%" PRIX64 ")", Offset);
     return Str.str();
   }
 
   Str << Sym;
   if (Disp > 0) {
-    Str << format(" +0x%X (0x%X)", Disp, Offset);
+    Str << format(" +0x%X (0x%" PRIX64 ")", Disp, Offset);
   } else {
-    Str << format(" (0x%X)", Offset);
+    Str << format(" (0x%" PRIX64 ")", Offset);
   }
 
   return Str.str();
@@ -512,23 +541,15 @@ error_code COFFDumper::getSection(
 }
 
 void COFFDumper::cacheRelocations() {
-  error_code EC;
-  for (section_iterator SecI = Obj->begin_sections(),
-                        SecE = Obj->end_sections();
-                        SecI != SecE; SecI.increment(EC)) {
-    if (error(EC))
-      break;
-
+  for (section_iterator SecI = Obj->section_begin(),
+                        SecE = Obj->section_end();
+       SecI != SecE; ++SecI) {
     const coff_section *Section = Obj->getCOFFSection(SecI);
 
-    for (relocation_iterator RelI = SecI->begin_relocations(),
-                             RelE = SecI->end_relocations();
-                             RelI != RelE; RelI.increment(EC)) {
-      if (error(EC))
-        break;
-
+    for (relocation_iterator RelI = SecI->relocation_begin(),
+                             RelE = SecI->relocation_end();
+         RelI != RelE; ++RelI)
       RelocMap[Section].push_back(*RelI);
-    }
 
     // Sort relocations by address.
     std::sort(RelocMap[Section].begin(), RelocMap[Section].end(),
@@ -536,40 +557,270 @@ void COFFDumper::cacheRelocations() {
   }
 }
 
+void COFFDumper::printDataDirectory(uint32_t Index, const std::string &FieldName) {
+  const data_directory *Data;
+  if (Obj->getDataDirectory(Index, Data))
+    return;
+  W.printHex(FieldName + "RVA", Data->RelativeVirtualAddress);
+  W.printHex(FieldName + "Size", Data->Size);
+}
+
 void COFFDumper::printFileHeaders() {
-  const coff_file_header *Header = 0;
-  if (error(Obj->getHeader(Header)))
+  // Print COFF header
+  const coff_file_header *COFFHeader = 0;
+  if (error(Obj->getCOFFHeader(COFFHeader)))
     return;
 
-  time_t TDS = Header->TimeDateStamp;
+  time_t TDS = COFFHeader->TimeDateStamp;
   char FormattedTime[20] = { };
   strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
 
   {
     DictScope D(W, "ImageFileHeader");
-    W.printEnum  ("Machine", Header->Machine,
+    W.printEnum  ("Machine", COFFHeader->Machine,
                     makeArrayRef(ImageFileMachineType));
-    W.printNumber("SectionCount", Header->NumberOfSections);
-    W.printHex   ("TimeDateStamp", FormattedTime, Header->TimeDateStamp);
-    W.printHex   ("PointerToSymbolTable", Header->PointerToSymbolTable);
-    W.printNumber("SymbolCount", Header->NumberOfSymbols);
-    W.printNumber("OptionalHeaderSize", Header->SizeOfOptionalHeader);
-    W.printFlags ("Characteristics", Header->Characteristics,
+    W.printNumber("SectionCount", COFFHeader->NumberOfSections);
+    W.printHex   ("TimeDateStamp", FormattedTime, COFFHeader->TimeDateStamp);
+    W.printHex   ("PointerToSymbolTable", COFFHeader->PointerToSymbolTable);
+    W.printNumber("SymbolCount", COFFHeader->NumberOfSymbols);
+    W.printNumber("OptionalHeaderSize", COFFHeader->SizeOfOptionalHeader);
+    W.printFlags ("Characteristics", COFFHeader->Characteristics,
                     makeArrayRef(ImageFileCharacteristics));
   }
+
+  // Print PE header. This header does not exist if this is an object file and
+  // not an executable.
+  const pe32_header *PEHeader = 0;
+  if (error(Obj->getPE32Header(PEHeader)))
+    return;
+  if (PEHeader)
+    printPEHeader<pe32_header>(PEHeader);
+
+  const pe32plus_header *PEPlusHeader = 0;
+  if (error(Obj->getPE32PlusHeader(PEPlusHeader)))
+    return;
+  if (PEPlusHeader)
+    printPEHeader<pe32plus_header>(PEPlusHeader);
 }
 
-void COFFDumper::printSections() {
-  error_code EC;
+template <class PEHeader>
+void COFFDumper::printPEHeader(const PEHeader *Hdr) {
+  DictScope D(W, "ImageOptionalHeader");
+  W.printNumber("MajorLinkerVersion", Hdr->MajorLinkerVersion);
+  W.printNumber("MinorLinkerVersion", Hdr->MinorLinkerVersion);
+  W.printNumber("SizeOfCode", Hdr->SizeOfCode);
+  W.printNumber("SizeOfInitializedData", Hdr->SizeOfInitializedData);
+  W.printNumber("SizeOfUninitializedData", Hdr->SizeOfUninitializedData);
+  W.printHex   ("AddressOfEntryPoint", Hdr->AddressOfEntryPoint);
+  W.printHex   ("BaseOfCode", Hdr->BaseOfCode);
+  printBaseOfDataField(Hdr);
+  W.printHex   ("ImageBase", Hdr->ImageBase);
+  W.printNumber("SectionAlignment", Hdr->SectionAlignment);
+  W.printNumber("FileAlignment", Hdr->FileAlignment);
+  W.printNumber("MajorOperatingSystemVersion",
+                Hdr->MajorOperatingSystemVersion);
+  W.printNumber("MinorOperatingSystemVersion",
+                Hdr->MinorOperatingSystemVersion);
+  W.printNumber("MajorImageVersion", Hdr->MajorImageVersion);
+  W.printNumber("MinorImageVersion", Hdr->MinorImageVersion);
+  W.printNumber("MajorSubsystemVersion", Hdr->MajorSubsystemVersion);
+  W.printNumber("MinorSubsystemVersion", Hdr->MinorSubsystemVersion);
+  W.printNumber("SizeOfImage", Hdr->SizeOfImage);
+  W.printNumber("SizeOfHeaders", Hdr->SizeOfHeaders);
+  W.printEnum  ("Subsystem", Hdr->Subsystem, makeArrayRef(PEWindowsSubsystem));
+  W.printFlags ("Subsystem", Hdr->DLLCharacteristics,
+                makeArrayRef(PEDLLCharacteristics));
+  W.printNumber("SizeOfStackReserve", Hdr->SizeOfStackReserve);
+  W.printNumber("SizeOfStackCommit", Hdr->SizeOfStackCommit);
+  W.printNumber("SizeOfHeapReserve", Hdr->SizeOfHeapReserve);
+  W.printNumber("SizeOfHeapCommit", Hdr->SizeOfHeapCommit);
+  W.printNumber("NumberOfRvaAndSize", Hdr->NumberOfRvaAndSize);
+
+  if (Hdr->NumberOfRvaAndSize > 0) {
+    DictScope D(W, "DataDirectory");
+    static const char * const directory[] = {
+      "ExportTable", "ImportTable", "ResourceTable", "ExceptionTable",
+      "CertificateTable", "BaseRelocationTable", "Debug", "Architecture",
+      "GlobalPtr", "TLSTable", "LoadConfigTable", "BoundImport", "IAT",
+      "DelayImportDescriptor", "CLRRuntimeHeader", "Reserved"
+    };
+
+    for (uint32_t i = 0; i < Hdr->NumberOfRvaAndSize; ++i) {
+      printDataDirectory(i, directory[i]);
+    }
+  }
+}
+
+void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) {
+  W.printHex("BaseOfData", Hdr->BaseOfData);
+}
+
+void COFFDumper::printBaseOfDataField(const pe32plus_header *) {}
+
+void COFFDumper::printCodeViewLineTables(section_iterator SecI) {
+  StringRef Data;
+  if (error(SecI->getContents(Data))) return;
+
+  SmallVector<StringRef, 10> FunctionNames;
+  StringMap<StringRef> FunctionLineTables;
+  StringRef FileIndexToStringOffsetTable;
+  StringRef StringTable;
+
+  ListScope D(W, "CodeViewLineTables");
+  {
+    DataExtractor DE(Data, true, 4);
+    uint32_t Offset = 0,
+             Magic = DE.getU32(&Offset);
+    W.printHex("Magic", Magic);
+    if (Magic != COFF::DEBUG_SECTION_MAGIC) {
+      error(object_error::parse_failed);
+      return;
+    }
+
+    bool Finished = false;
+    while (DE.isValidOffset(Offset) && !Finished) {
+      // The section consists of a number of subsection in the following format:
+      // |Type|PayloadSize|Payload...|
+      uint32_t SubSectionType = DE.getU32(&Offset),
+               PayloadSize = DE.getU32(&Offset);
+      ListScope S(W, "Subsection");
+      W.printHex("Type", SubSectionType);
+      W.printHex("PayloadSize", PayloadSize);
+      if (PayloadSize > Data.size() - Offset) {
+        error(object_error::parse_failed);
+        return;
+      }
+
+      // Print the raw contents to simplify debugging if anything goes wrong
+      // afterwards.
+      StringRef Contents = Data.substr(Offset, PayloadSize);
+      W.printBinaryBlock("Contents", Contents);
+
+      switch (SubSectionType) {
+      case COFF::DEBUG_LINE_TABLE_SUBSECTION: {
+        // Holds a PC to file:line table.  Some data to parse this subsection is
+        // stored in the other subsections, so just check sanity and store the
+        // pointers for deferred processing.
+
+        if (PayloadSize < 12) {
+          // There should be at least three words to store two function
+          // relocations and size of the code.
+          error(object_error::parse_failed);
+          return;
+        }
 
+        StringRef FunctionName;
+        if (error(resolveSymbolName(RelocMap[Obj->getCOFFSection(SecI)], Offset,
+                                    FunctionName)))
+          return;
+        W.printString("FunctionName", FunctionName);
+        if (FunctionLineTables.count(FunctionName) != 0) {
+          // Saw debug info for this function already?
+          error(object_error::parse_failed);
+          return;
+        }
+
+        FunctionLineTables[FunctionName] = Contents;
+        FunctionNames.push_back(FunctionName);
+        break;
+      }
+      case COFF::DEBUG_STRING_TABLE_SUBSECTION:
+        if (PayloadSize == 0 || StringTable.data() != 0 ||
+            Contents.back() != '\0') {
+          // Empty or duplicate or non-null-terminated subsection.
+          error(object_error::parse_failed);
+          return;
+        }
+        StringTable = Contents;
+        break;
+      case COFF::DEBUG_INDEX_SUBSECTION:
+        // Holds the translation table from file indices
+        // to offsets in the string table.
+
+        if (PayloadSize == 0 || FileIndexToStringOffsetTable.data() != 0) {
+          // Empty or duplicate subsection.
+          error(object_error::parse_failed);
+          return;
+        }
+        FileIndexToStringOffsetTable = Contents;
+        break;
+      }
+      Offset += PayloadSize;
+
+      // Align the reading pointer by 4.
+      Offset += (-Offset) % 4;
+    }
+  }
+
+  // Dump the line tables now that we've read all the subsections and know all
+  // the required information.
+  for (unsigned I = 0, E = FunctionNames.size(); I != E; ++I) {
+    StringRef Name = FunctionNames[I];
+    ListScope S(W, "FunctionLineTable");
+    W.printString("FunctionName", Name);
+
+    DataExtractor DE(FunctionLineTables[Name], true, 4);
+    uint32_t Offset = 8;  // Skip relocations.
+    uint32_t FunctionSize = DE.getU32(&Offset);
+    W.printHex("CodeSize", FunctionSize);
+    while (DE.isValidOffset(Offset)) {
+      // For each range of lines with the same filename, we have a segment
+      // in the line table.  The filename string is accessed using double
+      // indirection to the string table subsection using the index subsection.
+      uint32_t OffsetInIndex = DE.getU32(&Offset),
+               SegmentLength   = DE.getU32(&Offset),
+               FullSegmentSize = DE.getU32(&Offset);
+      if (FullSegmentSize != 12 + 8 * SegmentLength) {
+        error(object_error::parse_failed);
+        return;
+      }
+
+      uint32_t FilenameOffset;
+      {
+        DataExtractor SDE(FileIndexToStringOffsetTable, true, 4);
+        uint32_t OffsetInSDE = OffsetInIndex;
+        if (!SDE.isValidOffset(OffsetInSDE)) {
+          error(object_error::parse_failed);
+          return;
+        }
+        FilenameOffset = SDE.getU32(&OffsetInSDE);
+      }
+
+      if (FilenameOffset == 0 || FilenameOffset + 1 >= StringTable.size() ||
+          StringTable.data()[FilenameOffset - 1] != '\0') {
+        // Each string in an F3 subsection should be preceded by a null
+        // character.
+        error(object_error::parse_failed);
+        return;
+      }
+
+      StringRef Filename(StringTable.data() + FilenameOffset);
+      ListScope S(W, "FilenameSegment");
+      W.printString("Filename", Filename);
+      for (unsigned J = 0; J != SegmentLength && DE.isValidOffset(Offset);
+           ++J) {
+        // Then go the (PC, LineNumber) pairs.  The line number is stored in the
+        // least significant 31 bits of the respective word in the table.
+        uint32_t PC = DE.getU32(&Offset),
+                 LineNumber = DE.getU32(&Offset) & 0x7fffffff;
+        if (PC >= FunctionSize) {
+          error(object_error::parse_failed);
+          return;
+        }
+        char Buffer[32];
+        format("+0x%X", PC).snprint(Buffer, 32);
+        W.printNumber(Buffer, LineNumber);
+      }
+    }
+  }
+}
+
+void COFFDumper::printSections() {
   ListScope SectionsD(W, "Sections");
   int SectionNumber = 0;
-  for (section_iterator SecI = Obj->begin_sections(),
-                        SecE = Obj->end_sections();
-                        SecI != SecE; SecI.increment(EC)) {
-    if (error(EC))
-      break;
-
+  for (section_iterator SecI = Obj->section_begin(),
+                        SecE = Obj->section_end();
+       SecI != SecE; ++SecI) {
     ++SectionNumber;
     const coff_section *Section = Obj->getCOFFSection(SecI);
 
@@ -594,22 +845,17 @@ void COFFDumper::printSections() {
 
     if (opts::SectionRelocations) {
       ListScope D(W, "Relocations");
-      for (relocation_iterator RelI = SecI->begin_relocations(),
-                               RelE = SecI->end_relocations();
-                               RelI != RelE; RelI.increment(EC)) {
-        if (error(EC)) break;
-
+      for (relocation_iterator RelI = SecI->relocation_begin(),
+                               RelE = SecI->relocation_end();
+           RelI != RelE; ++RelI)
         printRelocation(SecI, RelI);
-      }
     }
 
     if (opts::SectionSymbols) {
       ListScope D(W, "Symbols");
-      for (symbol_iterator SymI = Obj->begin_symbols(),
-                           SymE = Obj->end_symbols();
-                           SymI != SymE; SymI.increment(EC)) {
-        if (error(EC)) break;
-
+      for (symbol_iterator SymI = Obj->symbol_begin(),
+                           SymE = Obj->symbol_end();
+           SymI != SymE; ++SymI) {
         bool Contained = false;
         if (SecI->containsSymbol(*SymI, Contained) || !Contained)
           continue;
@@ -618,6 +864,9 @@ void COFFDumper::printSections() {
       }
     }
 
+    if (Name == ".debug$S" && opts::CodeViewLineTables)
+      printCodeViewLineTables(SecI);
+
     if (opts::SectionData) {
       StringRef Data;
       if (error(SecI->getContents(Data))) break;
@@ -630,25 +879,19 @@ void COFFDumper::printSections() {
 void COFFDumper::printRelocations() {
   ListScope D(W, "Relocations");
 
-  error_code EC;
   int SectionNumber = 0;
-  for (section_iterator SecI = Obj->begin_sections(),
-                        SecE = Obj->end_sections();
-                        SecI != SecE; SecI.increment(EC)) {
+  for (section_iterator SecI = Obj->section_begin(),
+                        SecE = Obj->section_end();
+                        SecI != SecE; ++SecI) {
     ++SectionNumber;
-    if (error(EC))
-      break;
-
     StringRef Name;
     if (error(SecI->getName(Name)))
       continue;
 
     bool PrintedGroup = false;
-    for (relocation_iterator RelI = SecI->begin_relocations(),
-                             RelE = SecI->end_relocations();
-                             RelI != RelE; RelI.increment(EC)) {
-      if (error(EC)) break;
-
+    for (relocation_iterator RelI = SecI->relocation_begin(),
+                             RelE = SecI->relocation_end();
+         RelI != RelE; ++RelI) {
       if (!PrintedGroup) {
         W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n";
         W.indent();
@@ -670,14 +913,13 @@ void COFFDumper::printRelocation(section_iterator SecI,
   uint64_t Offset;
   uint64_t RelocType;
   SmallString<32> RelocName;
-  SymbolRef Symbol;
   StringRef SymbolName;
   StringRef Contents;
   if (error(RelI->getOffset(Offset))) return;
   if (error(RelI->getType(RelocType))) return;
   if (error(RelI->getTypeName(RelocName))) return;
-  if (error(RelI->getSymbol(Symbol))) return;
-  if (error(Symbol.getName(SymbolName))) return;
+  symbol_iterator Symbol = RelI->getSymbol();
+  if (error(Symbol->getName(SymbolName))) return;
   if (error(SecI->getContents(Contents))) return;
 
   if (opts::ExpandRelocs) {
@@ -697,14 +939,9 @@ void COFFDumper::printRelocation(section_iterator SecI,
 void COFFDumper::printSymbols() {
   ListScope Group(W, "Symbols");
 
-  error_code EC;
-  for (symbol_iterator SymI = Obj->begin_symbols(),
-                       SymE = Obj->end_symbols();
-                       SymI != SymE; SymI.increment(EC)) {
-    if (error(EC)) break;
-
+  for (symbol_iterator SymI = Obj->symbol_begin(), SymE = Obj->symbol_end();
+       SymI != SymE; ++SymI)
     printSymbol(SymI);
-  }
 }
 
 void COFFDumper::printDynamicSymbols() {
@@ -785,7 +1022,12 @@ void COFFDumper::printSymbol(symbol_iterator SymI) {
       if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
         break;
 
-    } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC) {
+      DictScope AS(W, "AuxFileRecord");
+      W.printString("FileName", StringRef(Aux->FileName));
+
+    } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC ||
+               (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL &&
+                Symbol->SectionNumber != COFF::IMAGE_SYM_UNDEFINED)) {
       const coff_aux_section_definition *Aux;
       if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
         break;
@@ -831,7 +1073,7 @@ void COFFDumper::printSymbol(symbol_iterator SymI) {
 
 void COFFDumper::printUnwindInfo() {
   const coff_file_header *Header;
-  if (error(Obj->getHeader(Header)))
+  if (error(Obj->getCOFFHeader(Header)))
     return;
 
   ListScope D(W, "UnwindInformation");
@@ -845,12 +1087,9 @@ void COFFDumper::printUnwindInfo() {
 }
 
 void COFFDumper::printX64UnwindInfo() {
-  error_code EC;
-  for (section_iterator SecI = Obj->begin_sections(),
-                        SecE = Obj->end_sections();
-                        SecI != SecE; SecI.increment(EC)) {
-    if (error(EC)) break;
-
+  for (section_iterator SecI = Obj->section_begin(),
+                        SecE = Obj->section_end();
+       SecI != SecE; ++SecI) {
     StringRef Name;
     if (error(SecI->getName(Name)))
       continue;