Author: Andrew Gontarek
Date: 2025-09-23T12:57:24-04:00
New Revision: c31d50378bdba3aab936dfc30b78911431641906

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

LOG: [LLDB] Fix 64 bit support for CIE and FDE handling in DWARFCallFrameInfo 
(#158350)

- Introduced a new helper function `IsCIEMarker` to determine if a given
`cie_id` indicates a CIE (Common Information Entry) or FDE (Frame
Description Entry).
- New helper function can now correctly identify both 32-bit and 64-bit
CIE based on the DWARF specifications.
- Updated the `ParseCIE` and `GetFDEIndex` methods to utilize the new
helper function for improved clarity and correctness in identifying CIE
and FDE entries.
- Replaced direct comparisons with `UINT32_MAX` and `UINT64_MAX` with
`std::numeric_limits` for better readability.

Added: 
    

Modified: 
    lldb/source/Symbol/DWARFCallFrameInfo.cpp
    lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp 
b/lldb/source/Symbol/DWARFCallFrameInfo.cpp
index 2f8f9e9182fb2..b490045cb3818 100644
--- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp
+++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp
@@ -20,6 +20,8 @@
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/Timer.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include <cstdint>
 #include <cstring>
 #include <list>
 #include <optional>
@@ -147,6 +149,23 @@ GetGNUEHPointer(const DataExtractor &DE, lldb::offset_t 
*offset_ptr,
   return baseAddress + addressValue;
 }
 
+// Check if the given cie_id value indicates a CIE (Common Information Entry)
+// as opposed to an FDE (Frame Description Entry).
+static bool IsCIEMarker(uint64_t cie_id, bool is_64bit,
+                        DWARFCallFrameInfo::Type type) {
+  // Check eh_frame CIE marker
+  if (type == DWARFCallFrameInfo::EH)
+    return cie_id == 0;
+
+  // Check debug_frame CIE marker
+  // DWARF64
+  if (is_64bit)
+    return cie_id == llvm::dwarf::DW64_CIE_ID;
+
+  // DWARF32
+  return cie_id == llvm::dwarf::DW_CIE_ID;
+}
+
 DWARFCallFrameInfo::DWARFCallFrameInfo(ObjectFile &objfile,
                                        SectionSP &section_sp, Type type)
     : m_objfile(objfile), m_section_sp(section_sp), m_type(type) {}
@@ -283,7 +302,7 @@ DWARFCallFrameInfo::ParseCIE(const dw_offset_t cie_offset) {
     GetCFIData();
   uint32_t length = m_cfi_data.GetU32(&offset);
   dw_offset_t cie_id, end_offset;
-  bool is_64bit = (length == UINT32_MAX);
+  bool is_64bit = (length == llvm::dwarf::DW_LENGTH_DWARF64);
   if (is_64bit) {
     length = m_cfi_data.GetU64(&offset);
     cie_id = m_cfi_data.GetU64(&offset);
@@ -292,8 +311,9 @@ DWARFCallFrameInfo::ParseCIE(const dw_offset_t cie_offset) {
     cie_id = m_cfi_data.GetU32(&offset);
     end_offset = cie_offset + length + 4;
   }
-  if (length > 0 && ((m_type == DWARF && cie_id == UINT32_MAX) ||
-                     (m_type == EH && cie_id == 0ul))) {
+
+  // Check if this is a CIE or FDE based on the CIE ID marker
+  if (length > 0 && IsCIEMarker(cie_id, is_64bit, m_type)) {
     size_t i;
     //    cie.offset = cie_offset;
     //    cie.length = length;
@@ -470,7 +490,7 @@ void DWARFCallFrameInfo::GetFDEIndex() {
     const dw_offset_t current_entry = offset;
     dw_offset_t cie_id, next_entry, cie_offset;
     uint32_t len = m_cfi_data.GetU32(&offset);
-    bool is_64bit = (len == UINT32_MAX);
+    bool is_64bit = (len == llvm::dwarf::DW_LENGTH_DWARF64);
     if (is_64bit) {
       len = m_cfi_data.GetU64(&offset);
       cie_id = m_cfi_data.GetU64(&offset);
@@ -493,11 +513,8 @@ void DWARFCallFrameInfo::GetFDEIndex() {
       return;
     }
 
-    // An FDE entry contains CIE_pointer in debug_frame in same place as cie_id
-    // in eh_frame. CIE_pointer is an offset into the .debug_frame section. So,
-    // variable cie_offset should be equal to cie_id for debug_frame.
-    // FDE entries with cie_id == 0 shouldn't be ignored for it.
-    if ((cie_id == 0 && m_type == EH) || cie_id == UINT32_MAX || len == 0) {
+    // Check if this is a CIE or FDE based on the CIE ID marker
+    if (IsCIEMarker(cie_id, is_64bit, m_type) || len == 0) {
       auto cie_sp = ParseCIE(current_entry);
       if (!cie_sp) {
         // Cannot parse, the reason is already logged
@@ -568,7 +585,7 @@ DWARFCallFrameInfo::ParseFDE(dw_offset_t dwarf_offset,
 
   uint32_t length = m_cfi_data.GetU32(&offset);
   dw_offset_t cie_offset;
-  bool is_64bit = (length == UINT32_MAX);
+  bool is_64bit = (length == llvm::dwarf::DW_LENGTH_DWARF64);
   if (is_64bit) {
     length = m_cfi_data.GetU64(&offset);
     cie_offset = m_cfi_data.GetU64(&offset);
@@ -577,7 +594,9 @@ DWARFCallFrameInfo::ParseFDE(dw_offset_t dwarf_offset,
   }
 
   // FDE entries with zeroth cie_offset may occur for debug_frame.
-  assert(!(m_type == EH && 0 == cie_offset) && cie_offset != UINT32_MAX);
+  assert(!(m_type == EH && 0 == cie_offset) &&
+         cie_offset !=
+             (is_64bit ? llvm::dwarf::DW64_CIE_ID : llvm::dwarf::DW_CIE_ID));
 
   // Translate the CIE_id from the eh_frame format, which is relative to the
   // FDE offset, into a __eh_frame section offset

diff  --git a/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp 
b/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp
index e113b8ca99341..c52e9a7387e14 100644
--- a/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp
+++ b/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp
@@ -380,3 +380,288 @@ void 
DWARFCallFrameInfoTest::TestValOffset(DWARFCallFrameInfo::Type type,
 TEST_F(DWARFCallFrameInfoTest, ValOffset_dwarf3) {
   TestValOffset(DWARFCallFrameInfo::DWARF, "debug_frame3");
 }
+
+// Test that we correctly handle invalid FDE entries that have CIE ID values
+TEST_F(DWARFCallFrameInfoTest, InvalidFDEWithCIEID_dwarf32) {
+  // Create an FDE with cie_offset of 0xFFFFFFFF (DW_CIE_ID) which is invalid
+  auto ExpectedFile = TestFile::fromYaml(R"(
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x0000000000000260
+    AddressAlign:    0x0000000000000010
+    Content:         554889E5897DFC8B45FC5DC3
+  - Name:            .debug_frame
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x0000000000000008
+    # First, a valid CIE
+    # 00000000 0000000000000014 ffffffff CIE
+    #   Version:               3
+    #   Augmentation:          ""
+    #   Code alignment factor: 1
+    #   Data alignment factor: -8
+    #   Return address column: 16
+    Content:         
14000000FFFFFFFF03000178100C0708900100000000000018000000FFFFFFFF60020000000000000C00000000000000
+    # Then an invalid FDE with CIE pointer = 0xFFFFFFFF (which would make it 
look like a CIE)
+    # 00000018 0000000000000018 ffffffff FDE cie=ffffffff 
pc=0000000000000260..000000000000026c
+    # The cie offset of 0xFFFFFFFF is invalid for an FDE in debug_frame
+Symbols:
+  - Name:            test_invalid
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x0000000000000260
+    Size:            0x000000000000000C
+    Binding:         STB_GLOBAL
+...
+)");
+  ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
+
+  auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
+  SectionList *list = module_sp->GetSectionList();
+  ASSERT_NE(nullptr, list);
+
+  auto section_sp = list->FindSectionByType(eSectionTypeDWARFDebugFrame, 
false);
+  ASSERT_NE(nullptr, section_sp);
+
+  DWARFCallFrameInfo cfi(*module_sp->GetObjectFile(), section_sp,
+                         DWARFCallFrameInfo::DWARF);
+
+  // This should trigger our assertion or return nullptr because the FDE is
+  // invalid
+  const Symbol *sym = module_sp->FindFirstSymbolWithNameAndType(
+      ConstString("test_invalid"), eSymbolTypeAny);
+  ASSERT_NE(nullptr, sym);
+
+  std::unique_ptr<UnwindPlan> plan_up = cfi.GetUnwindPlan(sym->GetAddress());
+  // The plan should be null because we have an invalid FDE
+  EXPECT_EQ(nullptr, plan_up);
+}
+
+// Test that we correctly handle invalid FDE entries that have CIE ID values
+TEST_F(DWARFCallFrameInfoTest, InvalidFDEWithCIEID_dwarf64) {
+  // Create an FDE with cie_offset of 0xFFFFFFFFFFFFFFFF (DW64_CIE_ID) which is
+  // invalid
+  auto ExpectedFile = TestFile::fromYaml(R"(
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x0000000000000260
+    AddressAlign:    0x0000000000000010
+    Content:         554889E5897DFC8B45FC5DC3
+  - Name:            .debug_frame
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x0000000000000008
+    # DWARF64 format CIE
+    # Initial length: 0xFFFFFFFF followed by 64-bit length
+    # 00000000 ffffffff 0000000000000014 ffffffffffffffff CIE
+    Content:         
FFFFFFFF1400000000000000FFFFFFFFFFFFFFFF03000178100C0708900100000000FFFFFFFF1800000000000000FFFFFFFFFFFFFFFF60020000000000000C00000000000000
+    # DWARF64 FDE with invalid CIE pointer = 0xFFFFFFFFFFFFFFFF
+    # Initial length: 0xFFFFFFFF, followed by 64-bit length (0x18)
+    # Then 64-bit CIE pointer: 0xFFFFFFFFFFFFFFFF (which is DW64_CIE_ID, 
invalid for FDE)
+Symbols:
+  - Name:            test_invalid64
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x0000000000000260
+    Size:            0x000000000000000C
+    Binding:         STB_GLOBAL
+...
+)");
+  ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
+
+  auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
+  SectionList *list = module_sp->GetSectionList();
+  ASSERT_NE(nullptr, list);
+
+  auto section_sp = list->FindSectionByType(eSectionTypeDWARFDebugFrame, 
false);
+  ASSERT_NE(nullptr, section_sp);
+
+  DWARFCallFrameInfo cfi(*module_sp->GetObjectFile(), section_sp,
+                         DWARFCallFrameInfo::DWARF);
+
+  const Symbol *sym = module_sp->FindFirstSymbolWithNameAndType(
+      ConstString("test_invalid64"), eSymbolTypeAny);
+  ASSERT_NE(nullptr, sym);
+
+  std::unique_ptr<UnwindPlan> plan_up = cfi.GetUnwindPlan(sym->GetAddress());
+  // The plan should be null because we have an invalid FDE
+  EXPECT_EQ(nullptr, plan_up);
+}
+
+// Test valid CIE markers in eh_frame format
+TEST_F(DWARFCallFrameInfoTest, ValidCIEMarkers_eh_frame) {
+  auto ExpectedFile = TestFile::fromYaml(R"(
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+  Machine:         EM_X86_64
+  Entry:           0x0000000000000260
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x0000000000000260
+    AddressAlign:    0x0000000000000010
+    Content:         554889E5897DFC8B45FC5DC3
+  - Name:            .eh_frame
+    Type:            SHT_X86_64_UNWIND
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x0000000000000290
+    AddressAlign:    0x0000000000000008
+    # eh_frame content
+    # CIE + FDE that works with address 0x260
+    Content:         
1400000000000000017A5200017810011B0C0708900100001C0000001C000000B0FFFFFF0C00000000410E108602430D0600000000000000
+Symbols:
+  - Name:            simple_function
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x0000000000000260
+    Size:            0x000000000000000F
+    Binding:         STB_GLOBAL
+...
+)");
+  ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
+
+  auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
+  SectionList *list = module_sp->GetSectionList();
+  ASSERT_NE(nullptr, list);
+
+  auto section_sp = list->FindSectionByType(eSectionTypeEHFrame, false);
+  ASSERT_NE(nullptr, section_sp);
+
+  DWARFCallFrameInfo cfi(*module_sp->GetObjectFile(), section_sp,
+                         DWARFCallFrameInfo::EH);
+
+  const Symbol *sym = module_sp->FindFirstSymbolWithNameAndType(
+      ConstString("simple_function"), eSymbolTypeAny);
+  ASSERT_NE(nullptr, sym);
+
+  std::unique_ptr<UnwindPlan> plan_up = cfi.GetUnwindPlan(sym->GetAddress());
+  // Should succeed with valid CIE and FDE
+  ASSERT_NE(nullptr, plan_up);
+  EXPECT_GE(plan_up->GetRowCount(), 1);
+}
+
+// Test valid CIE markers in debug_frame DWARF32 format
+TEST_F(DWARFCallFrameInfoTest, ValidCIEMarkers_dwarf32) {
+  auto ExpectedFile = TestFile::fromYaml(R"(
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x0000000000001130
+    AddressAlign:    0x0000000000000010
+    Content:         554889E5897DFC8B45FC83C0015DC3
+  - Name:            .debug_frame
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x0000000000000008
+    # debug_frame content in DWARF32 format
+    # CIE (length=0x14, CIE_id=0xFFFFFFFF, version=4)
+    # FDE (length=0x24, CIE_offset=0)
+    Content:         
14000000FFFFFFFF040008000178100C0708900100000000240000000000000030110000000000000F00000000000000410E108602430D064A0C070800000000
+Symbols:
+  - Name:            simple_function
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x0000000000001130
+    Size:            0x000000000000000F
+    Binding:         STB_GLOBAL
+...
+)");
+  ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
+
+  auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
+  SectionList *list = module_sp->GetSectionList();
+  ASSERT_NE(nullptr, list);
+
+  auto section_sp = list->FindSectionByType(eSectionTypeDWARFDebugFrame, 
false);
+  ASSERT_NE(nullptr, section_sp);
+
+  DWARFCallFrameInfo cfi(*module_sp->GetObjectFile(), section_sp,
+                         DWARFCallFrameInfo::DWARF);
+
+  const Symbol *sym = module_sp->FindFirstSymbolWithNameAndType(
+      ConstString("simple_function"), eSymbolTypeAny);
+  ASSERT_NE(nullptr, sym);
+
+  std::unique_ptr<UnwindPlan> plan_up = cfi.GetUnwindPlan(sym->GetAddress());
+  // Should succeed with valid CIE and FDE
+  ASSERT_NE(nullptr, plan_up);
+  EXPECT_GE(plan_up->GetRowCount(), 1);
+}
+
+// Test valid CIE markers in debug_frame DWARF64 format
+TEST_F(DWARFCallFrameInfoTest, ValidCIEMarkers_dwarf64) {
+  auto ExpectedFile = TestFile::fromYaml(R"(
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x0000000000001130
+    AddressAlign:    0x0000000000000010
+    Content:         554889E5897DFC8B45FC83C0015DC3
+  - Name:            .debug_frame
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x0000000000000008
+    # debug_frame content in DWARF64 format
+    # CIE: length_marker=0xFFFFFFFF, length=0x14, CIE_id=0xFFFFFFFFFFFFFFFF, 
version=4
+    # FDE: length_marker=0xFFFFFFFF, length=0x24, CIE_offset=0x0 (points to 
CIE)
+    Content:         
FFFFFFFF1400000000000000FFFFFFFFFFFFFFFF040008000178100C07089001FFFFFFFF2400000000000000000000000000000030110000000000000F00000000000000410E108602430D064A0C0708
+Symbols:
+  - Name:            simple_function
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x0000000000001130
+    Size:            0x000000000000000F
+    Binding:         STB_GLOBAL
+...
+)");
+  ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
+
+  auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
+  SectionList *list = module_sp->GetSectionList();
+  ASSERT_NE(nullptr, list);
+
+  auto section_sp = list->FindSectionByType(eSectionTypeDWARFDebugFrame, 
false);
+  ASSERT_NE(nullptr, section_sp);
+
+  DWARFCallFrameInfo cfi(*module_sp->GetObjectFile(), section_sp,
+                         DWARFCallFrameInfo::DWARF);
+
+  const Symbol *sym = module_sp->FindFirstSymbolWithNameAndType(
+      ConstString("simple_function"), eSymbolTypeAny);
+  ASSERT_NE(nullptr, sym);
+
+  std::unique_ptr<UnwindPlan> plan_up = cfi.GetUnwindPlan(sym->GetAddress());
+  // Should succeed with valid CIE and FDE
+  ASSERT_NE(nullptr, plan_up);
+  EXPECT_GE(plan_up->GetRowCount(), 1);
+}


        
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to