diff options
author | George Rimar <grimar@accesssoftek.com> | 2019-05-20 15:41:48 +0000 |
---|---|---|
committer | George Rimar <grimar@accesssoftek.com> | 2019-05-20 15:41:48 +0000 |
commit | 72f821d3de05448e71bff7b39d3e4993c447882a (patch) | |
tree | 1eb6c4cca48be0b0a5210287c229fb1013e66754 /llvm/tools/llvm-readobj | |
parent | 055906e1e50ddc35d6c8cdccab48ed83e93b47eb (diff) | |
download | bcm5719-llvm-72f821d3de05448e71bff7b39d3e4993c447882a.tar.gz bcm5719-llvm-72f821d3de05448e71bff7b39d3e4993c447882a.zip |
[llvm-readelf] - Rework how we parse the .dynamic section.
This is a result of what I found during my work on https://bugs.llvm.org/show_bug.cgi?id=41679.
Previously LLVM readelf took the information about .dynamic section
from its PT_DYNAMIC segment only. GNU tools have a bit different logic.
They also use the information from the .dynamic section header if it is available.
This patch changes the code to improve the compatibility with the GNU Binutils.
Differential revision: https://reviews.llvm.org/D61937
llvm-svn: 361165
Diffstat (limited to 'llvm/tools/llvm-readobj')
-rw-r--r-- | llvm/tools/llvm-readobj/ELFDumper.cpp | 80 | ||||
-rw-r--r-- | llvm/tools/llvm-readobj/llvm-readobj.cpp | 5 | ||||
-rw-r--r-- | llvm/tools/llvm-readobj/llvm-readobj.h | 1 |
3 files changed, 71 insertions, 15 deletions
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 75579879762..65abdbd6109 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -203,7 +203,8 @@ private: {ObjF->getELFFile()->base() + S->sh_offset, S->sh_size, S->sh_entsize}); } - void parseDynamicTable(ArrayRef<const Elf_Phdr *> LoadSegments); + void loadDynamicTable(const ELFFile<ELFT> *Obj); + void parseDynamicTable(); void printValue(uint64_t Type, uint64_t Value); @@ -1329,21 +1330,72 @@ static const char *getElfMipsOptionsOdkType(unsigned Odk) { } template <typename ELFT> -ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, - ScopedPrinter &Writer) - : ObjDumper(Writer), ObjF(ObjF) { - SmallVector<const Elf_Phdr *, 4> LoadSegments; - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); +void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) { + const Elf_Phdr *DynamicPhdr = nullptr; for (const Elf_Phdr &Phdr : unwrapOrError(Obj->program_headers())) { - if (Phdr.p_type == ELF::PT_DYNAMIC) { - DynamicTable = createDRIFrom(&Phdr, sizeof(Elf_Dyn)); + if (Phdr.p_type != ELF::PT_DYNAMIC) continue; - } - if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0) + DynamicPhdr = &Phdr; + break; + } + + // We do not want to dump dynamic section if we have no PT_DYNAMIC header. + // This matches GNU's behavior. + if (!DynamicPhdr) + return; + + // Try to locate the .dynamic section in the sections header table. + const Elf_Shdr *DynamicSec = nullptr; + for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { + if (Sec.sh_type != ELF::SHT_DYNAMIC) continue; - LoadSegments.push_back(&Phdr); + DynamicSec = &Sec; + break; } + // Information in the section header has priority over the information + // in a PT_DYNAMIC header. + // Ignore sh_entsize and use the expected value for entry size explicitly. + // This allows us to dump the dynamic sections with a broken sh_entsize + // field. + if (DynamicSec) + DynamicTable = checkDRI({ObjF->getELFFile()->base() + DynamicSec->sh_offset, + DynamicSec->sh_size, sizeof(Elf_Dyn)}); + + if (DynamicPhdr->p_offset + DynamicPhdr->p_filesz > + ObjF->getMemoryBufferRef().getBufferSize()) + reportError( + "PT_DYNAMIC segment offset + size exceeds the size of the file"); + + if (!DynamicSec) { + DynamicTable = createDRIFrom(DynamicPhdr, sizeof(Elf_Dyn)); + parseDynamicTable(); + return; + } + + StringRef Name = unwrapOrError(Obj->getSectionName(DynamicSec)); + + if (DynamicSec->sh_addr + DynamicSec->sh_size > + DynamicPhdr->p_vaddr + DynamicPhdr->p_memsz || + DynamicSec->sh_addr < DynamicPhdr->p_vaddr) + reportWarning("The SHT_DYNAMIC section '" + Name + + "' is not contained within the " + "PT_DYNAMIC segment"); + + if (DynamicSec->sh_addr != DynamicPhdr->p_vaddr) + reportWarning("The SHT_DYNAMIC section '" + Name + + "' is not at the start of " + "PT_DYNAMIC segment"); + + parseDynamicTable(); +} + +template <typename ELFT> +ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, + ScopedPrinter &Writer) + : ObjDumper(Writer), ObjF(ObjF) { + const ELFFile<ELFT> *Obj = ObjF->getELFFile(); + for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { switch (Sec.sh_type) { case ELF::SHT_SYMTAB: @@ -1390,7 +1442,7 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, } } - parseDynamicTable(LoadSegments); + loadDynamicTable(Obj); if (opts::Output == opts::GNU) ELFDumperStyle.reset(new GNUStyle<ELFT>(Writer, this)); @@ -1398,9 +1450,7 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, ELFDumperStyle.reset(new LLVMStyle<ELFT>(Writer, this)); } -template <typename ELFT> -void ELFDumper<ELFT>::parseDynamicTable( - ArrayRef<const Elf_Phdr *> LoadSegments) { +template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() { auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * { auto MappedAddrOrError = ObjF->getELFFile()->toMappedAddr(VAddr); if (!MappedAddrOrError) diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp index e8cea5a7fff..1836e0fd0d7 100644 --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -373,6 +373,11 @@ LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) { exit(1); } +void reportWarning(Twine Msg) { + errs() << "\n"; + WithColor::warning(errs()) << Msg << "\n"; +} + void error(Error EC) { if (!EC) return; diff --git a/llvm/tools/llvm-readobj/llvm-readobj.h b/llvm/tools/llvm-readobj/llvm-readobj.h index 54318b29676..c89871fbc7e 100644 --- a/llvm/tools/llvm-readobj/llvm-readobj.h +++ b/llvm/tools/llvm-readobj/llvm-readobj.h @@ -22,6 +22,7 @@ namespace llvm { // Various helper functions. LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg); + void reportWarning(Twine Msg); void error(std::error_code EC); void error(llvm::Error EC); template <typename T> T error(llvm::Expected<T> &&E) { |