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 
32 using namespace lldb_private;
33 using namespace lldb;
34 
35 class DWARFCallFrameInfoTest : public testing::Test {
36   SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab>
37       subsystems;
38 
39 protected:
40   void TestBasic(DWARFCallFrameInfo::Type type, llvm::StringRef symbol);
41 };
42 
43 namespace lldb_private {
operator <<(std::ostream & OS,const UnwindPlan::Row & row)44 static std::ostream &operator<<(std::ostream &OS, const UnwindPlan::Row &row) {
45   StreamString SS;
46   row.Dump(SS, nullptr, nullptr, 0);
47   return OS << SS.GetData();
48 }
49 } // namespace lldb_private
50 
GetExpectedRow0()51 static UnwindPlan::Row GetExpectedRow0() {
52   UnwindPlan::Row row;
53   row.SetOffset(0);
54   row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rsp_x86_64, 8);
55   row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
56   return row;
57 }
58 
GetExpectedRow1()59 static UnwindPlan::Row GetExpectedRow1() {
60   UnwindPlan::Row row;
61   row.SetOffset(1);
62   row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rsp_x86_64, 16);
63   row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
64   row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rbp_x86_64, -16, false);
65   return row;
66 }
67 
GetExpectedRow2()68 static UnwindPlan::Row GetExpectedRow2() {
69   UnwindPlan::Row row;
70   row.SetOffset(4);
71   row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rbp_x86_64, 16);
72   row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
73   row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rbp_x86_64, -16, false);
74   return row;
75 }
76 
TestBasic(DWARFCallFrameInfo::Type type,llvm::StringRef symbol)77 void DWARFCallFrameInfoTest::TestBasic(DWARFCallFrameInfo::Type type,
78                                        llvm::StringRef symbol) {
79   auto ExpectedFile = TestFile::fromYaml(R"(
80 --- !ELF
81 FileHeader:
82   Class:           ELFCLASS64
83   Data:            ELFDATA2LSB
84   Type:            ET_DYN
85   Machine:         EM_X86_64
86   Entry:           0x0000000000000260
87 Sections:
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)
200 Symbols:
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>(ExpectedFile->moduleSpec());
224   SectionList *list = module_sp->GetSectionList();
225   ASSERT_NE(nullptr, list);
226 
227   auto section_sp = list->FindSectionByType(type == DWARFCallFrameInfo::EH
228                                                 ? eSectionTypeEHFrame
229                                                 : eSectionTypeDWARFDebugFrame,
230                                             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       ConstString(symbol), 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 
TEST_F(DWARFCallFrameInfoTest,Basic_dwarf3)247 TEST_F(DWARFCallFrameInfoTest, Basic_dwarf3) {
248   TestBasic(DWARFCallFrameInfo::DWARF, "debug_frame3");
249 }
250 
TEST_F(DWARFCallFrameInfoTest,Basic_dwarf4)251 TEST_F(DWARFCallFrameInfoTest, Basic_dwarf4) {
252   TestBasic(DWARFCallFrameInfo::DWARF, "debug_frame4");
253 }
254 
TEST_F(DWARFCallFrameInfoTest,Basic_eh)255 TEST_F(DWARFCallFrameInfoTest, Basic_eh) {
256   TestBasic(DWARFCallFrameInfo::EH, "eh_frame");
257 }
258