CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
668 lines
23 KiB
C++
668 lines
23 KiB
C++
//===-- TestDWARFCallFrameInfo.cpp ----------------------------------------===//
|
|
//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
|
|
#include "Plugins/Process/Utility/RegisterContext_x86.h"
|
|
#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
|
|
#include "TestingSupport/SubsystemRAII.h"
|
|
#include "TestingSupport/TestUtilities.h"
|
|
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Core/ModuleSpec.h"
|
|
#include "lldb/Core/Section.h"
|
|
#include "lldb/Host/FileSystem.h"
|
|
#include "lldb/Host/HostInfo.h"
|
|
#include "lldb/Symbol/DWARFCallFrameInfo.h"
|
|
#include "lldb/Utility/StreamString.h"
|
|
#include "llvm/Testing/Support/Error.h"
|
|
|
|
#include "llvm/Support/FileUtilities.h"
|
|
#include "llvm/Support/Path.h"
|
|
#include "llvm/Support/Program.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace lldb_private;
|
|
using namespace lldb;
|
|
|
|
class DWARFCallFrameInfoTest : public testing::Test {
|
|
SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab>
|
|
subsystems;
|
|
|
|
protected:
|
|
void TestBasic(DWARFCallFrameInfo::Type type, llvm::StringRef symbol);
|
|
void TestValOffset(DWARFCallFrameInfo::Type type, llvm::StringRef symbol);
|
|
};
|
|
|
|
namespace lldb_private {
|
|
static std::ostream &operator<<(std::ostream &OS, const UnwindPlan::Row &row) {
|
|
StreamString SS;
|
|
row.Dump(SS, nullptr, nullptr, 0);
|
|
return OS << SS.GetData();
|
|
}
|
|
} // namespace lldb_private
|
|
|
|
static UnwindPlan::Row GetExpectedRow0() {
|
|
UnwindPlan::Row row;
|
|
row.SetOffset(0);
|
|
row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rsp_x86_64, 8);
|
|
row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
|
|
return row;
|
|
}
|
|
|
|
static UnwindPlan::Row GetExpectedRow1() {
|
|
UnwindPlan::Row row;
|
|
row.SetOffset(1);
|
|
row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rsp_x86_64, 16);
|
|
row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
|
|
row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rbp_x86_64, -16, false);
|
|
return row;
|
|
}
|
|
|
|
static UnwindPlan::Row GetExpectedRow2() {
|
|
UnwindPlan::Row row;
|
|
row.SetOffset(4);
|
|
row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rbp_x86_64, 16);
|
|
row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
|
|
row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rbp_x86_64, -16, false);
|
|
return row;
|
|
}
|
|
|
|
void DWARFCallFrameInfoTest::TestBasic(DWARFCallFrameInfo::Type type,
|
|
llvm::StringRef symbol) {
|
|
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: 554889E5897DFC8B45FC5DC30F1F4000554889E5897DFC8B45FC5DC30F1F4000554889E5897DFC8B45FC5DC3
|
|
#0000000000000260 <eh_frame>:
|
|
# 260: 55 push %rbp
|
|
# 261: 48 89 e5 mov %rsp,%rbp
|
|
# 264: 89 7d fc mov %edi,-0x4(%rbp)
|
|
# 267: 8b 45 fc mov -0x4(%rbp),%eax
|
|
# 26a: 5d pop %rbp
|
|
# 26b: c3 retq
|
|
# 26c: 0f 1f 40 00 nopl 0x0(%rax)
|
|
#
|
|
#0000000000000270 <debug_frame3>:
|
|
# 270: 55 push %rbp
|
|
# 271: 48 89 e5 mov %rsp,%rbp
|
|
# 274: 89 7d fc mov %edi,-0x4(%rbp)
|
|
# 277: 8b 45 fc mov -0x4(%rbp),%eax
|
|
# 27a: 5d pop %rbp
|
|
# 27b: c3 retq
|
|
# 27c: 0f 1f 40 00 nopl 0x0(%rax)
|
|
#
|
|
#0000000000000280 <debug_frame4>:
|
|
# 280: 55 push %rbp
|
|
# 281: 48 89 e5 mov %rsp,%rbp
|
|
# 284: 89 7d fc mov %edi,-0x4(%rbp)
|
|
# 287: 8b 45 fc mov -0x4(%rbp),%eax
|
|
# 28a: 5d pop %rbp
|
|
# 28b: c3 retq
|
|
- Name: .eh_frame
|
|
Type: SHT_X86_64_UNWIND
|
|
Flags: [ SHF_ALLOC ]
|
|
Address: 0x0000000000000290
|
|
AddressAlign: 0x0000000000000008
|
|
Content: 1400000000000000017A5200017810011B0C0708900100001C0000001C000000B0FFFFFF0C00000000410E108602430D0600000000000000
|
|
#00000000 0000000000000014 00000000 CIE
|
|
# Version: 1
|
|
# Augmentation: "zR"
|
|
# Code alignment factor: 1
|
|
# Data alignment factor: -8
|
|
# Return address column: 16
|
|
# Augmentation data: 1b
|
|
#
|
|
# DW_CFA_def_cfa: r7 (rsp) ofs 8
|
|
# DW_CFA_offset: r16 (rip) at cfa-8
|
|
# DW_CFA_nop
|
|
# DW_CFA_nop
|
|
#
|
|
#00000018 000000000000001c 0000001c FDE cie=00000000 pc=ffffffffffffffd0..ffffffffffffffdc
|
|
# DW_CFA_advance_loc: 1 to ffffffffffffffd1
|
|
# DW_CFA_def_cfa_offset: 16
|
|
# DW_CFA_offset: r6 (rbp) at cfa-16
|
|
# DW_CFA_advance_loc: 3 to ffffffffffffffd4
|
|
# DW_CFA_def_cfa_register: r6 (rbp)
|
|
# DW_CFA_nop
|
|
# DW_CFA_nop
|
|
# DW_CFA_nop
|
|
# DW_CFA_nop
|
|
# DW_CFA_nop
|
|
# DW_CFA_nop
|
|
# DW_CFA_nop
|
|
- Name: .debug_frame
|
|
Type: SHT_PROGBITS
|
|
AddressAlign: 0x0000000000000008
|
|
Content: 14000000FFFFFFFF03000178100C070890010000000000001C0000000000000070020000000000000C00000000000000410E108602430D0614000000FFFFFFFF040008000178100C07089001000000001C0000003800000080020000000000000C00000000000000410E108602430D06
|
|
#00000000 0000000000000014 ffffffff CIE
|
|
# Version: 3
|
|
# Augmentation: ""
|
|
# Code alignment factor: 1
|
|
# Data alignment factor: -8
|
|
# Return address column: 16
|
|
#
|
|
# DW_CFA_def_cfa: r7 (rsp) ofs 8
|
|
# DW_CFA_offset: r16 (rip) at cfa-8
|
|
# DW_CFA_nop
|
|
# DW_CFA_nop
|
|
# DW_CFA_nop
|
|
# DW_CFA_nop
|
|
# DW_CFA_nop
|
|
# DW_CFA_nop
|
|
#
|
|
#00000018 000000000000001c 00000000 FDE cie=00000000 pc=0000000000000270..000000000000027c
|
|
# DW_CFA_advance_loc: 1 to 0000000000000271
|
|
# DW_CFA_def_cfa_offset: 16
|
|
# DW_CFA_offset: r6 (rbp) at cfa-16
|
|
# DW_CFA_advance_loc: 3 to 0000000000000274
|
|
# DW_CFA_def_cfa_register: r6 (rbp)
|
|
#
|
|
#00000038 0000000000000014 ffffffff CIE
|
|
# Version: 4
|
|
# Augmentation: ""
|
|
# Pointer Size: 8
|
|
# Segment Size: 0
|
|
# Code alignment factor: 1
|
|
# Data alignment factor: -8
|
|
# Return address column: 16
|
|
#
|
|
# DW_CFA_def_cfa: r7 (rsp) ofs 8
|
|
# DW_CFA_offset: r16 (rip) at cfa-8
|
|
# DW_CFA_nop
|
|
# DW_CFA_nop
|
|
# DW_CFA_nop
|
|
# DW_CFA_nop
|
|
#
|
|
#00000050 000000000000001c 00000038 FDE cie=00000038 pc=0000000000000280..000000000000028c
|
|
# DW_CFA_advance_loc: 1 to 0000000000000281
|
|
# DW_CFA_def_cfa_offset: 16
|
|
# DW_CFA_offset: r6 (rbp) at cfa-16
|
|
# DW_CFA_advance_loc: 3 to 0000000000000284
|
|
# DW_CFA_def_cfa_register: r6 (rbp)
|
|
Symbols:
|
|
- Name: eh_frame
|
|
Type: STT_FUNC
|
|
Section: .text
|
|
Value: 0x0000000000000260
|
|
Size: 0x000000000000000C
|
|
Binding: STB_GLOBAL
|
|
- Name: debug_frame3
|
|
Type: STT_FUNC
|
|
Section: .text
|
|
Value: 0x0000000000000270
|
|
Size: 0x000000000000000C
|
|
Binding: STB_GLOBAL
|
|
- Name: debug_frame4
|
|
Type: STT_FUNC
|
|
Section: .text
|
|
Value: 0x0000000000000280
|
|
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(type == DWARFCallFrameInfo::EH
|
|
? eSectionTypeEHFrame
|
|
: eSectionTypeDWARFDebugFrame,
|
|
false);
|
|
ASSERT_NE(nullptr, section_sp);
|
|
|
|
DWARFCallFrameInfo cfi(*module_sp->GetObjectFile(), section_sp, type);
|
|
|
|
const Symbol *sym = module_sp->FindFirstSymbolWithNameAndType(
|
|
ConstString(symbol), eSymbolTypeAny);
|
|
ASSERT_NE(nullptr, sym);
|
|
|
|
std::unique_ptr<UnwindPlan> plan_up = cfi.GetUnwindPlan(sym->GetAddress());
|
|
ASSERT_TRUE(plan_up);
|
|
ASSERT_EQ(3, plan_up->GetRowCount());
|
|
EXPECT_THAT(plan_up->GetRowAtIndex(0), testing::Pointee(GetExpectedRow0()));
|
|
EXPECT_THAT(plan_up->GetRowAtIndex(1), testing::Pointee(GetExpectedRow1()));
|
|
EXPECT_THAT(plan_up->GetRowAtIndex(2), testing::Pointee(GetExpectedRow2()));
|
|
}
|
|
|
|
TEST_F(DWARFCallFrameInfoTest, Basic_dwarf3) {
|
|
TestBasic(DWARFCallFrameInfo::DWARF, "debug_frame3");
|
|
}
|
|
|
|
TEST_F(DWARFCallFrameInfoTest, Basic_dwarf4) {
|
|
TestBasic(DWARFCallFrameInfo::DWARF, "debug_frame4");
|
|
}
|
|
|
|
TEST_F(DWARFCallFrameInfoTest, Basic_eh) {
|
|
TestBasic(DWARFCallFrameInfo::EH, "eh_frame");
|
|
}
|
|
|
|
static UnwindPlan::Row GetValOffsetExpectedRow0() {
|
|
UnwindPlan::Row row;
|
|
row.SetOffset(0);
|
|
row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rsp_x86_64, 16);
|
|
row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
|
|
row.SetRegisterLocationToIsCFAPlusOffset(dwarf_rbp_x86_64, -16, false);
|
|
return row;
|
|
}
|
|
|
|
void DWARFCallFrameInfoTest::TestValOffset(DWARFCallFrameInfo::Type type,
|
|
llvm::StringRef symbol) {
|
|
// This test is artificial as X86 does not use DW_CFA_val_offset but this
|
|
// test verifies that we can successfully interpret them if they do occur.
|
|
// Note the distinction between RBP and RIP in this part of the DWARF dump:
|
|
// 0x0: CFA=RSP+16: RBP=CFA-16, RIP=[CFA-8]
|
|
// Whereas RIP is stored in the memory CFA-8 points at, RBP is reconstructed
|
|
// from the CFA without any memory access.
|
|
auto ExpectedFile = TestFile::fromYaml(R"(
|
|
--- !ELF
|
|
FileHeader:
|
|
Class: ELFCLASS64
|
|
Data: ELFDATA2LSB
|
|
Type: ET_REL
|
|
Machine: EM_X86_64
|
|
SectionHeaderStringTable: .strtab
|
|
Sections:
|
|
- Name: .text
|
|
Type: SHT_PROGBITS
|
|
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
|
AddressAlign: 0x4
|
|
Content: 0F1F00
|
|
- Name: .debug_frame
|
|
Type: SHT_PROGBITS
|
|
AddressAlign: 0x8
|
|
#00000000 00000014 ffffffff CIE
|
|
# Format: DWARF32
|
|
# Version: 4
|
|
# Augmentation: ""
|
|
# Address size: 8
|
|
# Segment desc size: 0
|
|
# Code alignment factor: 1
|
|
# Data alignment factor: -8
|
|
# Return address column: 16
|
|
#
|
|
# DW_CFA_def_cfa: RSP +8
|
|
# DW_CFA_offset: RIP -8
|
|
# DW_CFA_nop:
|
|
# DW_CFA_nop:
|
|
# DW_CFA_nop:
|
|
# DW_CFA_nop:
|
|
#
|
|
# CFA=RSP+8: RIP=[CFA-8]
|
|
#
|
|
#00000018 0000001c 00000000 FDE cie=00000000 pc=00000000...00000003
|
|
# Format: DWARF32
|
|
# DW_CFA_def_cfa_offset: +16
|
|
# DW_CFA_val_offset: RBP -16
|
|
# DW_CFA_nop:
|
|
# DW_CFA_nop:
|
|
# DW_CFA_nop:
|
|
#
|
|
# 0x0: CFA=RSP+16: RBP=CFA-16, RIP=[CFA-8]
|
|
Content: 14000000FFFFFFFF040008000178100C07089001000000001C00000000000000000000000000000003000000000000000E10140602000000
|
|
- Name: .rela.debug_frame
|
|
Type: SHT_RELA
|
|
Flags: [ SHF_INFO_LINK ]
|
|
Link: .symtab
|
|
AddressAlign: 0x8
|
|
Info: .debug_frame
|
|
Relocations:
|
|
- Offset: 0x1C
|
|
Symbol: .debug_frame
|
|
Type: R_X86_64_32
|
|
- Offset: 0x20
|
|
Symbol: .text
|
|
Type: R_X86_64_64
|
|
- Type: SectionHeaderTable
|
|
Sections:
|
|
- Name: .strtab
|
|
- Name: .text
|
|
- Name: .debug_frame
|
|
- Name: .rela.debug_frame
|
|
- Name: .symtab
|
|
Symbols:
|
|
- Name: .text
|
|
Type: STT_SECTION
|
|
Section: .text
|
|
- Name: debug_frame3
|
|
Section: .text
|
|
- Name: .debug_frame
|
|
Type: STT_SECTION
|
|
Section: .debug_frame
|
|
...
|
|
)");
|
|
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(type == DWARFCallFrameInfo::EH
|
|
? eSectionTypeEHFrame
|
|
: eSectionTypeDWARFDebugFrame,
|
|
false);
|
|
ASSERT_NE(nullptr, section_sp);
|
|
|
|
DWARFCallFrameInfo cfi(*module_sp->GetObjectFile(), section_sp, type);
|
|
|
|
const Symbol *sym = module_sp->FindFirstSymbolWithNameAndType(
|
|
ConstString(symbol), eSymbolTypeAny);
|
|
ASSERT_NE(nullptr, sym);
|
|
|
|
std::unique_ptr<UnwindPlan> plan_up = cfi.GetUnwindPlan(sym->GetAddress());
|
|
ASSERT_TRUE(plan_up);
|
|
ASSERT_EQ(1, plan_up->GetRowCount());
|
|
EXPECT_THAT(plan_up->GetRowAtIndex(0),
|
|
testing::Pointee(GetValOffsetExpectedRow0()));
|
|
}
|
|
|
|
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);
|
|
}
|