diff --git a/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test b/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test --- a/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test +++ b/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test @@ -458,8 +458,8 @@ - Tag: DT_NULL Value: 0 -## Check we report a warning when the DT_STRSZ value is broken so that the dynamic string -## table goes past the end of the file. Document we stop dumping symbols and report an error. +## Case 10: Check we report a warning when the DT_STRSZ value is broken so that the dynamic string +## table goes past the end of the file. Document we stop dumping symbols and report an error. # RUN: yaml2obj %s --docnum=13 -o %t14 # RUN: llvm-readobj --dyn-symbols %t14 2>&1 | \ @@ -539,17 +539,19 @@ - Section: .dynstr - Section: .dynamic -## Check we report a warning when the entry size of the dynamic symbol table is zero. -# RUN: yaml2obj %s --docnum=14 -o %t15 -# RUN: llvm-readobj --dyn-symbols %t15 2>&1 | FileCheck %s -DFILE=%t15 --check-prefix=DYNSYM-ZERO-ENTSIZE-LLVM -# RUN: llvm-readelf --dyn-symbols %t15 2>&1 | \ -# RUN: FileCheck %s -DFILE=%t15 --check-prefix=DYNSYM-ZERO-ENTSIZE-GNU --implicit-check-not="Symbol table" +## Case 11: check various warnings we report when fields of the SHT_DYNSYM section are broken. + +## a) check we report a warning when the entry size of the dynamic symbol table is zero. +# RUN: yaml2obj %s --docnum=14 -DENTSIZE=0x0 -o %t15.entsize +# RUN: llvm-readobj --dyn-symbols %t15.entsize 2>&1 | FileCheck %s -DFILE=%t15.entsize --check-prefix=DYNSYM-ZERO-ENTSIZE-LLVM +# RUN: llvm-readelf --dyn-symbols %t15.entsize 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t15.entsize --check-prefix=DYNSYM-ZERO-ENTSIZE-GNU --implicit-check-not="Symbol table" # DYNSYM-ZERO-ENTSIZE-LLVM: DynamicSymbols [ -# DYNSYM-ZERO-ENTSIZE-LLVM-NEXT: warning: '[[FILE]]': SHT_DYNSYM section with index 1 has invalid size (0x10) or entry size (0x0) +# DYNSYM-ZERO-ENTSIZE-LLVM-NEXT: warning: '[[FILE]]': SHT_DYNSYM section with index 1 has invalid size (0x20) or entry size (0x0) # DYNSYM-ZERO-ENTSIZE-LLVM-NEXT: ] -# DYNSYM-ZERO-ENTSIZE-GNU: warning: '[[FILE]]': SHT_DYNSYM section with index 1 has invalid size (0x10) or entry size (0x0) +# DYNSYM-ZERO-ENTSIZE-GNU: warning: '[[FILE]]': SHT_DYNSYM section with index 1 has invalid size (0x20) or entry size (0x0) --- !ELF FileHeader: @@ -557,6 +559,38 @@ Data: ELFDATA2LSB Type: ET_DYN Sections: - - Name: .dynsym - Type: SHT_DYNSYM - EntSize: 0x0 + - Name: .dynsym + Type: SHT_DYNSYM + EntSize: [[ENTSIZE=]] + ShOffset: [[OFFSET=]] + ShSize: [[SIZE=]] +DynamicSymbols: + - Name: foo + +## b) check we report a warning when the sh_offset field of the SHT_DYNSYM section is +## invalid (sh_offset + sh_size is greater than the file size). Check we don't dump +## dynamic symbols in this case. +# RUN: yaml2obj --docnum=14 %s -DOFFSET=0xffffffff -o %t15.offset +# RUN: llvm-readobj %t15.offset --dyn-symbols 2>&1 | FileCheck %s -DFILE=%t15.offset \ +# RUN: --check-prefixes=OFFSET-BROKEN,OFFSET-BROKEN-LLVM +# RUN: llvm-readelf %t15.offset --dyn-symbols 2>&1 | FileCheck %s -DFILE=%t15.offset \ +# RUN: --implicit-check-not="Symbol table" --check-prefix=OFFSET-BROKEN + +# OFFSET-BROKEN: warning: '[[FILE]]': unable to read dynamic symbols from SHT_DYNSYM section with index 1: offset (0xffffffff) + size (0x20) is greater than the file size (0x148) + +# OFFSET-BROKEN-LLVM: DynamicSymbols [ +# OFFSET-BROKEN-LLVM-NEXT: ] + +## c) check we report a warning when the sh_size field of the SHT_DYNSYM section is +## invalid (sh_offset + sh_size is greater than the file size). Check we don't dump +## dynamic symbols in this case. +# RUN: yaml2obj --docnum=14 %s -DSIZE=0xffffffff -o %t15.size +# RUN: llvm-readobj %t15.size --dyn-symbols 2>&1 | FileCheck %s -DFILE=%t15.size \ +# RUN: --check-prefixes=SIZE-BROKEN,SIZE-BROKEN-LLVM +# RUN: llvm-readelf %t15.size --dyn-symbols 2>&1 | FileCheck %s -DFILE=%t15.size \ +# RUN: --implicit-check-not="Symbol table" --check-prefix=SIZE-BROKEN + +# SIZE-BROKEN: warning: '[[FILE]]': unable to read dynamic symbols from SHT_DYNSYM section with index 1: offset (0x34) + size (0xffffffff) is greater than the file size (0x148) + +# SIZE-BROKEN-LLVM: DynamicSymbols [ +# SIZE-BROKEN-LLVM-NEXT: ] diff --git a/llvm/test/tools/llvm-readobj/ELF/malformed-pt-dynamic.test b/llvm/test/tools/llvm-readobj/ELF/malformed-pt-dynamic.test --- a/llvm/test/tools/llvm-readobj/ELF/malformed-pt-dynamic.test +++ b/llvm/test/tools/llvm-readobj/ELF/malformed-pt-dynamic.test @@ -33,14 +33,16 @@ ## Case B: Test case where the offset of the PT_DYNAMIC header is too large to be in the file. ## Case B.1: the section header table is present in the object. Check that we report a warning about the -## broken PT_DYNAMIC header, but document that we do not dump the dynamic table, because -## return an error earlier. +## broken PT_DYNAMIC header. Check we also report a warning about broken fields of the SHT_DYNAMIC section. # RUN: yaml2obj %s -DOFFSET=0x1131 -o %t2 -# RUN: not llvm-readobj %t2 --dynamic-table 2>&1 | FileCheck -DFILE=%t2 %s --check-prefix=WARN2 -# RUN: not llvm-readelf %t2 --dynamic-table 2>&1 | FileCheck -DFILE=%t2 %s --check-prefix=WARN2 +# RUN: llvm-readobj %t2 --dynamic-table 2>&1 | FileCheck -DFILE=%t2 %s \ +# RUN: --check-prefix=WARN2 --implicit-check-not=warning: +# RUN: llvm-readelf %t2 --dynamic-table 2>&1 | FileCheck -DFILE=%t2 %s \ +# RUN: --check-prefix=WARN2 --implicit-check-not=warning: # WARN2: warning: '[[FILE]]': PT_DYNAMIC segment offset (0x1131) + file size (0x10) exceeds the size of the file (0x1130) -# WARN2: error: '[[FILE]]': Invalid data was encountered while parsing the file +# WARN2: warning: '[[FILE]]': unable to read the dynamic table from SHT_DYNAMIC section with index 1: offset (0x1131) + size (0x10) is greater than the file size (0x1130) +# WARN2: warning: '[[FILE]]': no valid dynamic table was found ## Case B.2: in this case we drop section headers. The dynamic table is not dumped. # RUN: yaml2obj %s -DOFFSET=0x1119 -DNOHEADERS=true -o %t2.noheaders @@ -52,14 +54,18 @@ # WARN2-NOHEADERS: warning: '[[FILE]]': PT_DYNAMIC segment offset (0x1119) + file size (0x10) exceeds the size of the file (0x1118) ## Case C: test we report a warning when the offset + the file size of the PT_DYNAMIC is so large a -## value that it overflows the platform address size type. +## value that it overflows the platform address size type. Check we also report a warning about +## broken fields of the SHT_DYNAMIC section. # RUN: yaml2obj %s -DOFFSET=0xffffffffffffffff -o %t3 -# RUN: not llvm-readobj %t3 --dynamic-table 2>&1 | FileCheck -DFILE=%t3 %s --check-prefix=WARN3 -# RUN: not llvm-readelf %t3 --dynamic-table 2>&1 | FileCheck -DFILE=%t3 %s --check-prefix=WARN3 +# RUN: llvm-readobj %t3 --dynamic-table 2>&1 | FileCheck -DFILE=%t3 %s \ +# RUN: --check-prefix=WARN3 --implicit-check-not=warning: +# RUN: llvm-readelf %t3 --dynamic-table 2>&1 | FileCheck -DFILE=%t3 %s \ +# RUN: --check-prefix=WARN3 --implicit-check-not=warning: # WARN3: warning: '[[FILE]]': PT_DYNAMIC segment offset (0xffffffffffffffff) + file size (0x10) exceeds the size of the file (0x1130) -# WARN3: error: '[[FILE]]': Invalid data was encountered while parsing the file +# WARN3: warning: '[[FILE]]': unable to read the dynamic table from SHT_DYNAMIC section with index 1: offset (0xffffffffffffffff) + size (0x10) is greater than the file size (0x1130) +# WARN3: warning: '[[FILE]]': no valid dynamic table was found # RUN: yaml2obj %s -DNOHEADERS=true -DOFFSET=0xffffffffffffffff -o %t3.noheaders # RUN: llvm-readobj %t3.noheaders --dynamic-table 2>&1 | \ @@ -86,11 +92,14 @@ ## Case D: the same as "Case C", but for a 32-bit object. # RUN: yaml2obj %s -DBITS=32 -DOFFSET=0xffffffff -o %t5 -# RUN: not llvm-readobj %t5 --dynamic-table 2>&1 | FileCheck -DFILE=%t5 %s --check-prefix=WARN5 -# RUN: not llvm-readelf %t5 --dynamic-table 2>&1 | FileCheck -DFILE=%t5 %s --check-prefix=WARN5 +# RUN: llvm-readobj %t5 --dynamic-table 2>&1 | FileCheck -DFILE=%t5 %s \ +# RUN: --check-prefix=WARN5 --implicit-check-not=warning: +# RUN: llvm-readelf %t5 --dynamic-table 2>&1 | FileCheck -DFILE=%t5 %s \ +# RUN: --check-prefix=WARN5 --implicit-check-not=warning: # WARN5: warning: '[[FILE]]': PT_DYNAMIC segment offset (0xffffffff) + file size (0x8) exceeds the size of the file (0x10c8) -# WARN5: error: '[[FILE]]': Invalid data was encountered while parsing the file +# WARN5: warning: '[[FILE]]': unable to read the dynamic table from SHT_DYNAMIC section with index 1: offset (0xffffffff) + size (0x8) is greater than the file size (0x10c8) +# WARN5: warning: '[[FILE]]': no valid dynamic table was found # RUN: yaml2obj %s -DNOHEADERS=true -DBITS=32 -DOFFSET=0xffffffff -o %t5.noheaders # RUN: llvm-readobj %t5.noheaders --dynamic-table 2>&1 | \ diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -243,12 +243,16 @@ TYPEDEF_ELF_TYPES(ELFT) - DynRegionInfo createDRI(uint64_t Offset, uint64_t Size, uint64_t EntSize) { + Expected createDRI(uint64_t Offset, uint64_t Size, + uint64_t EntSize) { const ELFFile *Obj = ObjF->getELFFile(); if (Offset + Size < Offset || Offset + Size > Obj->getBufSize()) - reportError(errorCodeToError(llvm::object::object_error::parse_failed), - ObjF->getFileName()); - return {Obj->base() + Offset, Size, EntSize, ObjF->getFileName()}; + return createError("offset (0x" + Twine::utohexstr(Offset) + + ") + size (0x" + Twine::utohexstr(Size) + + ") is greater than the file size (0x" + + Twine::utohexstr(Obj->getBufSize()) + ")"); + return DynRegionInfo(Obj->base() + Offset, Size, EntSize, + ObjF->getFileName()); } void printAttributes(); @@ -1925,11 +1929,12 @@ DynRegionInfo FromPhdr(ObjF->getFileName()); bool IsPhdrTableValid = false; if (DynamicPhdr) { - FromPhdr = createDRI(DynamicPhdr->p_offset, DynamicPhdr->p_filesz, - sizeof(Elf_Dyn)); + // Use cantFail(), because p_offset/p_filesz fields of a PT_DYNAMIC are + // validated in findDynamic() and so createDRI() is not expected to fail. + FromPhdr = cantFail(createDRI(DynamicPhdr->p_offset, DynamicPhdr->p_filesz, + sizeof(Elf_Dyn))); FromPhdr.SizePrintName = "PT_DYNAMIC size"; FromPhdr.EntSizePrintName = ""; - IsPhdrTableValid = !FromPhdr.getAsArrayRef().empty(); } @@ -1940,12 +1945,18 @@ DynRegionInfo FromSec(ObjF->getFileName()); bool IsSecTableValid = false; if (DynamicSec) { - FromSec = + Expected RegOrErr = createDRI(DynamicSec->sh_offset, DynamicSec->sh_size, sizeof(Elf_Dyn)); - FromSec.Context = describe(*DynamicSec); - FromSec.EntSizePrintName = ""; - - IsSecTableValid = !FromSec.getAsArrayRef().empty(); + if (RegOrErr) { + FromSec = *RegOrErr; + FromSec.Context = describe(*DynamicSec); + FromSec.EntSizePrintName = ""; + IsSecTableValid = !FromSec.getAsArrayRef().empty(); + } else { + reportUniqueWarning(createError("unable to read the dynamic table from " + + describe(*DynamicSec) + ": " + + toString(RegOrErr.takeError()))); + } } // When we only have information from one of the SHT_DYNAMIC section header or @@ -2029,13 +2040,21 @@ DotDynsymSec = &Sec; if (!DynSymRegion) { - DynSymRegion = createDRI(Sec.sh_offset, Sec.sh_size, Sec.sh_entsize); - DynSymRegion->Context = describe(Sec); - - if (Expected E = Obj->getStringTableForSymtab(Sec)) - DynamicStringTable = *E; - else - reportWarning(E.takeError(), ObjF->getFileName()); + Expected RegOrErr = + createDRI(Sec.sh_offset, Sec.sh_size, Sec.sh_entsize); + if (RegOrErr) { + DynSymRegion = *RegOrErr; + DynSymRegion->Context = describe(Sec); + + if (Expected E = Obj->getStringTableForSymtab(Sec)) + DynamicStringTable = *E; + else + reportWarning(E.takeError(), ObjF->getFileName()); + } else { + reportUniqueWarning(createError( + "unable to read dynamic symbols from " + describe(Sec) + ": " + + toString(RegOrErr.takeError()))); + } } break; case ELF::SHT_SYMTAB_SHNDX: