Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SystemZ][z/OS] Add goffdumper/llvm-readobj tools #71071

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

ysyeda
Copy link
Contributor

@ysyeda ysyeda commented Nov 2, 2023

This PR adds the GOFFDumper. It contains a test which uses llvm-readobj to check the symbols of the provided GOFF object file.

@llvmbot
Copy link
Collaborator

llvmbot commented Nov 2, 2023

@llvm/pr-subscribers-llvm-binary-utilities

Author: Yusra Syeda (ysyeda)

Changes

This PR adds the GOFFDumper. It contains a test which uses llvm-readobj to check the symbols of the provided GOFF object file.


Full diff: https://github.com/llvm/llvm-project/pull/71071.diff

8 Files Affected:

  • (modified) llvm/lib/Object/GOFFObjectFile.cpp (+9)
  • (modified) llvm/lib/Object/ObjectFile.cpp (+2-1)
  • (added) llvm/test/tools/llvm-readobj/GOFF/Inputs/goff-basics.o ()
  • (added) llvm/test/tools/llvm-readobj/GOFF/goff-basics.test (+69)
  • (modified) llvm/tools/llvm-readobj/CMakeLists.txt (+1)
  • (added) llvm/tools/llvm-readobj/GOFFDumper.cpp (+94)
  • (modified) llvm/tools/llvm-readobj/ObjDumper.h (+4)
  • (modified) llvm/tools/llvm-readobj/llvm-readobj.cpp (+4)
diff --git a/llvm/lib/Object/GOFFObjectFile.cpp b/llvm/lib/Object/GOFFObjectFile.cpp
index 76a13559ebfe352..03f86f303668457 100644
--- a/llvm/lib/Object/GOFFObjectFile.cpp
+++ b/llvm/lib/Object/GOFFObjectFile.cpp
@@ -168,6 +168,15 @@ GOFFObjectFile::GOFFObjectFile(MemoryBufferRef Object, Error &Err)
       LLVM_DEBUG(dbgs() << "  --  ESD " << EsdId << "\n");
       break;
     }
+    case GOFF::RT_TXT:
+      LLVM_DEBUG(dbgs() << "  --  TXT (GOFF record type) unhandled\n");
+      break;
+    case GOFF::RT_RLD:
+      LLVM_DEBUG(dbgs() << "  --  RLD (GOFF record type) unhandled\n");
+      break;
+    case GOFF::RT_LEN:
+      LLVM_DEBUG(dbgs() << "  --  LEN (GOFF record type) unhandled\n");
+      break;
     case GOFF::RT_END:
       LLVM_DEBUG(dbgs() << "  --  END (GOFF record type) unhandled\n");
       break;
diff --git a/llvm/lib/Object/ObjectFile.cpp b/llvm/lib/Object/ObjectFile.cpp
index 428166f58070d0b..16c6003db4810ac 100644
--- a/llvm/lib/Object/ObjectFile.cpp
+++ b/llvm/lib/Object/ObjectFile.cpp
@@ -154,7 +154,6 @@ ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type,
   case file_magic::windows_resource:
   case file_magic::pdb:
   case file_magic::minidump:
-  case file_magic::goff_object:
   case file_magic::cuda_fatbinary:
   case file_magic::offload_binary:
   case file_magic::dxcontainer_object:
@@ -182,6 +181,8 @@ ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type,
   case file_magic::macho_kext_bundle:
   case file_magic::macho_file_set:
     return createMachOObjectFile(Object);
+  case file_magic::goff_object:
+    return createGOFFObjectFile(Object);
   case file_magic::coff_object:
   case file_magic::coff_import_library:
   case file_magic::pecoff_executable:
diff --git a/llvm/test/tools/llvm-readobj/GOFF/Inputs/goff-basics.o b/llvm/test/tools/llvm-readobj/GOFF/Inputs/goff-basics.o
new file mode 100644
index 000000000000000..4988c29ef3dc2f2
Binary files /dev/null and b/llvm/test/tools/llvm-readobj/GOFF/Inputs/goff-basics.o differ
diff --git a/llvm/test/tools/llvm-readobj/GOFF/goff-basics.test b/llvm/test/tools/llvm-readobj/GOFF/goff-basics.test
new file mode 100644
index 000000000000000..812cadd3c9b2654
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/GOFF/goff-basics.test
@@ -0,0 +1,69 @@
+# RUN: llvm-readobj --symbols %p/Inputs/goff-basics.o | \
+# RUN: FileCheck --check-prefix=SYMBOLSEXP %s
+
+# SYMBOLSEXP: File: {{.*}}goff-basics.o
+# SYMBOLSEXP-NEXT: Format: GOFF-SystemZ
+# SYMBOLSEXP-NEXT: Arch: s390x
+# SYMBOLSEXP-NEXT: AddressSize: 64bit
+# SYMBOLSEXP-NEXT: Symbols [
+# SYMBOLSEXP-NEXT:   Symbol {
+# SYMBOLSEXP-NEXT:     Name: goff-basics#S
+# SYMBOLSEXP-NEXT:     Value: 0
+# SYMBOLSEXP-NEXT:     Alignment: 0
+# SYMBOLSEXP-NEXT:   }
+# SYMBOLSEXP-NEXT:   Symbol {
+# SYMBOLSEXP-NEXT:     Name: goff-basics#C
+# SYMBOLSEXP-NEXT:     Value: 0
+# SYMBOLSEXP-NEXT:     Alignment: 0
+# SYMBOLSEXP-NEXT:   }
+# SYMBOLSEXP-NEXT:   Symbol {
+# SYMBOLSEXP-NEXT:     Name: .&ppa2
+# SYMBOLSEXP-NEXT:     Value: 0
+# SYMBOLSEXP-NEXT:     Alignment: 0
+# SYMBOLSEXP-NEXT:   }
+# SYMBOLSEXP-NEXT:   Symbol {
+# SYMBOLSEXP-NEXT:     Name: a
+# SYMBOLSEXP-NEXT:     Value: 0
+# SYMBOLSEXP-NEXT:     Alignment: 0
+# SYMBOLSEXP-NEXT:   }
+# SYMBOLSEXP-NEXT:   Symbol {
+# SYMBOLSEXP-NEXT:     Name: b
+# SYMBOLSEXP-NEXT:     Value: 0
+# SYMBOLSEXP-NEXT:     Alignment: 0
+# SYMBOLSEXP-NEXT:   }
+# SYMBOLSEXP-NEXT:   Symbol {
+# SYMBOLSEXP-NEXT:     Name: d
+# SYMBOLSEXP-NEXT:     Value: 0
+# SYMBOLSEXP-NEXT:     Alignment: 0
+# SYMBOLSEXP-NEXT:   }
+# SYMBOLSEXP-NEXT:   Symbol {
+# SYMBOLSEXP-NEXT:     Name: CELQSTRT
+# SYMBOLSEXP-NEXT:     Value: 0
+# SYMBOLSEXP-NEXT:     Alignment: 0
+# SYMBOLSEXP-NEXT:   }
+# SYMBOLSEXP-NEXT:   Symbol {
+# SYMBOLSEXP-NEXT:     Name: A
+# SYMBOLSEXP-NEXT:     Value: 16
+# SYMBOLSEXP-NEXT:     Alignment: 0
+# SYMBOLSEXP-NEXT:   }
+# SYMBOLSEXP-NEXT:   Symbol {
+# SYMBOLSEXP-NEXT:     Name: B
+# SYMBOLSEXP-NEXT:     Value: 48
+# SYMBOLSEXP-NEXT:     Alignment: 0
+# SYMBOLSEXP-NEXT:   }
+# SYMBOLSEXP-NEXT:   Symbol {
+# SYMBOLSEXP-NEXT:     Name: D
+# SYMBOLSEXP-NEXT:     Value: 80
+# SYMBOLSEXP-NEXT:     Alignment: 0
+# SYMBOLSEXP-NEXT:   }
+# SYMBOLSEXP-NEXT: ]
+
+
+# goff-basics.o was compiled with `clang -c goff-basics.c`
+# from the following source:
+# int a = 55;
+# int b;
+# double d;
+# int A() { return a; }
+# int B() { return b; }
+# double D() { return d; }
diff --git a/llvm/tools/llvm-readobj/CMakeLists.txt b/llvm/tools/llvm-readobj/CMakeLists.txt
index 0051f87b3c1039f..90637084ae7afa2 100644
--- a/llvm/tools/llvm-readobj/CMakeLists.txt
+++ b/llvm/tools/llvm-readobj/CMakeLists.txt
@@ -18,6 +18,7 @@ add_llvm_tool(llvm-readobj
   COFFDumper.cpp
   COFFImportDumper.cpp
   ELFDumper.cpp
+  GOFFDumper.cpp
   llvm-readobj.cpp
   MachODumper.cpp
   ObjDumper.cpp
diff --git a/llvm/tools/llvm-readobj/GOFFDumper.cpp b/llvm/tools/llvm-readobj/GOFFDumper.cpp
new file mode 100644
index 000000000000000..3cd3fd3866348e2
--- /dev/null
+++ b/llvm/tools/llvm-readobj/GOFFDumper.cpp
@@ -0,0 +1,94 @@
+#include "ObjDumper.h"
+#include "llvm-readobj.h"
+#include "llvm/Object/GOFFObjectFile.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+namespace {
+
+class GOFFDumper : public ObjDumper {
+public:
+  GOFFDumper(const GOFFObjectFile *Obj, ScopedPrinter &Writer)
+      : ObjDumper(Writer, Obj->getFileName()), Obj(Obj) {}
+
+  void printFileHeaders() override {}
+  void printSectionHeaders() override;
+  void printRelocations() override;
+  void printSymbols(bool ExtraSymInfo) override;
+  void printDynamicSymbols() override;
+  void printUnwindInfo() override {}
+  void printStackMap() const override {}
+
+  const object::GOFFObjectFile *getGOFFObject() const { return Obj; };
+
+private:
+  void printSymbol(const SymbolRef &Sym);
+
+  const GOFFObjectFile *Obj;
+};
+
+} // End anonymous namespace
+
+namespace llvm {
+std::unique_ptr<ObjDumper> createGOFFDumper(const object::GOFFObjectFile &Obj,
+                                            ScopedPrinter &Writer) {
+  return std::make_unique<GOFFDumper>(&Obj, Writer);
+}
+
+} // namespace llvm
+
+void GOFFDumper::printSymbol(const SymbolRef &Symbol) {
+  DictScope D(W, "Symbol");
+
+  Expected<StringRef> SymbolNameOrErr = Obj->getSymbolName(Symbol);
+  if (!SymbolNameOrErr)
+    reportError(SymbolNameOrErr.takeError(), Obj->getFileName());
+  W.printString("Name", SymbolNameOrErr.get());
+  Expected<uint64_t> SymVal = Symbol.getValue();
+  if (!SymVal)
+    reportError(SymVal.takeError(), Obj->getFileName());
+  W.printNumber("Value", *SymVal);
+  W.printNumber("Alignment", Symbol.getAlignment());
+}
+
+void GOFFDumper::printSectionHeaders() {
+  ListScope SectionsD(W, "Sections");
+  for (const SectionRef &Sec : Obj->sections()) {
+    StringRef Name = unwrapOrError(Obj->getFileName(), Sec.getName());
+
+    DictScope D(W, "Section");
+    W.printNumber("Index", Sec.getIndex());
+    W.printString("Name", Name);
+    W.printHex("Address", Sec.getAddress());
+    W.printHex("Size", Sec.getSize());
+    W.printNumber("Alignment", Sec.getAlignment().value());
+
+    if (opts::SectionSymbols) {
+      ListScope D(W, "Symbols");
+      for (const SymbolRef &Symbol : Obj->symbols()) {
+        if (!Sec.containsSymbol(Symbol))
+          continue;
+
+        printSymbol(Symbol);
+      }
+    }
+
+    if (opts::SectionData) {
+      StringRef Data = unwrapOrError(Obj->getFileName(), Sec.getContents());
+      W.printBinaryBlock("SectionData", Data);
+    }
+  }
+}
+
+void GOFFDumper::printSymbols(bool) {
+  ListScope Group(W, "Symbols");
+
+  for (const SymbolRef &Symbol : Obj->symbols())
+    printSymbol(Symbol);
+}
+
+void GOFFDumper::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); }
+
+void GOFFDumper::printRelocations() {}
diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
index 1d679453581bc84..a457e3bab331518 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -25,6 +25,7 @@ namespace object {
 class Archive;
 class COFFImportFile;
 class ObjectFile;
+class GOFFObjectFile;
 class XCOFFObjectFile;
 class ELFObjectFileBase;
 } // namespace object
@@ -206,6 +207,9 @@ std::unique_ptr<ObjDumper> createELFDumper(const object::ELFObjectFileBase &Obj,
 std::unique_ptr<ObjDumper> createMachODumper(const object::MachOObjectFile &Obj,
                                              ScopedPrinter &Writer);
 
+std::unique_ptr<ObjDumper> createGOFFDumper(const object::GOFFObjectFile &Obj,
+                                            ScopedPrinter &Writer);
+
 std::unique_ptr<ObjDumper> createWasmDumper(const object::WasmObjectFile &Obj,
                                             ScopedPrinter &Writer);
 
diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index ca633ceff90800e..472fdfa882b6059 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -27,6 +27,7 @@
 #include "llvm/Object/Archive.h"
 #include "llvm/Object/COFFImportFile.h"
 #include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/GOFFObjectFile.h"
 #include "llvm/Object/MachOUniversal.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Object/Wasm.h"
@@ -344,6 +345,9 @@ createDumper(const ObjectFile &Obj, ScopedPrinter &Writer) {
   if (const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(&Obj))
     return createMachODumper(*MachOObj, Writer);
 
+  if (const GOFFObjectFile *GOFFObj = dyn_cast<GOFFObjectFile>(&Obj))
+    return createGOFFDumper(*GOFFObj, Writer);
+
   if (const WasmObjectFile *WasmObj = dyn_cast<WasmObjectFile>(&Obj))
     return createWasmDumper(*WasmObj, Writer);
 

Copy link
Collaborator

@jh7370 jh7370 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should really try to avoid canned object files in the repository, because thwey are opaque and it's not clear what in them us important for testing them. They also don't play well with source control (you can't diff a binary file). A better approach would be to generate the object at test time. From most preferable to least, you could use a) yaml2obj, b) assembly and llvm-mc, or c) IR and llc. I expect yaml2obj doesn't support GOFF yet, but adding that support will be highly worthwhile if you plan on adding readobj and other tool support, because it allows you fine-grained control of your test inputs, allowing you to more easily test edge cases (especially for error handling).

You should also break this PR into multiple. The first would do nothing except add the bare framework for GOFF files, and the rest should add one feature (symbol dumping, section dumping etc) at a time.

GOFFDumper(const GOFFObjectFile *Obj, ScopedPrinter &Writer)
: ObjDumper(Writer, Obj->getFileName()), Obj(Obj) {}

void printFileHeaders() override {}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know the GOFF format at all, but will it make sense to support this (and printUnwindInfo and printStackMap) in the future? If so, I would recommend adding a warning to these methods saying that they are unimplemented.

ScopedPrinter &Writer) {
return std::make_unique<GOFFDumper>(&Obj, Writer);
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: be consistent with your start/end of your namespacing with regards to blank lines.

} // End anonymous namespace

namespace llvm {
std::unique_ptr<ObjDumper> createGOFFDumper(const object::GOFFObjectFile &Obj,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use namespace qualifiers, per the coding standard.

Comment on lines +92 to +94
void GOFFDumper::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); }

void GOFFDumper::printRelocations() {}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why you've provided these stub definitions out of line unlike the ones I commented on above?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants