[llvm-readelf/obj] - Improve diagnostics when printing NT_FILE notes.
authorGeorgii Rymar <grimar@accesssoftek.com>
Thu, 3 Dec 2020 14:14:05 +0000 (17:14 +0300)
committerGeorgii Rymar <grimar@accesssoftek.com>
Wed, 9 Dec 2020 09:31:46 +0000 (12:31 +0300)
This changes the `printNotesHelper` to report warnings on its side when
there are errors when dumping notes.

With that we can provide more content when reporting warnings about broken notes.

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

llvm/test/tools/llvm-readobj/ELF/note-core-ntfile-bad.test
llvm/tools/llvm-readobj/ELFDumper.cpp

index ca3033c..5a497c2 100644 (file)
@@ -9,7 +9,9 @@
 
 # RUN: yaml2obj --docnum=1 %s -o %t1.o
 # RUN: llvm-readelf -n %t1.o 2>&1 | FileCheck -DFILE=%t1.o %s --check-prefix=ERR-HEADER-SHORT
-# ERR-HEADER-SHORT: warning: '[[FILE]]': malformed note: header too short
+# RUN: llvm-readobj -n %t1.o 2>&1 | FileCheck -DFILE=%t1.o %s --check-prefix=ERR-HEADER-SHORT
+
+# ERR-HEADER-SHORT: warning: '[[FILE]]': unable to read note with index 0 from the PT_NOTE segment with index 1: the note of size 0x8 is too short, expected at least 0x10
 
 # .section ".note.foo", "a"
 #       .align 4
@@ -38,7 +40,9 @@ ProgramHeaders:
 
 # RUN: yaml2obj --docnum=2 %s -o %t2.o
 # RUN: llvm-readelf -n %t2.o 2>&1 | FileCheck -DFILE=%t2.o %s --check-prefix=ERR-NULL-TERM
-# ERR-NULL-TERM: warning: '[[FILE]]': malformed note: not NUL terminated
+# RUN: llvm-readobj -n %t2.o 2>&1 | FileCheck -DFILE=%t2.o %s --check-prefix=ERR-NULL-TERM
+
+# ERR-NULL-TERM: warning: '[[FILE]]': unable to read note with index 0 from the PT_NOTE segment with index 1: the note is not NUL terminated
 
 # .section ".note.foo", "a"
 #       .align 4
@@ -72,7 +76,9 @@ ProgramHeaders:
 
 # RUN: yaml2obj --docnum=3 %s -o %t3.o
 # RUN: llvm-readelf -n %t3.o 2>&1 | FileCheck -DFILE=%t3.o %s --check-prefix=ERR-FILE-COUNT
-# ERR-FILE-COUNT: warning: '[[FILE]]': malformed note: too short for number of files
+# RUN: llvm-readobj -n %t3.o 2>&1 | FileCheck -DFILE=%t3.o %s --check-prefix=ERR-FILE-COUNT
+
+# ERR-FILE-COUNT: warning: '[[FILE]]': unable to read note with index 0 from the PT_NOTE segment with index 1: unable to read file mappings (found 2): the note of size 0x2c is too short
 
 # .section ".note.foo", "a"
 #       .align 4
@@ -106,7 +112,9 @@ ProgramHeaders:
 
 # RUN: yaml2obj --docnum=4 %s -o %t4.o
 # RUN: llvm-readelf -n %t4.o 2>&1 | FileCheck -DFILE=%t4.o %s --check-prefix=ERR-FILE-END-EARLY
-# ERR-FILE-END-EARLY: warning: '[[FILE]]': malformed note: too few filenames
+# RUN: llvm-readobj -n %t4.o 2>&1 | FileCheck -DFILE=%t4.o %s --check-prefix=ERR-FILE-END-EARLY
+
+# ERR-FILE-END-EARLY: warning: '[[FILE]]': unable to read note with index 0 from the PT_NOTE segment with index 1: unable to read the file name for the mapping with index 2: the note of size 0x44 is truncated
 
 # .section ".note.foo", "a"
 #       .align 4
index 2a286cb..279e406 100644 (file)
@@ -5333,19 +5333,20 @@ static Expected<CoreNote> readCoreNote(DataExtractor Desc) {
   const int Bytes = Desc.getAddressSize();
 
   if (!Desc.isValidOffsetForAddress(2))
-    return createStringError(object_error::parse_failed,
-                             "malformed note: header too short");
+    return createError("the note of size 0x" + Twine::utohexstr(Desc.size()) +
+                       " is too short, expected at least 0x" +
+                       Twine::utohexstr(Bytes * 2));
   if (Desc.getData().back() != 0)
-    return createStringError(object_error::parse_failed,
-                             "malformed note: not NUL terminated");
+    return createError("the note is not NUL terminated");
 
   uint64_t DescOffset = 0;
   uint64_t FileCount = Desc.getAddress(&DescOffset);
   Ret.PageSize = Desc.getAddress(&DescOffset);
 
   if (!Desc.isValidOffsetForAddress(3 * FileCount * Bytes))
-    return createStringError(object_error::parse_failed,
-                             "malformed note: too short for number of files");
+    return createError("unable to read file mappings (found " +
+                       Twine(FileCount) + "): the note of size 0x" +
+                       Twine::utohexstr(Desc.size()) + " is too short");
 
   uint64_t FilenamesOffset = 0;
   DataExtractor Filenames(
@@ -5353,10 +5354,14 @@ static Expected<CoreNote> readCoreNote(DataExtractor Desc) {
       Desc.isLittleEndian(), Desc.getAddressSize());
 
   Ret.Mappings.resize(FileCount);
+  size_t I = 0;
   for (CoreFileMapping &Mapping : Ret.Mappings) {
+    ++I;
     if (!Filenames.isValidOffsetForDataOfSize(FilenamesOffset, 1))
-      return createStringError(object_error::parse_failed,
-                               "malformed note: too few filenames");
+      return createError(
+          "unable to read the file name for the mapping with index " +
+          Twine(I) + ": the note of size 0x" + Twine::utohexstr(Desc.size()) +
+          " is truncated");
     Mapping.Start = Desc.getAddress(&DescOffset);
     Mapping.End = Desc.getAddress(&DescOffset);
     Mapping.Offset = Desc.getAddress(&DescOffset);
@@ -5521,7 +5526,7 @@ static void printNotesHelper(
     llvm::function_ref<void(Optional<StringRef>, typename ELFT::Off,
                             typename ELFT::Addr)>
         StartNotesFn,
-    llvm::function_ref<void(const typename ELFT::Note &)> ProcessNoteFn,
+    llvm::function_ref<Error(const typename ELFT::Note &)> ProcessNoteFn,
     llvm::function_ref<void()> FinishNotesFn) {
   const ELFFile<ELFT> &Obj = Dumper.getElfObject().getELFFile();
 
@@ -5533,8 +5538,14 @@ static void printNotesHelper(
       StartNotesFn(expectedToOptional(Obj.getSectionName(S)), S.sh_offset,
                    S.sh_size);
       Error Err = Error::success();
-      for (const typename ELFT::Note Note : Obj.notes(S, Err))
-        ProcessNoteFn(Note);
+      size_t I = 0;
+      for (const typename ELFT::Note Note : Obj.notes(S, Err)) {
+        if (Error E = ProcessNoteFn(Note))
+          Dumper.reportUniqueWarning(
+              "unable to read note with index " + Twine(I) + " from the " +
+              describe(Obj, S) + ": " + toString(std::move(E)));
+        ++I;
+      }
       if (Err)
         Dumper.reportUniqueWarning("unable to read notes from the " +
                                    describe(Obj, S) + ": " +
@@ -5559,8 +5570,15 @@ static void printNotesHelper(
       continue;
     StartNotesFn(/*SecName=*/None, P.p_offset, P.p_filesz);
     Error Err = Error::success();
-    for (const typename ELFT::Note Note : Obj.notes(P, Err))
-      ProcessNoteFn(Note);
+    size_t Index = 0;
+    for (const typename ELFT::Note Note : Obj.notes(P, Err)) {
+      if (Error E = ProcessNoteFn(Note))
+        Dumper.reportUniqueWarning("unable to read note with index " +
+                                   Twine(Index) +
+                                   " from the PT_NOTE segment with index " +
+                                   Twine(I) + ": " + toString(std::move(E)));
+      ++Index;
+    }
     if (Err)
       Dumper.reportUniqueWarning(
           "unable to read notes from the PT_NOTE segment with index " +
@@ -5584,7 +5602,7 @@ template <class ELFT> void GNUStyle<ELFT>::printNotes() {
     OS << "  Owner                Data size \tDescription\n";
   };
 
-  auto ProcessNote = [&](const Elf_Note &Note) {
+  auto ProcessNote = [&](const Elf_Note &Note) -> Error {
     StringRef Name = Note.getName();
     ArrayRef<uint8_t> Descriptor = Note.getDesc();
     Elf_Word Type = Note.getType();
@@ -5617,11 +5635,10 @@ template <class ELFT> void GNUStyle<ELFT>::printNotes() {
         DataExtractor DescExtractor(Descriptor,
                                     ELFT::TargetEndianness == support::little,
                                     sizeof(Elf_Addr));
-        Expected<CoreNote> Note = readCoreNote(DescExtractor);
-        if (Note)
-          printCoreNote<ELFT>(OS, *Note);
+        if (Expected<CoreNote> NoteOrErr = readCoreNote(DescExtractor))
+          printCoreNote<ELFT>(OS, *NoteOrErr);
         else
-          reportWarning(Note.takeError(), this->FileName);
+          return NoteOrErr.takeError();
       }
     } else if (!Descriptor.empty()) {
       OS << "   description data:";
@@ -5629,6 +5646,7 @@ template <class ELFT> void GNUStyle<ELFT>::printNotes() {
         OS << " " << format("%02x", B);
       OS << '\n';
     }
+    return Error::success();
   };
 
   printNotesHelper(this->dumper(), PrintHeader, ProcessNote, []() {});
@@ -6836,7 +6854,7 @@ template <class ELFT> void LLVMStyle<ELFT>::printNotes() {
 
   auto EndNotes = [&] { NoteScope.reset(); };
 
-  auto ProcessNote = [&](const Elf_Note &Note) {
+  auto ProcessNote = [&](const Elf_Note &Note) -> Error {
     DictScope D2(W, "Note");
     StringRef Name = Note.getName();
     ArrayRef<uint8_t> Descriptor = Note.getDesc();
@@ -6871,15 +6889,15 @@ template <class ELFT> void LLVMStyle<ELFT>::printNotes() {
         DataExtractor DescExtractor(Descriptor,
                                     ELFT::TargetEndianness == support::little,
                                     sizeof(Elf_Addr));
-        Expected<CoreNote> Note = readCoreNote(DescExtractor);
-        if (Note)
+        if (Expected<CoreNote> Note = readCoreNote(DescExtractor))
           printCoreNoteLLVMStyle(*Note, W);
         else
-          reportWarning(Note.takeError(), this->FileName);
+          return Note.takeError();
       }
     } else if (!Descriptor.empty()) {
       W.printBinaryBlock("Description data", Descriptor);
     }
+    return Error::success();
   };
 
   printNotesHelper(this->dumper(), StartNotes, ProcessNote, EndNotes);