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

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