]> granicus.if.org Git - llvm/commitdiff
[DWARF] Introduce verification for the unit header chain in .debug_info section to...
authorSpyridoula Gravani <sgravani@apple.com>
Thu, 13 Jul 2017 23:25:24 +0000 (23:25 +0000)
committerSpyridoula Gravani <sgravani@apple.com>
Thu, 13 Jul 2017 23:25:24 +0000 (23:25 +0000)
This patch adds verification checks for the unit header chain in the .debug_info section.
Specifically, for each unit in the .debug_info section, the verifier checks that:

The unit length is valid (i.e. the unit can actually fit in the .debug_info section)
The dwarf version of the unit is valid
The address size is valid (4 or 8)
The unit type (if the unit is in dwarf5) is valid
The debug_abbrev_offset is valid

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@307975 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/DebugInfo/DWARF/DWARFUnit.h
include/llvm/DebugInfo/DWARF/DWARFVerifier.h
lib/DebugInfo/DWARF/DWARFContext.cpp
lib/DebugInfo/DWARF/DWARFVerifier.cpp
test/tools/llvm-dwarfdump/X86/verify_unit_header_chain.s [new file with mode: 0644]

index ea36ab7ab5b6b428fbf654c164be955e42a6dd88..056c1b77c65d1fdbc5a4d58cbc2b4676d307c698 100644 (file)
@@ -238,6 +238,34 @@ public:
 
   uint8_t getUnitType() const { return UnitType; }
 
+  static bool isValidUnitType(uint8_t UnitType) {
+    return UnitType == dwarf::DW_UT_compile || UnitType == dwarf::DW_UT_type ||
+           UnitType == dwarf::DW_UT_partial ||
+           UnitType == dwarf::DW_UT_skeleton ||
+           UnitType == dwarf::DW_UT_split_compile ||
+           UnitType == dwarf::DW_UT_split_type;
+  }
+
+  /// \brief Return the number of bytes for the header of a unit of
+  /// UnitType type.
+  ///
+  /// This function must be called with a valid unit type which in
+  /// DWARF5 is defined as one of the following six types.
+  static uint32_t getDWARF5HeaderSize(uint8_t UnitType) {
+    switch (UnitType) {
+    case dwarf::DW_UT_compile:
+    case dwarf::DW_UT_partial:
+      return 12;
+    case dwarf::DW_UT_skeleton:
+    case dwarf::DW_UT_split_compile:
+      return 20;
+    case dwarf::DW_UT_type:
+    case dwarf::DW_UT_split_type:
+      return 24;
+    }
+    llvm_unreachable("Invalid UnitType.");
+  }
+
   uint64_t getBaseAddress() const { return BaseAddr; }
 
   void setBaseAddress(uint64_t base_addr) {
index 9eb5c45faba8b36255f89baeb58ef601f832a111..d9e0e3aaa65e127c62c7ce7beae4a93af42e75b5 100644 (file)
@@ -21,6 +21,7 @@ class DWARFContext;
 class DWARFDie;
 class DWARFUnit;
 class DWARFAcceleratorTable;
+class DWARFDataExtractor;
 
 /// A class that verifies DWARF debug information given a DWARF Context.
 class DWARFVerifier {
@@ -34,6 +35,29 @@ class DWARFVerifier {
   uint32_t NumDebugLineErrors = 0;
   uint32_t NumAppleNamesErrors = 0;
 
+  /// Verifies the header of a unit in the .debug_info section.
+  ///
+  /// This function currently checks for:
+  /// - Unit is in 32-bit DWARF format. The function can be modified to
+  /// support 64-bit format.
+  /// - The DWARF version is valid
+  /// - The unit type is valid (if unit is in version >=5)
+  /// - The unit doesn't extend beyond .debug_info section
+  /// - The address size is valid
+  /// - The offset in the .debug_abbrev section is valid
+  ///
+  /// \param DebugInfoData The .debug_info section data
+  /// \param Offset A reference to the offset start of the unit. The offset will
+  /// be updated to point to the next unit in .debug_info
+  /// \param UnitIndex The index of the unit to be verified
+  /// \param isUnitDWARF64 A reference to a flag that shows whether the unit is
+  /// in 64-bit format.
+  ///
+  /// \returns true if the header is verified successfully, false otherwise.
+  bool verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
+                        uint32_t *Offset, unsigned UnitIndex,
+                        bool &isUnitDWARF64);
+
   /// Verifies the attribute's DWARF attribute and its value.
   ///
   /// This function currently checks for:
@@ -78,6 +102,14 @@ class DWARFVerifier {
 public:
   DWARFVerifier(raw_ostream &S, DWARFContext &D)
       : OS(S), DCtx(D) {}
+  /// Verify the unit header chain in the .debug_info section.
+  ///
+  /// Any errors are reported to the stream that this object was
+  /// constructed with.
+  ///
+  /// \returns true if the unit header chain verifies successfully, false
+  /// otherwise.
+  bool handleDebugInfoUnitHeaderChain();
   /// Verify the information in the .debug_info section.
   ///
   /// Any errors are reported to the stream that was this object was
index 495e09fbae355e5d48bec8dfb29ac759d363bb10..96114758e1832025c07feb7de0f23b559d4e9fc2 100644 (file)
@@ -414,6 +414,8 @@ DWARFDie DWARFContext::getDIEForOffset(uint32_t Offset) {
 bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) {
   bool Success = true;
   DWARFVerifier verifier(OS, *this);
+  if (!verifier.handleDebugInfoUnitHeaderChain())
+    Success = false;
   if (DumpType == DIDT_All || DumpType == DIDT_Info) {
     if (!verifier.handleDebugInfo())
       Success = false;
index 0a10e6b78911ddaa04c9b91101c9c8443661e9c6..8a90b23fa93d0e4873141a4d0db84119d58fe189 100644 (file)
@@ -24,6 +24,98 @@ using namespace llvm;
 using namespace dwarf;
 using namespace object;
 
+bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
+                               uint32_t *Offset, unsigned UnitIndex,
+                               bool &isUnitDWARF64) {
+  uint32_t AbbrOffset, Length;
+  uint8_t AddrSize = 0, UnitType = 0;
+  uint16_t Version;
+  bool Success = true;
+  uint32_t HeaderSize =
+      11; // means that we have only compile units in .debug_info
+
+  bool ValidLength = false;
+  bool ValidVersion = false;
+  bool ValidAddrSize = false;
+  bool ValidType = true;
+  bool ValidAbbrevOffset = true;
+
+  uint32_t OffsetStart = *Offset;
+  Length = DebugInfoData.getU32(Offset);
+  if (Length == UINT32_MAX) {
+    isUnitDWARF64 = true;
+    OS << format(
+        "Unit[%d] is in 64-bit DWARF format; cannot verify from this point.\n",
+        UnitIndex);
+    return false;
+  }
+  Version = DebugInfoData.getU16(Offset);
+
+  if (Version >= 5) {
+    UnitType = DebugInfoData.getU8(Offset);
+    AddrSize = DebugInfoData.getU8(Offset);
+    AbbrOffset = DebugInfoData.getU32(Offset);
+    ValidType = DWARFUnit::isValidUnitType(UnitType);
+    if (ValidType)
+      HeaderSize = DWARFUnit::getDWARF5HeaderSize(UnitType);
+  } else {
+    AbbrOffset = DebugInfoData.getU32(Offset);
+    AddrSize = DebugInfoData.getU8(Offset);
+  }
+
+  if (!DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset))
+    ValidAbbrevOffset = false;
+
+  ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3);
+  ValidVersion = DWARFContext::isSupportedVersion(Version);
+  ValidAddrSize = AddrSize == 4 || AddrSize == 8;
+  if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset ||
+      !ValidType) {
+    Success = false;
+    OS << format("Units[%d] - start offset: 0x%08x \n", UnitIndex, OffsetStart);
+    if (!ValidLength)
+      OS << "\tError: The length for this unit is too "
+            "large for the .debug_info provided.\n";
+    if (!ValidVersion)
+      OS << "\tError: The 16 bit unit header version is not valid.\n";
+    if (!ValidType)
+      OS << "\tError: The unit type encoding is not valid.\n";
+    if (!ValidAbbrevOffset)
+      OS << "\tError: The offset into the .debug_abbrev section is "
+            "not valid.\n";
+    if (!ValidAddrSize)
+      OS << "\tError: The address size is unsupported.\n";
+  }
+  *Offset = OffsetStart + Length + 4;
+  return Success;
+}
+
+bool DWARFVerifier::handleDebugInfoUnitHeaderChain() {
+  OS << "Verifying .debug_info Unit Header Chain...\n";
+
+  DWARFDataExtractor DebugInfoData(DCtx.getInfoSection(), DCtx.isLittleEndian(),
+                                   0);
+  uint32_t OffsetStart, Offset = 0, UnitIdx = 0;
+  bool isUnitDWARF64 = false;
+  bool Success = true;
+  bool hasDIE = DebugInfoData.isValidOffset(Offset);
+  while (hasDIE) {
+    OffsetStart = Offset;
+    if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, isUnitDWARF64)) {
+      Success = false;
+      if (isUnitDWARF64)
+        break;
+    }
+    hasDIE = DebugInfoData.isValidOffset(Offset);
+    ++UnitIdx;
+  }
+  if (UnitIdx == 0 && !hasDIE) {
+    OS << "Warning: .debug_info is empty.\n";
+    Success = true;
+  }
+  return Success;
+}
+
 void DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
                                              DWARFAttribute &AttrValue) {
   const auto Attr = AttrValue.Attr;
diff --git a/test/tools/llvm-dwarfdump/X86/verify_unit_header_chain.s b/test/tools/llvm-dwarfdump/X86/verify_unit_header_chain.s
new file mode 100644 (file)
index 0000000..a3a5407
--- /dev/null
@@ -0,0 +1,81 @@
+# RUN: llvm-mc %s -filetype obj -triple x86_64-apple-darwin -o - \
+# RUN: | not llvm-dwarfdump -verify - \
+# RUN: | FileCheck %s
+
+# CHECK: Verifying .debug_info Unit Header Chain...
+# CHECK-NEXT: Units[1] - start offset: 0x0000000d 
+# CHECK-NEXT:  Error: The unit type encoding is not valid.
+# CHECK-NEXT:  Error: The address size is unsupported.
+# CHECK-NEXT: Units[2] - start offset: 0x00000026 
+# CHECK-NEXT:  Error: The 16 bit unit header version is not valid.
+# CHECK-NEXT:  Error: The offset into the .debug_abbrev section is not valid.
+# CHECK-NEXT: Units[4] - start offset: 0x00000041 
+# CHECK-NEXT:  Error: The length for this unit is too large for the .debug_info provided.
+
+       .section        __TEXT,__text,regular,pure_instructions
+       .file   1 "basic.c"
+       .comm   _i,4,2                  ## @i
+       .comm   _j,4,2                  ## @j
+       .section        __DWARF,__debug_str,regular,debug
+Linfo_string:
+       .asciz  "clang version 5.0.0 (trunk 307232) (llvm/trunk 307042)" ## string offset=0
+       .asciz  "basic.c"               ## string offset=55
+       .asciz  "/Users/sgravani/Development/tests" ## string offset=63
+       .asciz  "i"                     ## string offset=97
+       .asciz  "int"                   ## string offset=99
+       .asciz  "j"                     ## string offset=103
+       .section        __DWARF,__debug_abbrev,regular,debug
+Lsection_abbrev:
+       .byte   1                       ## Abbreviation Code
+       .byte   17                      ## DW_TAG_compile_unit
+       .byte   0                       ## EOM(1)
+       .byte   0                       ## EOM(2)
+       .byte   0                       ## EOM(3)
+       .section        __DWARF,__debug_info,regular,debug
+Lsection_info:
+Lcu_begin0:
+       .long   9                      ## Length of Unit
+       .short  4                       ## DWARF version number
+Lset0 = Lsection_abbrev-Lsection_abbrev ## Offset Into Abbrev. Section
+       .long   Lset0
+       .byte   4                       ## Address Size (in bytes)
+       .byte   1                       ## Abbrev [1] 0xc:0x45 DW_TAG_compile_unit
+       .byte   0                       ## End Of Children Mark
+Ltu_begin0:
+       .long   21                      ## Length of Unit
+       .short  5                       ## DWARF version number
+       .byte   0                       ## DWARF Unit Type -- Error: The unit type encoding is not valid.
+       .byte   3                       ## Address Size (in bytes) -- Error: The address size is unsupported.
+       .long   0
+       .quad   0
+       .long   0
+       .byte   0
+Lcu_begin1:
+       .long   10                      ## Length of Unit
+       .short  6                       ## DWARF version number -- Error: The 16 bit unit header version is not valid.
+       .byte   1                       ## DWARF Unit Type
+       .byte   4                       ## Address Size (in bytes) -- The offset into the .debug_abbrev section is not valid.
+       .long   Lline_table_start0
+       .byte   1                       ## Abbrev [1] 0xc:0x45 DW_TAG_compile_unit
+       .byte   0                       ## End Of Children Mark
+Lcu_begin2:
+       .long   9                      ## Length of Unit
+       .short  5                       ## DWARF version number
+       .byte   1                       ## DWARF Unit Type
+       .byte   4                       ## Address Size (in bytes)
+       .long   0                                               ## Abbrev offset
+       .byte   0
+Ltu_begin1:
+       .long   26                      ## Length of Unit -- Error: The length for this unit is too large for the .debug_info provided.
+       .short  5                       ## DWARF version number
+       .byte   2                       ## DWARF Unit Type
+       .byte   4                       ## Address Size (in bytes)
+       .long   0
+       .quad   0
+       .long   0
+       .byte   0               
+
+.subsections_via_symbols
+       .section        __DWARF,__debug_line,regular,debug
+Lsection_line:
+Lline_table_start0: