summaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-readobj/ELFDumper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-readobj/ELFDumper.cpp')
-rw-r--r--llvm/tools/llvm-readobj/ELFDumper.cpp2020
1 files changed, 1341 insertions, 679 deletions
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 8ffb68283405b..15076f1f89337 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -52,6 +52,8 @@
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MipsABIFlags.h"
+#include "llvm/Support/RISCVAttributeParser.h"
+#include "llvm/Support/RISCVAttributes.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -135,19 +137,34 @@ struct DynRegionInfo {
/// Name of the file. Used for error reporting.
StringRef FileName;
+ /// Error prefix. Used for error reporting to provide more information.
+ std::string Context;
+ /// Region size name. Used for error reporting.
+ StringRef SizePrintName = "size";
+ /// Entry size name. Used for error reporting. If this field is empty, errors
+ /// will not mention the entry size.
+ StringRef EntSizePrintName = "entry size";
template <typename Type> ArrayRef<Type> getAsArrayRef() const {
const Type *Start = reinterpret_cast<const Type *>(Addr);
if (!Start)
return {Start, Start};
- if (EntSize != sizeof(Type) || Size % EntSize) {
- // TODO: Add a section index to this warning.
- reportWarning(createError("invalid section size (" + Twine(Size) +
- ") or entity size (" + Twine(EntSize) + ")"),
- FileName);
- return {Start, Start};
- }
- return {Start, Start + (Size / EntSize)};
+ if (EntSize == sizeof(Type) && (Size % EntSize == 0))
+ return {Start, Start + (Size / EntSize)};
+
+ std::string Msg;
+ if (!Context.empty())
+ Msg += Context + " has ";
+
+ Msg += ("invalid " + SizePrintName + " (0x" + Twine::utohexstr(Size) + ")")
+ .str();
+ if (!EntSizePrintName.empty())
+ Msg +=
+ (" or " + EntSizePrintName + " (0x" + Twine::utohexstr(EntSize) + ")")
+ .str();
+
+ reportWarning(createError(Msg.c_str()), FileName);
+ return {Start, Start};
}
};
@@ -204,7 +221,7 @@ public:
void printProgramHeaders(bool PrintProgramHeaders,
cl::boolOrDefault PrintSectionMapping) override;
void printHashTable() override;
- void printGnuHashTable() override;
+ void printGnuHashTable(const object::ObjectFile *Obj) override;
void printLoadName() override;
void printVersionInfo() override;
void printGroupSections() override;
@@ -213,7 +230,7 @@ public:
void printStackMap() const override;
- void printHashHistogram() override;
+ void printHashHistograms() override;
void printCGProfile() override;
void printAddrsig() override;
@@ -268,10 +285,10 @@ private:
DynRegionInfo DynRelaRegion;
DynRegionInfo DynRelrRegion;
DynRegionInfo DynPLTRelRegion;
- DynRegionInfo DynSymRegion;
+ Optional<DynRegionInfo> DynSymRegion;
DynRegionInfo DynamicTable;
StringRef DynamicStringTable;
- std::string SOName = "<Not found>";
+ StringRef SOName = "<Not found>";
const Elf_Hash *HashTable = nullptr;
const Elf_GnuHash *GnuHashTable = nullptr;
const Elf_Shdr *DotSymtabSec = nullptr;
@@ -290,6 +307,8 @@ private:
};
mutable SmallVector<Optional<VersionEntry>, 16> VersionMap;
+ std::unordered_set<std::string> Warnings;
+
public:
Elf_Dyn_Range dynamic_table() const {
// A valid .dynamic section contains an array of entries terminated
@@ -306,26 +325,31 @@ public:
return Table.slice(0, Size);
}
+ Optional<DynRegionInfo> getDynSymRegion() const { return DynSymRegion; }
+
Elf_Sym_Range dynamic_symbols() const {
- return DynSymRegion.getAsArrayRef<Elf_Sym>();
+ if (!DynSymRegion)
+ return Elf_Sym_Range();
+ return DynSymRegion->getAsArrayRef<Elf_Sym>();
}
Elf_Rel_Range dyn_rels() const;
Elf_Rela_Range dyn_relas() const;
Elf_Relr_Range dyn_relrs() const;
- std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable,
+ std::string getFullSymbolName(const Elf_Sym *Symbol,
+ Optional<StringRef> StrTable,
bool IsDynamic) const;
Expected<unsigned> getSymbolSectionIndex(const Elf_Sym *Symbol,
const Elf_Sym *FirstSym) const;
Expected<StringRef> getSymbolSectionName(const Elf_Sym *Symbol,
unsigned SectionIndex) const;
- Expected<std::string> getStaticSymbolName(uint32_t Index) const;
- std::string getDynamicString(uint64_t Value) const;
+ std::string getStaticSymbolName(uint32_t Index) const;
+ StringRef getDynamicString(uint64_t Value) const;
Expected<StringRef> getSymbolVersionByIndex(uint32_t VersionSymbolIndex,
bool &IsDefault) const;
void printSymbolsHelper(bool IsDynamic) const;
- void printDynamicEntry(raw_ostream &OS, uint64_t Type, uint64_t Value) const;
+ std::string getDynamicEntry(uint64_t Type, uint64_t Value) const;
const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; }
const Elf_Shdr *getDotCGProfileSec() const { return DotCGProfileSec; }
@@ -347,6 +371,12 @@ public:
getVersionDefinitions(const Elf_Shdr *Sec) const;
Expected<std::vector<VerNeed>>
getVersionDependencies(const Elf_Shdr *Sec) const;
+
+ Expected<std::pair<const Elf_Sym *, std::string>>
+ getRelocationTarget(const Elf_Shdr *SymTab, const Elf_Rela &R) const;
+
+ std::function<Error(const Twine &Msg)> WarningHandler;
+ void reportUniqueWarning(Error Err) const;
};
template <class ELFT>
@@ -439,12 +469,12 @@ ELFDumper<ELFT>::getVersionTable(const Elf_Shdr *Sec, ArrayRef<Elf_Sym> *SymTab,
Expected<std::pair<ArrayRef<Elf_Sym>, StringRef>> SymTabOrErr =
getLinkAsSymtab(Obj, Sec, SecNdx, SHT_DYNSYM);
if (!SymTabOrErr) {
- ELFDumperStyle->reportUniqueWarning(SymTabOrErr.takeError());
+ reportUniqueWarning(SymTabOrErr.takeError());
return *VersionsOrErr;
}
if (SymTabOrErr->first.size() != VersionsOrErr->size())
- ELFDumperStyle->reportUniqueWarning(
+ reportUniqueWarning(
createError("SHT_GNU_versym section with index " + Twine(SecNdx) +
": the number of entries (" + Twine(VersionsOrErr->size()) +
") does not match the number of symbols (" +
@@ -490,7 +520,7 @@ ELFDumper<ELFT>::getVersionDefinitions(const Elf_Shdr *Sec) const {
VerdAux Aux;
Aux.Offset = VerdauxBuf - Start;
if (Verdaux->vda_name <= StrTabOrErr->size())
- Aux.Name = StrTabOrErr->drop_front(Verdaux->vda_name);
+ Aux.Name = std::string(StrTabOrErr->drop_front(Verdaux->vda_name));
else
Aux.Name = "<invalid vda_name: " + to_string(Verdaux->vda_name) + ">";
return Aux;
@@ -558,7 +588,7 @@ ELFDumper<ELFT>::getVersionDependencies(const Elf_Shdr *Sec) const {
StringRef StrTab;
Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Obj, Sec, SecNdx);
if (!StrTabOrErr)
- ELFDumperStyle->reportUniqueWarning(StrTabOrErr.takeError());
+ reportUniqueWarning(StrTabOrErr.takeError());
else
StrTab = *StrTabOrErr;
@@ -600,7 +630,7 @@ ELFDumper<ELFT>::getVersionDependencies(const Elf_Shdr *Sec) const {
VN.Offset = VerneedBuf - Start;
if (Verneed->vn_file < StrTab.size())
- VN.File = StrTab.drop_front(Verneed->vn_file);
+ VN.File = std::string(StrTab.drop_front(Verneed->vn_file));
else
VN.File = "<corrupt vn_file: " + to_string(Verneed->vn_file) + ">";
@@ -630,7 +660,7 @@ ELFDumper<ELFT>::getVersionDependencies(const Elf_Shdr *Sec) const {
if (StrTab.size() <= Vernaux->vna_name)
Aux.Name = "<corrupt>";
else
- Aux.Name = StrTab.drop_front(Vernaux->vna_name);
+ Aux.Name = std::string(StrTab.drop_front(Vernaux->vna_name));
VernauxBuf += Vernaux->vna_next;
}
@@ -641,7 +671,8 @@ ELFDumper<ELFT>::getVersionDependencies(const Elf_Shdr *Sec) const {
template <class ELFT>
void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
- StringRef StrTable, SymtabName;
+ Optional<StringRef> StrTable;
+ StringRef SymtabName;
size_t Entries = 0;
Elf_Sym_Range Syms(nullptr, nullptr);
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
@@ -649,16 +680,36 @@ void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
StrTable = DynamicStringTable;
Syms = dynamic_symbols();
SymtabName = DynSymtabName;
- if (DynSymRegion.Addr)
- Entries = DynSymRegion.Size / DynSymRegion.EntSize;
+ Entries = Syms.size();
} else {
if (!DotSymtabSec)
return;
- StrTable = unwrapOrError(ObjF->getFileName(),
- Obj->getStringTableForSymtab(*DotSymtabSec));
- Syms = unwrapOrError(ObjF->getFileName(), Obj->symbols(DotSymtabSec));
- SymtabName =
- unwrapOrError(ObjF->getFileName(), Obj->getSectionName(DotSymtabSec));
+
+ if (Expected<StringRef> StrTableOrErr =
+ Obj->getStringTableForSymtab(*DotSymtabSec))
+ StrTable = *StrTableOrErr;
+ else
+ reportUniqueWarning(createError(
+ "unable to get the string table for the SHT_SYMTAB section: " +
+ toString(StrTableOrErr.takeError())));
+
+ if (Expected<Elf_Sym_Range> SymsOrErr = Obj->symbols(DotSymtabSec))
+ Syms = *SymsOrErr;
+ else
+ reportUniqueWarning(
+ createError("unable to read symbols from the SHT_SYMTAB section: " +
+ toString(SymsOrErr.takeError())));
+
+ if (Expected<StringRef> SymtabNameOrErr =
+ Obj->getSectionName(DotSymtabSec)) {
+ SymtabName = *SymtabNameOrErr;
+ } else {
+ reportUniqueWarning(
+ createError("unable to get the name of the SHT_SYMTAB section: " +
+ toString(SymtabNameOrErr.takeError())));
+ SymtabName = "<?>";
+ }
+
Entries = DotSymtabSec->getEntityCount();
}
if (Syms.begin() == Syms.end())
@@ -687,14 +738,6 @@ public:
DumpStyle(ELFDumper<ELFT> *Dumper) : Dumper(Dumper) {
FileName = this->Dumper->getElfObject()->getFileName();
-
- // Dumper reports all non-critical errors as warnings.
- // It does not print the same warning more than once.
- WarningHandler = [this](const Twine &Msg) {
- if (Warnings.insert(Msg.str()).second)
- reportWarning(createError(Msg), FileName);
- return Error::success();
- };
}
virtual ~DumpStyle() = default;
@@ -712,8 +755,9 @@ public:
virtual void printSymtabMessage(const ELFFile<ELFT> *Obj, StringRef Name,
size_t Offset, bool NonVisibilityBitsUsed) {}
virtual void printSymbol(const ELFFile<ELFT> *Obj, const Elf_Sym *Symbol,
- const Elf_Sym *FirstSym, StringRef StrTable,
- bool IsDynamic, bool NonVisibilityBitsUsed) = 0;
+ const Elf_Sym *FirstSym,
+ Optional<StringRef> StrTable, bool IsDynamic,
+ bool NonVisibilityBitsUsed) = 0;
virtual void printProgramHeaders(const ELFFile<ELFT> *Obj,
bool PrintProgramHeaders,
cl::boolOrDefault PrintSectionMapping) = 0;
@@ -723,7 +767,7 @@ public:
const Elf_Shdr *Sec) = 0;
virtual void printVersionDependencySection(const ELFFile<ELFT> *Obj,
const Elf_Shdr *Sec) = 0;
- virtual void printHashHistogram(const ELFFile<ELFT> *Obj) = 0;
+ virtual void printHashHistograms(const ELFFile<ELFT> *Obj) = 0;
virtual void printCGProfile(const ELFFile<ELFT> *Obj) = 0;
virtual void printAddrsig(const ELFFile<ELFT> *Obj) = 0;
virtual void printNotes(const ELFFile<ELFT> *Obj) = 0;
@@ -734,7 +778,7 @@ public:
void printRelocatableStackSizes(const ELFObjectFile<ELFT> *Obj,
std::function<void()> PrintHeader);
void printFunctionStackSize(const ELFObjectFile<ELFT> *Obj, uint64_t SymValue,
- SectionRef FunctionSec,
+ Optional<SectionRef> FunctionSec,
const StringRef SectionName, DataExtractor Data,
uint64_t *Offset);
void printStackSize(const ELFObjectFile<ELFT> *Obj, RelocationRef Rel,
@@ -747,14 +791,16 @@ public:
virtual void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) = 0;
const ELFDumper<ELFT> *dumper() const { return Dumper; }
- void reportUniqueWarning(Error Err) const;
-
protected:
- std::function<Error(const Twine &Msg)> WarningHandler;
+ void printDependentLibsHelper(
+ const ELFFile<ELFT> *Obj,
+ function_ref<void(const Elf_Shdr &)> OnSectionStart,
+ function_ref<void(StringRef, uint64_t)> OnSectionEntry);
+
+ void reportUniqueWarning(Error Err) const;
StringRef FileName;
private:
- std::unordered_set<std::string> Warnings;
const ELFDumper<ELFT> *Dumper;
};
@@ -790,7 +836,7 @@ public:
const Elf_Shdr *Sec) override;
void printVersionDependencySection(const ELFFile<ELFT> *Obj,
const Elf_Shdr *Sec) override;
- void printHashHistogram(const ELFFile<ELFT> *Obj) override;
+ void printHashHistograms(const ELFFile<ELFT> *Obj) override;
void printCGProfile(const ELFFile<ELFT> *Obj) override;
void printAddrsig(const ELFFile<ELFT> *Obj) override;
void printNotes(const ELFFile<ELFT> *Obj) override;
@@ -802,11 +848,18 @@ public:
void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) override;
private:
+ void printHashHistogram(const Elf_Hash &HashTable);
+ void printGnuHashHistogram(const Elf_GnuHash &GnuHashTable);
+
+ void printHashTableSymbols(const ELFO *Obj, const Elf_Hash &HashTable);
+ void printGnuHashTableSymbols(const ELFO *Obj,
+ const Elf_GnuHash &GnuHashTable);
+
struct Field {
std::string Str;
unsigned Column;
- Field(StringRef S, unsigned Col) : Str(S), Column(Col) {}
+ Field(StringRef S, unsigned Col) : Str(std::string(S)), Column(Col) {}
Field(unsigned Col) : Column(Col) {}
};
@@ -814,7 +867,7 @@ private:
std::string printEnum(T Value, ArrayRef<EnumEntry<TEnum>> EnumValues) {
for (const auto &EnumItem : EnumValues)
if (EnumItem.Value == Value)
- return EnumItem.AltName;
+ return std::string(EnumItem.AltName);
return to_hexString(Value, false);
}
@@ -855,20 +908,17 @@ private:
void printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym, uint32_t Sym,
StringRef StrTable, uint32_t Bucket);
void printRelocHeader(unsigned SType);
- void printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab,
- const Elf_Rela &R, bool IsRela);
+ void printRelocation(const ELFO *Obj, unsigned SecIndex,
+ const Elf_Shdr *SymTab, const Elf_Rela &R,
+ unsigned RelIndex, bool IsRela);
void printRelocation(const ELFO *Obj, const Elf_Sym *Sym,
StringRef SymbolName, const Elf_Rela &R, bool IsRela);
void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
- StringRef StrTable, bool IsDynamic,
+ Optional<StringRef> StrTable, bool IsDynamic,
bool NonVisibilityBitsUsed) override;
std::string getSymbolSectionNdx(const ELFO *Obj, const Elf_Sym *Symbol,
const Elf_Sym *FirstSym);
void printDynamicRelocation(const ELFO *Obj, Elf_Rela R, bool IsRela);
- bool checkTLSSections(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
- bool checkoffsets(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
- bool checkVMA(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
- bool checkPTDynamic(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
void printProgramHeaders(const ELFO *Obj);
void printSectionMapping(const ELFO *Obj);
void printGNUVersionSectionProlog(const ELFFile<ELFT> *Obj,
@@ -877,13 +927,18 @@ private:
};
template <class ELFT>
-void DumpStyle<ELFT>::reportUniqueWarning(Error Err) const {
+void ELFDumper<ELFT>::reportUniqueWarning(Error Err) const {
handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
cantFail(WarningHandler(EI.message()),
"WarningHandler should always return ErrorSuccess");
});
}
+template <class ELFT>
+void DumpStyle<ELFT>::reportUniqueWarning(Error Err) const {
+ this->dumper()->reportUniqueWarning(std::move(Err));
+}
+
template <typename ELFT> class LLVMStyle : public DumpStyle<ELFT> {
public:
TYPEDEF_ELF_TYPES(ELFT)
@@ -909,7 +964,7 @@ public:
const Elf_Shdr *Sec) override;
void printVersionDependencySection(const ELFFile<ELFT> *Obj,
const Elf_Shdr *Sec) override;
- void printHashHistogram(const ELFFile<ELFT> *Obj) override;
+ void printHashHistograms(const ELFFile<ELFT> *Obj) override;
void printCGProfile(const ELFFile<ELFT> *Obj) override;
void printAddrsig(const ELFFile<ELFT> *Obj) override;
void printNotes(const ELFFile<ELFT> *Obj) override;
@@ -921,13 +976,14 @@ public:
void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) override;
private:
- void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab);
+ void printRelocation(const ELFO *Obj, unsigned SecIndex, Elf_Rela Rel,
+ unsigned RelIndex, const Elf_Shdr *SymTab);
void printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel);
void printSymbols(const ELFO *Obj);
void printDynamicSymbols(const ELFO *Obj);
void printSymbolSection(const Elf_Sym *Symbol, const Elf_Sym *First);
void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
- StringRef StrTable, bool IsDynamic,
+ Optional<StringRef> StrTable, bool IsDynamic,
bool /*NonVisibilityBitsUsed*/) override;
void printProgramHeaders(const ELFO *Obj);
void printSectionMapping(const ELFO *Obj) {}
@@ -973,7 +1029,7 @@ std::error_code createELFDumper(const object::ObjectFile *Obj,
template <class ELFT> Error ELFDumper<ELFT>::LoadVersionMap() const {
// If there is no dynamic symtab or version table, there is nothing to do.
- if (!DynSymRegion.Addr || !SymbolVersionSection)
+ if (!DynSymRegion || !SymbolVersionSection)
return Error::success();
// Has the VersionMap already been loaded?
@@ -988,7 +1044,7 @@ template <class ELFT> Error ELFDumper<ELFT>::LoadVersionMap() const {
auto InsertEntry = [this](unsigned N, StringRef Version, bool IsVerdef) {
if (N >= VersionMap.size())
VersionMap.resize(N + 1);
- VersionMap[N] = {Version, IsVerdef};
+ VersionMap[N] = {std::string(Version), IsVerdef};
};
if (SymbolVersionDefSection) {
@@ -1023,38 +1079,85 @@ Expected<StringRef> ELFDumper<ELFT>::getSymbolVersion(const Elf_Sym *Sym,
return "";
}
+ assert(DynSymRegion && "DynSymRegion has not been initialised");
// Determine the position in the symbol table of this entry.
size_t EntryIndex = (reinterpret_cast<uintptr_t>(Sym) -
- reinterpret_cast<uintptr_t>(DynSymRegion.Addr)) /
- sizeof(Elf_Sym);
+ reinterpret_cast<uintptr_t>(DynSymRegion->Addr)) /
+ sizeof(Elf_Sym);
// Get the corresponding version index entry.
- const Elf_Versym *Versym = unwrapOrError(
- ObjF->getFileName(), ObjF->getELFFile()->template getEntry<Elf_Versym>(
- SymbolVersionSection, EntryIndex));
- return this->getSymbolVersionByIndex(Versym->vs_index, IsDefault);
+ if (Expected<const Elf_Versym *> EntryOrErr =
+ ObjF->getELFFile()->template getEntry<Elf_Versym>(
+ SymbolVersionSection, EntryIndex))
+ return this->getSymbolVersionByIndex((*EntryOrErr)->vs_index, IsDefault);
+ else
+ return EntryOrErr.takeError();
+}
+
+template <typename ELFT>
+Expected<std::pair<const typename ELFT::Sym *, std::string>>
+ELFDumper<ELFT>::getRelocationTarget(const Elf_Shdr *SymTab,
+ const Elf_Rela &R) const {
+ const ELFFile<ELFT> *Obj = ObjF->getELFFile();
+ Expected<const Elf_Sym *> SymOrErr = Obj->getRelocationSymbol(&R, SymTab);
+ if (!SymOrErr)
+ return SymOrErr.takeError();
+ const Elf_Sym *Sym = *SymOrErr;
+ if (!Sym)
+ return std::make_pair(nullptr, "");
+
+ // The st_name field of a STT_SECTION is usually 0 (empty string).
+ // This code block returns the section name.
+ if (Sym->getType() == ELF::STT_SECTION) {
+ Expected<const Elf_Shdr *> SecOrErr =
+ Obj->getSection(Sym, SymTab, ShndxTable);
+ if (!SecOrErr)
+ return SecOrErr.takeError();
+ // A section symbol describes the section at index 0.
+ if (*SecOrErr == nullptr)
+ return std::make_pair(Sym, "");
+
+ Expected<StringRef> NameOrErr = Obj->getSectionName(*SecOrErr);
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ return std::make_pair(Sym, NameOrErr->str());
+ }
+
+ Expected<StringRef> StrTableOrErr = Obj->getStringTableForSymtab(*SymTab);
+ if (!StrTableOrErr)
+ return StrTableOrErr.takeError();
+
+ std::string SymbolName =
+ getFullSymbolName(Sym, *StrTableOrErr, SymTab->sh_type == SHT_DYNSYM);
+ return std::make_pair(Sym, SymbolName);
}
static std::string maybeDemangle(StringRef Name) {
- return opts::Demangle ? demangle(Name) : Name.str();
+ return opts::Demangle ? demangle(std::string(Name)) : Name.str();
}
template <typename ELFT>
-Expected<std::string>
-ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {
+std::string ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {
+ auto Warn = [&](Error E) -> std::string {
+ this->reportUniqueWarning(
+ createError("unable to read the name of symbol with index " +
+ Twine(Index) + ": " + toString(std::move(E))));
+ return "<?>";
+ };
+
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
Expected<const typename ELFT::Sym *> SymOrErr =
Obj->getSymbol(DotSymtabSec, Index);
if (!SymOrErr)
- return SymOrErr.takeError();
+ return Warn(SymOrErr.takeError());
Expected<StringRef> StrTabOrErr = Obj->getStringTableForSymtab(*DotSymtabSec);
if (!StrTabOrErr)
- return StrTabOrErr.takeError();
+ return Warn(StrTabOrErr.takeError());
Expected<StringRef> NameOrErr = (*SymOrErr)->getName(*StrTabOrErr);
if (!NameOrErr)
- return NameOrErr.takeError();
+ return Warn(NameOrErr.takeError());
return maybeDemangle(*NameOrErr);
}
@@ -1087,10 +1190,18 @@ ELFDumper<ELFT>::getSymbolVersionByIndex(uint32_t SymbolVersionIndex,
template <typename ELFT>
std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol,
- StringRef StrTable,
+ Optional<StringRef> StrTable,
bool IsDynamic) const {
- std::string SymbolName = maybeDemangle(
- unwrapOrError(ObjF->getFileName(), Symbol->getName(StrTable)));
+ if (!StrTable)
+ return "<?>";
+
+ std::string SymbolName;
+ if (Expected<StringRef> NameOrErr = Symbol->getName(*StrTable)) {
+ SymbolName = maybeDemangle(*NameOrErr);
+ } else {
+ reportUniqueWarning(NameOrErr.takeError());
+ return "<?>";
+ }
if (SymbolName.empty() && Symbol->getType() == ELF::STT_SECTION) {
Elf_Sym_Range Syms = unwrapOrError(
@@ -1098,15 +1209,15 @@ std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol,
Expected<unsigned> SectionIndex =
getSymbolSectionIndex(Symbol, Syms.begin());
if (!SectionIndex) {
- ELFDumperStyle->reportUniqueWarning(SectionIndex.takeError());
+ reportUniqueWarning(SectionIndex.takeError());
return "<?>";
}
Expected<StringRef> NameOrErr = getSymbolSectionName(Symbol, *SectionIndex);
if (!NameOrErr) {
- ELFDumperStyle->reportUniqueWarning(NameOrErr.takeError());
+ reportUniqueWarning(NameOrErr.takeError());
return ("<section " + Twine(*SectionIndex) + ">").str();
}
- return *NameOrErr;
+ return std::string(*NameOrErr);
}
if (!IsDynamic)
@@ -1115,7 +1226,7 @@ std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol,
bool IsDefault;
Expected<StringRef> VersionOrErr = getSymbolVersion(&*Symbol, IsDefault);
if (!VersionOrErr) {
- ELFDumperStyle->reportUniqueWarning(VersionOrErr.takeError());
+ reportUniqueWarning(VersionOrErr.takeError());
return SymbolName + "@<corrupt>";
}
@@ -1170,7 +1281,7 @@ template <class ELFO>
static const typename ELFO::Elf_Shdr *
findNotEmptySectionByAddress(const ELFO *Obj, StringRef FileName,
uint64_t Addr) {
- for (const auto &Shdr : unwrapOrError(FileName, Obj->sections()))
+ for (const typename ELFO::Elf_Shdr &Shdr : cantFail(Obj->sections()))
if (Shdr.sh_addr == Addr && Shdr.sh_size > 0)
return &Shdr;
return nullptr;
@@ -1179,7 +1290,7 @@ findNotEmptySectionByAddress(const ELFO *Obj, StringRef FileName,
template <class ELFO>
static const typename ELFO::Elf_Shdr *
findSectionByName(const ELFO &Obj, StringRef FileName, StringRef Name) {
- for (const auto &Shdr : unwrapOrError(FileName, Obj.sections()))
+ for (const typename ELFO::Elf_Shdr &Shdr : cantFail(Obj.sections()))
if (Name == unwrapOrError(FileName, Obj.getSectionName(&Shdr)))
return &Shdr;
return nullptr;
@@ -1372,6 +1483,8 @@ static const EnumEntry<unsigned> ElfMachineType[] = {
ENUM_ENT(EM_STXP7X, "STMicroelectronics STxP7x family"),
ENUM_ENT(EM_NDS32, "Andes Technology compact code size embedded RISC processor family"),
ENUM_ENT(EM_ECOG1, "Cyan Technology eCOG1 microprocessor"),
+ // FIXME: Following EM_ECOG1X definitions is dead code since EM_ECOG1X has
+ // an identical number to EM_ECOG1.
ENUM_ENT(EM_ECOG1X, "Cyan Technology eCOG1X family"),
ENUM_ENT(EM_MAXQ30, "Dallas Semiconductor MAXQ30 Core microcontrollers"),
ENUM_ENT(EM_XIMO16, "New Japan Radio (NJR) 16-bit DSP Processor"),
@@ -1406,6 +1519,7 @@ static const EnumEntry<unsigned> ElfMachineType[] = {
ENUM_ENT(EM_RISCV, "RISC-V"),
ENUM_ENT(EM_LANAI, "EM_LANAI"),
ENUM_ENT(EM_BPF, "EM_BPF"),
+ ENUM_ENT(EM_VE, "NEC SX-Aurora Vector Engine"),
};
static const EnumEntry<unsigned> ElfSymbolBindings[] = {
@@ -1731,6 +1845,7 @@ static const EnumEntry<unsigned> ElfHeaderAMDGPUFlags[] = {
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1010),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1011),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1012),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1030),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_XNACK),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_SRAM_ECC)
};
@@ -1786,18 +1901,22 @@ std::pair<const typename ELFT::Phdr *, const typename ELFT::Shdr *>
ELFDumper<ELFT>::findDynamic(const ELFFile<ELFT> *Obj) {
// Try to locate the PT_DYNAMIC header.
const Elf_Phdr *DynamicPhdr = nullptr;
- for (const Elf_Phdr &Phdr :
- unwrapOrError(ObjF->getFileName(), Obj->program_headers())) {
- if (Phdr.p_type != ELF::PT_DYNAMIC)
- continue;
- DynamicPhdr = &Phdr;
- break;
+ if (Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers()) {
+ for (const Elf_Phdr &Phdr : *PhdrsOrErr) {
+ if (Phdr.p_type != ELF::PT_DYNAMIC)
+ continue;
+ DynamicPhdr = &Phdr;
+ break;
+ }
+ } else {
+ this->reportUniqueWarning(createError(
+ "unable to read program headers to locate the PT_DYNAMIC segment: " +
+ toString(PhdrsOrErr.takeError())));
}
// Try to locate the .dynamic section in the sections header table.
const Elf_Shdr *DynamicSec = nullptr;
- for (const Elf_Shdr &Sec :
- unwrapOrError(ObjF->getFileName(), Obj->sections())) {
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
if (Sec.sh_type != ELF::SHT_DYNAMIC)
continue;
DynamicSec = &Sec;
@@ -1847,6 +1966,9 @@ void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) {
bool IsPhdrTableValid = false;
if (DynamicPhdr) {
FromPhdr = createDRIFrom(DynamicPhdr, sizeof(Elf_Dyn));
+ FromPhdr.SizePrintName = "PT_DYNAMIC size";
+ FromPhdr.EntSizePrintName = "";
+
IsPhdrTableValid = !FromPhdr.getAsArrayRef<Elf_Dyn>().empty();
}
@@ -1860,6 +1982,11 @@ void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) {
FromSec =
checkDRI({ObjF->getELFFile()->base() + DynamicSec->sh_offset,
DynamicSec->sh_size, sizeof(Elf_Dyn), ObjF->getFileName()});
+ FromSec.Context = ("section with index " +
+ Twine(DynamicSec - &cantFail(Obj->sections()).front()))
+ .str();
+ FromSec.EntSizePrintName = "";
+
IsSecTableValid = !FromSec.getAsArrayRef<Elf_Dyn>().empty();
}
@@ -1917,19 +2044,33 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,
ScopedPrinter &Writer)
: ObjDumper(Writer), ObjF(ObjF), DynRelRegion(ObjF->getFileName()),
DynRelaRegion(ObjF->getFileName()), DynRelrRegion(ObjF->getFileName()),
- DynPLTRelRegion(ObjF->getFileName()), DynSymRegion(ObjF->getFileName()),
- DynamicTable(ObjF->getFileName()) {
+ DynPLTRelRegion(ObjF->getFileName()), DynamicTable(ObjF->getFileName()) {
+ // Dumper reports all non-critical errors as warnings.
+ // It does not print the same warning more than once.
+ WarningHandler = [this](const Twine &Msg) {
+ if (Warnings.insert(Msg.str()).second)
+ reportWarning(createError(Msg), this->ObjF->getFileName());
+ return Error::success();
+ };
+
+ if (opts::Output == opts::GNU)
+ ELFDumperStyle.reset(new GNUStyle<ELFT>(Writer, this));
+ else
+ ELFDumperStyle.reset(new LLVMStyle<ELFT>(Writer, this));
+
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
- for (const Elf_Shdr &Sec :
- unwrapOrError(ObjF->getFileName(), Obj->sections())) {
+ typename ELFT::ShdrRange Sections = cantFail(Obj->sections());
+ for (const Elf_Shdr &Sec : Sections) {
switch (Sec.sh_type) {
case ELF::SHT_SYMTAB:
if (!DotSymtabSec)
DotSymtabSec = &Sec;
break;
case ELF::SHT_DYNSYM:
- if (!DynSymRegion.Size) {
+ if (!DynSymRegion) {
DynSymRegion = createDRIFrom(&Sec);
+ DynSymRegion->Context =
+ ("section with index " + Twine(&Sec - &Sections.front())).str();
// This is only used (if Elf_Shdr present)for naming section in GNU
// style
DynSymtabName =
@@ -1968,11 +2109,6 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,
}
loadDynamicTable(Obj);
-
- if (opts::Output == opts::GNU)
- ELFDumperStyle.reset(new GNUStyle<ELFT>(Writer, this));
- else
- ELFDumperStyle.reset(new LLVMStyle<ELFT>(Writer, this));
}
template <typename ELFT>
@@ -1993,6 +2129,7 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) {
uint64_t SONameOffset = 0;
const char *StringTableBegin = nullptr;
uint64_t StringTableSize = 0;
+ Optional<DynRegionInfo> DynSymFromTable;
for (const Elf_Dyn &Dyn : dynamic_table()) {
switch (Dyn.d_tag) {
case ELF::DT_HASH:
@@ -2011,36 +2148,36 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) {
StringTableSize = Dyn.getVal();
break;
case ELF::DT_SYMTAB: {
- // Often we find the information about the dynamic symbol table
- // location in the SHT_DYNSYM section header. However, the value in
- // DT_SYMTAB has priority, because it is used by dynamic loaders to
- // locate .dynsym at runtime. The location we find in the section header
- // and the location we find here should match. If we can't map the
- // DT_SYMTAB value to an address (e.g. when there are no program headers), we
- // ignore its value.
+ // If we can't map the DT_SYMTAB value to an address (e.g. when there are
+ // no program headers), we ignore its value.
if (const uint8_t *VA = toMappedAddr(Dyn.getTag(), Dyn.getPtr())) {
- // EntSize is non-zero if the dynamic symbol table has been found via a
- // section header.
- if (DynSymRegion.EntSize && VA != DynSymRegion.Addr)
- reportWarning(
- createError(
- "SHT_DYNSYM section header and DT_SYMTAB disagree about "
- "the location of the dynamic symbol table"),
- ObjF->getFileName());
-
- DynSymRegion.Addr = VA;
- DynSymRegion.EntSize = sizeof(Elf_Sym);
+ DynSymFromTable.emplace(ObjF->getFileName());
+ DynSymFromTable->Addr = VA;
+ DynSymFromTable->EntSize = sizeof(Elf_Sym);
+ DynSymFromTable->EntSizePrintName = "";
}
break;
}
+ case ELF::DT_SYMENT: {
+ uint64_t Val = Dyn.getVal();
+ if (Val != sizeof(Elf_Sym))
+ reportWarning(createError("DT_SYMENT value of 0x" +
+ Twine::utohexstr(Val) +
+ " is not the size of a symbol (0x" +
+ Twine::utohexstr(sizeof(Elf_Sym)) + ")"),
+ ObjF->getFileName());
+ break;
+ }
case ELF::DT_RELA:
DynRelaRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
break;
case ELF::DT_RELASZ:
DynRelaRegion.Size = Dyn.getVal();
+ DynRelaRegion.SizePrintName = "DT_RELASZ value";
break;
case ELF::DT_RELAENT:
DynRelaRegion.EntSize = Dyn.getVal();
+ DynRelaRegion.EntSizePrintName = "DT_RELAENT value";
break;
case ELF::DT_SONAME:
SONameOffset = Dyn.getVal();
@@ -2050,9 +2187,11 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) {
break;
case ELF::DT_RELSZ:
DynRelRegion.Size = Dyn.getVal();
+ DynRelRegion.SizePrintName = "DT_RELSZ value";
break;
case ELF::DT_RELENT:
DynRelRegion.EntSize = Dyn.getVal();
+ DynRelRegion.EntSizePrintName = "DT_RELENT value";
break;
case ELF::DT_RELR:
case ELF::DT_ANDROID_RELR:
@@ -2061,10 +2200,16 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) {
case ELF::DT_RELRSZ:
case ELF::DT_ANDROID_RELRSZ:
DynRelrRegion.Size = Dyn.getVal();
+ DynRelrRegion.SizePrintName = Dyn.d_tag == ELF::DT_RELRSZ
+ ? "DT_RELRSZ value"
+ : "DT_ANDROID_RELRSZ value";
break;
case ELF::DT_RELRENT:
case ELF::DT_ANDROID_RELRENT:
DynRelrRegion.EntSize = Dyn.getVal();
+ DynRelrRegion.EntSizePrintName = Dyn.d_tag == ELF::DT_RELRENT
+ ? "DT_RELRENT value"
+ : "DT_ANDROID_RELRENT value";
break;
case ELF::DT_PLTREL:
if (Dyn.getVal() == DT_REL)
@@ -2075,18 +2220,78 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) {
reportError(createError(Twine("unknown DT_PLTREL value of ") +
Twine((uint64_t)Dyn.getVal())),
ObjF->getFileName());
+ DynPLTRelRegion.EntSizePrintName = "";
break;
case ELF::DT_JMPREL:
DynPLTRelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
break;
case ELF::DT_PLTRELSZ:
DynPLTRelRegion.Size = Dyn.getVal();
+ DynPLTRelRegion.SizePrintName = "DT_PLTRELSZ value";
break;
}
}
- if (StringTableBegin)
- DynamicStringTable = StringRef(StringTableBegin, StringTableSize);
+
+ if (StringTableBegin) {
+ const uint64_t FileSize = ObjF->getELFFile()->getBufSize();
+ const uint64_t Offset =
+ (const uint8_t *)StringTableBegin - ObjF->getELFFile()->base();
+ if (StringTableSize > FileSize - Offset)
+ reportUniqueWarning(createError(
+ "the dynamic string table at 0x" + Twine::utohexstr(Offset) +
+ " goes past the end of the file (0x" + Twine::utohexstr(FileSize) +
+ ") with DT_STRSZ = 0x" + Twine::utohexstr(StringTableSize)));
+ else
+ DynamicStringTable = StringRef(StringTableBegin, StringTableSize);
+ }
+
SOName = getDynamicString(SONameOffset);
+
+ if (DynSymRegion) {
+ // Often we find the information about the dynamic symbol table
+ // location in the SHT_DYNSYM section header. However, the value in
+ // DT_SYMTAB has priority, because it is used by dynamic loaders to
+ // locate .dynsym at runtime. The location we find in the section header
+ // and the location we find here should match.
+ if (DynSymFromTable && DynSymFromTable->Addr != DynSymRegion->Addr)
+ reportUniqueWarning(
+ createError("SHT_DYNSYM section header and DT_SYMTAB disagree about "
+ "the location of the dynamic symbol table"));
+
+ // According to the ELF gABI: "The number of symbol table entries should
+ // equal nchain". Check to see if the DT_HASH hash table nchain value
+ // conflicts with the number of symbols in the dynamic symbol table
+ // according to the section header.
+ if (HashTable) {
+ if (DynSymRegion->EntSize == 0)
+ reportUniqueWarning(
+ createError("SHT_DYNSYM section has sh_entsize == 0"));
+ else if (HashTable->nchain != DynSymRegion->Size / DynSymRegion->EntSize)
+ reportUniqueWarning(createError(
+ "hash table nchain (" + Twine(HashTable->nchain) +
+ ") differs from symbol count derived from SHT_DYNSYM section "
+ "header (" +
+ Twine(DynSymRegion->Size / DynSymRegion->EntSize) + ")"));
+ }
+ }
+
+ // Delay the creation of the actual dynamic symbol table until now, so that
+ // checks can always be made against the section header-based properties,
+ // without worrying about tag order.
+ if (DynSymFromTable) {
+ if (!DynSymRegion) {
+ DynSymRegion = DynSymFromTable;
+ } else {
+ DynSymRegion->Addr = DynSymFromTable->Addr;
+ DynSymRegion->EntSize = DynSymFromTable->EntSize;
+ DynSymRegion->EntSizePrintName = DynSymFromTable->EntSizePrintName;
+ }
+ }
+
+ // Derive the dynamic symbol table size from the DT_HASH hash table, if
+ // present.
+ if (HashTable && DynSymRegion)
+ DynSymRegion->Size = HashTable->nchain * DynSymRegion->EntSize;
}
template <typename ELFT>
@@ -2156,8 +2361,8 @@ template <class ELFT> void ELFDumper<ELFT>::printHashSymbols() {
ELFDumperStyle->printHashSymbols(ObjF->getELFFile());
}
-template <class ELFT> void ELFDumper<ELFT>::printHashHistogram() {
- ELFDumperStyle->printHashHistogram(ObjF->getELFFile());
+template <class ELFT> void ELFDumper<ELFT>::printHashHistograms() {
+ ELFDumperStyle->printHashHistograms(ObjF->getELFFile());
}
template <class ELFT> void ELFDumper<ELFT>::printCGProfile() {
@@ -2213,7 +2418,8 @@ static const EnumEntry<unsigned> ElfDynamicDTFlags1[] = {
LLVM_READOBJ_DT_FLAG_ENT(DF_1, NORELOC),
LLVM_READOBJ_DT_FLAG_ENT(DF_1, SYMINTPOSE),
LLVM_READOBJ_DT_FLAG_ENT(DF_1, GLOBAUDIT),
- LLVM_READOBJ_DT_FLAG_ENT(DF_1, SINGLETON)
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, SINGLETON),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, PIE),
};
static const EnumEntry<unsigned> ElfDynamicDTMipsFlags[] = {
@@ -2257,10 +2463,24 @@ void printFlags(T Value, ArrayRef<EnumEntry<TFlag>> Flags, raw_ostream &OS) {
}
template <class ELFT>
-void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
- uint64_t Value) const {
- const char *ConvChar =
- (opts::Output == opts::GNU) ? "0x%" PRIx64 : "0x%" PRIX64;
+std::string ELFDumper<ELFT>::getDynamicEntry(uint64_t Type,
+ uint64_t Value) const {
+ auto FormatHexValue = [](uint64_t V) {
+ std::string Str;
+ raw_string_ostream OS(Str);
+ const char *ConvChar =
+ (opts::Output == opts::GNU) ? "0x%" PRIx64 : "0x%" PRIX64;
+ OS << format(ConvChar, V);
+ return OS.str();
+ };
+
+ auto FormatFlags = [](uint64_t V,
+ llvm::ArrayRef<llvm::EnumEntry<unsigned int>> Array) {
+ std::string Str;
+ raw_string_ostream OS(Str);
+ printFlags(V, Array, OS);
+ return OS.str();
+ };
// Handle custom printing of architecture specific tags
switch (ObjF->getELFFile()->getHeader()->e_machine) {
@@ -2268,8 +2488,7 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
switch (Type) {
case DT_AARCH64_BTI_PLT:
case DT_AARCH64_PAC_PLT:
- OS << Value;
- return;
+ return std::to_string(Value);
default:
break;
}
@@ -2277,12 +2496,10 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
case EM_HEXAGON:
switch (Type) {
case DT_HEXAGON_VER:
- OS << Value;
- return;
+ return std::to_string(Value);
case DT_HEXAGON_SYMSZ:
case DT_HEXAGON_PLT:
- OS << format(ConvChar, Value);
- return;
+ return FormatHexValue(Value);
default:
break;
}
@@ -2293,8 +2510,7 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
case DT_MIPS_LOCAL_GOTNO:
case DT_MIPS_SYMTABNO:
case DT_MIPS_UNREFEXTNO:
- OS << Value;
- return;
+ return std::to_string(Value);
case DT_MIPS_TIME_STAMP:
case DT_MIPS_ICHECKSUM:
case DT_MIPS_IVERSION:
@@ -2335,11 +2551,9 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
case DT_MIPS_PLTGOT:
case DT_MIPS_RWPLT:
case DT_MIPS_RLD_MAP_REL:
- OS << format(ConvChar, Value);
- return;
+ return FormatHexValue(Value);
case DT_MIPS_FLAGS:
- printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS);
- return;
+ return FormatFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags));
default:
break;
}
@@ -2350,13 +2564,10 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
switch (Type) {
case DT_PLTREL:
- if (Value == DT_REL) {
- OS << "REL";
- break;
- } else if (Value == DT_RELA) {
- OS << "RELA";
- break;
- }
+ if (Value == DT_REL)
+ return "REL";
+ if (Value == DT_RELA)
+ return "RELA";
LLVM_FALLTHROUGH;
case DT_PLTGOT:
case DT_HASH:
@@ -2376,14 +2587,12 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
case DT_VERSYM:
case DT_GNU_HASH:
case DT_NULL:
- OS << format(ConvChar, Value);
- break;
+ return FormatHexValue(Value);
case DT_RELACOUNT:
case DT_RELCOUNT:
case DT_VERDEFNUM:
case DT_VERNEEDNUM:
- OS << Value;
- break;
+ return std::to_string(Value);
case DT_PLTRELSZ:
case DT_RELASZ:
case DT_RELAENT:
@@ -2396,8 +2605,7 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
case DT_PREINIT_ARRAYSZ:
case DT_ANDROID_RELSZ:
case DT_ANDROID_RELASZ:
- OS << Value << " (bytes)";
- break;
+ return std::to_string(Value) + " (bytes)";
case DT_NEEDED:
case DT_SONAME:
case DT_AUXILIARY:
@@ -2405,37 +2613,62 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
case DT_FILTER:
case DT_RPATH:
case DT_RUNPATH: {
- const std::map<uint64_t, const char*> TagNames = {
- {DT_NEEDED, "Shared library"},
- {DT_SONAME, "Library soname"},
- {DT_AUXILIARY, "Auxiliary library"},
- {DT_USED, "Not needed object"},
- {DT_FILTER, "Filter library"},
- {DT_RPATH, "Library rpath"},
- {DT_RUNPATH, "Library runpath"},
+ const std::map<uint64_t, const char *> TagNames = {
+ {DT_NEEDED, "Shared library"}, {DT_SONAME, "Library soname"},
+ {DT_AUXILIARY, "Auxiliary library"}, {DT_USED, "Not needed object"},
+ {DT_FILTER, "Filter library"}, {DT_RPATH, "Library rpath"},
+ {DT_RUNPATH, "Library runpath"},
};
- OS << TagNames.at(Type) << ": [" << getDynamicString(Value) << "]";
- break;
+
+ return (Twine(TagNames.at(Type)) + ": [" + getDynamicString(Value) + "]")
+ .str();
}
case DT_FLAGS:
- printFlags(Value, makeArrayRef(ElfDynamicDTFlags), OS);
- break;
+ return FormatFlags(Value, makeArrayRef(ElfDynamicDTFlags));
case DT_FLAGS_1:
- printFlags(Value, makeArrayRef(ElfDynamicDTFlags1), OS);
- break;
+ return FormatFlags(Value, makeArrayRef(ElfDynamicDTFlags1));
default:
- OS << format(ConvChar, Value);
- break;
+ return FormatHexValue(Value);
}
}
template <class ELFT>
-std::string ELFDumper<ELFT>::getDynamicString(uint64_t Value) const {
- if (DynamicStringTable.empty())
- return "<String table is empty or was not found>";
- if (Value < DynamicStringTable.size())
- return DynamicStringTable.data() + Value;
- return Twine("<Invalid offset 0x" + utohexstr(Value) + ">").str();
+StringRef ELFDumper<ELFT>::getDynamicString(uint64_t Value) const {
+ if (DynamicStringTable.empty() && !DynamicStringTable.data()) {
+ reportUniqueWarning(createError("string table was not found"));
+ return "<?>";
+ }
+
+ auto WarnAndReturn = [this](const Twine &Msg, uint64_t Offset) {
+ reportUniqueWarning(createError("string table at offset 0x" +
+ Twine::utohexstr(Offset) + Msg));
+ return "<?>";
+ };
+
+ const uint64_t FileSize = ObjF->getELFFile()->getBufSize();
+ const uint64_t Offset =
+ (const uint8_t *)DynamicStringTable.data() - ObjF->getELFFile()->base();
+ if (DynamicStringTable.size() > FileSize - Offset)
+ return WarnAndReturn(" with size 0x" +
+ Twine::utohexstr(DynamicStringTable.size()) +
+ " goes past the end of the file (0x" +
+ Twine::utohexstr(FileSize) + ")",
+ Offset);
+
+ if (Value >= DynamicStringTable.size())
+ return WarnAndReturn(
+ ": unable to read the string at 0x" + Twine::utohexstr(Offset + Value) +
+ ": it goes past the end of the table (0x" +
+ Twine::utohexstr(Offset + DynamicStringTable.size()) + ")",
+ Offset);
+
+ if (DynamicStringTable.back() != '\0')
+ return WarnAndReturn(": unable to read the string at 0x" +
+ Twine::utohexstr(Offset + Value) +
+ ": the string table is not null-terminated",
+ Offset);
+
+ return DynamicStringTable.data() + Value;
}
template <class ELFT> void ELFDumper<ELFT>::printUnwindInfo() {
@@ -2466,42 +2699,159 @@ template <class ELFT> void ELFDumper<ELFT>::printDynamicTable() {
template <class ELFT> void ELFDumper<ELFT>::printNeededLibraries() {
ListScope D(W, "NeededLibraries");
- std::vector<std::string> Libs;
+ std::vector<StringRef> Libs;
for (const auto &Entry : dynamic_table())
if (Entry.d_tag == ELF::DT_NEEDED)
Libs.push_back(getDynamicString(Entry.d_un.d_val));
- llvm::stable_sort(Libs);
+ llvm::sort(Libs);
- for (const auto &L : Libs)
+ for (StringRef L : Libs)
W.startLine() << L << "\n";
}
+template <class ELFT>
+static Error checkHashTable(const ELFFile<ELFT> *Obj,
+ const typename ELFT::Hash *H,
+ bool *IsHeaderValid = nullptr) {
+ auto MakeError = [&](uint64_t Off, const Twine &Msg = "") {
+ return createError("the hash table at offset 0x" + Twine::utohexstr(Off) +
+ " goes past the end of the file (0x" +
+ Twine::utohexstr(Obj->getBufSize()) + ")" + Msg);
+ };
+
+ // Each SHT_HASH section starts from two 32-bit fields: nbucket and nchain.
+ const unsigned HeaderSize = 2 * sizeof(typename ELFT::Word);
+ const uint64_t SecOffset = (const uint8_t *)H - Obj->base();
+
+ if (IsHeaderValid)
+ *IsHeaderValid = Obj->getBufSize() - SecOffset >= HeaderSize;
+
+ if (Obj->getBufSize() - SecOffset < HeaderSize)
+ return MakeError(SecOffset);
+
+ if (Obj->getBufSize() - SecOffset - HeaderSize <
+ ((uint64_t)H->nbucket + H->nchain) * sizeof(typename ELFT::Word))
+ return MakeError(SecOffset, ", nbucket = " + Twine(H->nbucket) +
+ ", nchain = " + Twine(H->nchain));
+ return Error::success();
+}
+
+template <class ELFT>
+static Error checkGNUHashTable(const ELFFile<ELFT> *Obj,
+ const typename ELFT::GnuHash *GnuHashTable,
+ bool *IsHeaderValid = nullptr) {
+ const uint8_t *TableData = reinterpret_cast<const uint8_t *>(GnuHashTable);
+ assert(TableData >= Obj->base() &&
+ TableData < Obj->base() + Obj->getBufSize() &&
+ "GnuHashTable must always point to a location inside the file");
+
+ uint64_t TableOffset = TableData - Obj->base();
+ if (IsHeaderValid)
+ *IsHeaderValid = TableOffset + /*Header size:*/ 16 < Obj->getBufSize();
+ if (TableOffset + 16 + (uint64_t)GnuHashTable->nbuckets * 4 +
+ (uint64_t)GnuHashTable->maskwords * sizeof(typename ELFT::Off) >=
+ Obj->getBufSize())
+ return createError("unable to dump the SHT_GNU_HASH "
+ "section at 0x" +
+ Twine::utohexstr(TableOffset) +
+ ": it goes past the end of the file");
+ return Error::success();
+}
+
template <typename ELFT> void ELFDumper<ELFT>::printHashTable() {
DictScope D(W, "HashTable");
if (!HashTable)
return;
- W.printNumber("Num Buckets", HashTable->nbucket);
- W.printNumber("Num Chains", HashTable->nchain);
+
+ bool IsHeaderValid;
+ Error Err = checkHashTable(ObjF->getELFFile(), HashTable, &IsHeaderValid);
+ if (IsHeaderValid) {
+ W.printNumber("Num Buckets", HashTable->nbucket);
+ W.printNumber("Num Chains", HashTable->nchain);
+ }
+
+ if (Err) {
+ reportUniqueWarning(std::move(Err));
+ return;
+ }
+
W.printList("Buckets", HashTable->buckets());
W.printList("Chains", HashTable->chains());
}
-template <typename ELFT> void ELFDumper<ELFT>::printGnuHashTable() {
+template <class ELFT>
+static Expected<ArrayRef<typename ELFT::Word>>
+getGnuHashTableChains(Optional<DynRegionInfo> DynSymRegion,
+ const typename ELFT::GnuHash *GnuHashTable) {
+ if (!DynSymRegion)
+ return createError("no dynamic symbol table found");
+
+ ArrayRef<typename ELFT::Sym> DynSymTable =
+ DynSymRegion->getAsArrayRef<typename ELFT::Sym>();
+ size_t NumSyms = DynSymTable.size();
+ if (!NumSyms)
+ return createError("the dynamic symbol table is empty");
+
+ if (GnuHashTable->symndx < NumSyms)
+ return GnuHashTable->values(NumSyms);
+
+ // A normal empty GNU hash table section produced by linker might have
+ // symndx set to the number of dynamic symbols + 1 (for the zero symbol)
+ // and have dummy null values in the Bloom filter and in the buckets
+ // vector (or no values at all). It happens because the value of symndx is not
+ // important for dynamic loaders when the GNU hash table is empty. They just
+ // skip the whole object during symbol lookup. In such cases, the symndx value
+ // is irrelevant and we should not report a warning.
+ ArrayRef<typename ELFT::Word> Buckets = GnuHashTable->buckets();
+ if (!llvm::all_of(Buckets, [](typename ELFT::Word V) { return V == 0; }))
+ return createError("the first hashed symbol index (" +
+ Twine(GnuHashTable->symndx) +
+ ") is larger than the number of dynamic symbols (" +
+ Twine(NumSyms) + ")");
+ // There is no way to represent an array of (dynamic symbols count - symndx)
+ // length.
+ return ArrayRef<typename ELFT::Word>();
+}
+
+template <typename ELFT>
+void ELFDumper<ELFT>::printGnuHashTable(const object::ObjectFile *Obj) {
DictScope D(W, "GnuHashTable");
if (!GnuHashTable)
return;
- W.printNumber("Num Buckets", GnuHashTable->nbuckets);
- W.printNumber("First Hashed Symbol Index", GnuHashTable->symndx);
- W.printNumber("Num Mask Words", GnuHashTable->maskwords);
- W.printNumber("Shift Count", GnuHashTable->shift2);
- W.printHexList("Bloom Filter", GnuHashTable->filter());
- W.printList("Buckets", GnuHashTable->buckets());
- Elf_Sym_Range Syms = dynamic_symbols();
- unsigned NumSyms = std::distance(Syms.begin(), Syms.end());
- if (!NumSyms)
- reportError(createError("No dynamic symbol section"), ObjF->getFileName());
- W.printHexList("Values", GnuHashTable->values(NumSyms));
+
+ bool IsHeaderValid;
+ Error Err =
+ checkGNUHashTable<ELFT>(ObjF->getELFFile(), GnuHashTable, &IsHeaderValid);
+ if (IsHeaderValid) {
+ W.printNumber("Num Buckets", GnuHashTable->nbuckets);
+ W.printNumber("First Hashed Symbol Index", GnuHashTable->symndx);
+ W.printNumber("Num Mask Words", GnuHashTable->maskwords);
+ W.printNumber("Shift Count", GnuHashTable->shift2);
+ }
+
+ if (Err) {
+ reportUniqueWarning(std::move(Err));
+ return;
+ }
+
+ ArrayRef<typename ELFT::Off> BloomFilter = GnuHashTable->filter();
+ W.printHexList("Bloom Filter", BloomFilter);
+
+ ArrayRef<Elf_Word> Buckets = GnuHashTable->buckets();
+ W.printList("Buckets", Buckets);
+
+ Expected<ArrayRef<Elf_Word>> Chains =
+ getGnuHashTableChains<ELFT>(DynSymRegion, GnuHashTable);
+ if (!Chains) {
+ reportUniqueWarning(
+ createError("unable to dump 'Values' for the SHT_GNU_HASH "
+ "section: " +
+ toString(Chains.takeError())));
+ return;
+ }
+
+ W.printHexList("Values", *Chains);
}
template <typename ELFT> void ELFDumper<ELFT>::printLoadName() {
@@ -2512,6 +2862,7 @@ template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() {
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
switch (Obj->getHeader()->e_machine) {
case EM_ARM:
+ case EM_RISCV:
printAttributes();
break;
case EM_MIPS: {
@@ -2521,9 +2872,14 @@ template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() {
MipsGOTParser<ELFT> Parser(Obj, ObjF->getFileName(), dynamic_table(),
dynamic_symbols());
- if (Parser.hasGot())
+ if (Error E = Parser.findGOT(dynamic_table(), dynamic_symbols()))
+ reportError(std::move(E), ObjF->getFileName());
+ else if (!Parser.isGotEmpty())
ELFDumperStyle->printMipsGOT(Parser);
- if (Parser.hasPlt())
+
+ if (Error E = Parser.findPLT(dynamic_table()))
+ reportError(std::move(E), ObjF->getFileName());
+ else if (!Parser.isPltEmpty())
ELFDumperStyle->printMipsPLT(Parser);
break;
}
@@ -2532,38 +2888,45 @@ template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() {
}
}
-template <class ELFT> void ELFDumper<ELFT>::printAttributes() {
- W.startLine() << "Attributes not implemented.\n";
-}
-
namespace {
-template <> void ELFDumper<ELF32LE>::printAttributes() {
- const ELFFile<ELF32LE> *Obj = ObjF->getELFFile();
- if (Obj->getHeader()->e_machine != EM_ARM) {
+template <class ELFT> void ELFDumper<ELFT>::printAttributes() {
+ const ELFFile<ELFT> *Obj = ObjF->getELFFile();
+ if (!Obj->isLE()) {
W.startLine() << "Attributes not implemented.\n";
return;
}
+ const unsigned Machine = Obj->getHeader()->e_machine;
+ assert((Machine == EM_ARM || Machine == EM_RISCV) &&
+ "Attributes not implemented.");
+
DictScope BA(W, "BuildAttributes");
- for (const ELFO::Elf_Shdr &Sec :
- unwrapOrError(ObjF->getFileName(), Obj->sections())) {
- if (Sec.sh_type != ELF::SHT_ARM_ATTRIBUTES)
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
+ if (Sec.sh_type != ELF::SHT_ARM_ATTRIBUTES &&
+ Sec.sh_type != ELF::SHT_RISCV_ATTRIBUTES)
continue;
ArrayRef<uint8_t> Contents =
unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(&Sec));
- if (Contents[0] != ARMBuildAttrs::Format_Version) {
- errs() << "unrecognised FormatVersion: 0x"
- << Twine::utohexstr(Contents[0]) << '\n';
+ if (Contents[0] != ELFAttrs::Format_Version) {
+ reportWarning(createError(Twine("unrecognised FormatVersion: 0x") +
+ Twine::utohexstr(Contents[0])),
+ ObjF->getFileName());
continue;
}
-
W.printHex("FormatVersion", Contents[0]);
if (Contents.size() == 1)
continue;
- ARMAttributeParser(&W).Parse(Contents, true);
+ // TODO: Delete the redundant FormatVersion check above.
+ if (Machine == EM_ARM) {
+ if (Error E = ARMAttributeParser(&W).parse(Contents, support::little))
+ reportWarning(std::move(E), ObjF->getFileName());
+ } else if (Machine == EM_RISCV) {
+ if (Error E = RISCVAttributeParser(&W).parse(Contents, support::little))
+ reportWarning(std::move(E), ObjF->getFileName());
+ }
}
}
@@ -2578,9 +2941,11 @@ public:
MipsGOTParser(const ELFO *Obj, StringRef FileName, Elf_Dyn_Range DynTable,
Elf_Sym_Range DynSyms);
+ Error findGOT(Elf_Dyn_Range DynTable, Elf_Sym_Range DynSyms);
+ Error findPLT(Elf_Dyn_Range DynTable);
- bool hasGot() const { return !GotEntries.empty(); }
- bool hasPlt() const { return !PltEntries.empty(); }
+ bool isGotEmpty() const { return GotEntries.empty(); }
+ bool isPltEmpty() const { return PltEntries.empty(); }
uint64_t getGp() const;
@@ -2628,7 +2993,11 @@ MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, StringRef FileName,
Elf_Sym_Range DynSyms)
: IsStatic(DynTable.empty()), Obj(Obj), GotSec(nullptr), LocalNum(0),
GlobalNum(0), PltSec(nullptr), PltRelSec(nullptr), PltSymTable(nullptr),
- FileName(FileName) {
+ FileName(FileName) {}
+
+template <class ELFT>
+Error MipsGOTParser<ELFT>::findGOT(Elf_Dyn_Range DynTable,
+ Elf_Sym_Range DynSyms) {
// See "Global Offset Table" in Chapter 5 in the following document
// for detailed GOT description.
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
@@ -2637,22 +3006,20 @@ MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, StringRef FileName,
if (IsStatic) {
GotSec = findSectionByName(*Obj, FileName, ".got");
if (!GotSec)
- return;
+ return Error::success();
ArrayRef<uint8_t> Content =
unwrapOrError(FileName, Obj->getSectionContents(GotSec));
GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()),
Content.size() / sizeof(Entry));
LocalNum = GotEntries.size();
- return;
+ return Error::success();
}
- // Lookup dynamic table tags which define GOT/PLT layouts.
+ // Lookup dynamic table tags which define the GOT layout.
Optional<uint64_t> DtPltGot;
Optional<uint64_t> DtLocalGotNum;
Optional<uint64_t> DtGotSym;
- Optional<uint64_t> DtMipsPltGot;
- Optional<uint64_t> DtJmpRel;
for (const auto &Entry : DynTable) {
switch (Entry.getTag()) {
case ELF::DT_PLTGOT:
@@ -2664,6 +3031,49 @@ MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, StringRef FileName,
case ELF::DT_MIPS_GOTSYM:
DtGotSym = Entry.getVal();
break;
+ }
+ }
+
+ if (!DtPltGot && !DtLocalGotNum && !DtGotSym)
+ return Error::success();
+
+ if (!DtPltGot)
+ return createError("cannot find PLTGOT dynamic tag");
+ if (!DtLocalGotNum)
+ return createError("cannot find MIPS_LOCAL_GOTNO dynamic tag");
+ if (!DtGotSym)
+ return createError("cannot find MIPS_GOTSYM dynamic tag");
+
+ size_t DynSymTotal = DynSyms.size();
+ if (*DtGotSym > DynSymTotal)
+ return createError("DT_MIPS_GOTSYM value (" + Twine(*DtGotSym) +
+ ") exceeds the number of dynamic symbols (" +
+ Twine(DynSymTotal) + ")");
+
+ GotSec = findNotEmptySectionByAddress(Obj, FileName, *DtPltGot);
+ if (!GotSec)
+ return createError("there is no non-empty GOT section at 0x" +
+ Twine::utohexstr(*DtPltGot));
+
+ LocalNum = *DtLocalGotNum;
+ GlobalNum = DynSymTotal - *DtGotSym;
+
+ ArrayRef<uint8_t> Content =
+ unwrapOrError(FileName, Obj->getSectionContents(GotSec));
+ GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()),
+ Content.size() / sizeof(Entry));
+ GotDynSyms = DynSyms.drop_front(*DtGotSym);
+
+ return Error::success();
+}
+
+template <class ELFT>
+Error MipsGOTParser<ELFT>::findPLT(Elf_Dyn_Range DynTable) {
+ // Lookup dynamic table tags which define the PLT layout.
+ Optional<uint64_t> DtMipsPltGot;
+ Optional<uint64_t> DtJmpRel;
+ for (const auto &Entry : DynTable) {
+ switch (Entry.getTag()) {
case ELF::DT_MIPS_PLTGOT:
DtMipsPltGot = Entry.getVal();
break;
@@ -2673,63 +3083,56 @@ MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, StringRef FileName,
}
}
- // Find dynamic GOT section.
- if (DtPltGot || DtLocalGotNum || DtGotSym) {
- if (!DtPltGot)
- report_fatal_error("Cannot find PLTGOT dynamic table tag.");
- if (!DtLocalGotNum)
- report_fatal_error("Cannot find MIPS_LOCAL_GOTNO dynamic table tag.");
- if (!DtGotSym)
- report_fatal_error("Cannot find MIPS_GOTSYM dynamic table tag.");
-
- size_t DynSymTotal = DynSyms.size();
- if (*DtGotSym > DynSymTotal)
- reportError(
- createError("MIPS_GOTSYM exceeds a number of dynamic symbols"),
- FileName);
-
- GotSec = findNotEmptySectionByAddress(Obj, FileName, *DtPltGot);
- if (!GotSec)
- reportError(createError("There is no not empty GOT section at 0x" +
- Twine::utohexstr(*DtPltGot)),
- FileName);
-
- LocalNum = *DtLocalGotNum;
- GlobalNum = DynSymTotal - *DtGotSym;
-
- ArrayRef<uint8_t> Content =
- unwrapOrError(FileName, Obj->getSectionContents(GotSec));
- GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()),
- Content.size() / sizeof(Entry));
- GotDynSyms = DynSyms.drop_front(*DtGotSym);
- }
+ if (!DtMipsPltGot && !DtJmpRel)
+ return Error::success();
// Find PLT section.
- if (DtMipsPltGot || DtJmpRel) {
- if (!DtMipsPltGot)
- report_fatal_error("Cannot find MIPS_PLTGOT dynamic table tag.");
- if (!DtJmpRel)
- report_fatal_error("Cannot find JMPREL dynamic table tag.");
-
- PltSec = findNotEmptySectionByAddress(Obj, FileName, * DtMipsPltGot);
- if (!PltSec)
- report_fatal_error("There is no not empty PLTGOT section at 0x " +
- Twine::utohexstr(*DtMipsPltGot));
-
- PltRelSec = findNotEmptySectionByAddress(Obj, FileName, * DtJmpRel);
- if (!PltRelSec)
- report_fatal_error("There is no not empty RELPLT section at 0x" +
- Twine::utohexstr(*DtJmpRel));
+ if (!DtMipsPltGot)
+ return createError("cannot find MIPS_PLTGOT dynamic tag");
+ if (!DtJmpRel)
+ return createError("cannot find JMPREL dynamic tag");
+
+ PltSec = findNotEmptySectionByAddress(Obj, FileName, *DtMipsPltGot);
+ if (!PltSec)
+ return createError("there is no non-empty PLTGOT section at 0x" +
+ Twine::utohexstr(*DtMipsPltGot));
+
+ PltRelSec = findNotEmptySectionByAddress(Obj, FileName, *DtJmpRel);
+ if (!PltRelSec)
+ return createError("there is no non-empty RELPLT section at 0x" +
+ Twine::utohexstr(*DtJmpRel));
+
+ if (Expected<ArrayRef<uint8_t>> PltContentOrErr =
+ Obj->getSectionContents(PltSec))
+ PltEntries =
+ Entries(reinterpret_cast<const Entry *>(PltContentOrErr->data()),
+ PltContentOrErr->size() / sizeof(Entry));
+ else
+ return createError("unable to read PLTGOT section content: " +
+ toString(PltContentOrErr.takeError()));
- ArrayRef<uint8_t> PltContent =
- unwrapOrError(FileName, Obj->getSectionContents(PltSec));
- PltEntries = Entries(reinterpret_cast<const Entry *>(PltContent.data()),
- PltContent.size() / sizeof(Entry));
+ if (Expected<const Elf_Shdr *> PltSymTableOrErr =
+ Obj->getSection(PltRelSec->sh_link)) {
+ PltSymTable = *PltSymTableOrErr;
+ } else {
+ unsigned SecNdx = PltRelSec - &cantFail(Obj->sections()).front();
+ return createError("unable to get a symbol table linked to the RELPLT "
+ "section with index " +
+ Twine(SecNdx) + ": " +
+ toString(PltSymTableOrErr.takeError()));
+ }
- PltSymTable = unwrapOrError(FileName, Obj->getSection(PltRelSec->sh_link));
- PltStrTable =
- unwrapOrError(FileName, Obj->getStringTableForSymtab(*PltSymTable));
+ if (Expected<StringRef> StrTabOrErr =
+ Obj->getStringTableForSymtab(*PltSymTable)) {
+ PltStrTable = *StrTabOrErr;
+ } else {
+ unsigned SecNdx = PltSymTable - &cantFail(Obj->sections()).front();
+ return createError(
+ "unable to get a string table for the symbol table with index " +
+ Twine(SecNdx) + ": " + toString(StrTabOrErr.takeError()));
}
+
+ return Error::success();
}
template <class ELFT> uint64_t MipsGOTParser<ELFT>::getGp() const {
@@ -2977,7 +3380,7 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsOptions() {
template <class ELFT> void ELFDumper<ELFT>::printStackMap() const {
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
const Elf_Shdr *StackMapSection = nullptr;
- for (const auto &Sec : unwrapOrError(ObjF->getFileName(), Obj->sections())) {
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
StringRef Name =
unwrapOrError(ObjF->getFileName(), Obj->getSectionName(&Sec));
if (Name == ".llvm_stackmaps") {
@@ -3020,7 +3423,7 @@ static std::string getSectionHeadersNumString(const ELFFile<ELFT> *Obj,
if (ElfHeader->e_shnum != 0)
return to_string(ElfHeader->e_shnum);
- ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(FileName, Obj->sections());
+ ArrayRef<typename ELFT::Shdr> Arr = cantFail(Obj->sections());
if (Arr.empty())
return "0";
return "0 (" + to_string(Arr[0].sh_size) + ")";
@@ -3033,7 +3436,7 @@ static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> *Obj,
if (ElfHeader->e_shstrndx != SHN_XINDEX)
return to_string(ElfHeader->e_shstrndx);
- ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(FileName, Obj->sections());
+ ArrayRef<typename ELFT::Shdr> Arr = cantFail(Obj->sections());
if (Arr.empty())
return "65535 (corrupt: out of range)";
return to_string(ElfHeader->e_shstrndx) + " (" + to_string(Arr[0].sh_link) +
@@ -3127,7 +3530,7 @@ std::vector<GroupSection> getGroups(const ELFFile<ELFT> *Obj,
std::vector<GroupSection> Ret;
uint64_t I = 0;
- for (const Elf_Shdr &Sec : unwrapOrError(FileName, Obj->sections())) {
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
++I;
if (Sec.sh_type != ELF::SHT_GROUP)
continue;
@@ -3202,23 +3605,18 @@ template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) {
}
template <class ELFT>
-void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab,
- const Elf_Rela &R, bool IsRela) {
- const Elf_Sym *Sym =
- unwrapOrError(this->FileName, Obj->getRelocationSymbol(&R, SymTab));
- std::string TargetName;
- if (Sym && Sym->getType() == ELF::STT_SECTION) {
- const Elf_Shdr *Sec = unwrapOrError(
- this->FileName,
- Obj->getSection(Sym, SymTab, this->dumper()->getShndxTable()));
- TargetName = unwrapOrError(this->FileName, Obj->getSectionName(Sec));
- } else if (Sym) {
- StringRef StrTable =
- unwrapOrError(this->FileName, Obj->getStringTableForSymtab(*SymTab));
- TargetName = this->dumper()->getFullSymbolName(
- Sym, StrTable, SymTab->sh_type == SHT_DYNSYM /* IsDynamic */);
- }
- printRelocation(Obj, Sym, TargetName, R, IsRela);
+void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, unsigned SecIndex,
+ const Elf_Shdr *SymTab, const Elf_Rela &R,
+ unsigned RelIndex, bool IsRela) {
+ Expected<std::pair<const typename ELFT::Sym *, std::string>> Target =
+ this->dumper()->getRelocationTarget(SymTab, R);
+ if (!Target)
+ this->reportUniqueWarning(createError(
+ "unable to print relocation " + Twine(RelIndex) + " in section " +
+ Twine(SecIndex) + ": " + toString(Target.takeError())));
+ else
+ printRelocation(Obj, /*Sym=*/Target->first, /*Name=*/Target->second, R,
+ IsRela);
}
template <class ELFT>
@@ -3237,10 +3635,10 @@ void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, const Elf_Sym *Sym,
Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName);
Fields[2].Str = RelocName.c_str();
- if (Sym && (!SymbolName.empty() || Sym->getValue() != 0))
+ if (Sym)
Fields[3].Str = to_string(format_hex_no_prefix(Sym->getValue(), Width));
- Fields[4].Str = SymbolName;
+ Fields[4].Str = std::string(SymbolName);
for (const Field &F : Fields)
printField(F);
@@ -3283,7 +3681,7 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocHeader(unsigned SType) {
template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {
bool HasRelocSections = false;
- for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) {
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA &&
Sec.sh_type != ELF::SHT_RELR && Sec.sh_type != ELF::SHT_ANDROID_REL &&
Sec.sh_type != ELF::SHT_ANDROID_RELA &&
@@ -3316,6 +3714,9 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {
printRelocHeader(Sec.sh_type);
const Elf_Shdr *SymTab =
unwrapOrError(this->FileName, Obj->getSection(Sec.sh_link));
+ unsigned SecNdx = &Sec - &cantFail(Obj->sections()).front();
+ unsigned RelNdx = 0;
+
switch (Sec.sh_type) {
case ELF::SHT_REL:
for (const auto &R : unwrapOrError(this->FileName, Obj->rels(&Sec))) {
@@ -3323,12 +3724,12 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {
Rela.r_offset = R.r_offset;
Rela.r_info = R.r_info;
Rela.r_addend = 0;
- printRelocation(Obj, SymTab, Rela, false);
+ printRelocation(Obj, SecNdx, SymTab, Rela, ++RelNdx, false);
}
break;
case ELF::SHT_RELA:
for (const auto &R : unwrapOrError(this->FileName, Obj->relas(&Sec)))
- printRelocation(Obj, SymTab, R, true);
+ printRelocation(Obj, SecNdx, SymTab, R, ++RelNdx, true);
break;
case ELF::SHT_RELR:
case ELF::SHT_ANDROID_RELR:
@@ -3338,12 +3739,13 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {
<< "\n";
else
for (const auto &R : RelrRelas)
- printRelocation(Obj, SymTab, R, false);
+ printRelocation(Obj, SecNdx, SymTab, R, ++RelNdx, false);
break;
case ELF::SHT_ANDROID_REL:
case ELF::SHT_ANDROID_RELA:
for (const auto &R : AndroidRelas)
- printRelocation(Obj, SymTab, R, Sec.sh_type == ELF::SHT_ANDROID_RELA);
+ printRelocation(Obj, SecNdx, SymTab, R, ++RelNdx,
+ Sec.sh_type == ELF::SHT_ANDROID_RELA);
break;
}
}
@@ -3402,6 +3804,11 @@ static std::string getSectionTypeString(unsigned Arch, unsigned Type) {
return "MIPS_ABIFLAGS";
}
break;
+ case EM_RISCV:
+ switch (Type) {
+ case SHT_RISCV_ATTRIBUTES:
+ return "RISCV_ATTRIBUTES";
+ }
}
switch (Type) {
case SHT_NULL:
@@ -3500,7 +3907,7 @@ static void printSectionDescription(formatted_raw_ostream &OS,
template <class ELFT>
void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
unsigned Bias = ELFT::Is64Bits ? 0 : 8;
- ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections());
+ ArrayRef<Elf_Shdr> Sections = cantFail(Obj->sections());
OS << "There are " << to_string(Sections.size())
<< " section headers, starting at offset "
<< "0x" << to_hexString(Obj->getHeader()->e_shoff, false) << ":\n\n";
@@ -3514,12 +3921,21 @@ void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
printField(F);
OS << "\n";
- const ELFObjectFile<ELFT> *ElfObj = this->dumper()->getElfObject();
+ StringRef SecStrTable;
+ if (Expected<StringRef> SecStrTableOrErr =
+ Obj->getSectionStringTable(Sections, this->dumper()->WarningHandler))
+ SecStrTable = *SecStrTableOrErr;
+ else
+ this->reportUniqueWarning(SecStrTableOrErr.takeError());
+
size_t SectionIndex = 0;
for (const Elf_Shdr &Sec : Sections) {
Fields[0].Str = to_string(SectionIndex);
- Fields[1].Str = unwrapOrError<StringRef>(
- ElfObj->getFileName(), Obj->getSectionName(&Sec, this->WarningHandler));
+ if (SecStrTable.empty())
+ Fields[1].Str = "<no-strings>";
+ else
+ Fields[1].Str = std::string(unwrapOrError<StringRef>(
+ this->FileName, Obj->getSectionName(&Sec, SecStrTable)));
Fields[2].Str =
getSectionTypeString(Obj->getHeader()->e_machine, Sec.sh_type);
Fields[3].Str =
@@ -3555,10 +3971,10 @@ void GNUStyle<ELFT>::printSymtabMessage(const ELFO *Obj, StringRef Name,
size_t Entries,
bool NonVisibilityBitsUsed) {
if (!Name.empty())
- OS << "\nSymbol table '" << Name << "' contains " << Entries
- << " entries:\n";
+ OS << "\nSymbol table '" << Name << "'";
else
- OS << "\n Symbol table for image:\n";
+ OS << "\nSymbol table for image";
+ OS << " contains " << Entries << " entries:\n";
if (ELFT::Is64Bits)
OS << " Num: Value Size Type Bind Vis";
@@ -3616,8 +4032,9 @@ std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj,
template <class ELFT>
void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
- const Elf_Sym *FirstSym, StringRef StrTable,
- bool IsDynamic, bool NonVisibilityBitsUsed) {
+ const Elf_Sym *FirstSym,
+ Optional<StringRef> StrTable, bool IsDynamic,
+ bool NonVisibilityBitsUsed) {
static int Idx = 0;
static bool Dynamic = true;
@@ -3707,67 +4124,110 @@ void GNUStyle<ELFT>::printSymbols(const ELFO *Obj, bool PrintSymbols,
this->dumper()->printSymbolsHelper(false);
}
-template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) {
- if (this->dumper()->getDynamicStringTable().empty())
+template <class ELFT>
+void GNUStyle<ELFT>::printHashTableSymbols(const ELFO *Obj,
+ const Elf_Hash &SysVHash) {
+ StringRef StringTable = this->dumper()->getDynamicStringTable();
+ if (StringTable.empty())
return;
- auto StringTable = this->dumper()->getDynamicStringTable();
- auto DynSyms = this->dumper()->dynamic_symbols();
- // Try printing .hash
- if (auto SysVHash = this->dumper()->getHashTable()) {
- OS << "\n Symbol table of .hash for image:\n";
- if (ELFT::Is64Bits)
- OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
- else
- OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
- OS << "\n";
+ if (ELFT::Is64Bits)
+ OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
+ else
+ OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
+ OS << "\n";
- auto Buckets = SysVHash->buckets();
- auto Chains = SysVHash->chains();
- for (uint32_t Buc = 0; Buc < SysVHash->nbucket; Buc++) {
- if (Buckets[Buc] == ELF::STN_UNDEF)
- continue;
- std::vector<bool> Visited(SysVHash->nchain);
- for (uint32_t Ch = Buckets[Buc]; Ch < SysVHash->nchain; Ch = Chains[Ch]) {
- if (Ch == ELF::STN_UNDEF)
- break;
+ Elf_Sym_Range DynSyms = this->dumper()->dynamic_symbols();
+ const Elf_Sym *FirstSym = DynSyms.empty() ? nullptr : &DynSyms[0];
+ if (!FirstSym) {
+ Optional<DynRegionInfo> DynSymRegion = this->dumper()->getDynSymRegion();
+ this->reportUniqueWarning(
+ createError(Twine("unable to print symbols for the .hash table: the "
+ "dynamic symbol table ") +
+ (DynSymRegion ? "is empty" : "was not found")));
+ return;
+ }
- if (Visited[Ch]) {
- reportWarning(
- createError(".hash section is invalid: bucket " + Twine(Ch) +
- ": a cycle was detected in the linked chain"),
- this->FileName);
- break;
- }
+ auto Buckets = SysVHash.buckets();
+ auto Chains = SysVHash.chains();
+ for (uint32_t Buc = 0; Buc < SysVHash.nbucket; Buc++) {
+ if (Buckets[Buc] == ELF::STN_UNDEF)
+ continue;
+ std::vector<bool> Visited(SysVHash.nchain);
+ for (uint32_t Ch = Buckets[Buc]; Ch < SysVHash.nchain; Ch = Chains[Ch]) {
+ if (Ch == ELF::STN_UNDEF)
+ break;
- printHashedSymbol(Obj, &DynSyms[0], Ch, StringTable, Buc);
- Visited[Ch] = true;
+ if (Visited[Ch]) {
+ reportWarning(createError(".hash section is invalid: bucket " +
+ Twine(Ch) +
+ ": a cycle was detected in the linked chain"),
+ this->FileName);
+ break;
}
+
+ printHashedSymbol(Obj, FirstSym, Ch, StringTable, Buc);
+ Visited[Ch] = true;
+ }
+ }
+}
+
+template <class ELFT>
+void GNUStyle<ELFT>::printGnuHashTableSymbols(const ELFO *Obj,
+ const Elf_GnuHash &GnuHash) {
+ StringRef StringTable = this->dumper()->getDynamicStringTable();
+ if (StringTable.empty())
+ return;
+
+ Elf_Sym_Range DynSyms = this->dumper()->dynamic_symbols();
+ const Elf_Sym *FirstSym = DynSyms.empty() ? nullptr : &DynSyms[0];
+ if (!FirstSym) {
+ Optional<DynRegionInfo> DynSymRegion = this->dumper()->getDynSymRegion();
+ this->reportUniqueWarning(createError(
+ Twine("unable to print symbols for the .gnu.hash table: the "
+ "dynamic symbol table ") +
+ (DynSymRegion ? "is empty" : "was not found")));
+ return;
+ }
+
+ ArrayRef<Elf_Word> Buckets = GnuHash.buckets();
+ for (uint32_t Buc = 0; Buc < GnuHash.nbuckets; Buc++) {
+ if (Buckets[Buc] == ELF::STN_UNDEF)
+ continue;
+ uint32_t Index = Buckets[Buc];
+ uint32_t GnuHashable = Index - GnuHash.symndx;
+ // Print whole chain
+ while (true) {
+ printHashedSymbol(Obj, FirstSym, Index++, StringTable, Buc);
+ // Chain ends at symbol with stopper bit
+ if ((GnuHash.values(DynSyms.size())[GnuHashable++] & 1) == 1)
+ break;
}
}
+}
+
+template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) {
+ if (const Elf_Hash *SysVHash = this->dumper()->getHashTable()) {
+ OS << "\n Symbol table of .hash for image:\n";
+ if (Error E = checkHashTable<ELFT>(Obj, SysVHash))
+ this->reportUniqueWarning(std::move(E));
+ else
+ printHashTableSymbols(Obj, *SysVHash);
+ }
- // Try printing .gnu.hash
- if (auto GnuHash = this->dumper()->getGnuHashTable()) {
+ // Try printing the .gnu.hash table.
+ if (const Elf_GnuHash *GnuHash = this->dumper()->getGnuHashTable()) {
OS << "\n Symbol table of .gnu.hash for image:\n";
if (ELFT::Is64Bits)
OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
else
OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
OS << "\n";
- auto Buckets = GnuHash->buckets();
- for (uint32_t Buc = 0; Buc < GnuHash->nbuckets; Buc++) {
- if (Buckets[Buc] == ELF::STN_UNDEF)
- continue;
- uint32_t Index = Buckets[Buc];
- uint32_t GnuHashable = Index - GnuHash->symndx;
- // Print whole chain
- while (true) {
- printHashedSymbol(Obj, &DynSyms[0], Index++, StringTable, Buc);
- // Chain ends at symbol with stopper bit
- if ((GnuHash->values(DynSyms.size())[GnuHashable++] & 1) == 1)
- break;
- }
- }
+
+ if (Error E = checkGNUHashTable<ELFT>(Obj, GnuHash))
+ this->reportUniqueWarning(std::move(E));
+ else
+ printGnuHashTableSymbols(Obj, *GnuHash);
}
}
@@ -3779,63 +4239,76 @@ static inline std::string printPhdrFlags(unsigned Flag) {
return Str;
}
-// SHF_TLS sections are only in PT_TLS, PT_LOAD or PT_GNU_RELRO
-// PT_TLS must only have SHF_TLS sections
template <class ELFT>
-bool GNUStyle<ELFT>::checkTLSSections(const Elf_Phdr &Phdr,
- const Elf_Shdr &Sec) {
- return (((Sec.sh_flags & ELF::SHF_TLS) &&
- ((Phdr.p_type == ELF::PT_TLS) || (Phdr.p_type == ELF::PT_LOAD) ||
- (Phdr.p_type == ELF::PT_GNU_RELRO))) ||
- (!(Sec.sh_flags & ELF::SHF_TLS) && Phdr.p_type != ELF::PT_TLS));
+static bool checkTLSSections(const typename ELFT::Phdr &Phdr,
+ const typename ELFT::Shdr &Sec) {
+ if (Sec.sh_flags & ELF::SHF_TLS) {
+ // .tbss must only be shown in the PT_TLS segment.
+ if (Sec.sh_type == ELF::SHT_NOBITS)
+ return Phdr.p_type == ELF::PT_TLS;
+
+ // SHF_TLS sections are only shown in PT_TLS, PT_LOAD or PT_GNU_RELRO
+ // segments.
+ return (Phdr.p_type == ELF::PT_TLS) || (Phdr.p_type == ELF::PT_LOAD) ||
+ (Phdr.p_type == ELF::PT_GNU_RELRO);
+ }
+
+ // PT_TLS must only have SHF_TLS sections.
+ return Phdr.p_type != ELF::PT_TLS;
}
-// Non-SHT_NOBITS must have its offset inside the segment
-// Only non-zero section can be at end of segment
template <class ELFT>
-bool GNUStyle<ELFT>::checkoffsets(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) {
+static bool checkOffsets(const typename ELFT::Phdr &Phdr,
+ const typename ELFT::Shdr &Sec) {
+ // SHT_NOBITS sections don't need to have an offset inside the segment.
if (Sec.sh_type == ELF::SHT_NOBITS)
return true;
- bool IsSpecial =
- (Sec.sh_type == ELF::SHT_NOBITS) && ((Sec.sh_flags & ELF::SHF_TLS) != 0);
- // .tbss is special, it only has memory in PT_TLS and has NOBITS properties
- auto SectionSize =
- (IsSpecial && Phdr.p_type != ELF::PT_TLS) ? 0 : Sec.sh_size;
- if (Sec.sh_offset >= Phdr.p_offset)
- return ((Sec.sh_offset + SectionSize <= Phdr.p_filesz + Phdr.p_offset)
- /*only non-zero sized sections at end*/
- && (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz));
- return false;
-}
-
-// SHF_ALLOC must have VMA inside segment
-// Only non-zero section can be at end of segment
+
+ if (Sec.sh_offset < Phdr.p_offset)
+ return false;
+
+ // Only non-empty sections can be at the end of a segment.
+ if (Sec.sh_size == 0)
+ return (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz);
+ return Sec.sh_offset + Sec.sh_size <= Phdr.p_offset + Phdr.p_filesz;
+}
+
+// Check that an allocatable section belongs to a virtual address
+// space of a segment.
template <class ELFT>
-bool GNUStyle<ELFT>::checkVMA(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) {
+static bool checkVMA(const typename ELFT::Phdr &Phdr,
+ const typename ELFT::Shdr &Sec) {
if (!(Sec.sh_flags & ELF::SHF_ALLOC))
return true;
- bool IsSpecial =
+
+ if (Sec.sh_addr < Phdr.p_vaddr)
+ return false;
+
+ bool IsTbss =
(Sec.sh_type == ELF::SHT_NOBITS) && ((Sec.sh_flags & ELF::SHF_TLS) != 0);
- // .tbss is special, it only has memory in PT_TLS and has NOBITS properties
- auto SectionSize =
- (IsSpecial && Phdr.p_type != ELF::PT_TLS) ? 0 : Sec.sh_size;
- if (Sec.sh_addr >= Phdr.p_vaddr)
- return ((Sec.sh_addr + SectionSize <= Phdr.p_vaddr + Phdr.p_memsz) &&
- (Sec.sh_addr + 1 <= Phdr.p_vaddr + Phdr.p_memsz));
- return false;
+ // .tbss is special, it only has memory in PT_TLS and has NOBITS properties.
+ bool IsTbssInNonTLS = IsTbss && Phdr.p_type != ELF::PT_TLS;
+ // Only non-empty sections can be at the end of a segment.
+ if (Sec.sh_size == 0 || IsTbssInNonTLS)
+ return Sec.sh_addr + 1 <= Phdr.p_vaddr + Phdr.p_memsz;
+ return Sec.sh_addr + Sec.sh_size <= Phdr.p_vaddr + Phdr.p_memsz;
}
-// No section with zero size must be at start or end of PT_DYNAMIC
template <class ELFT>
-bool GNUStyle<ELFT>::checkPTDynamic(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) {
- if (Phdr.p_type != ELF::PT_DYNAMIC || Sec.sh_size != 0 || Phdr.p_memsz == 0)
+static bool checkPTDynamic(const typename ELFT::Phdr &Phdr,
+ const typename ELFT::Shdr &Sec) {
+ if (Phdr.p_type != ELF::PT_DYNAMIC || Phdr.p_memsz == 0 || Sec.sh_size != 0)
return true;
- // Is section within the phdr both based on offset and VMA ?
- return ((Sec.sh_type == ELF::SHT_NOBITS) ||
- (Sec.sh_offset > Phdr.p_offset &&
- Sec.sh_offset < Phdr.p_offset + Phdr.p_filesz)) &&
- (!(Sec.sh_flags & ELF::SHF_ALLOC) ||
- (Sec.sh_addr > Phdr.p_vaddr && Sec.sh_addr < Phdr.p_memsz));
+
+ // We get here when we have an empty section. Only non-empty sections can be
+ // at the start or at the end of PT_DYNAMIC.
+ // Is section within the phdr both based on offset and VMA?
+ bool CheckOffset = (Sec.sh_type == ELF::SHT_NOBITS) ||
+ (Sec.sh_offset > Phdr.p_offset &&
+ Sec.sh_offset < Phdr.p_offset + Phdr.p_filesz);
+ bool CheckVA = !(Sec.sh_flags & ELF::SHF_ALLOC) ||
+ (Sec.sh_addr > Phdr.p_vaddr && Sec.sh_addr < Phdr.p_memsz);
+ return CheckOffset && CheckVA;
}
template <class ELFT>
@@ -3872,8 +4345,15 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
unsigned Width = ELFT::Is64Bits ? 18 : 10;
unsigned SizeWidth = ELFT::Is64Bits ? 8 : 7;
- for (const auto &Phdr :
- unwrapOrError(this->FileName, Obj->program_headers())) {
+
+ Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers();
+ if (!PhdrsOrErr) {
+ this->reportUniqueWarning(createError("unable to dump program headers: " +
+ toString(PhdrsOrErr.takeError())));
+ return;
+ }
+
+ for (const Elf_Phdr &Phdr : *PhdrsOrErr) {
Fields[0].Str = getElfPtType(Header->e_machine, Phdr.p_type);
Fields[1].Str = to_string(format_hex(Phdr.p_offset, 8));
Fields[2].Str = to_string(format_hex(Phdr.p_vaddr, Width));
@@ -3885,8 +4365,31 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
for (auto Field : Fields)
printField(Field);
if (Phdr.p_type == ELF::PT_INTERP) {
- OS << "\n [Requesting program interpreter: ";
- OS << reinterpret_cast<const char *>(Obj->base()) + Phdr.p_offset << "]";
+ OS << "\n";
+ auto ReportBadInterp = [&](const Twine &Msg) {
+ reportWarning(
+ createError("unable to read program interpreter name at offset 0x" +
+ Twine::utohexstr(Phdr.p_offset) + ": " + Msg),
+ this->FileName);
+ };
+
+ if (Phdr.p_offset >= Obj->getBufSize()) {
+ ReportBadInterp("it goes past the end of the file (0x" +
+ Twine::utohexstr(Obj->getBufSize()) + ")");
+ continue;
+ }
+
+ const char *Data =
+ reinterpret_cast<const char *>(Obj->base()) + Phdr.p_offset;
+ size_t MaxSize = Obj->getBufSize() - Phdr.p_offset;
+ size_t Len = strnlen(Data, MaxSize);
+ if (Len == MaxSize) {
+ ReportBadInterp("it is not null-terminated");
+ continue;
+ }
+
+ OS << " [Requesting program interpreter: ";
+ OS << StringRef(Data, Len) << "]";
}
OS << "\n";
}
@@ -3897,21 +4400,28 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) {
OS << "\n Section to Segment mapping:\n Segment Sections...\n";
DenseSet<const Elf_Shdr *> BelongsToSegment;
int Phnum = 0;
- for (const Elf_Phdr &Phdr :
- unwrapOrError(this->FileName, Obj->program_headers())) {
+
+ Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers();
+ if (!PhdrsOrErr) {
+ this->reportUniqueWarning(createError(
+ "can't read program headers to build section to segment mapping: " +
+ toString(PhdrsOrErr.takeError())));
+ return;
+ }
+
+ for (const Elf_Phdr &Phdr : *PhdrsOrErr) {
std::string Sections;
OS << format(" %2.2d ", Phnum++);
- for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) {
- // Check if each section is in a segment and then print mapping.
+ // Check if each section is in a segment and then print mapping.
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
+ if (Sec.sh_type == ELF::SHT_NULL)
+ continue;
+
// readelf additionally makes sure it does not print zero sized sections
// at end of segments and for PT_DYNAMIC both start and end of section
// .tbss must only be shown in PT_TLS section.
- bool TbssInNonTLS = (Sec.sh_type == ELF::SHT_NOBITS) &&
- ((Sec.sh_flags & ELF::SHF_TLS) != 0) &&
- Phdr.p_type != ELF::PT_TLS;
- if (!TbssInNonTLS && checkTLSSections(Phdr, Sec) &&
- checkoffsets(Phdr, Sec) && checkVMA(Phdr, Sec) &&
- checkPTDynamic(Phdr, Sec) && (Sec.sh_type != ELF::SHT_NULL)) {
+ if (checkTLSSections<ELFT>(Phdr, Sec) && checkOffsets<ELFT>(Phdr, Sec) &&
+ checkVMA<ELFT>(Phdr, Sec) && checkPTDynamic<ELFT>(Phdr, Sec)) {
Sections +=
unwrapOrError(this->FileName, Obj->getSectionName(&Sec)).str() +
" ";
@@ -3924,7 +4434,7 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) {
// Display sections that do not belong to a segment.
std::string Sections;
- for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) {
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
if (BelongsToSegment.find(&Sec) == BelongsToSegment.end())
Sections +=
unwrapOrError(this->FileName, Obj->getSectionName(&Sec)).str() + ' ';
@@ -3946,21 +4456,35 @@ RelSymbol<ELFT> getSymbolForReloc(const ELFFile<ELFT> *Obj, StringRef FileName,
const ELFDumper<ELFT> *Dumper,
const typename ELFT::Rela &Reloc) {
uint32_t SymIndex = Reloc.getSymbol(Obj->isMips64EL());
- const typename ELFT::Sym *Sym = Dumper->dynamic_symbols().begin() + SymIndex;
- Expected<StringRef> ErrOrName = Sym->getName(Dumper->getDynamicStringTable());
-
- std::string Name;
- if (ErrOrName) {
- Name = maybeDemangle(*ErrOrName);
- } else {
+ auto WarnAndReturn = [&](const typename ELFT::Sym *Sym,
+ const Twine &Reason) -> RelSymbol<ELFT> {
reportWarning(
createError("unable to get name of the dynamic symbol with index " +
- Twine(SymIndex) + ": " + toString(ErrOrName.takeError())),
+ Twine(SymIndex) + ": " + Reason),
FileName);
- Name = "<corrupt>";
- }
+ return {Sym, "<corrupt>"};
+ };
- return {Sym, std::move(Name)};
+ ArrayRef<typename ELFT::Sym> Symbols = Dumper->dynamic_symbols();
+ const typename ELFT::Sym *FirstSym = Symbols.begin();
+ if (!FirstSym)
+ return WarnAndReturn(nullptr, "no dynamic symbol table found");
+
+ // We might have an object without a section header. In this case the size of
+ // Symbols is zero, because there is no way to know the size of the dynamic
+ // table. We should allow this case and not print a warning.
+ if (!Symbols.empty() && SymIndex >= Symbols.size())
+ return WarnAndReturn(
+ nullptr,
+ "index is greater than or equal to the number of dynamic symbols (" +
+ Twine(Symbols.size()) + ")");
+
+ const typename ELFT::Sym *Sym = FirstSym + SymIndex;
+ Expected<StringRef> ErrOrName = Sym->getName(Dumper->getDynamicStringTable());
+ if (!ErrOrName)
+ return WarnAndReturn(Sym, toString(ErrOrName.takeError()));
+
+ return {Sym == FirstSym ? nullptr : Sym, maybeDemangle(*ErrOrName)};
}
} // namespace
@@ -3971,6 +4495,15 @@ void GNUStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela R,
printRelocation(Obj, S.Sym, S.Name, R, IsRela);
}
+template <class ELFT>
+static size_t getMaxDynamicTagSize(const ELFFile<ELFT> *Obj,
+ typename ELFT::DynRange Tags) {
+ size_t Max = 0;
+ for (const typename ELFT::Dyn &Dyn : Tags)
+ Max = std::max(Max, Obj->getDynamicTagAsString(Dyn.d_tag).size());
+ return Max;
+}
+
template <class ELFT> void GNUStyle<ELFT>::printDynamic(const ELFO *Obj) {
Elf_Dyn_Range Table = this->dumper()->dynamic_table();
if (Table.empty())
@@ -3985,19 +4518,22 @@ template <class ELFT> void GNUStyle<ELFT>::printDynamic(const ELFO *Obj) {
1)
<< " contains " << Table.size() << " entries:\n";
- bool Is64 = ELFT::Is64Bits;
- if (Is64)
- OS << " Tag Type Name/Value\n";
- else
- OS << " Tag Type Name/Value\n";
+ // The type name is surrounded with round brackets, hence add 2.
+ size_t MaxTagSize = getMaxDynamicTagSize(Obj, Table) + 2;
+ // The "Name/Value" column should be indented from the "Type" column by N
+ // spaces, where N = MaxTagSize - length of "Type" (4) + trailing
+ // space (1) = 3.
+ OS << " Tag" + std::string(ELFT::Is64Bits ? 16 : 8, ' ') + "Type"
+ << std::string(MaxTagSize - 3, ' ') << "Name/Value\n";
+
+ std::string ValueFmt = " %-" + std::to_string(MaxTagSize) + "s ";
for (auto Entry : Table) {
uintX_t Tag = Entry.getTag();
- std::string TypeString =
+ std::string Type =
std::string("(") + Obj->getDynamicTagAsString(Tag).c_str() + ")";
- OS << " " << format_hex(Tag, Is64 ? 18 : 10)
- << format(" %-20s ", TypeString.c_str());
- this->dumper()->printDynamicEntry(OS, Tag, Entry.getVal());
- OS << "\n";
+ std::string Value = this->dumper()->getDynamicEntry(Tag, Entry.getVal());
+ OS << " " << format_hex(Tag, ELFT::Is64Bits ? 18 : 10)
+ << format(ValueFmt.c_str(), Type.c_str()) << Value << "\n";
}
}
@@ -4052,19 +4588,20 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
Obj->base(),
1)
<< " contains " << DynPLTRelRegion.Size << " bytes:\n";
- }
- if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) {
- printRelocHeader(ELF::SHT_RELA);
- for (const Elf_Rela &Rela : DynPLTRelRegion.getAsArrayRef<Elf_Rela>())
- printDynamicRelocation(Obj, Rela, true);
- } else {
- printRelocHeader(ELF::SHT_REL);
- for (const Elf_Rel &Rel : DynPLTRelRegion.getAsArrayRef<Elf_Rel>()) {
- Elf_Rela Rela;
- Rela.r_offset = Rel.r_offset;
- Rela.r_info = Rel.r_info;
- Rela.r_addend = 0;
- printDynamicRelocation(Obj, Rela, false);
+
+ if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) {
+ printRelocHeader(ELF::SHT_RELA);
+ for (const Elf_Rela &Rela : DynPLTRelRegion.getAsArrayRef<Elf_Rela>())
+ printDynamicRelocation(Obj, Rela, true);
+ } else {
+ printRelocHeader(ELF::SHT_REL);
+ for (const Elf_Rel &Rel : DynPLTRelRegion.getAsArrayRef<Elf_Rel>()) {
+ Elf_Rela Rela;
+ Rela.r_offset = Rel.r_offset;
+ Rela.r_info = Rel.r_info;
+ Rela.r_addend = 0;
+ printDynamicRelocation(Obj, Rela, false);
+ }
}
}
}
@@ -4231,116 +4768,137 @@ void GNUStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
OS << '\n';
}
-// Hash histogram shows statistics of how efficient the hash was for the
-// dynamic symbol table. The table shows number of hash buckets for different
-// lengths of chains as absolute number and percentage of the total buckets.
-// Additionally cumulative coverage of symbols for each set of buckets.
template <class ELFT>
-void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
- // Print histogram for .hash section
- if (const Elf_Hash *HashTable = this->dumper()->getHashTable()) {
- size_t NBucket = HashTable->nbucket;
- size_t NChain = HashTable->nchain;
- ArrayRef<Elf_Word> Buckets = HashTable->buckets();
- ArrayRef<Elf_Word> Chains = HashTable->chains();
- size_t TotalSyms = 0;
- // If hash table is correct, we have at least chains with 0 length
- size_t MaxChain = 1;
- size_t CumulativeNonZero = 0;
-
- if (NChain == 0 || NBucket == 0)
- return;
+void GNUStyle<ELFT>::printHashHistogram(const Elf_Hash &HashTable) {
+ size_t NBucket = HashTable.nbucket;
+ size_t NChain = HashTable.nchain;
+ ArrayRef<Elf_Word> Buckets = HashTable.buckets();
+ ArrayRef<Elf_Word> Chains = HashTable.chains();
+ size_t TotalSyms = 0;
+ // If hash table is correct, we have at least chains with 0 length
+ size_t MaxChain = 1;
+ size_t CumulativeNonZero = 0;
+
+ if (NChain == 0 || NBucket == 0)
+ return;
- std::vector<size_t> ChainLen(NBucket, 0);
- // Go over all buckets and and note chain lengths of each bucket (total
- // unique chain lengths).
- for (size_t B = 0; B < NBucket; B++) {
- std::vector<bool> Visited(NChain);
- for (size_t C = Buckets[B]; C < NChain; C = Chains[C]) {
- if (C == ELF::STN_UNDEF)
- break;
- if (Visited[C]) {
- reportWarning(
- createError(".hash section is invalid: bucket " + Twine(C) +
- ": a cycle was detected in the linked chain"),
- this->FileName);
- break;
- }
- Visited[C] = true;
- if (MaxChain <= ++ChainLen[B])
- MaxChain++;
+ std::vector<size_t> ChainLen(NBucket, 0);
+ // Go over all buckets and and note chain lengths of each bucket (total
+ // unique chain lengths).
+ for (size_t B = 0; B < NBucket; B++) {
+ std::vector<bool> Visited(NChain);
+ for (size_t C = Buckets[B]; C < NChain; C = Chains[C]) {
+ if (C == ELF::STN_UNDEF)
+ break;
+ if (Visited[C]) {
+ reportWarning(createError(".hash section is invalid: bucket " +
+ Twine(C) +
+ ": a cycle was detected in the linked chain"),
+ this->FileName);
+ break;
}
- TotalSyms += ChainLen[B];
+ Visited[C] = true;
+ if (MaxChain <= ++ChainLen[B])
+ MaxChain++;
}
+ TotalSyms += ChainLen[B];
+ }
- if (!TotalSyms)
- return;
+ if (!TotalSyms)
+ return;
- std::vector<size_t> Count(MaxChain, 0) ;
- // Count how long is the chain for each bucket
- for (size_t B = 0; B < NBucket; B++)
- ++Count[ChainLen[B]];
- // Print Number of buckets with each chain lengths and their cumulative
- // coverage of the symbols
- OS << "Histogram for bucket list length (total of " << NBucket
- << " buckets)\n"
- << " Length Number % of total Coverage\n";
- for (size_t I = 0; I < MaxChain; I++) {
- CumulativeNonZero += Count[I] * I;
- OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I],
- (Count[I] * 100.0) / NBucket,
- (CumulativeNonZero * 100.0) / TotalSyms);
- }
+ std::vector<size_t> Count(MaxChain, 0);
+ // Count how long is the chain for each bucket
+ for (size_t B = 0; B < NBucket; B++)
+ ++Count[ChainLen[B]];
+ // Print Number of buckets with each chain lengths and their cumulative
+ // coverage of the symbols
+ OS << "Histogram for bucket list length (total of " << NBucket
+ << " buckets)\n"
+ << " Length Number % of total Coverage\n";
+ for (size_t I = 0; I < MaxChain; I++) {
+ CumulativeNonZero += Count[I] * I;
+ OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I],
+ (Count[I] * 100.0) / NBucket,
+ (CumulativeNonZero * 100.0) / TotalSyms);
}
+}
- // Print histogram for .gnu.hash section
- if (const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable()) {
- size_t NBucket = GnuHashTable->nbuckets;
- ArrayRef<Elf_Word> Buckets = GnuHashTable->buckets();
- unsigned NumSyms = this->dumper()->dynamic_symbols().size();
- if (!NumSyms)
- return;
- ArrayRef<Elf_Word> Chains = GnuHashTable->values(NumSyms);
- size_t Symndx = GnuHashTable->symndx;
- size_t TotalSyms = 0;
- size_t MaxChain = 1;
- size_t CumulativeNonZero = 0;
+template <class ELFT>
+void GNUStyle<ELFT>::printGnuHashHistogram(const Elf_GnuHash &GnuHashTable) {
+ Expected<ArrayRef<Elf_Word>> ChainsOrErr = getGnuHashTableChains<ELFT>(
+ this->dumper()->getDynSymRegion(), &GnuHashTable);
+ if (!ChainsOrErr) {
+ this->reportUniqueWarning(
+ createError("unable to print the GNU hash table histogram: " +
+ toString(ChainsOrErr.takeError())));
+ return;
+ }
- if (Chains.empty() || NBucket == 0)
- return;
+ ArrayRef<Elf_Word> Chains = *ChainsOrErr;
+ size_t Symndx = GnuHashTable.symndx;
+ size_t TotalSyms = 0;
+ size_t MaxChain = 1;
+ size_t CumulativeNonZero = 0;
- std::vector<size_t> ChainLen(NBucket, 0);
+ size_t NBucket = GnuHashTable.nbuckets;
+ if (Chains.empty() || NBucket == 0)
+ return;
- for (size_t B = 0; B < NBucket; B++) {
- if (!Buckets[B])
- continue;
- size_t Len = 1;
- for (size_t C = Buckets[B] - Symndx;
- C < Chains.size() && (Chains[C] & 1) == 0; C++)
- if (MaxChain < ++Len)
- MaxChain++;
- ChainLen[B] = Len;
- TotalSyms += Len;
- }
- MaxChain++;
+ ArrayRef<Elf_Word> Buckets = GnuHashTable.buckets();
+ std::vector<size_t> ChainLen(NBucket, 0);
+ for (size_t B = 0; B < NBucket; B++) {
+ if (!Buckets[B])
+ continue;
+ size_t Len = 1;
+ for (size_t C = Buckets[B] - Symndx;
+ C < Chains.size() && (Chains[C] & 1) == 0; C++)
+ if (MaxChain < ++Len)
+ MaxChain++;
+ ChainLen[B] = Len;
+ TotalSyms += Len;
+ }
+ MaxChain++;
- if (!TotalSyms)
- return;
+ if (!TotalSyms)
+ return;
- std::vector<size_t> Count(MaxChain, 0) ;
- for (size_t B = 0; B < NBucket; B++)
- ++Count[ChainLen[B]];
- // Print Number of buckets with each chain lengths and their cumulative
- // coverage of the symbols
- OS << "Histogram for `.gnu.hash' bucket list length (total of " << NBucket
- << " buckets)\n"
- << " Length Number % of total Coverage\n";
- for (size_t I = 0; I <MaxChain; I++) {
- CumulativeNonZero += Count[I] * I;
- OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I],
- (Count[I] * 100.0) / NBucket,
- (CumulativeNonZero * 100.0) / TotalSyms);
- }
+ std::vector<size_t> Count(MaxChain, 0);
+ for (size_t B = 0; B < NBucket; B++)
+ ++Count[ChainLen[B]];
+ // Print Number of buckets with each chain lengths and their cumulative
+ // coverage of the symbols
+ OS << "Histogram for `.gnu.hash' bucket list length (total of " << NBucket
+ << " buckets)\n"
+ << " Length Number % of total Coverage\n";
+ for (size_t I = 0; I < MaxChain; I++) {
+ CumulativeNonZero += Count[I] * I;
+ OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I],
+ (Count[I] * 100.0) / NBucket,
+ (CumulativeNonZero * 100.0) / TotalSyms);
+ }
+}
+
+// Hash histogram shows statistics of how efficient the hash was for the
+// dynamic symbol table. The table shows the number of hash buckets for
+// different lengths of chains as an absolute number and percentage of the total
+// buckets, and the cumulative coverage of symbols for each set of buckets.
+template <class ELFT>
+void GNUStyle<ELFT>::printHashHistograms(const ELFFile<ELFT> *Obj) {
+ // Print histogram for the .hash section.
+ if (const Elf_Hash *HashTable = this->dumper()->getHashTable()) {
+ if (Error E = checkHashTable<ELFT>(Obj, HashTable))
+ this->reportUniqueWarning(std::move(E));
+ else
+ printHashHistogram(*HashTable);
+ }
+
+ // Print histogram for the .gnu.hash section.
+ if (const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable()) {
+ if (Error E = checkGNUHashTable<ELFT>(Obj, GnuHashTable))
+ this->reportUniqueWarning(std::move(E));
+ else
+ printGnuHashHistogram(*GnuHashTable);
}
}
@@ -4713,7 +5271,7 @@ template <typename ELFT> static GNUAbiTag getGNUAbiTag(ArrayRef<uint8_t> Desc) {
std::string str;
raw_string_ostream ABI(str);
ABI << Major << "." << Minor << "." << Patch;
- return {OSName, ABI.str(), /*IsValid=*/true};
+ return {std::string(OSName), ABI.str(), /*IsValid=*/true};
}
static std::string getGNUBuildId(ArrayRef<uint8_t> Desc) {
@@ -4883,11 +5441,18 @@ static void printCoreNote(raw_ostream &OS, const CoreNote &Note) {
template <class ELFT>
void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
- auto PrintHeader = [&](const typename ELFT::Off Offset,
+ auto PrintHeader = [&](Optional<StringRef> SecName,
+ const typename ELFT::Off Offset,
const typename ELFT::Addr Size) {
- OS << "Displaying notes found at file offset " << format_hex(Offset, 10)
- << " with length " << format_hex(Size, 10) << ":\n"
- << " Owner Data size \tDescription\n";
+ OS << "Displaying notes found ";
+
+ if (SecName)
+ OS << "in: " << *SecName << "\n";
+ else
+ OS << "at file offset " << format_hex(Offset, 10) << " with length "
+ << format_hex(Size, 10) << ":\n";
+
+ OS << " Owner Data size \tDescription\n";
};
auto ProcessNote = [&](const Elf_Note &Note) {
@@ -4947,12 +5512,13 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
}
};
- ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections());
+ ArrayRef<Elf_Shdr> Sections = cantFail(Obj->sections());
if (Obj->getHeader()->e_type != ELF::ET_CORE && !Sections.empty()) {
for (const auto &S : Sections) {
if (S.sh_type != SHT_NOTE)
continue;
- PrintHeader(S.sh_offset, S.sh_size);
+ PrintHeader(expectedToOptional(Obj->getSectionName(&S)), S.sh_offset,
+ S.sh_size);
Error Err = Error::success();
for (auto Note : Obj->notes(S, Err))
ProcessNote(Note);
@@ -4960,11 +5526,18 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
reportError(std::move(Err), this->FileName);
}
} else {
- for (const auto &P :
- unwrapOrError(this->FileName, Obj->program_headers())) {
+ Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers();
+ if (!PhdrsOrErr) {
+ this->reportUniqueWarning(createError(
+ "unable to read program headers to locate the PT_NOTE segment: " +
+ toString(PhdrsOrErr.takeError())));
+ return;
+ }
+
+ for (const Elf_Phdr &P : *PhdrsOrErr) {
if (P.p_type != PT_NOTE)
continue;
- PrintHeader(P.p_offset, P.p_filesz);
+ PrintHeader(/*SecName=*/None, P.p_offset, P.p_filesz);
Error Err = Error::success();
for (auto Note : Obj->notes(P, Err))
ProcessNote(Note);
@@ -4980,8 +5553,87 @@ void GNUStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) {
}
template <class ELFT>
+void DumpStyle<ELFT>::printDependentLibsHelper(
+ const ELFFile<ELFT> *Obj,
+ function_ref<void(const Elf_Shdr &)> OnSectionStart,
+ function_ref<void(StringRef, uint64_t)> OnLibEntry) {
+ auto Warn = [this](unsigned SecNdx, StringRef Msg) {
+ this->reportUniqueWarning(
+ createError("SHT_LLVM_DEPENDENT_LIBRARIES section at index " +
+ Twine(SecNdx) + " is broken: " + Msg));
+ };
+
+ unsigned I = -1;
+ for (const Elf_Shdr &Shdr : cantFail(Obj->sections())) {
+ ++I;
+ if (Shdr.sh_type != ELF::SHT_LLVM_DEPENDENT_LIBRARIES)
+ continue;
+
+ OnSectionStart(Shdr);
+
+ Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(&Shdr);
+ if (!ContentsOrErr) {
+ Warn(I, toString(ContentsOrErr.takeError()));
+ continue;
+ }
+
+ ArrayRef<uint8_t> Contents = *ContentsOrErr;
+ if (!Contents.empty() && Contents.back() != 0) {
+ Warn(I, "the content is not null-terminated");
+ continue;
+ }
+
+ for (const uint8_t *I = Contents.begin(), *E = Contents.end(); I < E;) {
+ StringRef Lib((const char *)I);
+ OnLibEntry(Lib, I - Contents.begin());
+ I += Lib.size() + 1;
+ }
+ }
+}
+
+template <class ELFT>
void GNUStyle<ELFT>::printDependentLibs(const ELFFile<ELFT> *Obj) {
- OS << "printDependentLibs not implemented!\n";
+ bool SectionStarted = false;
+ struct NameOffset {
+ StringRef Name;
+ uint64_t Offset;
+ };
+ std::vector<NameOffset> SecEntries;
+ NameOffset Current;
+ auto PrintSection = [&]() {
+ OS << "Dependent libraries section " << Current.Name << " at offset "
+ << format_hex(Current.Offset, 1) << " contains " << SecEntries.size()
+ << " entries:\n";
+ for (NameOffset Entry : SecEntries)
+ OS << " [" << format("%6tx", Entry.Offset) << "] " << Entry.Name
+ << "\n";
+ OS << "\n";
+ SecEntries.clear();
+ };
+
+ auto OnSectionStart = [&](const Elf_Shdr &Shdr) {
+ if (SectionStarted)
+ PrintSection();
+ SectionStarted = true;
+ Current.Offset = Shdr.sh_offset;
+ Expected<StringRef> Name = Obj->getSectionName(&Shdr);
+ if (!Name) {
+ Current.Name = "<?>";
+ this->reportUniqueWarning(
+ createError("cannot get section name of "
+ "SHT_LLVM_DEPENDENT_LIBRARIES section: " +
+ toString(Name.takeError())));
+ } else {
+ Current.Name = *Name;
+ }
+ };
+ auto OnLibEntry = [&](StringRef Lib, uint64_t Offset) {
+ SecEntries.push_back(NameOffset{Lib, Offset});
+ };
+
+ this->printDependentLibsHelper(Obj, OnSectionStart, OnLibEntry);
+ if (SectionStarted)
+ PrintSection();
}
// Used for printing section names in places where possible errors can be
@@ -5005,9 +5657,12 @@ static std::string getSymbolName(const ELFSymbolRef &Sym) {
}
template <class ELFT>
-void DumpStyle<ELFT>::printFunctionStackSize(
- const ELFObjectFile<ELFT> *Obj, uint64_t SymValue, SectionRef FunctionSec,
- const StringRef SectionName, DataExtractor Data, uint64_t *Offset) {
+void DumpStyle<ELFT>::printFunctionStackSize(const ELFObjectFile<ELFT> *Obj,
+ uint64_t SymValue,
+ Optional<SectionRef> FunctionSec,
+ const StringRef SectionName,
+ DataExtractor Data,
+ uint64_t *Offset) {
// This function ignores potentially erroneous input, unless it is directly
// related to stack size reporting.
SymbolRef FuncSym;
@@ -5017,9 +5672,15 @@ void DumpStyle<ELFT>::printFunctionStackSize(
consumeError(SymAddrOrErr.takeError());
continue;
}
+ if (Expected<uint32_t> SymFlags = Symbol.getFlags()) {
+ if (*SymFlags & SymbolRef::SF_Undefined)
+ continue;
+ } else
+ consumeError(SymFlags.takeError());
if (Symbol.getELFType() == ELF::STT_FUNC && *SymAddrOrErr == SymValue) {
- // Check if the symbol is in the right section.
- if (FunctionSec.containsSymbol(Symbol)) {
+ // Check if the symbol is in the right section. FunctionSec == None means
+ // "any section".
+ if (!FunctionSec || FunctionSec->containsSymbol(Symbol)) {
FuncSym = Symbol;
break;
}
@@ -5130,11 +5791,6 @@ void DumpStyle<ELFT>::printNonRelocatableStackSizes(
ArrayRef<uint8_t> Contents =
unwrapOrError(this->FileName, EF->getSectionContents(ElfSec));
DataExtractor Data(Contents, Obj->isLittleEndian(), sizeof(Elf_Addr));
- // 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 Elf_Shdr *FunctionELFSec =
- unwrapOrError(this->FileName, EF->getSection(ElfSec->sh_link));
uint64_t Offset = 0;
while (Offset < Contents.size()) {
// The function address is followed by a ULEB representing the stack
@@ -5148,8 +5804,8 @@ void DumpStyle<ELFT>::printNonRelocatableStackSizes(
FileStr);
}
uint64_t SymValue = Data.getAddress(&Offset);
- printFunctionStackSize(Obj, SymValue, Obj->toSectionRef(FunctionELFSec),
- SectionName, Data, &Offset);
+ printFunctionStackSize(Obj, SymValue, /*FunctionSec=*/None, SectionName,
+ Data, &Offset);
}
}
}
@@ -5532,7 +6188,7 @@ template <class ELFT> void LLVMStyle<ELFT>::printRelocations(const ELFO *Obj) {
ListScope D(W, "Relocations");
int SectionNumber = -1;
- for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) {
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
++SectionNumber;
if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA &&
@@ -5557,6 +6213,8 @@ template <class ELFT>
void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) {
const Elf_Shdr *SymTab =
unwrapOrError(this->FileName, Obj->getSection(Sec->sh_link));
+ unsigned SecNdx = Sec - &cantFail(Obj->sections()).front();
+ unsigned RelNdx = 0;
switch (Sec->sh_type) {
case ELF::SHT_REL:
@@ -5565,12 +6223,12 @@ void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) {
Rela.r_offset = R.r_offset;
Rela.r_info = R.r_info;
Rela.r_addend = 0;
- printRelocation(Obj, Rela, SymTab);
+ printRelocation(Obj, SecNdx, Rela, ++RelNdx, SymTab);
}
break;
case ELF::SHT_RELA:
for (const Elf_Rela &R : unwrapOrError(this->FileName, Obj->relas(Sec)))
- printRelocation(Obj, R, SymTab);
+ printRelocation(Obj, SecNdx, R, ++RelNdx, SymTab);
break;
case ELF::SHT_RELR:
case ELF::SHT_ANDROID_RELR: {
@@ -5582,7 +6240,7 @@ void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) {
std::vector<Elf_Rela> RelrRelas =
unwrapOrError(this->FileName, Obj->decode_relrs(Relrs));
for (const Elf_Rela &R : RelrRelas)
- printRelocation(Obj, R, SymTab);
+ printRelocation(Obj, SecNdx, R, ++RelNdx, SymTab);
}
break;
}
@@ -5590,30 +6248,27 @@ void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) {
case ELF::SHT_ANDROID_RELA:
for (const Elf_Rela &R :
unwrapOrError(this->FileName, Obj->android_relas(Sec)))
- printRelocation(Obj, R, SymTab);
+ printRelocation(Obj, SecNdx, R, ++RelNdx, SymTab);
break;
}
}
template <class ELFT>
-void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, Elf_Rela Rel,
+void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, unsigned SecIndex,
+ Elf_Rela Rel, unsigned RelIndex,
const Elf_Shdr *SymTab) {
+ Expected<std::pair<const typename ELFT::Sym *, std::string>> Target =
+ this->dumper()->getRelocationTarget(SymTab, Rel);
+ if (!Target) {
+ this->reportUniqueWarning(createError(
+ "unable to print relocation " + Twine(RelIndex) + " in section " +
+ Twine(SecIndex) + ": " + toString(Target.takeError())));
+ return;
+ }
+
+ std::string TargetName = Target->second;
SmallString<32> RelocName;
Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName);
- std::string TargetName;
- const Elf_Sym *Sym =
- unwrapOrError(this->FileName, Obj->getRelocationSymbol(&Rel, SymTab));
- if (Sym && Sym->getType() == ELF::STT_SECTION) {
- const Elf_Shdr *Sec = unwrapOrError(
- this->FileName,
- Obj->getSection(Sym, SymTab, this->dumper()->getShndxTable()));
- TargetName = unwrapOrError(this->FileName, Obj->getSectionName(Sec));
- } else if (Sym) {
- StringRef StrTable =
- unwrapOrError(this->FileName, Obj->getStringTableForSymtab(*SymTab));
- TargetName = this->dumper()->getFullSymbolName(
- Sym, StrTable, SymTab->sh_type == SHT_DYNSYM /* IsDynamic */);
- }
if (opts::ExpandRelocs) {
DictScope Group(W, "Relocation");
@@ -5635,13 +6290,16 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
ListScope SectionsD(W, "Sections");
int SectionIndex = -1;
- ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections());
- const ELFObjectFile<ELFT> *ElfObj = this->dumper()->getElfObject();
std::vector<EnumEntry<unsigned>> FlagsList =
getSectionFlagsForTarget(Obj->getHeader()->e_machine);
- for (const Elf_Shdr &Sec : Sections) {
- StringRef Name = unwrapOrError(
- ElfObj->getFileName(), Obj->getSectionName(&Sec, this->WarningHandler));
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
+ StringRef Name = "<?>";
+ if (Expected<StringRef> SecNameOrErr =
+ Obj->getSectionName(&Sec, this->dumper()->WarningHandler))
+ Name = *SecNameOrErr;
+ else
+ this->reportUniqueWarning(SecNameOrErr.takeError());
+
DictScope SectionD(W, "Section");
W.printNumber("Index", ++SectionIndex);
W.printNumber("Name", Name, Sec.sh_name);
@@ -5709,7 +6367,12 @@ void LLVMStyle<ELFT>::printSymbolSection(const Elf_Sym *Symbol,
Expected<StringRef> SectionName =
this->dumper()->getSymbolSectionName(Symbol, *SectionIndex);
if (!SectionName) {
- this->reportUniqueWarning(SectionName.takeError());
+ // Don't report an invalid section name if the section headers are missing.
+ // In such situations, all sections will be "invalid".
+ if (!this->dumper()->getElfObject()->sections().empty())
+ this->reportUniqueWarning(SectionName.takeError());
+ else
+ consumeError(SectionName.takeError());
W.printHex("Section", "<?>", *SectionIndex);
} else {
W.printHex("Section", *SectionName, *SectionIndex);
@@ -5718,8 +6381,8 @@ void LLVMStyle<ELFT>::printSymbolSection(const Elf_Sym *Symbol,
template <class ELFT>
void LLVMStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
- const Elf_Sym *First, StringRef StrTable,
- bool IsDynamic,
+ const Elf_Sym *First,
+ Optional<StringRef> StrTable, bool IsDynamic,
bool /*NonVisibilityBitsUsed*/) {
std::string FullSymbolName =
this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic);
@@ -5785,20 +6448,24 @@ template <class ELFT> void LLVMStyle<ELFT>::printDynamic(const ELFFile<ELFT> *Ob
if (Table.empty())
return;
- raw_ostream &OS = W.getOStream();
W.startLine() << "DynamicSection [ (" << Table.size() << " entries)\n";
- bool Is64 = ELFT::Is64Bits;
- if (Is64)
- W.startLine() << " Tag Type Name/Value\n";
- else
- W.startLine() << " Tag Type Name/Value\n";
+ size_t MaxTagSize = getMaxDynamicTagSize(Obj, Table);
+ // The "Name/Value" column should be indented from the "Type" column by N
+ // spaces, where N = MaxTagSize - length of "Type" (4) + trailing
+ // space (1) = -3.
+ W.startLine() << " Tag" << std::string(ELFT::Is64Bits ? 16 : 8, ' ')
+ << "Type" << std::string(MaxTagSize - 3, ' ') << "Name/Value\n";
+
+ std::string ValueFmt = "%-" + std::to_string(MaxTagSize) + "s ";
for (auto Entry : Table) {
uintX_t Tag = Entry.getTag();
- W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, true) << " "
- << format("%-21s", Obj->getDynamicTagAsString(Tag).c_str());
- this->dumper()->printDynamicEntry(OS, Tag, Entry.getVal());
- OS << "\n";
+ std::string Value = this->dumper()->getDynamicEntry(Tag, Entry.getVal());
+ W.startLine() << " " << format_hex(Tag, ELFT::Is64Bits ? 18 : 10, true)
+ << " "
+ << format(ValueFmt.c_str(),
+ Obj->getDynamicTagAsString(Tag).c_str())
+ << Value << "\n";
}
W.startLine() << "]\n";
}
@@ -5809,14 +6476,14 @@ void LLVMStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
const DynRegionInfo &DynRelaRegion = this->dumper()->getDynRelaRegion();
const DynRegionInfo &DynRelrRegion = this->dumper()->getDynRelrRegion();
const DynRegionInfo &DynPLTRelRegion = this->dumper()->getDynPLTRelRegion();
- if (DynRelRegion.Size && DynRelaRegion.Size)
- report_fatal_error("There are both REL and RELA dynamic relocations");
+
W.startLine() << "Dynamic Relocations {\n";
W.indent();
- if (DynRelaRegion.Size > 0)
+ if (DynRelaRegion.Size > 0) {
for (const Elf_Rela &Rela : this->dumper()->dyn_relas())
printDynamicRelocation(Obj, Rela);
- else
+ }
+ if (DynRelRegion.Size > 0) {
for (const Elf_Rel &Rel : this->dumper()->dyn_rels()) {
Elf_Rela Rela;
Rela.r_offset = Rel.r_offset;
@@ -5824,6 +6491,8 @@ void LLVMStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
Rela.r_addend = 0;
printDynamicRelocation(Obj, Rela);
}
+ }
+
if (DynRelrRegion.Size > 0) {
Elf_Relr_Range Relrs = this->dumper()->dyn_relrs();
std::vector<Elf_Rela> RelrRelas =
@@ -5881,8 +6550,14 @@ template <class ELFT>
void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
ListScope L(W, "ProgramHeaders");
- for (const Elf_Phdr &Phdr :
- unwrapOrError(this->FileName, Obj->program_headers())) {
+ Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers();
+ if (!PhdrsOrErr) {
+ this->reportUniqueWarning(createError("unable to dump program headers: " +
+ toString(PhdrsOrErr.takeError())));
+ return;
+ }
+
+ for (const Elf_Phdr &Phdr : *PhdrsOrErr) {
DictScope P(W, "ProgramHeader");
W.printHex("Type",
getElfSegmentType(Obj->getHeader()->e_machine, Phdr.p_type),
@@ -5982,7 +6657,7 @@ void LLVMStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
}
template <class ELFT>
-void LLVMStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
+void LLVMStyle<ELFT>::printHashHistograms(const ELFFile<ELFT> *Obj) {
W.startLine() << "Hash Histogram not implemented!\n";
}
@@ -5991,21 +6666,23 @@ void LLVMStyle<ELFT>::printCGProfile(const ELFFile<ELFT> *Obj) {
ListScope L(W, "CGProfile");
if (!this->dumper()->getDotCGProfileSec())
return;
- auto CGProfile = unwrapOrError(
- this->FileName, Obj->template getSectionContentsAsArray<Elf_CGProfile>(
- this->dumper()->getDotCGProfileSec()));
- for (const Elf_CGProfile &CGPE : CGProfile) {
+
+ Expected<ArrayRef<Elf_CGProfile>> CGProfileOrErr =
+ Obj->template getSectionContentsAsArray<Elf_CGProfile>(
+ this->dumper()->getDotCGProfileSec());
+ if (!CGProfileOrErr) {
+ this->reportUniqueWarning(
+ createError("unable to dump the SHT_LLVM_CALL_GRAPH_PROFILE section: " +
+ toString(CGProfileOrErr.takeError())));
+ return;
+ }
+
+ for (const Elf_CGProfile &CGPE : *CGProfileOrErr) {
DictScope D(W, "CGProfileEntry");
- W.printNumber(
- "From",
- unwrapOrError(this->FileName,
- this->dumper()->getStaticSymbolName(CGPE.cgp_from)),
- CGPE.cgp_from);
- W.printNumber(
- "To",
- unwrapOrError(this->FileName,
- this->dumper()->getStaticSymbolName(CGPE.cgp_to)),
- CGPE.cgp_to);
+ W.printNumber("From", this->dumper()->getStaticSymbolName(CGPE.cgp_from),
+ CGPE.cgp_from);
+ W.printNumber("To", this->dumper()->getStaticSymbolName(CGPE.cgp_to),
+ CGPE.cgp_to);
W.printNumber("Weight", CGPE.cgp_weight);
}
}
@@ -6096,8 +6773,10 @@ template <class ELFT>
void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
ListScope L(W, "Notes");
- auto PrintHeader = [&](const typename ELFT::Off Offset,
+ auto PrintHeader = [&](Optional<StringRef> SecName,
+ const typename ELFT::Off Offset,
const typename ELFT::Addr Size) {
+ W.printString("Name", SecName ? *SecName : "<?>");
W.printHex("Offset", Offset);
W.printHex("Size", Size);
};
@@ -6158,13 +6837,14 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
}
};
- ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections());
+ ArrayRef<Elf_Shdr> Sections = cantFail(Obj->sections());
if (Obj->getHeader()->e_type != ELF::ET_CORE && !Sections.empty()) {
for (const auto &S : Sections) {
if (S.sh_type != SHT_NOTE)
continue;
DictScope D(W, "NoteSection");
- PrintHeader(S.sh_offset, S.sh_size);
+ PrintHeader(expectedToOptional(Obj->getSectionName(&S)), S.sh_offset,
+ S.sh_size);
Error Err = Error::success();
for (auto Note : Obj->notes(S, Err))
ProcessNote(Note);
@@ -6172,12 +6852,19 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
reportError(std::move(Err), this->FileName);
}
} else {
- for (const auto &P :
- unwrapOrError(this->FileName, Obj->program_headers())) {
+ Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers();
+ if (!PhdrsOrErr) {
+ this->reportUniqueWarning(createError(
+ "unable to read program headers to locate the PT_NOTE segment: " +
+ toString(PhdrsOrErr.takeError())));
+ return;
+ }
+
+ for (const Elf_Phdr &P : *PhdrsOrErr) {
if (P.p_type != PT_NOTE)
continue;
DictScope D(W, "NoteSection");
- PrintHeader(P.p_offset, P.p_filesz);
+ PrintHeader(/*SecName=*/None, P.p_offset, P.p_filesz);
Error Err = Error::success();
for (auto Note : Obj->notes(P, Err))
ProcessNote(Note);
@@ -6192,35 +6879,38 @@ void LLVMStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) {
ListScope L(W, "LinkerOptions");
unsigned I = -1;
- for (const Elf_Shdr &Shdr : unwrapOrError(this->FileName, Obj->sections())) {
+ for (const Elf_Shdr &Shdr : cantFail(Obj->sections())) {
++I;
if (Shdr.sh_type != ELF::SHT_LLVM_LINKER_OPTIONS)
continue;
- ArrayRef<uint8_t> Contents =
- unwrapOrError(this->FileName, Obj->getSectionContents(&Shdr));
- if (Contents.empty())
+ Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(&Shdr);
+ if (!ContentsOrErr) {
+ this->reportUniqueWarning(
+ createError("unable to read the content of the "
+ "SHT_LLVM_LINKER_OPTIONS section: " +
+ toString(ContentsOrErr.takeError())));
+ continue;
+ }
+ if (ContentsOrErr->empty())
continue;
- if (Contents.back() != 0) {
- reportWarning(createError("SHT_LLVM_LINKER_OPTIONS section at index " +
- Twine(I) +
- " is broken: the "
- "content is not null-terminated"),
- this->FileName);
+ if (ContentsOrErr->back() != 0) {
+ this->reportUniqueWarning(
+ createError("SHT_LLVM_LINKER_OPTIONS section at index " + Twine(I) +
+ " is broken: the "
+ "content is not null-terminated"));
continue;
}
SmallVector<StringRef, 16> Strings;
- toStringRef(Contents.drop_back()).split(Strings, '\0');
+ toStringRef(ContentsOrErr->drop_back()).split(Strings, '\0');
if (Strings.size() % 2 != 0) {
- reportWarning(
- createError(
- "SHT_LLVM_LINKER_OPTIONS section at index " + Twine(I) +
- " is broken: an incomplete "
- "key-value pair was found. The last possible key was: \"" +
- Strings.back() + "\""),
- this->FileName);
+ this->reportUniqueWarning(createError(
+ "SHT_LLVM_LINKER_OPTIONS section at index " + Twine(I) +
+ " is broken: an incomplete "
+ "key-value pair was found. The last possible key was: \"" +
+ Strings.back() + "\""));
continue;
}
@@ -6232,37 +6922,9 @@ void LLVMStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) {
template <class ELFT>
void LLVMStyle<ELFT>::printDependentLibs(const ELFFile<ELFT> *Obj) {
ListScope L(W, "DependentLibs");
-
- auto Warn = [this](unsigned SecNdx, StringRef Msg) {
- this->reportUniqueWarning(
- createError("SHT_LLVM_DEPENDENT_LIBRARIES section at index " +
- Twine(SecNdx) + " is broken: " + Msg));
- };
-
- unsigned I = -1;
- for (const Elf_Shdr &Shdr : unwrapOrError(this->FileName, Obj->sections())) {
- ++I;
- if (Shdr.sh_type != ELF::SHT_LLVM_DEPENDENT_LIBRARIES)
- continue;
-
- Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(&Shdr);
- if (!ContentsOrErr) {
- Warn(I, toString(ContentsOrErr.takeError()));
- continue;
- }
-
- ArrayRef<uint8_t> Contents = *ContentsOrErr;
- if (!Contents.empty() && Contents.back() != 0) {
- Warn(I, "the content is not null-terminated");
- continue;
- }
-
- for (const uint8_t *I = Contents.begin(), *E = Contents.end(); I < E;) {
- StringRef Lib((const char *)I);
- W.printString(Lib);
- I += Lib.size() + 1;
- }
- }
+ this->printDependentLibsHelper(
+ Obj, [](const Elf_Shdr &) {},
+ [this](StringRef Lib, uint64_t) { W.printString(Lib); });
}
template <class ELFT>