[llvm] c245c21 - [llvm-readelf] Support dumping the BB address map section with --bb-addr-map.

Rahman Lavaee via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 8 16:20:32 PST 2021


Author: Rahman Lavaee
Date: 2021-03-08T16:20:11-08:00
New Revision: c245c21c436b5d29da62a7c416f08f8631f5df95

URL: https://github.com/llvm/llvm-project/commit/c245c21c436b5d29da62a7c416f08f8631f5df95
DIFF: https://github.com/llvm/llvm-project/commit/c245c21c436b5d29da62a7c416f08f8631f5df95.diff

LOG: [llvm-readelf] Support dumping the BB address map section with --bb-addr-map.

This patch lets llvm-readelf dump the content of the BB address map
section in the following format:
```
Function {
  At: <address>
  BB entries [
    {
      Offset:   <offset>
      Size:     <size>
      Metadata: <metadata>
    },
    ...
  ]
}
...
```

Reviewed By: jhenderson

Differential Revision: https://reviews.llvm.org/D95511

Added: 
    llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test

Modified: 
    llvm/docs/CommandGuide/llvm-readelf.rst
    llvm/docs/CommandGuide/llvm-readobj.rst
    llvm/include/llvm/Object/ELF.h
    llvm/include/llvm/Object/ELFTypes.h
    llvm/include/llvm/ObjectYAML/ELFYAML.h
    llvm/lib/Object/ELF.cpp
    llvm/tools/llvm-readobj/ELFDumper.cpp
    llvm/tools/llvm-readobj/ObjDumper.h
    llvm/tools/llvm-readobj/llvm-readobj.cpp
    llvm/unittests/Object/ELFObjectFileTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CommandGuide/llvm-readelf.rst b/llvm/docs/CommandGuide/llvm-readelf.rst
index b566ad2ff5bc..cf4222f00c54 100644
--- a/llvm/docs/CommandGuide/llvm-readelf.rst
+++ b/llvm/docs/CommandGuide/llvm-readelf.rst
@@ -32,6 +32,11 @@ OPTIONS
 
  Display architecture-specific information, e.g. the ARM attributes section on ARM.
 
+.. option:: --bb-addr-map
+
+ Display the contents of the basic block address map section(s), which contain the
+ address of each function, along with the relative offset of each basic block.
+
 .. option:: --color
 
  Use colors in the output for warnings and errors.

diff  --git a/llvm/docs/CommandGuide/llvm-readobj.rst b/llvm/docs/CommandGuide/llvm-readobj.rst
index ba5511bb765a..201d1df803c0 100644
--- a/llvm/docs/CommandGuide/llvm-readobj.rst
+++ b/llvm/docs/CommandGuide/llvm-readobj.rst
@@ -148,6 +148,11 @@ The following options are implemented only for the ELF file format.
 
  Display architecture-specific information, e.g. the ARM attributes section on ARM.
 
+.. option:: --bb-addr-map
+
+ Display the contents of the basic block address map section(s), which contain the
+ address of each function, along with the relative offset of each basic block.
+
 .. option:: --demangle, -C
 
  Display demangled symbol names in the output.

diff  --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h
index 03e64e1d34dc..c5f966891bd0 100644
--- a/llvm/include/llvm/Object/ELF.h
+++ b/llvm/include/llvm/Object/ELF.h
@@ -392,6 +392,8 @@ class ELFFile {
   Expected<ArrayRef<T>> getSectionContentsAsArray(const Elf_Shdr &Sec) const;
   Expected<ArrayRef<uint8_t>> getSectionContents(const Elf_Shdr &Sec) const;
   Expected<ArrayRef<uint8_t>> getSegmentContents(const Elf_Phdr &Phdr) const;
+  Expected<std::vector<Elf_BBAddrMap>>
+  decodeBBAddrMap(const Elf_Shdr &Sec) const;
 };
 
 using ELF32LEFile = ELFFile<ELF32LE>;

diff  --git a/llvm/include/llvm/Object/ELFTypes.h b/llvm/include/llvm/Object/ELFTypes.h
index f64e7c06e03b..32548f1435f7 100644
--- a/llvm/include/llvm/Object/ELFTypes.h
+++ b/llvm/include/llvm/Object/ELFTypes.h
@@ -43,6 +43,7 @@ template <class ELFT> struct Elf_Nhdr_Impl;
 template <class ELFT> class Elf_Note_Impl;
 template <class ELFT> class Elf_Note_Iterator_Impl;
 template <class ELFT> struct Elf_CGProfile_Impl;
+template <class ELFT> struct Elf_BBAddrMap_Impl;
 
 template <endianness E, bool Is64> struct ELFType {
 private:
@@ -74,6 +75,7 @@ template <endianness E, bool Is64> struct ELFType {
   using Note = Elf_Note_Impl<ELFType<E, Is64>>;
   using NoteIterator = Elf_Note_Iterator_Impl<ELFType<E, Is64>>;
   using CGProfile = Elf_CGProfile_Impl<ELFType<E, Is64>>;
+  using BBAddrMap = Elf_BBAddrMap_Impl<ELFType<E, Is64>>;
   using DynRange = ArrayRef<Dyn>;
   using ShdrRange = ArrayRef<Shdr>;
   using SymRange = ArrayRef<Sym>;
@@ -128,13 +130,14 @@ using ELF64BE = ELFType<support::big, true>;
   using Elf_Note = typename ELFT::Note;                                        \
   using Elf_Note_Iterator = typename ELFT::NoteIterator;                       \
   using Elf_CGProfile = typename ELFT::CGProfile;                              \
+  using Elf_BBAddrMap = typename ELFT::BBAddrMap;                              \
   using Elf_Dyn_Range = typename ELFT::DynRange;                               \
   using Elf_Shdr_Range = typename ELFT::ShdrRange;                             \
   using Elf_Sym_Range = typename ELFT::SymRange;                               \
   using Elf_Rel_Range = typename ELFT::RelRange;                               \
   using Elf_Rela_Range = typename ELFT::RelaRange;                             \
   using Elf_Relr_Range = typename ELFT::RelrRange;                             \
-  using Elf_Phdr_Range = typename ELFT::PhdrRange;                             \
+  using Elf_Phdr_Range = typename ELFT::PhdrRange;
 
 #define LLVM_ELF_COMMA ,
 #define LLVM_ELF_IMPORT_TYPES(E, W)                                            \
@@ -788,6 +791,28 @@ template <class ELFT> struct Elf_Mips_ABIFlags {
   Elf_Word flags2;   // General flags
 };
 
+// Struct representing the BBAddrMap for one function.
+template <class ELFT> struct Elf_BBAddrMap_Impl {
+  LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+  uintX_t Addr; // Function address
+  // Struct representing the BBAddrMap information for one basic block.
+  struct BBEntry {
+    uint32_t Offset; // Offset of basic block relative to function start.
+    uint32_t Size;   // Size of the basic block.
+
+    // The following fields are decoded from the Metadata field. The encoding
+    // happens in AsmPrinter.cpp:getBBAddrMapMetadata.
+    bool HasReturn;   // If this block ends with a return (or tail call).
+    bool HasTailCall; // If this block ends with a tail call.
+    bool IsEHPad;     // If this is an exception handling block.
+
+    BBEntry(uint32_t Offset, uint32_t Size, uint32_t Metadata)
+        : Offset(Offset), Size(Size), HasReturn(Metadata & 1),
+          HasTailCall(Metadata & (1 << 1)), IsEHPad(Metadata & (1 << 2)){};
+  };
+  std::vector<BBEntry> BBEntries; // Basic block entries for this function.
+};
+
 } // end namespace object.
 } // end namespace llvm.
 

diff  --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 29b3c1da03da..874aa32acdc0 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -161,7 +161,7 @@ struct BBAddrMapEntry {
     llvm::yaml::Hex64 Metadata;
   };
   llvm::yaml::Hex64 Address;
-  Optional<uint32_t> NumBlocks;
+  Optional<uint64_t> NumBlocks;
   Optional<std::vector<BBEntry>> BBEntries;
 };
 

diff  --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index ffeec3112b7e..ca2ed4449120 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -612,6 +612,58 @@ ELFFile<ELFT>::toMappedAddr(uint64_t VAddr, WarningHandler WarnHandler) const {
   return base() + Offset;
 }
 
+template <class ELFT>
+Expected<std::vector<typename ELFT::BBAddrMap>>
+ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec) const {
+  Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec);
+  if (!ContentsOrErr)
+    return ContentsOrErr.takeError();
+  ArrayRef<uint8_t> Content = *ContentsOrErr;
+  DataExtractor Data(Content, isLE(), ELFT::Is64Bits ? 8 : 4);
+  std::vector<Elf_BBAddrMap> FunctionEntries;
+
+  DataExtractor::Cursor Cur(0);
+  Error ULEBSizeErr = Error::success();
+
+  // Helper to extract and decode the next ULEB128 value as uint32_t.
+  // Returns zero and sets ULEBSizeErr if the ULEB128 value exceeds the uint32_t
+  // limit.
+  // Also returns zero if ULEBSizeErr is already in an error state.
+  auto ReadULEB128AsUInt32 = [&Data, &Cur, &ULEBSizeErr]() -> uint32_t {
+    // Bail out and do not extract data if ULEBSizeErr is already set.
+    if (ULEBSizeErr)
+      return 0;
+    uint64_t Offset = Cur.tell();
+    uint64_t Value = Data.getULEB128(Cur);
+    if (Value > UINT32_MAX) {
+      ULEBSizeErr = createError(
+          "ULEB128 value at offset 0x" + Twine::utohexstr(Offset) +
+          " exceeds UINT32_MAX (0x" + Twine::utohexstr(Value) + ")");
+      return 0;
+    }
+    return static_cast<uint32_t>(Value);
+  };
+
+  while (!ULEBSizeErr && Cur && Cur.tell() < Content.size()) {
+    uintX_t Address = static_cast<uintX_t>(Data.getAddress(Cur));
+    uint32_t NumBlocks = ReadULEB128AsUInt32();
+    std::vector<typename Elf_BBAddrMap::BBEntry> BBEntries;
+    for (uint32_t BlockID = 0; !ULEBSizeErr && Cur && (BlockID < NumBlocks);
+         ++BlockID) {
+      uint32_t Offset = ReadULEB128AsUInt32();
+      uint32_t Size = ReadULEB128AsUInt32();
+      uint32_t Metadata = ReadULEB128AsUInt32();
+      BBEntries.push_back({Offset, Size, Metadata});
+    }
+    FunctionEntries.push_back({Address, BBEntries});
+  }
+  // Either Cur is in the error state, or ULEBSizeError is set (not both), but
+  // we join the two errors here to be safe.
+  if (!Cur || ULEBSizeErr)
+    return joinErrors(Cur.takeError(), std::move(ULEBSizeErr));
+  return FunctionEntries;
+}
+
 template class llvm::object::ELFFile<ELF32LE>;
 template class llvm::object::ELFFile<ELF32BE>;
 template class llvm::object::ELFFile<ELF64LE>;

diff  --git a/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test
new file mode 100644
index 000000000000..f9b9dc0980e5
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test
@@ -0,0 +1,119 @@
+## This test checks how we handle the --bb-addr-map option.
+
+## Check 64-bit:
+# RUN: yaml2obj %s -DBITS=64 -DADDR=0xFFFFFFFF1 -o %t1.x64.o
+# RUN: llvm-readobj %t1.x64.o --bb-addr-map | FileCheck %s -DADDR=0xFFFFFFFF1 --check-prefix=LLVM
+# RUN: llvm-readelf %t1.x64.o --bb-addr-map | FileCheck %s --check-prefix=GNU
+
+## Check 32-bit:
+# RUN: yaml2obj %s -DBITS=32 -o %t1.x32.o
+# RUN: llvm-readobj %t1.x32.o --bb-addr-map | FileCheck -DADDR=0x11111 %s --check-prefix=LLVM
+# RUN: llvm-readelf %t1.x32.o --bb-addr-map | FileCheck %s --check-prefix=GNU
+
+## Check that a malformed section can be handled.
+# RUN: yaml2obj %s -DBITS=32 -DSIZE=4 -o %t2.o
+# RUN: llvm-readobj %t2.o --bb-addr-map 2>&1 | FileCheck %s -DOFFSET=0x00000004 -DFILE=%t2.o --check-prefix=TRUNCATED
+
+# LLVM:      BBAddrMap [
+# LLVM-NEXT:   Function {
+# LLVM-NEXT:     At: [[ADDR]]
+# LLVM-NEXT:     BB entries [
+# LLVM-NEXT:       {
+# LLVM-NEXT:         Offset: 0x0
+# LLVM-NEXT:         Size: 0x1
+# LLVM-NEXT:         HasReturn: No
+# LLVM-NEXT:         HasTailCall: Yes
+# LLVM-NEXT:         IsEHPad: No
+# LLVM-NEXT:       }
+# LLVM-NEXT:       {
+# LLVM-NEXT:         Offset: 0x3
+# LLVM-NEXT:         Size: 0x4
+# LLVM-NEXT:         HasReturn: Yes
+# LLVM-NEXT:         HasTailCall: No
+# LLVM-NEXT:         IsEHPad: Yes
+# LLVM-NEXT:       }
+# LLVM-NEXT:     ]
+# LLVM-NEXT:   }
+# LLVM-NEXT:   Function {
+# LLVM-NEXT:     At: 0x22222
+# LLVM-NEXT:     BB entries [
+# LLVM-NEXT:       {
+# LLVM-NEXT:         Offset: 0x6
+# LLVM-NEXT:         Size: 0x7
+# LLVM-NEXT:         HasReturn: No
+# LLVM-NEXT:         HasTailCall: No
+# LLVM-NEXT:         IsEHPad: No
+# LLVM-NEXT:       }
+# LLVM-NEXT:     ]
+# LLVM-NEXT:   }
+# LLVM-NEXT: ]
+# LLVM-NEXT: BBAddrMap [
+# LLVM-NEXT:   Function {
+# LLVM-NEXT:     At: 0x33333
+# LLVM-NEXT:     BB entries [
+# LLVM-NEXT:       {
+# LLVM-NEXT:         Offset: 0x9
+# LLVM-NEXT:         Size: 0xA
+# LLVM-NEXT:         HasReturn: Yes
+# LLVM-NEXT:         HasTailCall: Yes
+# LLVM-NEXT:         IsEHPad: No
+# LLVM-NEXT:       }
+# LLVM-NEXT:     ]
+# LLVM-NEXT:   }
+# LLVM-NEXT: ]
+
+# GNU: GNUStyle::printBBAddrMaps not implemented
+
+# TRUNCATED:      BBAddrMap [
+# TRUNCATED-NEXT:   warning: '[[FILE]]': unable to dump SHT_LLVM_BB_ADDR_MAP section with index 1: unable to decode LEB128 at offset [[OFFSET]]: malformed uleb128, extends past end
+# TRUNCATED-NEXT: ]
+## Check that the other valid section is properly dumped.
+# TRUNCATED-NEXT: BBAddrMap [
+# TRUNCATED-NEXT:   Function {
+# TRUNCATED-NEXT:          At: 0x33333
+# TRUNCATED-NEXT:          BB entries [
+# TRUNCATED-NEXT:            {
+# TRUNCATED-NEXT:         Offset: 0x9
+# TRUNCATED-NEXT:         Size: 0xA
+# TRUNCATED-NEXT:         HasReturn: Yes
+# TRUNCATED-NEXT:         HasTailCall: Yes
+# TRUNCATED-NEXT:         IsEHPad: No
+# TRUNCATED-NEXT:       }
+# TRUNCATED-NEXT:     ]
+# TRUNCATED-NEXT:   }
+# TRUNCATED-NEXT: ]
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS[[BITS]]
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+Sections:
+  - Name:   bb_addr_map_1
+    Type:   SHT_LLVM_BB_ADDR_MAP
+    ShSize: [[SIZE=<none>]]
+    Entries:
+      - Address: [[ADDR=0x11111]]
+        BBEntries:
+          - AddressOffset: 0x0
+            Size:          0x1
+            Metadata:      0xF0000002
+          - AddressOffset: 0x3
+            Size:          0x4
+            Metadata:      0x5
+      - Address: 0x22222
+        BBEntries:
+          - AddressOffset: 0x6
+            Size:          0x7
+            Metadata:      0x8
+  - Name:   dummy_section
+    Type:   SHT_PROGBITS
+    Size:   16
+  - Name:   bb_addr_map_2
+    Type:   SHT_LLVM_BB_ADDR_MAP
+    Entries:
+      - Address: 0x33333
+        BBEntries:
+          - AddressOffset: 0x9
+            Size:          0xa
+            Metadata:      0xb

diff  --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 03288e4a45c9..2535ae7830ae 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -550,6 +550,7 @@ template <typename ELFT> class GNUELFDumper : public ELFDumper<ELFT> {
   void printVersionDependencySection(const Elf_Shdr *Sec) override;
   void printHashHistograms() override;
   void printCGProfile() override;
+  void printBBAddrMaps() override;
   void printAddrsig() override;
   void printNotes() override;
   void printELFLinkerOptions() override;
@@ -660,6 +661,7 @@ template <typename ELFT> class LLVMELFDumper : public ELFDumper<ELFT> {
   void printVersionDependencySection(const Elf_Shdr *Sec) override;
   void printHashHistograms() override;
   void printCGProfile() override;
+  void printBBAddrMaps() override;
   void printAddrsig() override;
   void printNotes() override;
   void printELFLinkerOptions() override;
@@ -4617,6 +4619,10 @@ template <class ELFT> void GNUELFDumper<ELFT>::printCGProfile() {
   OS << "GNUStyle::printCGProfile not implemented\n";
 }
 
+template <class ELFT> void GNUELFDumper<ELFT>::printBBAddrMaps() {
+  OS << "GNUStyle::printBBAddrMaps not implemented\n";
+}
+
 static Expected<std::vector<uint64_t>> toULEB128Array(ArrayRef<uint8_t> Data) {
   std::vector<uint64_t> Ret;
   const uint8_t *Cur = Data.begin();
@@ -6520,6 +6526,34 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printCGProfile() {
   }
 }
 
+template <class ELFT> void LLVMELFDumper<ELFT>::printBBAddrMaps() {
+  for (const Elf_Shdr &Sec : cantFail(this->Obj.sections())) {
+    if (Sec.sh_type != SHT_LLVM_BB_ADDR_MAP)
+      continue;
+    ListScope L(W, "BBAddrMap");
+    Expected<std::vector<Elf_BBAddrMap>> BBAddrMapOrErr =
+        this->Obj.decodeBBAddrMap(Sec);
+    if (!BBAddrMapOrErr) {
+      this->reportUniqueWarning("unable to dump " + this->describe(Sec) + ": " +
+                                toString(BBAddrMapOrErr.takeError()));
+      continue;
+    }
+    for (const Elf_BBAddrMap &AM : *BBAddrMapOrErr) {
+      DictScope D(W, "Function");
+      W.printHex("At", AM.Addr);
+      ListScope L(W, "BB entries");
+      for (const typename Elf_BBAddrMap::BBEntry &BBE : AM.BBEntries) {
+        DictScope L(W);
+        W.printHex("Offset", BBE.Offset);
+        W.printHex("Size", BBE.Size);
+        W.printBoolean("HasReturn", BBE.HasReturn);
+        W.printBoolean("HasTailCall", BBE.HasTailCall);
+        W.printBoolean("IsEHPad", BBE.IsEHPad);
+      }
+    }
+  }
+}
+
 template <class ELFT> void LLVMELFDumper<ELFT>::printAddrsig() {
   ListScope L(W, "Addrsig");
   if (!this->DotAddrsigSec)

diff  --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
index d4e166b504cf..e707c36713d4 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -72,6 +72,7 @@ class ObjDumper {
   virtual void printGroupSections() {}
   virtual void printHashHistograms() {}
   virtual void printCGProfile() {}
+  virtual void printBBAddrMaps() {}
   virtual void printAddrsig() {}
   virtual void printNotes() {}
   virtual void printELFLinkerOptions() {}

diff  --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index 841313ebe2b1..5d6ee25961f2 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -367,6 +367,10 @@ namespace opts {
   cl::alias ELFCGProfile("elf-cg-profile", cl::desc("Alias for --cg-profile"),
                          cl::aliasopt(CGProfile));
 
+  // --bb-addr-map
+  cl::opt<bool> BBAddrMap("bb-addr-map",
+                          cl::desc("Display the BB address map section"));
+
   // -addrsig
   cl::opt<bool> Addrsig("addrsig",
                         cl::desc("Display address-significance table"));
@@ -542,6 +546,8 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
       Dumper->printHashHistograms();
     if (opts::CGProfile)
       Dumper->printCGProfile();
+    if (opts::BBAddrMap)
+      Dumper->printBBAddrMaps();
     if (opts::Addrsig)
       Dumper->printAddrsig();
     if (opts::Notes)

diff  --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp
index 8021b724afbc..bf59d4aa705b 100644
--- a/llvm/unittests/Object/ELFObjectFileTest.cpp
+++ b/llvm/unittests/Object/ELFObjectFileTest.cpp
@@ -482,3 +482,111 @@ TEST(ELFObjectFileTest, InvalidSymbolTest) {
   DoCheck(0xFFFFFFFF, "can't read an entry at 0x17ffffffe8: it goes past the "
                       "end of the section (0x18)");
 }
+
+// Tests for error paths of the ELFFile::decodeBBAddrMap API.
+TEST(ELFObjectFileTest, InvalidBBAddrMap) {
+  StringRef CommonYamlString(R"(
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+Sections:
+  - Name: .llvm_bb_addr_map
+    Type: SHT_LLVM_BB_ADDR_MAP
+    Entries:
+      - Address: 0x11111
+        BBEntries:
+          - AddressOffset: 0x0
+            Size:          0x1
+            Metadata:      0x2
+)");
+
+  auto DoCheck = [&](StringRef YamlString, const char *ErrMsg) {
+    SmallString<0> Storage;
+    Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
+        toBinary<ELF64LE>(Storage, YamlString);
+    ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
+    const ELFFile<ELF64LE> &Elf = ElfOrErr->getELFFile();
+
+    Expected<const typename ELF64LE::Shdr *> BBAddrMapSecOrErr =
+        Elf.getSection(1);
+    ASSERT_THAT_EXPECTED(BBAddrMapSecOrErr, Succeeded());
+    EXPECT_THAT_ERROR(Elf.decodeBBAddrMap(**BBAddrMapSecOrErr).takeError(),
+                      FailedWithMessage(ErrMsg));
+  };
+
+  // Check that we can detect the malformed encoding when the section is
+  // truncated.
+  SmallString<128> TruncatedYamlString(CommonYamlString);
+  TruncatedYamlString += R"(
+    ShSize: 0x8
+)";
+  DoCheck(TruncatedYamlString, "unable to decode LEB128 at offset 0x00000008: "
+                               "malformed uleb128, extends past end");
+
+  // Check that we can detect when the encoded BB entry fields exceed the UINT32
+  // limit.
+  SmallVector<SmallString<128>, 3> OverInt32LimitYamlStrings(3,
+                                                             CommonYamlString);
+  OverInt32LimitYamlStrings[0] += R"(
+          - AddressOffset: 0x100000000
+            Size:          0xFFFFFFFF
+            Metadata:      0xFFFFFFFF
+)";
+
+  OverInt32LimitYamlStrings[1] += R"(
+          - AddressOffset: 0xFFFFFFFF
+            Size:          0x100000000
+            Metadata:      0xFFFFFFFF
+)";
+
+  OverInt32LimitYamlStrings[2] += R"(
+          - AddressOffset: 0xFFFFFFFF
+            Size:          0xFFFFFFFF
+            Metadata:      0x100000000
+)";
+
+  DoCheck(OverInt32LimitYamlStrings[0],
+          "ULEB128 value at offset 0xc exceeds UINT32_MAX (0x100000000)");
+  DoCheck(OverInt32LimitYamlStrings[1],
+          "ULEB128 value at offset 0x11 exceeds UINT32_MAX (0x100000000)");
+  DoCheck(OverInt32LimitYamlStrings[2],
+          "ULEB128 value at offset 0x16 exceeds UINT32_MAX (0x100000000)");
+
+  // Check the proper error handling when the section has fields exceeding
+  // UINT32 and is also truncated. This is for checking that we don't generate
+  // unhandled errors.
+  SmallVector<SmallString<128>, 3> OverInt32LimitAndTruncated(
+      3, OverInt32LimitYamlStrings[1]);
+  // Truncate before the end of the 5-byte field.
+  OverInt32LimitAndTruncated[0] += R"(
+    ShSize: 0x15
+)";
+  // Truncate at the end of the 5-byte field.
+  OverInt32LimitAndTruncated[1] += R"(
+    ShSize: 0x16
+)";
+  // Truncate after the end of the 5-byte field.
+  OverInt32LimitAndTruncated[2] += R"(
+    ShSize: 0x17
+)";
+
+  DoCheck(OverInt32LimitAndTruncated[0],
+          "unable to decode LEB128 at offset 0x00000011: malformed uleb128, "
+          "extends past end");
+  DoCheck(OverInt32LimitAndTruncated[1],
+          "ULEB128 value at offset 0x11 exceeds UINT32_MAX (0x100000000)");
+  DoCheck(OverInt32LimitAndTruncated[2],
+          "ULEB128 value at offset 0x11 exceeds UINT32_MAX (0x100000000)");
+
+  // Check for proper error handling when the 'NumBlocks' field is overridden
+  // with an out-of-range value.
+  SmallString<128> OverLimitNumBlocks(CommonYamlString);
+  OverLimitNumBlocks += R"(
+        NumBlocks: 0x100000000
+)";
+
+  DoCheck(OverLimitNumBlocks,
+          "ULEB128 value at offset 0x8 exceeds UINT32_MAX (0x100000000)");
+}


        


More information about the llvm-commits mailing list