[Object][XCOFF] Add intial support for section header table.

Adds a representation of the section header table to XCOFFObjectFile,
and implements enough to dump the section headers with llvm-obdump.

Differential Revision: https://reviews.llvm.org/D60784

llvm-svn: 359244
diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp
index 2903251..e740855 100644
--- a/llvm/lib/Object/XCOFFObjectFile.cpp
+++ b/llvm/lib/Object/XCOFFObjectFile.cpp
@@ -22,6 +22,10 @@
 namespace llvm {
 namespace object {
 
+enum { XCOFF32FileHeaderSize = 20 };
+static_assert(sizeof(XCOFFFileHeader) == XCOFF32FileHeaderSize,
+              "Wrong size for XCOFF file header.");
+
 // Sets Obj unless any bytes in [addr, addr + size) fall outsize of m.
 // Returns unexpected_eof on error.
 template <typename T>
@@ -35,6 +39,40 @@
   return std::error_code();
 }
 
+template <typename T> static const T *viewAs(uintptr_t in) {
+  return reinterpret_cast<const T *>(in);
+}
+
+const XCOFFSectionHeader *XCOFFObjectFile::toSection(DataRefImpl Ref) const {
+  auto Sec = viewAs<XCOFFSectionHeader>(Ref.p);
+#ifndef NDEBUG
+  if (Sec < SectionHdrTablePtr ||
+      Sec >= (SectionHdrTablePtr + getNumberOfSections()))
+    report_fatal_error("Section header outside of section header table.");
+
+  uintptr_t Offset = uintptr_t(Sec) - uintptr_t(SectionHdrTablePtr);
+  if (Offset % getSectionHeaderSize() != 0)
+    report_fatal_error(
+        "Section header pointer does not point to a valid section header.");
+#endif
+  return Sec;
+}
+
+// The next 2 functions are not exactly necessary yet, but they are useful to
+// abstract over the size difference between XCOFF32 and XCOFF64 structure
+// definitions.
+size_t XCOFFObjectFile::getFileHeaderSize() const {
+  return sizeof(XCOFFFileHeader);
+}
+
+size_t XCOFFObjectFile::getSectionHeaderSize() const {
+  return sizeof(XCOFFSectionHeader);
+}
+
+uint16_t XCOFFObjectFile::getNumberOfSections() const {
+  return FileHdrPtr->NumberOfSections;
+}
+
 void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
   llvm_unreachable("Not yet implemented!");
   return;
@@ -77,32 +115,32 @@
 }
 
 void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {
-  llvm_unreachable("Not yet implemented!");
-  return;
+  const char *Ptr = reinterpret_cast<const char *>(Sec.p);
+  Sec.p = reinterpret_cast<uintptr_t>(Ptr + getSectionHeaderSize());
 }
 
 std::error_code XCOFFObjectFile::getSectionName(DataRefImpl Sec,
                                                 StringRef &Res) const {
-  llvm_unreachable("Not yet implemented!");
+  const char *Name = toSection(Sec)->Name;
+  auto NulCharPtr =
+      static_cast<const char *>(memchr(Name, '\0', XCOFF::SectionNameSize));
+  Res = NulCharPtr ? StringRef(Name, NulCharPtr - Name)
+                   : StringRef(Name, XCOFF::SectionNameSize);
   return std::error_code();
 }
 
 uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {
-  uint64_t Result = 0;
-  llvm_unreachable("Not yet implemented!");
-  return Result;
+  return toSection(Sec)->VirtualAddress;
 }
 
 uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const {
-  uint64_t Result = 0;
-  llvm_unreachable("Not yet implemented!");
-  return Result;
+  // Section numbers in XCOFF are numbered beginning at 1. A section number of
+  // zero is used to indicate that a symbol is being imported or is undefined.
+  return toSection(Sec) - SectionHdrTablePtr + 1;
 }
 
 uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const {
-  uint64_t Result = 0;
-  llvm_unreachable("Not yet implemented!");
-  return Result;
+  return toSection(Sec)->SectionSize;
 }
 
 std::error_code XCOFFObjectFile::getSectionContents(DataRefImpl Sec,
@@ -124,21 +162,17 @@
 }
 
 bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const {
-  bool Result = false;
-  llvm_unreachable("Not yet implemented!");
-  return Result;
+  return toSection(Sec)->Flags & XCOFF::STYP_TEXT;
 }
 
 bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const {
-  bool Result = false;
-  llvm_unreachable("Not yet implemented!");
-  return Result;
+  unsigned Flags = toSection(Sec)->Flags;
+  return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA);
 }
 
 bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const {
-  bool Result = false;
-  llvm_unreachable("Not yet implemented!");
-  return Result;
+  unsigned Flags = toSection(Sec)->Flags;
+  return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS);
 }
 
 bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const {
@@ -202,13 +236,16 @@
 }
 
 section_iterator XCOFFObjectFile::section_begin() const {
-  llvm_unreachable("Not yet implemented!");
-  return section_iterator(SectionRef());
+  DataRefImpl DRI;
+  DRI.p = reinterpret_cast<uintptr_t>(SectionHdrTablePtr);
+  return section_iterator(SectionRef(DRI, this));
 }
 
 section_iterator XCOFFObjectFile::section_end() const {
-  llvm_unreachable("Not yet implemented!");
-  return section_iterator(SectionRef());
+  DataRefImpl DRI;
+  DRI.p =
+      reinterpret_cast<uintptr_t>(SectionHdrTablePtr + getNumberOfSections());
+  return section_iterator(SectionRef(DRI, this));
 }
 
 uint8_t XCOFFObjectFile::getBytesInAddress() const {
@@ -218,13 +255,13 @@
 }
 
 StringRef XCOFFObjectFile::getFileFormatName() const {
-  llvm_unreachable("Not yet implemented!");
-  return "";
+  assert(getFileHeaderSize() == XCOFF32FileHeaderSize);
+  return "aixcoff-rs6000";
 }
 
 Triple::ArchType XCOFFObjectFile::getArch() const {
-  llvm_unreachable("Not yet implemented!");
-  return Triple::UnknownArch;
+  assert(getFileHeaderSize() == XCOFF32FileHeaderSize);
+  return Triple::ppc;
 }
 
 SubtargetFeatures XCOFFObjectFile::getFeatures() const {
@@ -238,6 +275,12 @@
   return Result;
 }
 
+Expected<uint64_t> XCOFFObjectFile::getStartAddress() const {
+  // TODO FIXME Should get from auxiliary_header->o_entry when support for the
+  // auxiliary_header is added.
+  return 0;
+}
+
 XCOFFObjectFile::XCOFFObjectFile(MemoryBufferRef Object, std::error_code &EC)
     : ObjectFile(Binary::ID_XCOFF32, Object) {
 
@@ -246,6 +289,17 @@
 
   if ((EC = getObject(FileHdrPtr, Data, base() + CurPtr)))
     return;
+
+  CurPtr += getFileHeaderSize();
+  // TODO FIXME we don't have support for an optional header yet, so just skip
+  // past it.
+  CurPtr += FileHdrPtr->AuxHeaderSize;
+
+  if (getNumberOfSections() != 0) {
+    if ((EC = getObject(SectionHdrTablePtr, Data, base() + CurPtr,
+                        getNumberOfSections() * getSectionHeaderSize())))
+      return;
+  }
 }
 
 Expected<std::unique_ptr<ObjectFile>>