[llvm] bccd2ec - [llvm-readobj/elf] - Simplify and refine the implementation which dumps .stack_sizes

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 15 01:57:22 PDT 2020


Author: Georgii Rymar
Date: 2020-09-15T11:57:00+03:00
New Revision: bccd2ec3e216fed04c46df7077462165435703a1

URL: https://github.com/llvm/llvm-project/commit/bccd2ec3e216fed04c46df7077462165435703a1
DIFF: https://github.com/llvm/llvm-project/commit/bccd2ec3e216fed04c46df7077462165435703a1.diff

LOG: [llvm-readobj/elf] - Simplify and refine the implementation which dumps .stack_sizes

Our implementation of stack sizes section dumping heavily uses `ELFObjectFile<ELFT>`,
while the rest of the code uses `ELFFile<ELFT>`.

That APIs are very different. `ELFObjectFile<ELFT>` is very generic
and has `SectionRef`, `RelocationRef`, `SymbolRef` and other generic concepts.
The `ELFFile<ELFT>` class works directly with `Elf_Shdr`, `Elf_Rel[a]`, `Elf_Sym` etc,
what is probably much cleaner for ELF dumper.

Also, `ELFObjectFile<ELFT>` API does not always provide a way to check
for possible errors. E.g. the implementation of `symbol_end()` does not verify the `sh_size`:

```
template <class ELFT>
basic_symbol_iterator ELFObjectFile<ELFT>::symbol_end() const {
  const Elf_Shdr *SymTab = DotSymtabSec;
  if (!SymTab)
    return symbol_begin();
  DataRefImpl Sym = toDRI(SymTab, SymTab->sh_size / sizeof(Elf_Sym));
  return basic_symbol_iterator(SymbolRef(Sym, this));
}
```
There are many other examples which makes me thing we might win from
switching to `ELFFile<ELFT>` API, where we heavily validate an input data already.

This patch is the first step in this direction. I've converted the large portion of the code
to use `ELFFile<ELFT>`.

Differential revision: https://reviews.llvm.org/D87362

Added: 
    

Modified: 
    llvm/tools/llvm-readobj/ELFDumper.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 86d76b056b92..e28d4ece226c 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -722,8 +722,9 @@ template <typename ELFT> class DumpStyle {
   TYPEDEF_ELF_TYPES(ELFT)
 
   DumpStyle(ELFDumper<ELFT> *Dumper)
-      : Obj(*Dumper->getElfObject()->getELFFile()), Dumper(Dumper) {
-    FileName = this->Dumper->getElfObject()->getFileName();
+      : Obj(*Dumper->getElfObject()->getELFFile()),
+        ElfObj(*Dumper->getElfObject()), Dumper(Dumper) {
+    FileName = ElfObj.getFileName();
   }
 
   virtual ~DumpStyle() = default;
@@ -752,17 +753,15 @@ template <typename ELFT> class DumpStyle {
   virtual void printAddrsig() = 0;
   virtual void printNotes() = 0;
   virtual void printELFLinkerOptions() = 0;
-  virtual void printStackSizes(const ELFObjectFile<ELFT> *Obj) = 0;
-  void printNonRelocatableStackSizes(const ELFObjectFile<ELFT> *Obj,
-                                     std::function<void()> PrintHeader);
-  void printRelocatableStackSizes(const ELFObjectFile<ELFT> *Obj,
-                                  std::function<void()> PrintHeader);
-  void printFunctionStackSize(const ELFObjectFile<ELFT> *Obj, uint64_t SymValue,
-                              Optional<SectionRef> FunctionSec,
+  virtual void printStackSizes() = 0;
+  void printNonRelocatableStackSizes(std::function<void()> PrintHeader);
+  void printRelocatableStackSizes(std::function<void()> PrintHeader);
+  void printFunctionStackSize(uint64_t SymValue,
+                              Optional<const Elf_Shdr *> FunctionSec,
                               const Elf_Shdr &StackSizeSec, DataExtractor Data,
                               uint64_t *Offset);
-  void printStackSize(const ELFObjectFile<ELFT> *Obj, RelocationRef Rel,
-                      SectionRef FunctionSec, const Elf_Shdr &StackSizeSec,
+  void printStackSize(RelocationRef Rel, const Elf_Shdr *FunctionSec,
+                      const Elf_Shdr &StackSizeSec,
                       const RelocationResolver &Resolver, DataExtractor Data);
   virtual void printStackSizeEntry(uint64_t Size, StringRef FuncName) = 0;
   virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0;
@@ -790,6 +789,7 @@ template <typename ELFT> class DumpStyle {
 
   StringRef FileName;
   const ELFFile<ELFT> &Obj;
+  const ELFObjectFile<ELFT> &ElfObj;
 
 private:
   const ELFDumper<ELFT> *Dumper;
@@ -828,7 +828,7 @@ template <typename ELFT> class GNUStyle : public DumpStyle<ELFT> {
   void printAddrsig() override;
   void printNotes() override;
   void printELFLinkerOptions() override;
-  void printStackSizes(const ELFObjectFile<ELFT> *Obj) override;
+  void printStackSizes() override;
   void printStackSizeEntry(uint64_t Size, StringRef FuncName) override;
   void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
   void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override;
@@ -952,7 +952,7 @@ template <typename ELFT> class LLVMStyle : public DumpStyle<ELFT> {
   void printAddrsig() override;
   void printNotes() override;
   void printELFLinkerOptions() override;
-  void printStackSizes(const ELFObjectFile<ELFT> *Obj) override;
+  void printStackSizes() override;
   void printStackSizeEntry(uint64_t Size, StringRef FuncName) override;
   void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
   void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override;
@@ -2333,7 +2333,7 @@ template <class ELFT> void ELFDumper<ELFT>::printELFLinkerOptions() {
 }
 
 template <class ELFT> void ELFDumper<ELFT>::printStackSizes() {
-  ELFDumperStyle->printStackSizes(ObjF);
+  ELFDumperStyle->printStackSizes();
 }
 
 #define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum)                                 \
@@ -5503,16 +5503,6 @@ template <class ELFT> void GNUStyle<ELFT>::printDependentLibs() {
     PrintSection();
 }
 
-// Used for printing section names in places where possible errors can be
-// ignored.
-static StringRef getSectionName(const SectionRef &Sec) {
-  Expected<StringRef> NameOrErr = Sec.getName();
-  if (NameOrErr)
-    return *NameOrErr;
-  consumeError(NameOrErr.takeError());
-  return "<?>";
-}
-
 // Used for printing symbol names in places where possible errors can be
 // ignored.
 static std::string getSymbolName(const ELFSymbolRef &Sym) {
@@ -5524,16 +5514,13 @@ static std::string getSymbolName(const ELFSymbolRef &Sym) {
 }
 
 template <class ELFT>
-void DumpStyle<ELFT>::printFunctionStackSize(const ELFObjectFile<ELFT> *Obj,
-                                             uint64_t SymValue,
-                                             Optional<SectionRef> FunctionSec,
-                                             const Elf_Shdr &StackSizeSec,
-                                             DataExtractor Data,
-                                             uint64_t *Offset) {
+void DumpStyle<ELFT>::printFunctionStackSize(
+    uint64_t SymValue, Optional<const Elf_Shdr *> FunctionSec,
+    const Elf_Shdr &StackSizeSec, DataExtractor Data, uint64_t *Offset) {
   // This function ignores potentially erroneous input, unless it is directly
   // related to stack size reporting.
   SymbolRef FuncSym;
-  for (const ELFSymbolRef &Symbol : Obj->symbols()) {
+  for (const ELFSymbolRef &Symbol : ElfObj.symbols()) {
     Expected<uint64_t> SymAddrOrErr = Symbol.getAddress();
     if (!SymAddrOrErr) {
       consumeError(SymAddrOrErr.takeError());
@@ -5547,7 +5534,8 @@ void DumpStyle<ELFT>::printFunctionStackSize(const ELFObjectFile<ELFT> *Obj,
     if (Symbol.getELFType() == ELF::STT_FUNC && *SymAddrOrErr == SymValue) {
       // Check if the symbol is in the right section. FunctionSec == None means
       // "any section".
-      if (!FunctionSec || FunctionSec->containsSymbol(Symbol)) {
+      if (!FunctionSec ||
+          ElfObj.toSectionRef(*FunctionSec).containsSymbol(Symbol)) {
         FuncSym = Symbol;
         break;
       }
@@ -5561,7 +5549,7 @@ void DumpStyle<ELFT>::printFunctionStackSize(const ELFObjectFile<ELFT> *Obj,
   else
     reportWarning(
         createError("could not identify function symbol for stack size entry"),
-        Obj->getFileName());
+        FileName);
 
   // Extract the size. The expectation is that Offset is pointing to the right
   // place, i.e. past the function address.
@@ -5570,11 +5558,10 @@ void DumpStyle<ELFT>::printFunctionStackSize(const ELFObjectFile<ELFT> *Obj,
   // getULEB128() does not advance Offset if it is not able to extract a valid
   // integer.
   if (*Offset == PrevOffset) {
-    reportWarning(
-        createStringError(object_error::parse_failed,
-                          "could not extract a valid stack size in " +
-                              describe(*Obj->getELFFile(), StackSizeSec)),
-        Obj->getFileName());
+    reportWarning(createStringError(object_error::parse_failed,
+                                    "could not extract a valid stack size in " +
+                                        describe(Obj, StackSizeSec)),
+                  FileName);
     return;
   }
 
@@ -5590,9 +5577,8 @@ void GNUStyle<ELFT>::printStackSizeEntry(uint64_t Size, StringRef FuncName) {
 }
 
 template <class ELFT>
-void DumpStyle<ELFT>::printStackSize(const ELFObjectFile<ELFT> *Obj,
-                                     RelocationRef Reloc,
-                                     SectionRef FunctionSec,
+void DumpStyle<ELFT>::printStackSize(RelocationRef Reloc,
+                                     const Elf_Shdr *FunctionSec,
                                      const Elf_Shdr &StackSizeSec,
                                      const RelocationResolver &Resolver,
                                      DataExtractor Data) {
@@ -5600,8 +5586,7 @@ void DumpStyle<ELFT>::printStackSize(const ELFObjectFile<ELFT> *Obj,
   // related to stack size reporting.
   object::symbol_iterator RelocSym = Reloc.getSymbol();
   uint64_t RelocSymValue = 0;
-  StringRef FileStr = Obj->getFileName();
-  if (RelocSym != Obj->symbol_end()) {
+  if (RelocSym != ElfObj.symbol_end()) {
     // Ensure that the relocation symbol is in the function section, i.e. the
     // section where the functions whose stack sizes we are reporting are
     // located.
@@ -5610,16 +5595,16 @@ void DumpStyle<ELFT>::printStackSize(const ELFObjectFile<ELFT> *Obj,
       reportWarning(
           createError("cannot identify the section for relocation symbol '" +
                       getSymbolName(*RelocSym) + "'"),
-          FileStr);
+          FileName);
       consumeError(SectionOrErr.takeError());
-    } else if (*SectionOrErr != FunctionSec) {
+    } else if (*SectionOrErr != ElfObj.toSectionRef(FunctionSec)) {
       reportWarning(createError("relocation symbol '" +
                                 getSymbolName(*RelocSym) +
                                 "' is not in the expected section"),
-                    FileStr);
+                    FileName);
       // Pretend that the symbol is in the correct section and report its
       // stack size anyway.
-      FunctionSec = **SectionOrErr;
+      FunctionSec = ElfObj.getSection((*SectionOrErr)->getRawDataRefImpl());
     }
 
     Expected<uint64_t> RelocSymValueOrErr = RelocSym->getValue();
@@ -5634,31 +5619,29 @@ void DumpStyle<ELFT>::printStackSize(const ELFObjectFile<ELFT> *Obj,
     reportUniqueWarning(createStringError(
         object_error::parse_failed,
         "found invalid relocation offset (0x" + Twine::utohexstr(Offset) +
-            ") into " + describe(*Obj->getELFFile(), StackSizeSec) +
+            ") into " + describe(Obj, StackSizeSec) +
             " while trying to extract a stack size entry"));
     return;
   }
 
   uint64_t Addend = Data.getAddress(&Offset);
   uint64_t SymValue = Resolver(Reloc, RelocSymValue, Addend);
-  this->printFunctionStackSize(Obj, SymValue, FunctionSec, StackSizeSec, Data,
+  this->printFunctionStackSize(SymValue, FunctionSec, StackSizeSec, Data,
                                &Offset);
 }
 
 template <class ELFT>
 void DumpStyle<ELFT>::printNonRelocatableStackSizes(
-    const ELFObjectFile<ELFT> *Obj, std::function<void()> PrintHeader) {
+    std::function<void()> PrintHeader) {
   // This function ignores potentially erroneous input, unless it is directly
   // related to stack size reporting.
-  const ELFFile<ELFT> *EF = Obj->getELFFile();
-  for (const SectionRef &Sec : Obj->sections()) {
-    if (getSectionName(Sec) != ".stack_sizes")
+  for (const Elf_Shdr &Sec : cantFail(Obj.sections())) {
+    if (this->getPrintableSectionName(Sec) != ".stack_sizes")
       continue;
     PrintHeader();
-    const Elf_Shdr *ElfSec = Obj->getSection(Sec.getRawDataRefImpl());
     ArrayRef<uint8_t> Contents =
-        unwrapOrError(this->FileName, EF->getSectionContents(*ElfSec));
-    DataExtractor Data(Contents, Obj->isLittleEndian(), sizeof(Elf_Addr));
+        unwrapOrError(this->FileName, Obj.getSectionContents(Sec));
+    DataExtractor Data(Contents, Obj.isLE(), sizeof(Elf_Addr));
     uint64_t Offset = 0;
     while (Offset < Contents.size()) {
       // The function address is followed by a ULEB representing the stack
@@ -5666,12 +5649,12 @@ void DumpStyle<ELFT>::printNonRelocatableStackSizes(
       if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(Elf_Addr) + 1)) {
         reportUniqueWarning(createStringError(
             object_error::parse_failed,
-            describe(*EF, *ElfSec) +
+            describe(Obj, Sec) +
                 " ended while trying to extract a stack size entry"));
         break;
       }
       uint64_t SymValue = Data.getAddress(&Offset);
-      printFunctionStackSize(Obj, SymValue, /*FunctionSec=*/None, *ElfSec, Data,
+      printFunctionStackSize(SymValue, /*FunctionSec=*/None, Sec, Data,
                              &Offset);
     }
   }
@@ -5679,17 +5662,13 @@ void DumpStyle<ELFT>::printNonRelocatableStackSizes(
 
 template <class ELFT>
 void DumpStyle<ELFT>::printRelocatableStackSizes(
-    const ELFObjectFile<ELFT> *Obj, std::function<void()> PrintHeader) {
-  const ELFFile<ELFT> *EF = Obj->getELFFile();
-
+    std::function<void()> PrintHeader) {
   // Build a map between stack size sections and their corresponding relocation
   // sections.
-  llvm::MapVector<SectionRef, SectionRef> StackSizeRelocMap;
-  const SectionRef NullSection{};
-
-  for (const SectionRef &Sec : Obj->sections()) {
+  llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> StackSizeRelocMap;
+  for (const Elf_Shdr &Sec : cantFail(Obj.sections())) {
     StringRef SectionName;
-    if (Expected<StringRef> NameOrErr = Sec.getName())
+    if (Expected<StringRef> NameOrErr = Obj.getSectionName(Sec))
       SectionName = *NameOrErr;
     else
       consumeError(NameOrErr.takeError());
@@ -5697,92 +5676,80 @@ void DumpStyle<ELFT>::printRelocatableStackSizes(
     // A stack size section that we haven't encountered yet is mapped to the
     // null section until we find its corresponding relocation section.
     if (SectionName == ".stack_sizes")
-      if (StackSizeRelocMap.count(Sec) == 0) {
-        StackSizeRelocMap[Sec] = NullSection;
+      if (StackSizeRelocMap
+              .insert(std::make_pair(&Sec, (const Elf_Shdr *)nullptr))
+              .second)
         continue;
-      }
 
     // Check relocation sections if they are relocating contents of a
     // stack sizes section.
-    const Elf_Shdr *ElfSec = Obj->getSection(Sec.getRawDataRefImpl());
-    uint32_t SectionType = ElfSec->sh_type;
-    if (SectionType != ELF::SHT_RELA && SectionType != ELF::SHT_REL)
+    if (Sec.sh_type != ELF::SHT_RELA && Sec.sh_type != ELF::SHT_REL)
       continue;
 
-    Expected<section_iterator> RelSecOrErr = Sec.getRelocatedSection();
+    Expected<const Elf_Shdr *> RelSecOrErr = Obj.getSection(Sec.sh_info);
     if (!RelSecOrErr) {
-      reportUniqueWarning(
-          createStringError(object_error::parse_failed,
-                            describe(*Obj->getELFFile(), *ElfSec) +
-                                ": failed to get a relocated section: " +
-                                toString(RelSecOrErr.takeError())));
+      reportUniqueWarning(createStringError(
+          object_error::parse_failed,
+          describe(Obj, Sec) + ": failed to get a relocated section: " +
+              toString(RelSecOrErr.takeError())));
       continue;
     }
 
-    const Elf_Shdr *ContentsSec =
-        Obj->getSection((*RelSecOrErr)->getRawDataRefImpl());
-    Expected<StringRef> ContentsSectionNameOrErr =
-        EF->getSectionName(*ContentsSec);
-    if (!ContentsSectionNameOrErr) {
-      consumeError(ContentsSectionNameOrErr.takeError());
-      continue;
-    }
-    if (*ContentsSectionNameOrErr != ".stack_sizes")
+    const Elf_Shdr *ContentsSec = *RelSecOrErr;
+    if (this->getPrintableSectionName(**RelSecOrErr) != ".stack_sizes")
       continue;
+
     // Insert a mapping from the stack sizes section to its relocation section.
-    StackSizeRelocMap[Obj->toSectionRef(ContentsSec)] = Sec;
+    StackSizeRelocMap[ContentsSec] = &Sec;
   }
 
   for (const auto &StackSizeMapEntry : StackSizeRelocMap) {
     PrintHeader();
-    const SectionRef &StackSizesSec = StackSizeMapEntry.first;
-    const SectionRef &RelocSec = StackSizeMapEntry.second;
-    const Elf_Shdr *StackSizesELFSec =
-        Obj->getSection(StackSizesSec.getRawDataRefImpl());
+    const Elf_Shdr *StackSizesELFSec = StackSizeMapEntry.first;
+    const Elf_Shdr *RelocSec = StackSizeMapEntry.second;
 
     // Warn about stack size sections without a relocation section.
-    if (RelocSec == NullSection) {
-      reportWarning(
-          createError(".stack_sizes (" +
-                      describe(*Obj->getELFFile(), *StackSizesELFSec) +
-                      ") does not have a corresponding "
-                      "relocation section"),
-          Obj->getFileName());
+    if (!RelocSec) {
+      reportWarning(createError(".stack_sizes (" +
+                                describe(Obj, *StackSizesELFSec) +
+                                ") does not have a corresponding "
+                                "relocation section"),
+                    FileName);
       continue;
     }
 
     // A .stack_sizes section header's sh_link field is supposed to point
     // to the section that contains the functions whose stack sizes are
     // described in it.
-    const SectionRef FunctionSec = Obj->toSectionRef(unwrapOrError(
-        this->FileName, EF->getSection(StackSizesELFSec->sh_link)));
-
+    const Elf_Shdr *FunctionSec = unwrapOrError(
+        this->FileName, Obj.getSection(StackSizesELFSec->sh_link));
     bool (*IsSupportedFn)(uint64_t);
     RelocationResolver Resolver;
-    std::tie(IsSupportedFn, Resolver) = getRelocationResolver(*Obj);
-    auto Contents = unwrapOrError(this->FileName, StackSizesSec.getContents());
-    DataExtractor Data(Contents, Obj->isLittleEndian(), sizeof(Elf_Addr));
+    std::tie(IsSupportedFn, Resolver) = getRelocationResolver(ElfObj);
+    ArrayRef<uint8_t> Contents =
+        unwrapOrError(this->FileName, Obj.getSectionContents(*StackSizesELFSec));
+    DataExtractor Data(Contents, Obj.isLE(), sizeof(Elf_Addr));
+
     size_t I = 0;
-    for (const RelocationRef &Reloc : RelocSec.relocations()) {
+    for (const RelocationRef &Reloc :
+         ElfObj.toSectionRef(RelocSec).relocations()) {
       ++I;
       if (!IsSupportedFn || !IsSupportedFn(Reloc.getType())) {
-        const Elf_Shdr *RelocSecShdr =
-            Obj->getSection(RelocSec.getRawDataRefImpl());
         reportUniqueWarning(createStringError(
             object_error::parse_failed,
-            describe(*EF, *RelocSecShdr) +
+            describe(Obj, *RelocSec) +
                 " contains an unsupported relocation with index " + Twine(I) +
-                ": " + EF->getRelocationTypeName(Reloc.getType())));
+                ": " + Obj.getRelocationTypeName(Reloc.getType())));
         continue;
       }
-      this->printStackSize(Obj, Reloc, FunctionSec, *StackSizesELFSec, Resolver,
+      this->printStackSize(Reloc, FunctionSec, *StackSizesELFSec, Resolver,
                            Data);
     }
   }
 }
 
 template <class ELFT>
-void GNUStyle<ELFT>::printStackSizes(const ELFObjectFile<ELFT> *Obj) {
+void GNUStyle<ELFT>::printStackSizes() {
   bool HeaderHasBeenPrinted = false;
   auto PrintHeader = [&]() {
     if (HeaderHasBeenPrinted)
@@ -5797,10 +5764,10 @@ void GNUStyle<ELFT>::printStackSizes(const ELFObjectFile<ELFT> *Obj) {
 
   // For non-relocatable objects, look directly for sections whose name starts
   // with .stack_sizes and process the contents.
-  if (Obj->isRelocatableObject())
-    this->printRelocatableStackSizes(Obj, PrintHeader);
+  if (this->Obj.getHeader().e_type == ELF::ET_REL)
+    this->printRelocatableStackSizes(PrintHeader);
   else
-    this->printNonRelocatableStackSizes(Obj, PrintHeader);
+    this->printNonRelocatableStackSizes(PrintHeader);
 }
 
 template <class ELFT>
@@ -6697,12 +6664,12 @@ template <class ELFT> void LLVMStyle<ELFT>::printDependentLibs() {
 }
 
 template <class ELFT>
-void LLVMStyle<ELFT>::printStackSizes(const ELFObjectFile<ELFT> *Obj) {
+void LLVMStyle<ELFT>::printStackSizes() {
   ListScope L(W, "StackSizes");
-  if (Obj->isRelocatableObject())
-    this->printRelocatableStackSizes(Obj, []() {});
+  if (this->Obj.getHeader().e_type == ELF::ET_REL)
+    this->printRelocatableStackSizes([]() {});
   else
-    this->printNonRelocatableStackSizes(Obj, []() {});
+    this->printNonRelocatableStackSizes([]() {});
 }
 
 template <class ELFT>


        


More information about the llvm-commits mailing list