1//===-- TestDWARFCallFrameInfo.cpp ----------------------------------------===//
2//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#include "gtest/gtest.h"
11
12#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
13#include "Plugins/Process/Utility/RegisterContext_x86.h"
14#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
15#include "TestingSupport/SubsystemRAII.h"
16#include "TestingSupport/TestUtilities.h"
17
18#include "lldb/Core/Module.h"
19#include "lldb/Core/ModuleSpec.h"
20#include "lldb/Core/Section.h"
21#include "lldb/Host/FileSystem.h"
22#include "lldb/Host/HostInfo.h"
23#include "lldb/Symbol/DWARFCallFrameInfo.h"
24#include "lldb/Utility/StreamString.h"
25#include "llvm/Testing/Support/Error.h"
26
27#include "llvm/Support/FileUtilities.h"
28#include "llvm/Support/Path.h"
29#include "llvm/Support/Program.h"
30#include "llvm/Support/raw_ostream.h"
31
32using namespace lldb_private;
33using namespace lldb;
34
35class DWARFCallFrameInfoTest : public testing::Test {
36 SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab>
37 subsystems;
38
39protected:
40 void TestBasic(DWARFCallFrameInfo::Type type, llvm::StringRef symbol);
41};
42
43namespace lldb_private {
44static std::ostream &operator<<(std::ostream &OS, const UnwindPlan::Row &row) {
45 StreamString SS;
46 row.Dump(s&: SS, unwind_plan: nullptr, thread: nullptr, base_addr: 0);
47 return OS << SS.GetData();
48}
49} // namespace lldb_private
50
51static UnwindPlan::Row GetExpectedRow0() {
52 UnwindPlan::Row row;
53 row.SetOffset(0);
54 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: dwarf_rsp_x86_64, offset: 8);
55 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: dwarf_rip_x86_64, offset: -8, can_replace: false);
56 return row;
57}
58
59static UnwindPlan::Row GetExpectedRow1() {
60 UnwindPlan::Row row;
61 row.SetOffset(1);
62 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: dwarf_rsp_x86_64, offset: 16);
63 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: dwarf_rip_x86_64, offset: -8, can_replace: false);
64 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: dwarf_rbp_x86_64, offset: -16, can_replace: false);
65 return row;
66}
67
68static UnwindPlan::Row GetExpectedRow2() {
69 UnwindPlan::Row row;
70 row.SetOffset(4);
71 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: dwarf_rbp_x86_64, offset: 16);
72 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: dwarf_rip_x86_64, offset: -8, can_replace: false);
73 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: dwarf_rbp_x86_64, offset: -16, can_replace: false);
74 return row;
75}
76
77void DWARFCallFrameInfoTest::TestBasic(DWARFCallFrameInfo::Type type,
78 llvm::StringRef symbol) {
79 auto ExpectedFile = TestFile::fromYaml(Yaml: R"(
80--- !ELF
81FileHeader:
82 Class: ELFCLASS64
83 Data: ELFDATA2LSB
84 Type: ET_DYN
85 Machine: EM_X86_64
86 Entry: 0x0000000000000260
87Sections:
88 - Name: .text
89 Type: SHT_PROGBITS
90 Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
91 Address: 0x0000000000000260
92 AddressAlign: 0x0000000000000010
93 Content: 554889E5897DFC8B45FC5DC30F1F4000554889E5897DFC8B45FC5DC30F1F4000554889E5897DFC8B45FC5DC3
94#0000000000000260 <eh_frame>:
95# 260: 55 push %rbp
96# 261: 48 89 e5 mov %rsp,%rbp
97# 264: 89 7d fc mov %edi,-0x4(%rbp)
98# 267: 8b 45 fc mov -0x4(%rbp),%eax
99# 26a: 5d pop %rbp
100# 26b: c3 retq
101# 26c: 0f 1f 40 00 nopl 0x0(%rax)
102#
103#0000000000000270 <debug_frame3>:
104# 270: 55 push %rbp
105# 271: 48 89 e5 mov %rsp,%rbp
106# 274: 89 7d fc mov %edi,-0x4(%rbp)
107# 277: 8b 45 fc mov -0x4(%rbp),%eax
108# 27a: 5d pop %rbp
109# 27b: c3 retq
110# 27c: 0f 1f 40 00 nopl 0x0(%rax)
111#
112#0000000000000280 <debug_frame4>:
113# 280: 55 push %rbp
114# 281: 48 89 e5 mov %rsp,%rbp
115# 284: 89 7d fc mov %edi,-0x4(%rbp)
116# 287: 8b 45 fc mov -0x4(%rbp),%eax
117# 28a: 5d pop %rbp
118# 28b: c3 retq
119 - Name: .eh_frame
120 Type: SHT_X86_64_UNWIND
121 Flags: [ SHF_ALLOC ]
122 Address: 0x0000000000000290
123 AddressAlign: 0x0000000000000008
124 Content: 1400000000000000017A5200017810011B0C0708900100001C0000001C000000B0FFFFFF0C00000000410E108602430D0600000000000000
125#00000000 0000000000000014 00000000 CIE
126# Version: 1
127# Augmentation: "zR"
128# Code alignment factor: 1
129# Data alignment factor: -8
130# Return address column: 16
131# Augmentation data: 1b
132#
133# DW_CFA_def_cfa: r7 (rsp) ofs 8
134# DW_CFA_offset: r16 (rip) at cfa-8
135# DW_CFA_nop
136# DW_CFA_nop
137#
138#00000018 000000000000001c 0000001c FDE cie=00000000 pc=ffffffffffffffd0..ffffffffffffffdc
139# DW_CFA_advance_loc: 1 to ffffffffffffffd1
140# DW_CFA_def_cfa_offset: 16
141# DW_CFA_offset: r6 (rbp) at cfa-16
142# DW_CFA_advance_loc: 3 to ffffffffffffffd4
143# DW_CFA_def_cfa_register: r6 (rbp)
144# DW_CFA_nop
145# DW_CFA_nop
146# DW_CFA_nop
147# DW_CFA_nop
148# DW_CFA_nop
149# DW_CFA_nop
150# DW_CFA_nop
151 - Name: .debug_frame
152 Type: SHT_PROGBITS
153 AddressAlign: 0x0000000000000008
154 Content: 14000000FFFFFFFF03000178100C070890010000000000001C0000000000000070020000000000000C00000000000000410E108602430D0614000000FFFFFFFF040008000178100C07089001000000001C0000003800000080020000000000000C00000000000000410E108602430D06
155#00000000 0000000000000014 ffffffff CIE
156# Version: 3
157# Augmentation: ""
158# Code alignment factor: 1
159# Data alignment factor: -8
160# Return address column: 16
161#
162# DW_CFA_def_cfa: r7 (rsp) ofs 8
163# DW_CFA_offset: r16 (rip) at cfa-8
164# DW_CFA_nop
165# DW_CFA_nop
166# DW_CFA_nop
167# DW_CFA_nop
168# DW_CFA_nop
169# DW_CFA_nop
170#
171#00000018 000000000000001c 00000000 FDE cie=00000000 pc=0000000000000270..000000000000027c
172# DW_CFA_advance_loc: 1 to 0000000000000271
173# DW_CFA_def_cfa_offset: 16
174# DW_CFA_offset: r6 (rbp) at cfa-16
175# DW_CFA_advance_loc: 3 to 0000000000000274
176# DW_CFA_def_cfa_register: r6 (rbp)
177#
178#00000038 0000000000000014 ffffffff CIE
179# Version: 4
180# Augmentation: ""
181# Pointer Size: 8
182# Segment Size: 0
183# Code alignment factor: 1
184# Data alignment factor: -8
185# Return address column: 16
186#
187# DW_CFA_def_cfa: r7 (rsp) ofs 8
188# DW_CFA_offset: r16 (rip) at cfa-8
189# DW_CFA_nop
190# DW_CFA_nop
191# DW_CFA_nop
192# DW_CFA_nop
193#
194#00000050 000000000000001c 00000038 FDE cie=00000038 pc=0000000000000280..000000000000028c
195# DW_CFA_advance_loc: 1 to 0000000000000281
196# DW_CFA_def_cfa_offset: 16
197# DW_CFA_offset: r6 (rbp) at cfa-16
198# DW_CFA_advance_loc: 3 to 0000000000000284
199# DW_CFA_def_cfa_register: r6 (rbp)
200Symbols:
201 - Name: eh_frame
202 Type: STT_FUNC
203 Section: .text
204 Value: 0x0000000000000260
205 Size: 0x000000000000000C
206 Binding: STB_GLOBAL
207 - Name: debug_frame3
208 Type: STT_FUNC
209 Section: .text
210 Value: 0x0000000000000270
211 Size: 0x000000000000000C
212 Binding: STB_GLOBAL
213 - Name: debug_frame4
214 Type: STT_FUNC
215 Section: .text
216 Value: 0x0000000000000280
217 Size: 0x000000000000000C
218 Binding: STB_GLOBAL
219...
220)");
221 ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
222
223 auto module_sp = std::make_shared<Module>(args: ExpectedFile->moduleSpec());
224 SectionList *list = module_sp->GetSectionList();
225 ASSERT_NE(nullptr, list);
226
227 auto section_sp = list->FindSectionByType(sect_type: type == DWARFCallFrameInfo::EH
228 ? eSectionTypeEHFrame
229 : eSectionTypeDWARFDebugFrame,
230 check_children: false);
231 ASSERT_NE(nullptr, section_sp);
232
233 DWARFCallFrameInfo cfi(*module_sp->GetObjectFile(), section_sp, type);
234
235 const Symbol *sym = module_sp->FindFirstSymbolWithNameAndType(
236 name: ConstString(symbol), symbol_type: eSymbolTypeAny);
237 ASSERT_NE(nullptr, sym);
238
239 UnwindPlan plan(eRegisterKindGeneric);
240 ASSERT_TRUE(cfi.GetUnwindPlan(sym->GetAddress(), plan));
241 ASSERT_EQ(3, plan.GetRowCount());
242 EXPECT_EQ(GetExpectedRow0(), *plan.GetRowAtIndex(0));
243 EXPECT_EQ(GetExpectedRow1(), *plan.GetRowAtIndex(1));
244 EXPECT_EQ(GetExpectedRow2(), *plan.GetRowAtIndex(2));
245}
246
247TEST_F(DWARFCallFrameInfoTest, Basic_dwarf3) {
248 TestBasic(type: DWARFCallFrameInfo::DWARF, symbol: "debug_frame3");
249}
250
251TEST_F(DWARFCallFrameInfoTest, Basic_dwarf4) {
252 TestBasic(type: DWARFCallFrameInfo::DWARF, symbol: "debug_frame4");
253}
254
255TEST_F(DWARFCallFrameInfoTest, Basic_eh) {
256 TestBasic(type: DWARFCallFrameInfo::EH, symbol: "eh_frame");
257}
258

source code of lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp