1//===-- Testx86AssemblyInspectionEngine.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 <memory>
13#include <vector>
14
15#include "Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h"
16#include "lldb/Core/Address.h"
17#include "lldb/Core/AddressRange.h"
18#include "lldb/Symbol/UnwindPlan.h"
19#include "lldb/Utility/ArchSpec.h"
20#include "lldb/Utility/StreamString.h"
21
22#include "llvm/Support/TargetSelect.h"
23
24using namespace lldb;
25using namespace lldb_private;
26
27class Testx86AssemblyInspectionEngine : public testing::Test {
28public:
29 static void SetUpTestCase();
30
31 // static void TearDownTestCase() { }
32
33 // virtual void SetUp() override { }
34
35 // virtual void TearDown() override { }
36
37protected:
38};
39
40void Testx86AssemblyInspectionEngine::SetUpTestCase() {
41 llvm::InitializeAllTargets();
42 llvm::InitializeAllAsmPrinters();
43 llvm::InitializeAllTargetMCs();
44 llvm::InitializeAllDisassemblers();
45}
46
47// only defining the register names / numbers that the unwinder is actually
48// using today
49
50// names should match the constants below. These will be the eRegisterKindLLDB
51// register numbers.
52
53const char *x86_64_reg_names[] = {"rax", "rbx", "rcx", "rdx", "rsp", "rbp",
54 "rsi", "rdi", "r8", "r9", "r10", "r11",
55 "r12", "r13", "r14", "r15", "rip"};
56
57enum x86_64_regs {
58 k_rax = 0,
59 k_rbx = 1,
60 k_rcx = 2,
61 k_rdx = 3,
62 k_rsp = 4,
63 k_rbp = 5,
64 k_rsi = 6,
65 k_rdi = 7,
66 k_r8 = 8,
67 k_r9 = 9,
68 k_r10 = 10,
69 k_r11 = 11,
70 k_r12 = 12,
71 k_r13 = 13,
72 k_r14 = 14,
73 k_r15 = 15,
74 k_rip = 16
75};
76
77// names should match the constants below. These will be the eRegisterKindLLDB
78// register numbers.
79
80const char *i386_reg_names[] = {"eax", "ecx", "edx", "ebx", "esp",
81 "ebp", "esi", "edi", "eip"};
82
83enum i386_regs {
84 k_eax = 0,
85 k_ecx = 1,
86 k_edx = 2,
87 k_ebx = 3,
88 k_esp = 4,
89 k_ebp = 5,
90 k_esi = 6,
91 k_edi = 7,
92 k_eip = 8
93};
94
95std::unique_ptr<x86AssemblyInspectionEngine> Getx86_64Inspector() {
96
97 ArchSpec arch("x86_64-apple-macosx");
98 std::unique_ptr<x86AssemblyInspectionEngine> engine(
99 new x86AssemblyInspectionEngine(arch));
100
101 std::vector<x86AssemblyInspectionEngine::lldb_reg_info> lldb_regnums;
102 int i = 0;
103 for (const auto &name : x86_64_reg_names) {
104 x86AssemblyInspectionEngine::lldb_reg_info ri;
105 ri.name = name;
106 ri.lldb_regnum = i++;
107 lldb_regnums.push_back(x: ri);
108 }
109
110 engine->Initialize(reg_info&: lldb_regnums);
111 return engine;
112}
113
114std::unique_ptr<x86AssemblyInspectionEngine> Geti386Inspector() {
115
116 ArchSpec arch("i386-apple-macosx");
117 std::unique_ptr<x86AssemblyInspectionEngine> engine(
118 new x86AssemblyInspectionEngine(arch));
119
120 std::vector<x86AssemblyInspectionEngine::lldb_reg_info> lldb_regnums;
121 int i = 0;
122 for (const auto &name : i386_reg_names) {
123 x86AssemblyInspectionEngine::lldb_reg_info ri;
124 ri.name = name;
125 ri.lldb_regnum = i++;
126 lldb_regnums.push_back(x: ri);
127 }
128
129 engine->Initialize(reg_info&: lldb_regnums);
130 return engine;
131}
132
133namespace lldb_private {
134static std::ostream &operator<<(std::ostream &OS,
135 const UnwindPlan::Row::FAValue &CFA) {
136 StreamString S;
137 CFA.Dump(s&: S, unwind_plan: nullptr, thread: nullptr);
138 return OS << S.GetData();
139}
140} // namespace lldb_private
141
142TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitFrameFunction) {
143 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
144
145 // 'int main() { }' compiled for x86_64-apple-macosx with clang
146 uint8_t data[] = {
147 0x55, // offset 0 -- pushq %rbp
148 0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp
149 0x31, 0xc0, // offset 4 -- xorl %eax, %eax
150 0x5d, // offset 6 -- popq %rbp
151 0xc3 // offset 7 -- retq
152 };
153
154 AddressRange sample_range(0x1000, sizeof(data));
155
156 UnwindPlan unwind_plan(eRegisterKindLLDB);
157 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
158 data, sizeof(data), sample_range, unwind_plan));
159
160 // Expect four unwind rows:
161 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
162 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
163 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
164 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
165
166 EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp);
167 EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
168 eLazyBoolYes);
169 EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
170
171 UnwindPlan::Row::RegisterLocation regloc;
172
173 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
174 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(offset: 0);
175 EXPECT_EQ(0ull, row_sp->GetOffset());
176 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
177 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
178 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
179
180 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
181 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
182 EXPECT_EQ(-8, regloc.GetOffset());
183
184 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
185 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 1);
186 EXPECT_EQ(1ull, row_sp->GetOffset());
187 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
188 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
189 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
190
191 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
192 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
193 EXPECT_EQ(-8, regloc.GetOffset());
194
195 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
196 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 4);
197 EXPECT_EQ(4ull, row_sp->GetOffset());
198 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
199 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
200 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
201
202 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
203 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
204 EXPECT_EQ(-8, regloc.GetOffset());
205
206 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
207 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 7);
208 EXPECT_EQ(7ull, row_sp->GetOffset());
209 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
210 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
211 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
212
213 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
214 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
215 EXPECT_EQ(-8, regloc.GetOffset());
216}
217
218TEST_F(Testx86AssemblyInspectionEngine, TestSimple32bitFrameFunction) {
219 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
220
221 // 'int main() { }' compiled for i386-apple-macosx with clang
222 uint8_t data[] = {
223 0x55, // offset 0 -- pushl %ebp
224 0x89, 0xe5, // offset 1 -- movl %esp, %ebp
225 0x31, 0xc0, // offset 3 -- xorl %eax, %eax
226 0x5d, // offset 5 -- popl %ebp
227 0xc3 // offset 6 -- retl
228 };
229
230 AddressRange sample_range(0x1000, sizeof(data));
231
232 UnwindPlan unwind_plan(eRegisterKindLLDB);
233 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
234 data, sizeof(data), sample_range, unwind_plan));
235
236 // Expect four unwind rows:
237 // 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
238 // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
239 // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
240 // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
241
242 EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_esp);
243 EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
244 eLazyBoolYes);
245 EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
246
247 UnwindPlan::Row::RegisterLocation regloc;
248
249 // offset 0 -- pushl %ebp
250 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(offset: 0);
251 EXPECT_EQ(0ull, row_sp->GetOffset());
252 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
253 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
254 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
255
256 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
257 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
258 EXPECT_TRUE(regloc.GetOffset() == -4);
259
260 // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
261 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 1);
262 EXPECT_EQ(1ull, row_sp->GetOffset());
263 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
264 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
265 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
266
267 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
268 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
269 EXPECT_EQ(-4, regloc.GetOffset());
270
271 // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
272 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 3);
273 EXPECT_EQ(3ull, row_sp->GetOffset());
274 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
275 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
276 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
277
278 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
279 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
280 EXPECT_EQ(-4, regloc.GetOffset());
281
282 // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
283 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 6);
284 EXPECT_EQ(6ull, row_sp->GetOffset());
285 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
286 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
287 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
288
289 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
290 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
291 EXPECT_EQ(-4, regloc.GetOffset());
292}
293
294TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessBigStackFrame) {
295 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
296
297 // this source file:
298 //
299 // #include <stdio.h>
300 // int main (int argc, char **argv)
301 // {
302 //
303 // const int arrsize = 60;
304 // int buf[arrsize * arrsize];
305 // int accum = argc;
306 // for (int i = 0; i < arrsize; i++)
307 // for (int j = 0; j < arrsize; j++)
308 // {
309 // if (i > 0 && j > 0)
310 // {
311 // int n = buf[(i-1) * (j-1)] * 2;
312 // int m = buf[(i-1) * (j-1)] / 2;
313 // int j = buf[(i-1) * (j-1)] + 2;
314 // int k = buf[(i-1) * (j-1)] - 2;
315 // printf ("%d ", n + m + j + k);
316 // buf[(i-1) * (j-1)] += n - m + j - k;
317 // }
318 // buf[i*j] = accum++;
319 // }
320 //
321 // return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *
322 // arrsize) - 3]);
323 // }
324 //
325 // compiled 'clang -fomit-frame-pointer -Os' for x86_64-apple-macosx
326
327 uint8_t data[] = {
328 0x55, // offset 0 -- pushq %rbp
329 0x41, 0x57, // offset 1 -- pushq %r15
330 0x41, 0x56, // offset 3 -- pushq %r14
331 0x41, 0x55, // offset 5 -- pushq %r13
332 0x41, 0x54, // offset 7 -- pushq %r12
333 0x53, // offset 9 -- pushq %rbx
334 0x48, 0x81, 0xec, 0x68, 0x38, 0x00,
335 0x00, // offset 10 -- subq $0x3868, %rsp
336
337 // ....
338
339 0x48, 0x81, 0xc4, 0x68, 0x38, 0x00,
340 0x00, // offset 17 -- addq $0x3868, %rsp
341 0x5b, // offset 24 -- popq %rbx
342 0x41, 0x5c, // offset 25 -- popq %r12
343 0x41, 0x5d, // offset 27 -- popq %r13
344 0x41, 0x5e, // offset 29 -- popq %r14
345 0x41, 0x5f, // offset 31 -- popq %r15
346 0x5d, // offset 33 -- popq %rbp
347 0xc3, // offset 34 -- retq
348 0xe8, 0x12, 0x34, 0x56, 0x78 // offset 35 -- callq whatever
349 };
350
351 AddressRange sample_range(0x1000, sizeof(data));
352
353 UnwindPlan unwind_plan(eRegisterKindLLDB);
354 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
355 data, sizeof(data), sample_range, unwind_plan));
356
357 // Unwind rules should look like
358 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
359 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
360 // 3: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8]
361 // 5: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24]
362 // rip=[CFA-8
363 // 7: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32]
364 // r15=[CFA-24] rip=[CFA-8]
365 // 9: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40]
366 // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
367 // 10: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
368 // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
369 // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
370 // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
371
372 // 24: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
373 // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
374 // 25: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40]
375 // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
376 // 27: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32]
377 // r15=[CFA-24] rip=[CFA-8]
378 // 29: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24]
379 // rip=[CFA-8]
380 // 31: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8]
381 // 33: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
382 // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
383
384 UnwindPlan::Row::RegisterLocation regloc;
385
386 // grab the Row for when the prologue has finished executing:
387 // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
388 // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
389
390 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(offset: 17);
391
392 EXPECT_EQ(17ull, row_sp->GetOffset());
393 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
394 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
395 EXPECT_EQ(14496, row_sp->GetCFAValue().GetOffset());
396
397 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
398 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
399 EXPECT_EQ(-8, regloc.GetOffset());
400
401 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
402 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
403 EXPECT_EQ(-16, regloc.GetOffset());
404
405 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
406 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
407 EXPECT_EQ(-24, regloc.GetOffset());
408
409 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
410 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
411 EXPECT_EQ(-32, regloc.GetOffset());
412
413 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc));
414 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
415 EXPECT_EQ(-40, regloc.GetOffset());
416
417 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc));
418 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
419 EXPECT_EQ(-48, regloc.GetOffset());
420
421 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
422 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
423 EXPECT_EQ(-56, regloc.GetOffset());
424
425 // grab the Row for when the epilogue has finished executing:
426 // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
427
428 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 34);
429
430 EXPECT_EQ(34ull, row_sp->GetOffset());
431 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
432 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
433 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
434
435 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
436 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
437 EXPECT_EQ(-8, regloc.GetOffset());
438
439 // these could be set to IsSame and be valid -- meaning that the
440 // register value is the same as the caller's -- but I'd rather
441 // they not be mentioned at all.
442
443 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rax, regloc));
444 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
445 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rcx, regloc));
446 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdx, regloc));
447 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
448 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rsi, regloc));
449 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdi, regloc));
450 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r8, regloc));
451 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r9, regloc));
452 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r10, regloc));
453 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r11, regloc));
454 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
455 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
456 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
457 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
458}
459
460TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessBigStackFrame) {
461 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
462
463 // this source file:
464 //
465 // #include <stdio.h>
466 // int main (int argc, char **argv)
467 // {
468 //
469 // const int arrsize = 60;
470 // int buf[arrsize * arrsize];
471 // int accum = argc;
472 // for (int i = 0; i < arrsize; i++)
473 // for (int j = 0; j < arrsize; j++)
474 // {
475 // if (i > 0 && j > 0)
476 // {
477 // int n = buf[(i-1) * (j-1)] * 2;
478 // int m = buf[(i-1) * (j-1)] / 2;
479 // int j = buf[(i-1) * (j-1)] + 2;
480 // int k = buf[(i-1) * (j-1)] - 2;
481 // printf ("%d ", n + m + j + k);
482 // buf[(i-1) * (j-1)] += n - m + j - k;
483 // }
484 // buf[i*j] = accum++;
485 // }
486 //
487 // return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *
488 // arrsize) - 3]);
489 // }
490 //
491 // compiled 'clang -arch i386 -fomit-frame-pointer -Os' for i386-apple-macosx
492
493 // simplified assembly version of the above function, which is used as the
494 // input
495 // data:
496 //
497 // .section __TEXT,__text,regular,pure_instructions
498 // .macosx_version_min 10, 12
499 // .globl _main
500 // .align 4, 0x90
501 // _main: ## @main
502 // ## BB#0:
503 // pushl %ebp
504 // pushl %ebx
505 // pushl %edi
506 // pushl %esi
507 // L0$pb:
508 // subl $0x386c, %esp
509 // calll L1
510 // L1:
511 // popl %ecx
512 // movl %ecx, 0x8(%esp)
513 // subl $0x8, %esp
514 // pushl %eax
515 // pushl 0x20(%esp)
516 // calll _puts
517 // addl $0x10, %esp
518 // incl %ebx
519 // addl $0x386c, %esp
520 // popl %esi
521 // popl %edi
522 // popl %ebx
523 // popl %ebp
524 // retl
525 //
526 // .section __TEXT,__cstring,cstring_literals
527 // L_.str: ## @.str
528 // .asciz "HI"
529 //
530 //
531 // .subsections_via_symbols
532
533 uint8_t data[] = {
534 0x55,
535 // offset 0 -- pushl %ebp
536
537 0x53,
538 // offset 1 -- pushl %ebx
539
540 0x57,
541 // offset 2 -- pushl %edi
542
543 0x56,
544 // offset 3 -- pushl %esi
545
546 0x81, 0xec, 0x6c, 0x38, 0x00, 0x00,
547 // offset 4 -- subl $0x386c, %esp
548
549 0xe8, 0x00, 0x00, 0x00, 0x00,
550 // offset 10 -- calll 0
551 // call the next instruction, to put the pc on the stack
552
553 0x59,
554 // offset 15 -- popl %ecx
555 // pop the saved pc address into ecx
556
557 0x89, 0x4c, 0x24, 0x08,
558 // offset 16 -- movl %ecx, 0x8(%esp)
559
560 // ....
561
562 0x83, 0xec, 0x08,
563 // offset 20 -- subl $0x8, %esp
564
565 0x50,
566 // offset 23 -- pushl %eax
567
568 0xff, 0x74, 0x24, 0x20,
569 // offset 24 -- pushl 0x20(%esp)
570
571 0xe8, 0x8c, 0x00, 0x00, 0x00,
572 // offset 28 -- calll puts
573
574 0x83, 0xc4, 0x10,
575 // offset 33 -- addl $0x10, %esp
576 // get esp back to the value it was before the
577 // alignment & argument saves for the puts call
578
579 0x43,
580 // offset 36 -- incl %ebx
581
582 // ....
583
584 0x81, 0xc4, 0x6c, 0x38, 0x00, 0x00,
585 // offset 37 -- addl $0x386c, %esp
586
587 0x5e,
588 // offset 43 -- popl %esi
589
590 0x5f,
591 // offset 44 -- popl %edi
592
593 0x5b,
594 // offset 45 -- popl %ebx
595
596 0x5d,
597 // offset 46 -- popl %ebp
598
599 0xc3,
600 // offset 47 -- retl
601
602 0xe8, 0x12, 0x34, 0x56, 0x78,
603 // offset 48 -- calll __stack_chk_fail
604 };
605
606 AddressRange sample_range(0x1000, sizeof(data));
607
608 UnwindPlan unwind_plan(eRegisterKindLLDB);
609 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
610 data, sizeof(data), sample_range, unwind_plan));
611
612 // Unwind rules should look like
613 //
614 // 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
615 // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
616 // 2: CFA=esp+12 => ebx=[CFA-12] ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
617 // 3: CFA=esp+16 => ebx=[CFA-12] edi=[CFA-16] ebp=[CFA-8] esp=CFA+0
618 // eip=[CFA-4]
619 // 4: CFA=esp+20 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
620 // esp=CFA+0 eip=[CFA-4]
621 // 10: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
622 // esp=CFA+0 eip=[CFA-4]
623 // 15: CFA=esp+14468 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
624 // esp=CFA+0 eip=[CFA-4]
625 // 16: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
626 // esp=CFA+0 eip=[CFA-4]
627 //
628 // ....
629 //
630 // 23: CFA=esp+14472 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
631 // esp=CFA+0 eip=[CFA-4]
632 // 24: CFA=esp+14476 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
633 // esp=CFA+0 eip=[CFA-4]
634 // 28: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
635 // esp=CFA+0 eip=[CFA-4]
636 // 36: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
637 // esp=CFA+0 eip=[CFA-4]
638 //
639 // .....
640 //
641 // 37: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
642 // esp=CFA+0 eip=[CFA-4]
643 // 43: CFA=esp+20 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
644 // esp=CFA+0 eip=[CFA-4]
645 // 44: CFA=esp+16 => ebx=[CFA-12] edi=[CFA-16] ebp=[CFA-8] esp=CFA+0
646 // eip=[CFA-4]
647 // 45: CFA=esp+12 => ebx=[CFA-12] ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
648 // 46: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
649 // 47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
650 // 48: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
651 // esp=CFA+0 eip=[CFA-4]
652
653 UnwindPlan::Row::RegisterLocation regloc;
654 UnwindPlan::RowSP row_sp;
655
656 // Check that we get the CFA correct for the pic base setup sequence
657
658 // CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
659 // esp=CFA+0 eip=[CFA-4]
660 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 10);
661 EXPECT_EQ(10ull, row_sp->GetOffset());
662 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
663 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
664 EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
665
666 // 15: CFA=esp+14468 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
667 // esp=CFA+0 eip=[CFA-4]
668 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 15);
669 EXPECT_EQ(15ull, row_sp->GetOffset());
670 EXPECT_EQ(14468, row_sp->GetCFAValue().GetOffset());
671
672 // 16: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
673 // esp=CFA+0 eip=[CFA-4]
674 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 16);
675 EXPECT_EQ(16ull, row_sp->GetOffset());
676 EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
677
678 // Check that the row for offset 16 has the registers saved that we expect
679
680 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
681 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
682 EXPECT_EQ(-4, regloc.GetOffset());
683
684 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
685 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
686 EXPECT_EQ(-8, regloc.GetOffset());
687
688 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
689 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
690 EXPECT_EQ(-12, regloc.GetOffset());
691
692 EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc));
693 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
694 EXPECT_EQ(-16, regloc.GetOffset());
695
696 EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
697 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
698 EXPECT_EQ(-20, regloc.GetOffset());
699
700 //
701 // Check the pushing & popping around the call printf instruction
702
703 // 23: CFA=esp+14472 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
704 // esp=CFA+0 eip=[CFA-4]
705 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 23);
706 EXPECT_EQ(23ull, row_sp->GetOffset());
707 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
708 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
709 EXPECT_EQ(14472, row_sp->GetCFAValue().GetOffset());
710
711 // 24: CFA=esp+14476 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
712 // esp=CFA+0 eip=[CFA-4]
713 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 24);
714 EXPECT_EQ(24ull, row_sp->GetOffset());
715 EXPECT_EQ(14476, row_sp->GetCFAValue().GetOffset());
716
717 // 28: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
718 // esp=CFA+0 eip=[CFA-4]
719 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 28);
720 EXPECT_EQ(28ull, row_sp->GetOffset());
721 EXPECT_EQ(14480, row_sp->GetCFAValue().GetOffset());
722
723 // 36: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
724 // esp=CFA+0 eip=[CFA-4]
725 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 36);
726 EXPECT_EQ(36ull, row_sp->GetOffset());
727 EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
728
729 // Check that the epilogue gets us back to the original unwind state
730
731 // 47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
732 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 47);
733 EXPECT_EQ(47ull, row_sp->GetOffset());
734 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
735 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
736 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
737
738 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
739 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
740 EXPECT_EQ(-4, regloc.GetOffset());
741
742 EXPECT_TRUE(row_sp->GetRegisterInfo(k_esp, regloc));
743 EXPECT_TRUE(regloc.IsCFAPlusOffset());
744 EXPECT_EQ(0, regloc.GetOffset());
745
746 // Check that no unexpected registers were saved
747
748 EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
749 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
750 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
751 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
752 EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
753 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
754 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
755}
756
757TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessSmallStackFrame) {
758 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
759
760 // this source file:
761 // #include <stdio.h>
762 // int main () {
763 // puts ("HI");
764 // }
765 //
766 // compiled 'clang -fomit-frame-pointer' for x86_64-apple-macosx
767
768 uint8_t data[] = {
769 0x50,
770 // offset 0 -- pushq %rax
771
772 0x48, 0x8d, 0x3d, 0x32, 0x00, 0x00, 0x00,
773 // offset 1 -- leaq 0x32(%rip), %rdi ; "HI"
774
775 0xe8, 0x0b, 0x00, 0x00, 0x00,
776 // offset 8 -- callq 0x100000f58 ; puts
777
778 0x31, 0xc9,
779 // offset 13 -- xorl %ecx, %ecx
780
781 0x89, 0x44, 0x24, 0x04,
782 // offset 15 -- movl %eax, 0x4(%rsp)
783
784 0x89, 0xc8,
785 // offset 19 -- movl %ecx, %eax
786
787 0x59,
788 // offset 21 -- popq %rcx
789
790 0xc3
791 // offset 22 -- retq
792 };
793
794 AddressRange sample_range(0x1000, sizeof(data));
795
796 UnwindPlan unwind_plan(eRegisterKindLLDB);
797 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
798 data, sizeof(data), sample_range, unwind_plan));
799
800 // Unwind rules should look like
801 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
802 // 1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8]
803 // 22: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
804
805 UnwindPlan::Row::RegisterLocation regloc;
806
807 // grab the Row for when the prologue has finished executing:
808 // 1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8]
809
810 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(offset: 13);
811
812 EXPECT_EQ(1ull, row_sp->GetOffset());
813 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
814 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
815 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
816
817 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
818 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
819 EXPECT_EQ(-8, regloc.GetOffset());
820
821 // none of these were spilled
822
823 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rax, regloc));
824 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
825 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rcx, regloc));
826 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdx, regloc));
827 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
828 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rsi, regloc));
829 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdi, regloc));
830 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r8, regloc));
831 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r9, regloc));
832 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r10, regloc));
833 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r11, regloc));
834 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
835 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
836 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
837 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
838
839 // grab the Row for when the epilogue has finished executing:
840 // 22: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
841
842 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 22);
843
844 EXPECT_EQ(22ull, row_sp->GetOffset());
845 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
846 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
847 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
848
849 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
850 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
851 EXPECT_EQ(-8, regloc.GetOffset());
852}
853
854TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessSmallStackFrame) {
855 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
856
857 // this source file:
858 // #include <stdio.h>
859 // int main () {
860 // puts ("HI");
861 // }
862 //
863 // compiled 'clang -arch i386 -fomit-frame-pointer' for i386-apple-macosx
864
865 uint8_t data[] = {
866 0x83, 0xec, 0x0c,
867 // offset 0 -- subl $0xc, %esp
868
869 0xe8, 0x00, 0x00, 0x00, 0x00,
870 // offset 3 -- calll 0 {call the next instruction, to put the pc on
871 // the stack}
872
873 0x58,
874 // offset 8 -- popl %eax {pop the saved pc value off stack, into eax}
875
876 0x8d, 0x80, 0x3a, 0x00, 0x00, 0x00,
877 // offset 9 -- leal 0x3a(%eax),%eax
878
879 0x89, 0x04, 0x24,
880 // offset 15 -- movl %eax, (%esp)
881
882 0xe8, 0x0d, 0x00, 0x00, 0x00,
883 // offset 18 -- calll 0x1f94 (puts)
884
885 0x31, 0xc9,
886 // offset 23 -- xorl %ecx, %ecx
887
888 0x89, 0x44, 0x24, 0x08,
889 // offset 25 -- movl %eax, 0x8(%esp)
890
891 0x89, 0xc8,
892 // offset 29 -- movl %ecx, %eax
893
894 0x83, 0xc4, 0x0c,
895 // offset 31 -- addl $0xc, %esp
896
897 0xc3
898 // offset 34 -- retl
899 };
900
901 AddressRange sample_range(0x1000, sizeof(data));
902
903 UnwindPlan unwind_plan(eRegisterKindLLDB);
904 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
905 data, sizeof(data), sample_range, unwind_plan));
906
907 // Unwind rules should look like
908 // row[0]: 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
909 // row[1]: 3: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
910 // row[2]: 8: CFA=esp+20 => esp=CFA+0 eip=[CFA-4]
911 // row[3]: 9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
912 // row[4]: 34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
913
914 UnwindPlan::Row::RegisterLocation regloc;
915
916 // Check unwind state before we set up the picbase register
917 // 3: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
918
919 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(offset: 3);
920
921 EXPECT_EQ(3ull, row_sp->GetOffset());
922 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
923 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
924 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
925
926 // Check unwind state after we call the next instruction
927 // 8: CFA=esp+20 => esp=CFA+0 eip=[CFA-4]
928
929 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 8);
930 EXPECT_EQ(8ull, row_sp->GetOffset());
931 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
932 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
933 EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
934
935 // Check unwind state after we pop the pic base value off the stack
936 // row[3]: 9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
937
938 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 9);
939 EXPECT_EQ(9ull, row_sp->GetOffset());
940 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
941 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
942 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
943
944 // Check that no unexpected registers were saved
945
946 EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
947 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
948 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
949 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
950 EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
951 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
952 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
953
954 // verify that we get back to the original unwind state before the ret
955 // 34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
956
957 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 34);
958 EXPECT_EQ(34ull, row_sp->GetOffset());
959 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
960 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
961 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
962}
963
964TEST_F(Testx86AssemblyInspectionEngine, TestPushRBP) {
965 UnwindPlan::Row::RegisterLocation regloc;
966 UnwindPlan::RowSP row_sp;
967
968 uint8_t data[] = {
969 0x55, // pushq %rbp
970 0x90 // nop
971 };
972
973 AddressRange sample_range(0x1000, sizeof(data));
974 UnwindPlan unwind_plan(eRegisterKindLLDB);
975
976 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
977 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
978 data, sizeof(data), sample_range, unwind_plan));
979
980 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 1);
981
982 EXPECT_EQ(1ull, row_sp->GetOffset());
983 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
984 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
985 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
986
987 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
988 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
989 EXPECT_EQ(-16, regloc.GetOffset());
990
991 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
992 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
993 data, sizeof(data), sample_range, unwind_plan));
994
995 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 1);
996
997 EXPECT_EQ(1ull, row_sp->GetOffset());
998 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
999 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1000 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1001
1002 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
1003 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1004 EXPECT_EQ(-8, regloc.GetOffset());
1005}
1006
1007TEST_F(Testx86AssemblyInspectionEngine, TestPushImm) {
1008 UnwindPlan::Row::RegisterLocation regloc;
1009 UnwindPlan::RowSP row_sp;
1010
1011 uint8_t data[] = {
1012 0x68, 0xff, 0xff, 0x01, 0x69, // pushq $0x6901ffff
1013 0x6a, 0x7d, // pushl $0x7d
1014 0x90 // nop
1015 };
1016
1017 AddressRange sample_range(0x1000, sizeof(data));
1018 UnwindPlan unwind_plan(eRegisterKindLLDB);
1019
1020 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1021 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1022 data, sizeof(data), sample_range, unwind_plan));
1023
1024 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 5);
1025 EXPECT_EQ(5ull, row_sp->GetOffset());
1026 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1027 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1028 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1029
1030 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 7);
1031 EXPECT_EQ(7ull, row_sp->GetOffset());
1032 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1033 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1034 EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset());
1035
1036 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1037 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1038 data, sizeof(data), sample_range, unwind_plan));
1039
1040 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 5);
1041 EXPECT_EQ(5ull, row_sp->GetOffset());
1042 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1043 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1044 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1045
1046 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 7);
1047 EXPECT_EQ(7ull, row_sp->GetOffset());
1048 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1049 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1050 EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset());
1051}
1052
1053// We treat 'pushq $0' / 'pushl $0' specially - this shows up
1054// in the first function called in a new thread and it needs to
1055// put a 0 as the saved pc. We pretend it didn't change the CFA.
1056TEST_F(Testx86AssemblyInspectionEngine, TestPush0) {
1057 UnwindPlan::Row::RegisterLocation regloc;
1058 UnwindPlan::RowSP row_sp;
1059
1060 uint8_t data[] = {
1061 0x6a, 0x00, // pushq $0
1062 0x90 // nop
1063 };
1064
1065 AddressRange sample_range(0x1000, sizeof(data));
1066 UnwindPlan unwind_plan(eRegisterKindLLDB);
1067
1068 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1069 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1070 data, sizeof(data), sample_range, unwind_plan));
1071
1072 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
1073
1074 // We're verifying that no row was created for the 'pushq $0'
1075 EXPECT_EQ(0ull, row_sp->GetOffset());
1076
1077 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1078 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1079 data, sizeof(data), sample_range, unwind_plan));
1080
1081 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
1082
1083 // We're verifying that no row was created for the 'pushq $0'
1084 EXPECT_EQ(0ull, row_sp->GetOffset());
1085}
1086
1087TEST_F(Testx86AssemblyInspectionEngine, TestPushExtended) {
1088 UnwindPlan::Row::RegisterLocation regloc;
1089 UnwindPlan::RowSP row_sp;
1090
1091 uint8_t data[] = {
1092 0xff, 0x74, 0x24, 0x20, // pushl 0x20(%esp)
1093 0xff, 0xb6, 0xce, 0x01, 0xf0, 0x00, // pushl 0xf001ce(%esi)
1094 0xff, 0x30, // pushl (%eax)
1095 0x90 // nop
1096 };
1097
1098 AddressRange sample_range(0x1000, sizeof(data));
1099 UnwindPlan unwind_plan(eRegisterKindLLDB);
1100
1101 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1102 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1103 data, sizeof(data), sample_range, unwind_plan));
1104
1105 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 4);
1106
1107 EXPECT_EQ(4ull, row_sp->GetOffset());
1108 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1109 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1110 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1111
1112 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1113 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1114 data, sizeof(data), sample_range, unwind_plan));
1115
1116 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 4);
1117 EXPECT_EQ(4ull, row_sp->GetOffset());
1118 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1119 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1120 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1121
1122 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 10);
1123 EXPECT_EQ(10ull, row_sp->GetOffset());
1124 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1125 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1126 EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset());
1127
1128 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 12);
1129 EXPECT_EQ(12ull, row_sp->GetOffset());
1130 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1131 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1132 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1133}
1134
1135TEST_F(Testx86AssemblyInspectionEngine, TestPushR15) {
1136 UnwindPlan::Row::RegisterLocation regloc;
1137 UnwindPlan::RowSP row_sp;
1138
1139 uint8_t data[] = {
1140 0x41, 0x57, // pushq %r15
1141 0x90 // nop
1142 };
1143
1144 AddressRange sample_range(0x1000, sizeof(data));
1145 UnwindPlan unwind_plan(eRegisterKindLLDB);
1146
1147 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1148 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1149 data, sizeof(data), sample_range, unwind_plan));
1150
1151 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
1152
1153 EXPECT_EQ(2ull, row_sp->GetOffset());
1154 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1155 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1156 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1157
1158 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
1159 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1160 EXPECT_EQ(-16, regloc.GetOffset());
1161}
1162
1163TEST_F(Testx86AssemblyInspectionEngine, TestPushR14) {
1164 UnwindPlan::Row::RegisterLocation regloc;
1165 UnwindPlan::RowSP row_sp;
1166
1167 uint8_t data[] = {
1168 0x41, 0x56, // pushq %r14
1169 0x90 // nop
1170 };
1171
1172 AddressRange sample_range(0x1000, sizeof(data));
1173 UnwindPlan unwind_plan(eRegisterKindLLDB);
1174
1175 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1176 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1177 data, sizeof(data), sample_range, unwind_plan));
1178
1179 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
1180
1181 EXPECT_EQ(2ull, row_sp->GetOffset());
1182 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1183 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1184 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1185
1186 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
1187 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1188 EXPECT_EQ(-16, regloc.GetOffset());
1189}
1190
1191TEST_F(Testx86AssemblyInspectionEngine, TestPushR13) {
1192 UnwindPlan::Row::RegisterLocation regloc;
1193 UnwindPlan::RowSP row_sp;
1194
1195 uint8_t data[] = {
1196 0x41, 0x55, // pushq %r13
1197 0x90 // nop
1198 };
1199
1200 AddressRange sample_range(0x1000, sizeof(data));
1201 UnwindPlan unwind_plan(eRegisterKindLLDB);
1202
1203 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1204 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1205 data, sizeof(data), sample_range, unwind_plan));
1206
1207 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
1208
1209 EXPECT_EQ(2ull, row_sp->GetOffset());
1210 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1211 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1212 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1213
1214 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc));
1215 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1216 EXPECT_EQ(-16, regloc.GetOffset());
1217}
1218
1219TEST_F(Testx86AssemblyInspectionEngine, TestPushR12) {
1220 UnwindPlan::Row::RegisterLocation regloc;
1221 UnwindPlan::RowSP row_sp;
1222
1223 uint8_t data[] = {
1224 0x41, 0x54, // pushq %r13
1225 0x90 // nop
1226 };
1227
1228 AddressRange sample_range(0x1000, sizeof(data));
1229 UnwindPlan unwind_plan(eRegisterKindLLDB);
1230
1231 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1232 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1233 data, sizeof(data), sample_range, unwind_plan));
1234
1235 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
1236
1237 EXPECT_EQ(2ull, row_sp->GetOffset());
1238 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1239 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1240 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1241
1242 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc));
1243 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1244 EXPECT_EQ(-16, regloc.GetOffset());
1245}
1246
1247TEST_F(Testx86AssemblyInspectionEngine, TestPushRBX) {
1248 UnwindPlan::Row::RegisterLocation regloc;
1249 UnwindPlan::RowSP row_sp;
1250
1251 uint8_t data[] = {
1252 0x53, // pushq %rbx
1253 0x90 // nop
1254 };
1255
1256 AddressRange sample_range(0x1000, sizeof(data));
1257 UnwindPlan unwind_plan(eRegisterKindLLDB);
1258
1259 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1260 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1261 data, sizeof(data), sample_range, unwind_plan));
1262
1263 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 1);
1264
1265 EXPECT_EQ(1ull, row_sp->GetOffset());
1266 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1267 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1268 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1269
1270 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
1271 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1272 EXPECT_EQ(-16, regloc.GetOffset());
1273}
1274
1275// The ABI is hardcoded in x86AssemblyInspectionEngine such that
1276// eax, ecx, edx are all considered volatile and push/pops of them are
1277// not tracked (except to keep track of stack pointer movement)
1278TEST_F(Testx86AssemblyInspectionEngine, TestPushEAX) {
1279 UnwindPlan::Row::RegisterLocation regloc;
1280 UnwindPlan::RowSP row_sp;
1281 AddressRange sample_range;
1282 UnwindPlan unwind_plan(eRegisterKindLLDB);
1283 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1284
1285 uint8_t data[] = {
1286 0x50, // pushl %eax
1287 0x90 // nop
1288 };
1289
1290 sample_range = AddressRange(0x1000, sizeof(data));
1291
1292 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1293 data, sizeof(data), sample_range, unwind_plan));
1294
1295 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 1);
1296 EXPECT_EQ(1ull, row_sp->GetOffset());
1297 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1298 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1299 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1300
1301 EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
1302}
1303
1304// The ABI is hardcoded in x86AssemblyInspectionEngine such that
1305// eax, ecx, edx are all considered volatile and push/pops of them are
1306// not tracked (except to keep track of stack pointer movement)
1307TEST_F(Testx86AssemblyInspectionEngine, TestPushECX) {
1308 UnwindPlan::Row::RegisterLocation regloc;
1309 UnwindPlan::RowSP row_sp;
1310 AddressRange sample_range;
1311 UnwindPlan unwind_plan(eRegisterKindLLDB);
1312 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1313
1314 uint8_t data[] = {
1315 0x51, // pushl %ecx
1316 0x90 // nop
1317 };
1318
1319 sample_range = AddressRange(0x1000, sizeof(data));
1320
1321 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1322 data, sizeof(data), sample_range, unwind_plan));
1323
1324 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 1);
1325 EXPECT_EQ(1ull, row_sp->GetOffset());
1326 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1327 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1328 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1329
1330 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
1331}
1332
1333// The ABI is hardcoded in x86AssemblyInspectionEngine such that
1334// eax, ecx, edx are all considered volatile and push/pops of them are
1335// not tracked (except to keep track of stack pointer movement)
1336TEST_F(Testx86AssemblyInspectionEngine, TestPushEDX) {
1337 UnwindPlan::Row::RegisterLocation regloc;
1338 UnwindPlan::RowSP row_sp;
1339 AddressRange sample_range;
1340 UnwindPlan unwind_plan(eRegisterKindLLDB);
1341 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1342
1343 uint8_t data[] = {
1344 0x52, // pushl %edx
1345 0x90 // nop
1346 };
1347
1348 sample_range = AddressRange(0x1000, sizeof(data));
1349
1350 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1351 data, sizeof(data), sample_range, unwind_plan));
1352
1353 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 1);
1354 EXPECT_EQ(1ull, row_sp->GetOffset());
1355 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1356 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1357 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1358
1359 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
1360}
1361
1362TEST_F(Testx86AssemblyInspectionEngine, TestPushEBX) {
1363 UnwindPlan::Row::RegisterLocation regloc;
1364 UnwindPlan::RowSP row_sp;
1365 AddressRange sample_range;
1366 UnwindPlan unwind_plan(eRegisterKindLLDB);
1367 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1368
1369 uint8_t data[] = {
1370 0x53, // pushl %ebx
1371 0x90 // nop
1372 };
1373
1374 sample_range = AddressRange(0x1000, sizeof(data));
1375
1376 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1377 data, sizeof(data), sample_range, unwind_plan));
1378
1379 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 1);
1380 EXPECT_EQ(1ull, row_sp->GetOffset());
1381 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1382 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1383 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1384
1385 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
1386 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1387 EXPECT_EQ(-8, regloc.GetOffset());
1388}
1389
1390TEST_F(Testx86AssemblyInspectionEngine, TestPushEBP) {
1391 UnwindPlan::Row::RegisterLocation regloc;
1392 UnwindPlan::RowSP row_sp;
1393 AddressRange sample_range;
1394 UnwindPlan unwind_plan(eRegisterKindLLDB);
1395 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1396
1397 uint8_t data[] = {
1398 0x55, // pushl %ebp
1399 0x90 // nop
1400 };
1401
1402 sample_range = AddressRange(0x1000, sizeof(data));
1403
1404 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1405 data, sizeof(data), sample_range, unwind_plan));
1406
1407 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 1);
1408 EXPECT_EQ(1ull, row_sp->GetOffset());
1409 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1410 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1411 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1412
1413 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
1414 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1415 EXPECT_EQ(-8, regloc.GetOffset());
1416}
1417
1418TEST_F(Testx86AssemblyInspectionEngine, TestPushRBPWithREX) {
1419 UnwindPlan::Row::RegisterLocation regloc;
1420 UnwindPlan::RowSP row_sp;
1421
1422 uint8_t data[] = {
1423 0x40, 0x55, // pushq %rbp
1424 0x90 // nop
1425 };
1426
1427 AddressRange sample_range(0x1000, sizeof(data));
1428 UnwindPlan unwind_plan(eRegisterKindLLDB);
1429
1430 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1431 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1432 data, sizeof(data), sample_range, unwind_plan));
1433
1434 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
1435
1436 EXPECT_EQ(2ull, row_sp->GetOffset());
1437 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1438 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1439 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
1440
1441 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
1442 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1443 EXPECT_EQ(-16, regloc.GetOffset());
1444}
1445
1446TEST_F(Testx86AssemblyInspectionEngine, TestPushESI) {
1447 UnwindPlan::Row::RegisterLocation regloc;
1448 UnwindPlan::RowSP row_sp;
1449 AddressRange sample_range;
1450 UnwindPlan unwind_plan(eRegisterKindLLDB);
1451 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1452
1453 uint8_t data[] = {
1454 0x56, // pushl %esi
1455 0x90 // nop
1456 };
1457
1458 sample_range = AddressRange(0x1000, sizeof(data));
1459
1460 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1461 data, sizeof(data), sample_range, unwind_plan));
1462
1463 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 1);
1464 EXPECT_EQ(1ull, row_sp->GetOffset());
1465 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1466 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1467 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1468
1469 EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
1470 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1471 EXPECT_EQ(-8, regloc.GetOffset());
1472}
1473
1474TEST_F(Testx86AssemblyInspectionEngine, TestPushEDI) {
1475 UnwindPlan::Row::RegisterLocation regloc;
1476 UnwindPlan::RowSP row_sp;
1477 AddressRange sample_range;
1478 UnwindPlan unwind_plan(eRegisterKindLLDB);
1479 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1480
1481 uint8_t data[] = {
1482 0x57, // pushl %edi
1483 0x90 // nop
1484 };
1485
1486 sample_range = AddressRange(0x1000, sizeof(data));
1487
1488 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1489 data, sizeof(data), sample_range, unwind_plan));
1490
1491 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 1);
1492 EXPECT_EQ(1ull, row_sp->GetOffset());
1493 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
1494 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1495 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1496
1497 EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc));
1498 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1499 EXPECT_EQ(-8, regloc.GetOffset());
1500}
1501
1502TEST_F(Testx86AssemblyInspectionEngine, TestMovRSPtoRBP) {
1503 UnwindPlan::Row::RegisterLocation regloc;
1504 UnwindPlan::RowSP row_sp;
1505
1506 uint8_t data64_1[] = {
1507 0x48, 0x8b, 0xec, // movq %rsp, %rbp
1508 0x90 // nop
1509 };
1510
1511 AddressRange sample_range(0x1000, sizeof(data64_1));
1512 UnwindPlan unwind_plan(eRegisterKindLLDB);
1513
1514 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1515 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1516 data64_1, sizeof(data64_1), sample_range, unwind_plan));
1517
1518 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 3);
1519
1520 EXPECT_EQ(3ull, row_sp->GetOffset());
1521 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
1522 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1523 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1524
1525 uint8_t data64_2[] = {
1526 0x48, 0x89, 0xe5, // movq %rsp, %rbp
1527 0x90 // nop
1528 };
1529
1530 sample_range = AddressRange(0x1000, sizeof(data64_2));
1531 unwind_plan.Clear();
1532 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1533 data64_2, sizeof(data64_2), sample_range, unwind_plan));
1534
1535 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 3);
1536 EXPECT_EQ(3ull, row_sp->GetOffset());
1537 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
1538 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1539 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1540
1541 uint8_t data32_1[] = {
1542 0x8b, 0xec, // movl %rsp, %rbp
1543 0x90 // nop
1544 };
1545
1546 sample_range = AddressRange(0x1000, sizeof(data32_1));
1547 unwind_plan.Clear();
1548 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1549 data32_1, sizeof(data32_1), sample_range, unwind_plan));
1550
1551 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
1552 EXPECT_EQ(2ull, row_sp->GetOffset());
1553 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
1554 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1555 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1556
1557 uint8_t data32_2[] = {
1558 0x89, 0xe5, // movl %rsp, %rbp
1559 0x90 // nop
1560 };
1561
1562 sample_range = AddressRange(0x1000, sizeof(data32_2));
1563 unwind_plan.Clear();
1564 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1565 data32_2, sizeof(data32_2), sample_range, unwind_plan));
1566
1567 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
1568 EXPECT_EQ(2ull, row_sp->GetOffset());
1569 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
1570 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1571 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1572}
1573
1574TEST_F(Testx86AssemblyInspectionEngine, TestSubRSP) {
1575 UnwindPlan::Row::RegisterLocation regloc;
1576 UnwindPlan::RowSP row_sp;
1577 AddressRange sample_range;
1578 UnwindPlan unwind_plan(eRegisterKindLLDB);
1579 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1580
1581 uint8_t data1[] = {
1582 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $0x100, $rsp
1583 0x90 // nop
1584 };
1585
1586 sample_range = AddressRange(0x1000, sizeof(data1));
1587
1588 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1589 data1, sizeof(data1), sample_range, unwind_plan));
1590
1591 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 7);
1592 EXPECT_EQ(7ull, row_sp->GetOffset());
1593 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1594 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1595 EXPECT_EQ(264, row_sp->GetCFAValue().GetOffset());
1596
1597 uint8_t data2[] = {
1598 0x48, 0x83, 0xec, 0x10, // subq $0x10, %rsp
1599 0x90 // nop
1600 };
1601
1602 sample_range = AddressRange(0x1000, sizeof(data2));
1603
1604 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1605 data2, sizeof(data2), sample_range, unwind_plan));
1606
1607 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 4);
1608 EXPECT_EQ(4ull, row_sp->GetOffset());
1609 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1610 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1611 EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset());
1612}
1613
1614TEST_F(Testx86AssemblyInspectionEngine, TestSubESP) {
1615 UnwindPlan::Row::RegisterLocation regloc;
1616 UnwindPlan::RowSP row_sp;
1617 AddressRange sample_range;
1618 UnwindPlan unwind_plan(eRegisterKindLLDB);
1619 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1620
1621 uint8_t data1[] = {
1622 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subl $0x100, %esp
1623 0x90 // nop
1624 };
1625
1626 sample_range = AddressRange(0x1000, sizeof(data1));
1627
1628 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1629 data1, sizeof(data1), sample_range, unwind_plan));
1630
1631 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 6);
1632 EXPECT_EQ(6ull, row_sp->GetOffset());
1633 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1634 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1635 EXPECT_EQ(260, row_sp->GetCFAValue().GetOffset());
1636
1637 uint8_t data2[] = {
1638 0x83, 0xec, 0x10, // subq $0x10, %esp
1639 0x90 // nop
1640 };
1641
1642 sample_range = AddressRange(0x1000, sizeof(data2));
1643
1644 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1645 data2, sizeof(data2), sample_range, unwind_plan));
1646
1647 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 3);
1648 EXPECT_EQ(3ull, row_sp->GetOffset());
1649 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1650 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1651 EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
1652}
1653
1654TEST_F(Testx86AssemblyInspectionEngine, TestAddRSP) {
1655 UnwindPlan::Row::RegisterLocation regloc;
1656 UnwindPlan::RowSP row_sp;
1657 AddressRange sample_range;
1658 UnwindPlan unwind_plan(eRegisterKindLLDB);
1659 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
1660
1661 uint8_t data1[] = {
1662 0x48, 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addq $0x100, %rsp
1663 0x90 // nop
1664 };
1665
1666 sample_range = AddressRange(0x1000, sizeof(data1));
1667
1668 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1669 data1, sizeof(data1), sample_range, unwind_plan));
1670
1671 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 7);
1672 EXPECT_EQ(7ull, row_sp->GetOffset());
1673 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1674 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1675 EXPECT_EQ(8 - 256, row_sp->GetCFAValue().GetOffset());
1676
1677 uint8_t data2[] = {
1678 0x48, 0x83, 0xc4, 0x10, // addq $0x10, %rsp
1679 0x90 // nop
1680 };
1681
1682 sample_range = AddressRange(0x1000, sizeof(data2));
1683
1684 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
1685 data2, sizeof(data2), sample_range, unwind_plan));
1686
1687 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 4);
1688 EXPECT_EQ(4ull, row_sp->GetOffset());
1689 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1690 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1691 EXPECT_EQ(8 - 16, row_sp->GetCFAValue().GetOffset());
1692}
1693
1694TEST_F(Testx86AssemblyInspectionEngine, TestAddESP) {
1695 UnwindPlan::Row::RegisterLocation regloc;
1696 UnwindPlan::RowSP row_sp;
1697 AddressRange sample_range;
1698 UnwindPlan unwind_plan(eRegisterKindLLDB);
1699 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
1700
1701 uint8_t data1[] = {
1702 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addl $0x100, %esp
1703 0x90 // nop
1704 };
1705
1706 sample_range = AddressRange(0x1000, sizeof(data1));
1707
1708 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1709 data1, sizeof(data1), sample_range, unwind_plan));
1710
1711 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 6);
1712 EXPECT_EQ(6ull, row_sp->GetOffset());
1713 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1714 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1715 EXPECT_EQ(4 - 256, row_sp->GetCFAValue().GetOffset());
1716
1717 uint8_t data2[] = {
1718 0x83, 0xc4, 0x10, // addq $0x10, %esp
1719 0x90 // nop
1720 };
1721
1722 sample_range = AddressRange(0x1000, sizeof(data2));
1723
1724 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
1725 data2, sizeof(data2), sample_range, unwind_plan));
1726
1727 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 3);
1728 EXPECT_EQ(3ull, row_sp->GetOffset());
1729 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1730 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1731 EXPECT_EQ(4 - 16, row_sp->GetCFAValue().GetOffset());
1732}
1733
1734// FIXME add test for lea_rsp_pattern_p
1735
1736TEST_F(Testx86AssemblyInspectionEngine, TestPopRBX) {
1737 UnwindPlan::Row::RegisterLocation regloc;
1738 UnwindPlan::RowSP row_sp;
1739 AddressRange sample_range;
1740 UnwindPlan unwind_plan(eRegisterKindLLDB);
1741 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1742
1743 uint8_t data[] = {
1744 0x53, // pushq %rbx
1745 0x5b, // popq %rbx
1746 0x90 // nop
1747 };
1748
1749 sample_range = AddressRange(0x1000, sizeof(data));
1750
1751 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1752 data, sizeof(data), sample_range, unwind_plan));
1753
1754 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
1755 EXPECT_EQ(2ull, row_sp->GetOffset());
1756 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1757 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1758 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1759 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
1760}
1761
1762TEST_F(Testx86AssemblyInspectionEngine, TestPopRBP) {
1763 UnwindPlan::Row::RegisterLocation regloc;
1764 UnwindPlan::RowSP row_sp;
1765 AddressRange sample_range;
1766 UnwindPlan unwind_plan(eRegisterKindLLDB);
1767 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1768
1769 uint8_t data[] = {
1770 0x55, // pushq %rbp
1771 0x5d, // popq %rbp
1772 0x90 // nop
1773 };
1774
1775 sample_range = AddressRange(0x1000, sizeof(data));
1776
1777 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1778 data, sizeof(data), sample_range, unwind_plan));
1779
1780 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
1781 EXPECT_EQ(2ull, row_sp->GetOffset());
1782 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1783 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1784 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1785 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
1786}
1787
1788TEST_F(Testx86AssemblyInspectionEngine, TestPopR12) {
1789 UnwindPlan::Row::RegisterLocation regloc;
1790 UnwindPlan::RowSP row_sp;
1791 AddressRange sample_range;
1792 UnwindPlan unwind_plan(eRegisterKindLLDB);
1793 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1794
1795 uint8_t data[] = {
1796 0x41, 0x54, // pushq %r12
1797 0x41, 0x5c, // popq %r12
1798 0x90 // nop
1799 };
1800
1801 sample_range = AddressRange(0x1000, sizeof(data));
1802
1803 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1804 data, sizeof(data), sample_range, unwind_plan));
1805
1806 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 4);
1807 EXPECT_EQ(4ull, row_sp->GetOffset());
1808 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1809 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1810 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1811 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
1812}
1813
1814TEST_F(Testx86AssemblyInspectionEngine, TestPopR13) {
1815 UnwindPlan::Row::RegisterLocation regloc;
1816 UnwindPlan::RowSP row_sp;
1817 AddressRange sample_range;
1818 UnwindPlan unwind_plan(eRegisterKindLLDB);
1819 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1820
1821 uint8_t data[] = {
1822 0x41, 0x55, // pushq %r13
1823 0x41, 0x5d, // popq %r13
1824 0x90 // nop
1825 };
1826
1827 sample_range = AddressRange(0x1000, sizeof(data));
1828
1829 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1830 data, sizeof(data), sample_range, unwind_plan));
1831
1832 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 4);
1833 EXPECT_EQ(4ull, row_sp->GetOffset());
1834 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1835 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1836 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1837 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
1838}
1839
1840TEST_F(Testx86AssemblyInspectionEngine, TestPopR14) {
1841 UnwindPlan::Row::RegisterLocation regloc;
1842 UnwindPlan::RowSP row_sp;
1843 AddressRange sample_range;
1844 UnwindPlan unwind_plan(eRegisterKindLLDB);
1845 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1846
1847 uint8_t data[] = {
1848 0x41, 0x56, // pushq %r14
1849 0x41, 0x5e, // popq %r14
1850 0x90 // nop
1851 };
1852
1853 sample_range = AddressRange(0x1000, sizeof(data));
1854
1855 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1856 data, sizeof(data), sample_range, unwind_plan));
1857
1858 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 4);
1859 EXPECT_EQ(4ull, row_sp->GetOffset());
1860 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1861 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1862 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1863 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
1864}
1865
1866TEST_F(Testx86AssemblyInspectionEngine, TestPopR15) {
1867 UnwindPlan::Row::RegisterLocation regloc;
1868 UnwindPlan::RowSP row_sp;
1869 AddressRange sample_range;
1870 UnwindPlan unwind_plan(eRegisterKindLLDB);
1871 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1872
1873 uint8_t data[] = {
1874 0x41, 0x57, // pushq %r15
1875 0x41, 0x5f, // popq %r15
1876 0x90 // nop
1877 };
1878
1879 sample_range = AddressRange(0x1000, sizeof(data));
1880
1881 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1882 data, sizeof(data), sample_range, unwind_plan));
1883
1884 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 4);
1885 EXPECT_EQ(4ull, row_sp->GetOffset());
1886 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1887 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1888 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1889 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
1890}
1891
1892TEST_F(Testx86AssemblyInspectionEngine, TestPopEBX) {
1893 UnwindPlan::Row::RegisterLocation regloc;
1894 UnwindPlan::RowSP row_sp;
1895 AddressRange sample_range;
1896 UnwindPlan unwind_plan(eRegisterKindLLDB);
1897 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1898
1899 uint8_t data[] = {
1900 0x53, // pushl %ebx
1901 0x5b, // popl %ebx
1902 0x90 // nop
1903 };
1904
1905 sample_range = AddressRange(0x1000, sizeof(data));
1906
1907 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1908 data, sizeof(data), sample_range, unwind_plan));
1909
1910 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
1911 EXPECT_EQ(2ull, row_sp->GetOffset());
1912 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1913 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1914 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
1915 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
1916}
1917
1918TEST_F(Testx86AssemblyInspectionEngine, TestPopEBP) {
1919 UnwindPlan::Row::RegisterLocation regloc;
1920 UnwindPlan::RowSP row_sp;
1921 AddressRange sample_range;
1922 UnwindPlan unwind_plan(eRegisterKindLLDB);
1923 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1924
1925 uint8_t data[] = {
1926 0x55, // pushl %ebp
1927 0x5d, // popl %ebp
1928 0x90 // nop
1929 };
1930
1931 sample_range = AddressRange(0x1000, sizeof(data));
1932
1933 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1934 data, sizeof(data), sample_range, unwind_plan));
1935
1936 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
1937 EXPECT_EQ(2ull, row_sp->GetOffset());
1938 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1939 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1940 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
1941 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
1942}
1943
1944TEST_F(Testx86AssemblyInspectionEngine, TestPopRBPWithREX) {
1945 UnwindPlan::Row::RegisterLocation regloc;
1946 UnwindPlan::RowSP row_sp;
1947 AddressRange sample_range;
1948 UnwindPlan unwind_plan(eRegisterKindLLDB);
1949 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1950
1951 uint8_t data[] = {
1952 0x40, 0x55, // pushq %rbp
1953 0x40, 0x5d, // popq %rbp
1954 0x90 // nop
1955 };
1956
1957 sample_range = AddressRange(0x1000, sizeof(data));
1958
1959 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1960 data, sizeof(data), sample_range, unwind_plan));
1961
1962 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 4);
1963 EXPECT_EQ(4ull, row_sp->GetOffset());
1964 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1965 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1966 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
1967 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
1968}
1969
1970TEST_F(Testx86AssemblyInspectionEngine, TestPopESI) {
1971 UnwindPlan::Row::RegisterLocation regloc;
1972 UnwindPlan::RowSP row_sp;
1973 AddressRange sample_range;
1974 UnwindPlan unwind_plan(eRegisterKindLLDB);
1975 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1976
1977 uint8_t data[] = {
1978 0x56, // pushl %esi
1979 0x5e, // popl %esi
1980 0x90 // nop
1981 };
1982
1983 sample_range = AddressRange(0x1000, sizeof(data));
1984
1985 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1986 data, sizeof(data), sample_range, unwind_plan));
1987
1988 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
1989 EXPECT_EQ(2ull, row_sp->GetOffset());
1990 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
1991 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
1992 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
1993 EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
1994}
1995
1996TEST_F(Testx86AssemblyInspectionEngine, TestPopEDI) {
1997 UnwindPlan::Row::RegisterLocation regloc;
1998 UnwindPlan::RowSP row_sp;
1999 AddressRange sample_range;
2000 UnwindPlan unwind_plan(eRegisterKindLLDB);
2001 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2002
2003 uint8_t data[] = {
2004 0x57, // pushl %edi
2005 0x5f, // popl %edi
2006 0x90 // nop
2007 };
2008
2009 sample_range = AddressRange(0x1000, sizeof(data));
2010
2011 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
2012 data, sizeof(data), sample_range, unwind_plan));
2013
2014 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
2015 EXPECT_EQ(2ull, row_sp->GetOffset());
2016 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2017 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2018 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
2019 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
2020}
2021
2022// We don't track these registers, but make sure the CFA address is updated
2023// if we're defining the CFA in term of esp.
2024TEST_F(Testx86AssemblyInspectionEngine, Testi386IgnoredRegisters) {
2025 UnwindPlan::Row::RegisterLocation regloc;
2026 UnwindPlan::RowSP row_sp;
2027 AddressRange sample_range;
2028 UnwindPlan unwind_plan(eRegisterKindLLDB);
2029 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2030
2031 uint8_t data[] = {
2032 0x0e, // push cs
2033 0x16, // push ss
2034 0x1e, // push ds
2035 0x06, // push es
2036
2037 0x07, // pop es
2038 0x1f, // pop ds
2039 0x17, // pop ss
2040
2041 0x90 // nop
2042 };
2043
2044 sample_range = AddressRange(0x1000, sizeof(data));
2045
2046 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
2047 data, sizeof(data), sample_range, unwind_plan));
2048
2049 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 4);
2050 EXPECT_EQ(4ull, row_sp->GetOffset());
2051 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2052 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2053 EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
2054
2055 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 7);
2056 EXPECT_EQ(7ull, row_sp->GetOffset());
2057 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2058 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2059 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2060}
2061
2062TEST_F(Testx86AssemblyInspectionEngine, TestLEAVE) {
2063 UnwindPlan::Row::RegisterLocation regloc;
2064 UnwindPlan::RowSP row_sp;
2065 AddressRange sample_range;
2066 UnwindPlan unwind_plan(eRegisterKindLLDB);
2067 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2068 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2069
2070 uint8_t data[] = {
2071 0x55, // push %rbp/ebp
2072 0xc9, // leave
2073 0x90 // nop
2074 };
2075
2076 sample_range = AddressRange(0x1000, sizeof(data));
2077
2078 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2079 data, sizeof(data), sample_range, unwind_plan));
2080
2081 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
2082 EXPECT_EQ(2ull, row_sp->GetOffset());
2083 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2084 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2085 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2086 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
2087
2088 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2089 data, sizeof(data), sample_range, unwind_plan));
2090
2091 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
2092 EXPECT_EQ(2ull, row_sp->GetOffset());
2093 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2094 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2095 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
2096 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
2097}
2098
2099// In i386, which lacks pc-relative addressing, a common code sequence
2100// is to call the next instruction (i.e. call imm32, value of 0) which
2101// pushes the addr of the next insn on the stack, and then pop that value
2102// into a register (the "pic base" register).
2103TEST_F(Testx86AssemblyInspectionEngine, TestCALLNextInsn) {
2104 UnwindPlan::Row::RegisterLocation regloc;
2105 UnwindPlan::RowSP row_sp;
2106 AddressRange sample_range;
2107 UnwindPlan unwind_plan(eRegisterKindLLDB);
2108 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2109
2110 uint8_t data[] = {
2111 0xe8, 0x00, 0x00, 0x00, 0x00, // call 0
2112 0x90 // nop
2113 };
2114
2115 sample_range = AddressRange(0x1000, sizeof(data));
2116
2117 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2118 data, sizeof(data), sample_range, unwind_plan));
2119
2120 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 5);
2121 EXPECT_EQ(5ull, row_sp->GetOffset());
2122 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2123 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2124 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2125 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
2126}
2127
2128TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVx86_64) {
2129 UnwindPlan::Row::RegisterLocation regloc;
2130 UnwindPlan::RowSP row_sp;
2131 AddressRange sample_range;
2132 UnwindPlan unwind_plan(eRegisterKindLLDB);
2133 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2134
2135 uint8_t data[] = {
2136 0x55, // pushq %rbp
2137 0x48, 0x89, 0xe5, // movq %rsp, %rbp
2138 0x4c, 0x89, 0x75, 0xc0, // movq %r14, -0x40(%rbp)
2139 0x4c, 0x89, 0xbd, 0x28, 0xfa, 0xff, 0xff, // movq %r15, -0x5d8(%rbp)
2140 0x48, 0x89, 0x5d, 0xb8, // movq %rbx, -0x48(%rbp)
2141 0x90 // nop
2142 };
2143
2144 sample_range = AddressRange(0x1000, sizeof(data));
2145
2146 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2147 data, sizeof(data), sample_range, unwind_plan));
2148
2149 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 19);
2150 EXPECT_EQ(19ull, row_sp->GetOffset());
2151 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2152 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2153
2154 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
2155 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2156 EXPECT_EQ(-80, regloc.GetOffset());
2157
2158 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
2159 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2160 EXPECT_EQ(-1512, regloc.GetOffset());
2161
2162 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
2163 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2164 EXPECT_EQ(-88, regloc.GetOffset());
2165}
2166
2167TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVi386) {
2168 UnwindPlan::Row::RegisterLocation regloc;
2169 UnwindPlan::RowSP row_sp;
2170 AddressRange sample_range;
2171 UnwindPlan unwind_plan(eRegisterKindLLDB);
2172 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2173
2174 uint8_t data[] = {
2175 0x55, // pushl %ebp
2176 0x89, 0xe5, // movl %esp, %ebp
2177 0x89, 0x9d, 0xb0, 0xfe, 0xff, 0xff, // movl %ebx, -0x150(%ebp)
2178 0x89, 0x75, 0xe0, // movl %esi, -0x20(%ebp)
2179 0x90 // nop
2180 };
2181
2182 sample_range = AddressRange(0x1000, sizeof(data));
2183
2184 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2185 data, sizeof(data), sample_range, unwind_plan));
2186
2187 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 12);
2188 EXPECT_EQ(12ull, row_sp->GetOffset());
2189 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2190 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2191
2192 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
2193 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2194 EXPECT_EQ(-344, regloc.GetOffset());
2195
2196 EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
2197 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2198 EXPECT_EQ(-40, regloc.GetOffset());
2199}
2200
2201TEST_F(Testx86AssemblyInspectionEngine, TestSpArithx86_64Augmented) {
2202 UnwindPlan::Row::RegisterLocation regloc;
2203 UnwindPlan::RowSP row_sp;
2204 AddressRange sample_range;
2205 UnwindPlan unwind_plan(eRegisterKindLLDB);
2206 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2207
2208 uint8_t data[] = {
2209 0x55, // pushq %rbp
2210 0x48, 0x89, 0xe5, // movq %rsp, %rbp
2211
2212 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2213 // has a bug where it can't augment a function that is just
2214 // prologue+epilogue - it needs at least one other instruction
2215 // in between.
2216
2217 0x90, // nop
2218 0x48, 0x81, 0xec, 0x88, 0, 0, 0, // subq $0x88, %rsp
2219 0x90, // nop
2220 0x48, 0x81, 0xc4, 0x88, 0, 0, 0, // addq $0x88, %rsp
2221
2222 0x5d, // popq %rbp
2223 0xc3 // retq
2224 };
2225
2226 sample_range = AddressRange(0x1000, sizeof(data));
2227
2228 unwind_plan.SetSourceName("unit testing hand-created unwind plan");
2229 unwind_plan.SetPlanValidAddressRange(sample_range);
2230 unwind_plan.SetRegisterKind(eRegisterKindLLDB);
2231
2232 row_sp = std::make_shared<UnwindPlan::Row>();
2233
2234 // Describe offset 0
2235 row_sp->SetOffset(0);
2236 row_sp->GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_rsp, offset: 8);
2237
2238 regloc.SetAtCFAPlusOffset(-8);
2239 row_sp->SetRegisterInfo(reg_num: k_rip, register_location: regloc);
2240
2241 unwind_plan.AppendRow(row_sp);
2242
2243 // Allocate a new Row, populate it with the existing Row contents.
2244 UnwindPlan::Row *new_row = new UnwindPlan::Row;
2245 *new_row = *row_sp.get();
2246 row_sp.reset(p: new_row);
2247
2248 // Describe offset 1
2249 row_sp->SetOffset(1);
2250 row_sp->GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_rsp, offset: 16);
2251 regloc.SetAtCFAPlusOffset(-16);
2252 row_sp->SetRegisterInfo(reg_num: k_rbp, register_location: regloc);
2253 unwind_plan.AppendRow(row_sp);
2254
2255 // Allocate a new Row, populate it with the existing Row contents.
2256 new_row = new UnwindPlan::Row;
2257 *new_row = *row_sp.get();
2258 row_sp.reset(p: new_row);
2259
2260 // Describe offset 4
2261 row_sp->SetOffset(4);
2262 row_sp->GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_rsp, offset: 16);
2263 unwind_plan.AppendRow(row_sp);
2264
2265 RegisterContextSP reg_ctx_sp;
2266 EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite(
2267 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
2268
2269 // Before we touch the stack pointer, we should still refer to the
2270 // row from after the prologue.
2271 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 5);
2272 EXPECT_EQ(4ull, row_sp->GetOffset());
2273
2274 // Check the first stack pointer update.
2275 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 12);
2276 EXPECT_EQ(12ull, row_sp->GetOffset());
2277 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2278 EXPECT_EQ(152, row_sp->GetCFAValue().GetOffset());
2279
2280 // After the nop, we should still refer to the same row.
2281 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 13);
2282 EXPECT_EQ(12ull, row_sp->GetOffset());
2283
2284 // Check that the second stack pointer update is reflected in the
2285 // unwind plan.
2286 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 20);
2287 EXPECT_EQ(20ull, row_sp->GetOffset());
2288 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2289 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2290}
2291
2292TEST_F(Testx86AssemblyInspectionEngine, TestSimplex86_64Augmented) {
2293 UnwindPlan::Row::RegisterLocation regloc;
2294 UnwindPlan::RowSP row_sp;
2295 AddressRange sample_range;
2296 UnwindPlan unwind_plan(eRegisterKindLLDB);
2297 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2298
2299 uint8_t data[] = {
2300 0x55, // pushq %rbp
2301 0x48, 0x89, 0xe5, // movq %rsp, %rbp
2302
2303 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2304 // has a bug where it can't augment a function that is just
2305 // prologue+epilogue - it needs at least one other instruction
2306 // in between.
2307 0x90, // nop
2308
2309 0x5d, // popq %rbp
2310 0xc3 // retq
2311 };
2312
2313 sample_range = AddressRange(0x1000, sizeof(data));
2314
2315 unwind_plan.SetSourceName("unit testing hand-created unwind plan");
2316 unwind_plan.SetPlanValidAddressRange(sample_range);
2317 unwind_plan.SetRegisterKind(eRegisterKindLLDB);
2318
2319 row_sp = std::make_shared<UnwindPlan::Row>();
2320
2321 // Describe offset 0
2322 row_sp->SetOffset(0);
2323 row_sp->GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_rsp, offset: 8);
2324
2325 regloc.SetAtCFAPlusOffset(-8);
2326 row_sp->SetRegisterInfo(reg_num: k_rip, register_location: regloc);
2327
2328 unwind_plan.AppendRow(row_sp);
2329
2330 // Allocate a new Row, populate it with the existing Row contents.
2331 UnwindPlan::Row *new_row = new UnwindPlan::Row;
2332 *new_row = *row_sp.get();
2333 row_sp.reset(p: new_row);
2334
2335 // Describe offset 1
2336 row_sp->SetOffset(1);
2337 row_sp->GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_rsp, offset: 16);
2338 regloc.SetAtCFAPlusOffset(-16);
2339 row_sp->SetRegisterInfo(reg_num: k_rbp, register_location: regloc);
2340 unwind_plan.AppendRow(row_sp);
2341
2342 // Allocate a new Row, populate it with the existing Row contents.
2343 new_row = new UnwindPlan::Row;
2344 *new_row = *row_sp.get();
2345 row_sp.reset(p: new_row);
2346
2347 // Describe offset 4
2348 row_sp->SetOffset(4);
2349 row_sp->GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_rbp, offset: 16);
2350 unwind_plan.AppendRow(row_sp);
2351
2352 RegisterContextSP reg_ctx_sp;
2353 EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite(
2354 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
2355
2356 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 6);
2357 EXPECT_EQ(6ull, row_sp->GetOffset());
2358 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2359 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2360
2361 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2362 // doesn't track register restores (pop'ing a reg value back from
2363 // the stack) - it was just written to make stepping work correctly.
2364 // Technically we should be able to do the following test, but it
2365 // won't work today - the unwind plan will still say that the caller's
2366 // rbp is on the stack.
2367 // EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
2368}
2369
2370TEST_F(Testx86AssemblyInspectionEngine, TestSimplei386ugmented) {
2371 UnwindPlan::Row::RegisterLocation regloc;
2372 UnwindPlan::RowSP row_sp;
2373 AddressRange sample_range;
2374 UnwindPlan unwind_plan(eRegisterKindLLDB);
2375 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2376
2377 uint8_t data[] = {
2378 0x55, // pushl %ebp
2379 0x89, 0xe5, // movl %esp, %ebp
2380
2381 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2382 // has a bug where it can't augment a function that is just
2383 // prologue+epilogue - it needs at least one other instruction
2384 // in between.
2385 0x90, // nop
2386
2387 0x5d, // popl %ebp
2388 0xc3 // retl
2389 };
2390
2391 sample_range = AddressRange(0x1000, sizeof(data));
2392
2393 unwind_plan.SetSourceName("unit testing hand-created unwind plan");
2394 unwind_plan.SetPlanValidAddressRange(sample_range);
2395 unwind_plan.SetRegisterKind(eRegisterKindLLDB);
2396
2397 row_sp = std::make_shared<UnwindPlan::Row>();
2398
2399 // Describe offset 0
2400 row_sp->SetOffset(0);
2401 row_sp->GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_esp, offset: 4);
2402
2403 regloc.SetAtCFAPlusOffset(-4);
2404 row_sp->SetRegisterInfo(reg_num: k_eip, register_location: regloc);
2405
2406 unwind_plan.AppendRow(row_sp);
2407
2408 // Allocate a new Row, populate it with the existing Row contents.
2409 UnwindPlan::Row *new_row = new UnwindPlan::Row;
2410 *new_row = *row_sp.get();
2411 row_sp.reset(p: new_row);
2412
2413 // Describe offset 1
2414 row_sp->SetOffset(1);
2415 row_sp->GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_esp, offset: 8);
2416 regloc.SetAtCFAPlusOffset(-8);
2417 row_sp->SetRegisterInfo(reg_num: k_ebp, register_location: regloc);
2418 unwind_plan.AppendRow(row_sp);
2419
2420 // Allocate a new Row, populate it with the existing Row contents.
2421 new_row = new UnwindPlan::Row;
2422 *new_row = *row_sp.get();
2423 row_sp.reset(p: new_row);
2424
2425 // Describe offset 3
2426 row_sp->SetOffset(3);
2427 row_sp->GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_ebp, offset: 8);
2428 unwind_plan.AppendRow(row_sp);
2429
2430 RegisterContextSP reg_ctx_sp;
2431 EXPECT_TRUE(engine32->AugmentUnwindPlanFromCallSite(
2432 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
2433
2434 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 5);
2435 EXPECT_EQ(5ull, row_sp->GetOffset());
2436 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
2437 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
2438
2439 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2440 // doesn't track register restores (pop'ing a reg value back from
2441 // the stack) - it was just written to make stepping work correctly.
2442 // Technically we should be able to do the following test, but it
2443 // won't work today - the unwind plan will still say that the caller's
2444 // ebp is on the stack.
2445 // EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
2446}
2447
2448// Check that the i386 disassembler disassembles past an opcode that
2449// is only valid in 32-bit mode (non-long mode), and the x86_64 disassembler
2450// stops
2451// disassembling at that point (long-mode).
2452TEST_F(Testx86AssemblyInspectionEngine, Test32BitOnlyInstruction) {
2453 UnwindPlan::Row::RegisterLocation regloc;
2454 UnwindPlan::RowSP row_sp;
2455 AddressRange sample_range;
2456 UnwindPlan unwind_plan(eRegisterKindLLDB);
2457 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2458 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2459
2460 uint8_t data[] = {
2461 0x43, // incl $ebx --- an invalid opcode in 64-bit mode
2462 0x55, // pushl %ebp
2463 0x90 // nop
2464 };
2465
2466 sample_range = AddressRange(0x1000, sizeof(data));
2467
2468 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2469 data, sizeof(data), sample_range, unwind_plan));
2470
2471 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
2472 EXPECT_EQ(2ull, row_sp->GetOffset());
2473 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
2474 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2475 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2476
2477 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
2478 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2479 EXPECT_EQ(-8, regloc.GetOffset());
2480
2481 unwind_plan.Clear();
2482
2483 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2484 data, sizeof(data), sample_range, unwind_plan));
2485
2486 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 2);
2487 EXPECT_EQ(0ull, row_sp->GetOffset());
2488 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2489 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2490 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2491
2492 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
2493}
2494
2495TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign8BitDisp_i386) {
2496 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2497
2498 uint8_t data[] = {
2499 0x55, // pushl %ebp
2500 0x89, 0xe5, // movl %esp, %ebp
2501 0x53, // pushl %ebx
2502 0x83, 0xe4, 0xf0, // andl $-16, %esp
2503 0x83, 0xec, 0x10, // subl $16, %esp
2504 0x8d, 0x65, 0xfc, // leal -4(%ebp), %esp
2505 0x5b, // popl %ebx
2506 0x5d, // popl %ebp
2507 0xc3, // retl
2508 };
2509
2510 AddressRange sample_range(0x1000, sizeof(data));
2511 UnwindPlan plan(eRegisterKindLLDB);
2512 ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
2513 sample_range, plan));
2514
2515 UnwindPlan::Row::FAValue esp_plus_4, esp_plus_8, ebp_plus_8;
2516 esp_plus_4.SetIsRegisterPlusOffset(reg_num: k_esp, offset: 4);
2517 esp_plus_8.SetIsRegisterPlusOffset(reg_num: k_esp, offset: 8);
2518 ebp_plus_8.SetIsRegisterPlusOffset(reg_num: k_ebp, offset: 8);
2519
2520 EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue());
2521 EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue());
2522 for (size_t i = 3; i < sizeof(data) - 2; ++i)
2523 EXPECT_EQ(ebp_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue())
2524 << "i: " << i;
2525 EXPECT_EQ(esp_plus_4,
2526 plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());
2527}
2528
2529TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign32BitDisp_x86_64) {
2530 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
2531
2532 uint8_t data[] = {
2533 0x55, // pushq %rbp
2534 0x48, 0x89, 0xe5, // movq %rsp, %rbp
2535 0x53, // pushl %rbx
2536 0x48, 0x83, 0xe4, 0xf0, // andq $-16, %rsp
2537 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $256, %rsp
2538 0x48, 0x8d, 0x65, 0xf8, // leaq -8(%rbp), %rsp
2539 0x5b, // popq %rbx
2540 0x5d, // popq %rbp
2541 0xc3, // retq
2542 };
2543
2544 AddressRange sample_range(0x1000, sizeof(data));
2545 UnwindPlan plan(eRegisterKindLLDB);
2546 ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
2547 sample_range, plan));
2548
2549 UnwindPlan::Row::FAValue rsp_plus_8, rsp_plus_16, rbp_plus_16;
2550 rsp_plus_8.SetIsRegisterPlusOffset(reg_num: k_rsp, offset: 8);
2551 rsp_plus_16.SetIsRegisterPlusOffset(reg_num: k_rsp, offset: 16);
2552 rbp_plus_16.SetIsRegisterPlusOffset(reg_num: k_rbp, offset: 16);
2553
2554 EXPECT_EQ(rsp_plus_8, plan.GetRowForFunctionOffset(0)->GetCFAValue());
2555 EXPECT_EQ(rsp_plus_16, plan.GetRowForFunctionOffset(1)->GetCFAValue());
2556 for (size_t i = 4; i < sizeof(data) - 2; ++i)
2557 EXPECT_EQ(rbp_plus_16, plan.GetRowForFunctionOffset(i)->GetCFAValue())
2558 << "i: " << i;
2559 EXPECT_EQ(rsp_plus_8,
2560 plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());
2561}
2562
2563TEST_F(Testx86AssemblyInspectionEngine, TestStackRealignMSVC_i386) {
2564 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2565
2566 uint8_t data[] = {
2567 0x53, // offset 00 -- pushl %ebx
2568 0x8b, 0xdc, // offset 01 -- movl %esp, %ebx
2569 0x83, 0xec, 0x08, // offset 03 -- subl $8, %esp
2570 0x81, 0xe4, 0x00, 0xff, 0xff, 0xff, // offset 06 -- andl $-256, %esp
2571 0x83, 0xc4, 0x04, // offset 12 -- addl $4, %esp
2572 0x55, // offset 15 -- pushl %ebp
2573 0x8b, 0xec, // offset 16 -- movl %esp, %ebp
2574 0x81, 0xec, 0x00, 0x02, 0x00, 0x00, // offset 18 -- subl $512, %esp
2575 0x89, 0x7d, 0xfc, // offset 24 -- movl %edi, -4(%ebp)
2576 0x8b, 0xe5, // offset 27 -- movl %ebp, %esp
2577 0x5d, // offset 29 -- popl %ebp
2578 0x8b, 0xe3, // offset 30 -- movl %ebx, %esp
2579 0x5b, // offset 32 -- popl %ebx
2580 0xc3 // offset 33 -- retl
2581 };
2582
2583 AddressRange sample_range(0x1000, sizeof(data));
2584 UnwindPlan plan(eRegisterKindLLDB);
2585 ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
2586 sample_range, plan));
2587
2588 UnwindPlan::Row::FAValue esp_minus_4, esp_plus_0, esp_plus_4, esp_plus_8,
2589 ebx_plus_8, ebp_plus_0;
2590 esp_minus_4.SetIsRegisterPlusOffset(reg_num: k_esp, offset: -4);
2591 esp_plus_0.SetIsRegisterPlusOffset(reg_num: k_esp, offset: 0);
2592 esp_plus_4.SetIsRegisterPlusOffset(reg_num: k_esp, offset: 4);
2593 esp_plus_8.SetIsRegisterPlusOffset(reg_num: k_esp, offset: 8);
2594 ebx_plus_8.SetIsRegisterPlusOffset(reg_num: k_ebx, offset: 8);
2595 ebp_plus_0.SetIsRegisterPlusOffset(reg_num: k_ebp, offset: 0);
2596
2597 // Test CFA
2598 EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue());
2599 EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue());
2600 for (size_t i = 3; i < 33; ++i)
2601 EXPECT_EQ(ebx_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue())
2602 << "i: " << i;
2603 EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(33)->GetCFAValue());
2604
2605 // Test AFA
2606 EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(12)->GetAFAValue());
2607 EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(15)->GetAFAValue());
2608 EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(16)->GetAFAValue());
2609 for (size_t i = 18; i < 30; ++i)
2610 EXPECT_EQ(ebp_plus_0, plan.GetRowForFunctionOffset(i)->GetAFAValue())
2611 << "i: " << i;
2612 EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(30)->GetAFAValue());
2613
2614 // Test saved register
2615 UnwindPlan::Row::RegisterLocation reg_loc;
2616 EXPECT_TRUE(
2617 plan.GetRowForFunctionOffset(27)->GetRegisterInfo(k_edi, reg_loc));
2618 EXPECT_TRUE(reg_loc.IsAtAFAPlusOffset());
2619 EXPECT_EQ(-4, reg_loc.GetOffset());
2620}
2621
2622// Give the disassembler random bytes to test that it doesn't exceed
2623// the bounds of the array when run under clang's address sanitizer.
2624TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyJunkBytes) {
2625 AddressRange sample_range;
2626 UnwindPlan unwind_plan(eRegisterKindLLDB);
2627 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2628 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2629
2630 uint8_t data[] = {
2631 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
2632 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
2633
2634 sample_range = AddressRange(0x1000, sizeof(data));
2635
2636 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2637 data, sizeof(data), sample_range, unwind_plan));
2638
2639 unwind_plan.Clear();
2640
2641 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2642 data, sizeof(data), sample_range, unwind_plan));
2643
2644}
2645
2646TEST_F(Testx86AssemblyInspectionEngine, TestReturnDetect) {
2647 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
2648
2649 // Single fragment with all four return forms.
2650 // We want to verify that the unwind state is reset after each ret.
2651 uint8_t data[] = {
2652 0x55, // offset 0 -- pushq %rbp
2653 0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp
2654 0x31, 0xc0, // offset 4 -- xorl %eax, %eax
2655 0x5d, // offset 6 -- popq %rbp
2656 0xc3, // offset 7 -- retq
2657 0x31, 0xc0, // offset 8 -- xorl %eax, %eax
2658 0x5d, // offset 10 -- popq %rbp
2659 0xcb, // offset 11 -- retf
2660 0x31, 0xc0, // offset 12 -- xorl %eax, %eax
2661 0x5d, // offset 14 -- popq %rbp
2662 0xc2, 0x22, 0x11, // offset 15 -- retq 0x1122
2663 0x31, 0xc0, // offset 18 -- xorl %eax, %eax
2664 0x5d, // offset 20 -- popq %rbp
2665 0xca, 0x44, 0x33, // offset 21 -- retf 0x3344
2666 0x31, 0xc0, // offset 24 -- xorl %eax, %eax
2667 };
2668
2669 AddressRange sample_range(0x1000, sizeof(data));
2670
2671 UnwindPlan unwind_plan(eRegisterKindLLDB);
2672 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
2673 data, sizeof(data), sample_range, unwind_plan));
2674
2675 // Expect following unwind rows:
2676 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2677 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2678 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2679 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2680 // 8: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2681 // 11: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2682 // 12: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2683 // 15: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2684 // 18: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2685 // 21: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2686 // 24: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2687
2688 EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp);
2689 EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
2690 eLazyBoolYes);
2691 EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
2692
2693 UnwindPlan::Row::RegisterLocation regloc;
2694
2695 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2696 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(offset: 0);
2697 EXPECT_EQ(0ull, row_sp->GetOffset());
2698 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2699 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2700 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2701
2702 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2703 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2704 EXPECT_EQ(-8, regloc.GetOffset());
2705
2706 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2707 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 1);
2708 EXPECT_EQ(1ull, row_sp->GetOffset());
2709 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2710 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2711 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2712
2713 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2714 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2715 EXPECT_EQ(-8, regloc.GetOffset());
2716
2717 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2718 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 4);
2719 EXPECT_EQ(4ull, row_sp->GetOffset());
2720 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2721 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2722 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2723
2724 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2725 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2726 EXPECT_EQ(-8, regloc.GetOffset());
2727
2728 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2729 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 7);
2730 EXPECT_EQ(7ull, row_sp->GetOffset());
2731 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2732 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2733 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2734
2735 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2736 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2737 EXPECT_EQ(-8, regloc.GetOffset());
2738
2739 // 8: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2740 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 8);
2741 EXPECT_EQ(8ull, row_sp->GetOffset());
2742 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2743 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2744 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2745
2746 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2747 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2748 EXPECT_EQ(-8, regloc.GetOffset());
2749
2750 // 11: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2751 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 11);
2752 EXPECT_EQ(11ull, row_sp->GetOffset());
2753 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2754 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2755 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2756
2757 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2758 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2759 EXPECT_EQ(-8, regloc.GetOffset());
2760
2761 // 12: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2762 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 12);
2763 EXPECT_EQ(12ull, row_sp->GetOffset());
2764 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2765 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2766 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2767
2768 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2769 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2770 EXPECT_EQ(-8, regloc.GetOffset());
2771
2772 // 15: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2773 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 15);
2774 EXPECT_EQ(15ull, row_sp->GetOffset());
2775 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2776 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2777 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2778
2779 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2780 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2781 EXPECT_EQ(-8, regloc.GetOffset());
2782
2783 // 18: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2784 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 18);
2785 EXPECT_EQ(18ull, row_sp->GetOffset());
2786 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2787 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2788 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2789
2790 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2791 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2792 EXPECT_EQ(-8, regloc.GetOffset());
2793
2794 // 21: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2795 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 21);
2796 EXPECT_EQ(21ull, row_sp->GetOffset());
2797 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2798 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2799 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
2800
2801 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2802 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2803 EXPECT_EQ(-8, regloc.GetOffset());
2804
2805 // 24: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2806 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 24);
2807 EXPECT_EQ(24ull, row_sp->GetOffset());
2808 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2809 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2810 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
2811
2812 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
2813 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2814 EXPECT_EQ(-8, regloc.GetOffset());
2815}
2816
2817
2818// Test mid-function epilogues - the unwind state post-prologue
2819// should be re-instated.
2820
2821TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyMidFunctionEpilogues) {
2822 AddressRange sample_range;
2823 UnwindPlan unwind_plan(eRegisterKindLLDB);
2824 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2825 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2826
2827 uint8_t data[] = {
2828 0x55, // <+0>: pushq %rbp
2829 0x48, 0x89, 0xe5, // <+1>: movq %rsp, %rbp
2830 0x48, 0x83, 0xec, 0x70, // <+4>: subq $0x70, %rsp
2831 0x90, // <+8>: nop // prologue set up
2832
2833 0x74, 0x7, // <+9>: je 7 <+18>
2834 0x48, 0x83, 0xc4, 0x70, // <+11>: addq $0x70, %rsp
2835 0x5d, // <+15>: popq %rbp
2836 0xff, 0xe0, // <+16>: jmpq *%rax // epilogue completed
2837
2838 0x90, // <+18>: nop // prologue setup back
2839
2840 0x74, 0x7, // <+19>: je 6 <+27>
2841 0x48, 0x83, 0xc4, 0x70, // <+21>: addq $0x70, %rsp
2842 0x5d, // <+25>: popq %rbp
2843 0xc3, // <+26>: retq // epilogue completed
2844
2845 0x90, // <+27>: nop // prologue setup back
2846
2847 0x48, 0x83, 0xc4, 0x70, // <+28>: addq $0x70, %rsp
2848 0x5d, // <+32>: popq %rbp
2849 0xc3, // <+33>: retq // epilogue completed
2850
2851 };
2852
2853 sample_range = AddressRange(0x1000, sizeof(data));
2854
2855 int wordsize = 4;
2856 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2857 data, sizeof(data), sample_range, unwind_plan));
2858
2859 // Check that we've unwound the stack after the first mid-function epilogue
2860 // row: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
2861 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(offset: 16);
2862 EXPECT_EQ(16ull, row_sp->GetOffset());
2863 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
2864 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2865 EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
2866
2867 // Check that we've reinstated the stack frame setup
2868 // unwind instructions after a jmpq *%eax
2869 // row: CFA=ebp +8 => esp=CFA+0 eip=[CFA-8]
2870 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 18);
2871 EXPECT_EQ(18ull, row_sp->GetOffset());
2872 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
2873 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2874 EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
2875
2876 // Check that we've reinstated the stack frame setup
2877 // unwind instructions after a mid-function retq
2878 // row: CFA=ebp +8 => esp=CFA+0 eip=[CFA-8]
2879 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 27);
2880 EXPECT_EQ(27ull, row_sp->GetOffset());
2881 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
2882 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2883 EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
2884
2885 // After last instruction in the function, verify that
2886 // the stack frame has been unwound
2887 // row: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
2888 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 33);
2889 EXPECT_EQ(33ull, row_sp->GetOffset());
2890 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
2891 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2892 EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
2893
2894
2895 unwind_plan.Clear();
2896
2897 wordsize = 8;
2898 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2899 data, sizeof(data), sample_range, unwind_plan));
2900
2901 // Check that we've unwound the stack after the first mid-function epilogue
2902 // row: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2903 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 16);
2904 EXPECT_EQ(16ull, row_sp->GetOffset());
2905 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2906 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2907 EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
2908
2909 // Check that we've reinstated the stack frame setup
2910 // unwind instructions after a jmpq *%eax
2911 // row: CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16]
2912 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 18);
2913 EXPECT_EQ(18ull, row_sp->GetOffset());
2914 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2915 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2916 EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
2917
2918 // Check that we've reinstated the stack frame setup
2919 // unwind instructions after a mid-function retq
2920 // row: CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16]
2921 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 27);
2922 EXPECT_EQ(27ull, row_sp->GetOffset());
2923 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
2924 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2925 EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
2926
2927 // After last instruction in the function, verify that
2928 // the stack frame has been unwound
2929 // row: CFA=rsp +8 => esp=CFA+0 rip=[CFA-8]
2930 row_sp = unwind_plan.GetRowForFunctionOffset(offset: 33);
2931 EXPECT_EQ(33ull, row_sp->GetOffset());
2932 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
2933 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
2934 EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
2935
2936
2937}
2938

source code of lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp