Data: ELFDATA2LSB
Type: ET_DYN
Symbols: []
+
+## A symbol table without the null entry is non-conforming.
+## Check we don't print "Symbols" and "DynamicSymbols" keys in this case.
+
+# RUN: yaml2obj --docnum=3 %s -o %t3
+# RUN: obj2yaml %t3 | FileCheck %s --check-prefix=EMPTY
+
+# EMPTY: Sections:
+# EMPTY-NEXT: - Name: .symtab
+# EMPTY-NEXT: Type: SHT_SYMTAB
+# EMPTY-NEXT: Link: .strtab
+## TODO: we shouldn't dump the default "EntSize" value.
+# EMPTY-NEXT: EntSize: 0x18
+# EMPTY-NEXT: Size: 0x0
+# EMPTY-NEXT: - Name: .dynsym
+# EMPTY-NEXT: Type: SHT_DYNSYM
+# EMPTY-NEXT: Flags: [ SHF_ALLOC ]
+## TODO: we shouldn't dump the default "EntSize" value.
+# EMPTY-NEXT: EntSize: 0x18
+# EMPTY-NEXT: Size: 0x0
+# EMPTY-NEXT: ...
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+Sections:
+ - Name: .symtab
+ Type: SHT_SYMTAB
+ Size: 0
+ - Name: .dynsym
+ Type: SHT_DYNSYM
+ Size: 0
dumpDWARFSections(std::vector<std::unique_ptr<ELFYAML::Chunk>> &Sections);
Error dumpSymbols(const Elf_Shdr *Symtab,
- std::vector<ELFYAML::Symbol> &Symbols);
+ Optional<std::vector<ELFYAML::Symbol>> &Symbols);
Error dumpSymbol(const Elf_Sym *Sym, const Elf_Shdr *SymTab,
StringRef StrTable, ELFYAML::Symbol &S);
Expected<std::vector<std::unique_ptr<ELFYAML::Chunk>>> dumpSections();
// Generally we are trying to reduce noise in the YAML output. Because
// of that we do not print non-allocatable versions of such sections and
// assume they are placed at the end.
+ // We also dump symbol tables when the Size field is set. It happens when they
+ // are empty, which should not normally happen.
if (S.Type == ELF::SHT_STRTAB || S.Type == ELF::SHT_SYMTAB ||
- S.Type == ELF::SHT_DYNSYM)
- return S.Flags.getValueOr(ELFYAML::ELF_SHF(0)) & ELF::SHF_ALLOC;
+ S.Type == ELF::SHT_DYNSYM) {
+ return S.Size || S.Flags.getValueOr(ELFYAML::ELF_SHF(0)) & ELF::SHF_ALLOC;
+ }
return true;
}
}
}
- if (SymTab) {
- Y->Symbols.emplace();
- if (Error E = dumpSymbols(SymTab, *Y->Symbols))
+ if (SymTab)
+ if (Error E = dumpSymbols(SymTab, Y->Symbols))
return std::move(E);
- }
- if (DynSymTab) {
- Y->DynamicSymbols.emplace();
- if (Error E = dumpSymbols(DynSymTab, *Y->DynamicSymbols))
+ if (DynSymTab)
+ if (Error E = dumpSymbols(DynSymTab, Y->DynamicSymbols))
return std::move(E);
- }
// We dump all sections first. It is simple and allows us to verify that all
// sections are valid and also to generalize the code. But we are not going to
auto S = std::make_unique<ELFYAML::RawContentSection>();
if (Error E = dumpCommonSection(Shdr, *S.get()))
return std::move(E);
+
+ // Normally symbol tables should not be empty. We dump the "Size"
+ // key when they are.
+ if ((Shdr->sh_type == ELF::SHT_SYMTAB || Shdr->sh_type == ELF::SHT_DYNSYM) &&
+ !Shdr->sh_size)
+ S->Size.emplace();
+
return S.release();
}
}
template <class ELFT>
-Error ELFDumper<ELFT>::dumpSymbols(const Elf_Shdr *Symtab,
- std::vector<ELFYAML::Symbol> &Symbols) {
+Error ELFDumper<ELFT>::dumpSymbols(
+ const Elf_Shdr *Symtab, Optional<std::vector<ELFYAML::Symbol>> &Symbols) {
if (!Symtab)
return Error::success();
- auto StrTableOrErr = Obj.getStringTableForSymtab(*Symtab);
- if (!StrTableOrErr)
- return StrTableOrErr.takeError();
- StringRef StrTable = *StrTableOrErr;
-
auto SymtabOrErr = Obj.symbols(Symtab);
if (!SymtabOrErr)
return SymtabOrErr.takeError();
+ if (SymtabOrErr->empty())
+ return Error::success();
+
+ auto StrTableOrErr = Obj.getStringTableForSymtab(*Symtab);
+ if (!StrTableOrErr)
+ return StrTableOrErr.takeError();
+
if (Symtab->sh_type == ELF::SHT_SYMTAB) {
SymTable = *SymtabOrErr;
SymbolNames.resize(SymTable.size());
}
+ Symbols.emplace();
for (const auto &Sym : (*SymtabOrErr).drop_front()) {
ELFYAML::Symbol S;
- if (auto EC = dumpSymbol(&Sym, Symtab, StrTable, S))
+ if (auto EC = dumpSymbol(&Sym, Symtab, *StrTableOrErr, S))
return EC;
- Symbols.push_back(S);
+ Symbols->push_back(S);
}
return Error::success();