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::AbstractRegisterLocation regloc;
172
173 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
174 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(offset: 0);
175 EXPECT_EQ(0, row->GetOffset());
176 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
177 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
178 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
179
180 EXPECT_TRUE(row->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 = unwind_plan.GetRowForFunctionOffset(offset: 1);
186 EXPECT_EQ(1, row->GetOffset());
187 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
188 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
189 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
190
191 EXPECT_TRUE(row->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 = unwind_plan.GetRowForFunctionOffset(offset: 4);
197 EXPECT_EQ(4, row->GetOffset());
198 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);
199 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
200 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
201
202 EXPECT_TRUE(row->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 = unwind_plan.GetRowForFunctionOffset(offset: 7);
208 EXPECT_EQ(7, row->GetOffset());
209 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
210 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
211 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
212
213 EXPECT_TRUE(row->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::AbstractRegisterLocation regloc;
248
249 // offset 0 -- pushl %ebp
250 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(offset: 0);
251 EXPECT_EQ(0, row->GetOffset());
252 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
253 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
254 EXPECT_EQ(4, row->GetCFAValue().GetOffset());
255
256 EXPECT_TRUE(row->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 = unwind_plan.GetRowForFunctionOffset(offset: 1);
262 EXPECT_EQ(1, row->GetOffset());
263 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
264 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
265 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
266
267 EXPECT_TRUE(row->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 = unwind_plan.GetRowForFunctionOffset(offset: 3);
273 EXPECT_EQ(3, row->GetOffset());
274 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_ebp);
275 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
276 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
277
278 EXPECT_TRUE(row->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 = unwind_plan.GetRowForFunctionOffset(offset: 6);
284 EXPECT_EQ(6, row->GetOffset());
285 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
286 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
287 EXPECT_EQ(4, row->GetCFAValue().GetOffset());
288
289 EXPECT_TRUE(row->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::AbstractRegisterLocation 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 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(offset: 17);
391
392 EXPECT_EQ(17, row->GetOffset());
393 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
394 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
395 EXPECT_EQ(14496, row->GetCFAValue().GetOffset());
396
397 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));
398 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
399 EXPECT_EQ(-8, regloc.GetOffset());
400
401 EXPECT_TRUE(row->GetRegisterInfo(k_rbp, regloc));
402 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
403 EXPECT_EQ(-16, regloc.GetOffset());
404
405 EXPECT_TRUE(row->GetRegisterInfo(k_r15, regloc));
406 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
407 EXPECT_EQ(-24, regloc.GetOffset());
408
409 EXPECT_TRUE(row->GetRegisterInfo(k_r14, regloc));
410 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
411 EXPECT_EQ(-32, regloc.GetOffset());
412
413 EXPECT_TRUE(row->GetRegisterInfo(k_r13, regloc));
414 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
415 EXPECT_EQ(-40, regloc.GetOffset());
416
417 EXPECT_TRUE(row->GetRegisterInfo(k_r12, regloc));
418 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
419 EXPECT_EQ(-48, regloc.GetOffset());
420
421 EXPECT_TRUE(row->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 = unwind_plan.GetRowForFunctionOffset(offset: 34);
429
430 EXPECT_EQ(34, row->GetOffset());
431 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
432 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
433 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
434
435 EXPECT_TRUE(row->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->GetRegisterInfo(k_rax, regloc));
444 EXPECT_FALSE(row->GetRegisterInfo(k_rbx, regloc));
445 EXPECT_FALSE(row->GetRegisterInfo(k_rcx, regloc));
446 EXPECT_FALSE(row->GetRegisterInfo(k_rdx, regloc));
447 EXPECT_FALSE(row->GetRegisterInfo(k_rbp, regloc));
448 EXPECT_FALSE(row->GetRegisterInfo(k_rsi, regloc));
449 EXPECT_FALSE(row->GetRegisterInfo(k_rdi, regloc));
450 EXPECT_FALSE(row->GetRegisterInfo(k_r8, regloc));
451 EXPECT_FALSE(row->GetRegisterInfo(k_r9, regloc));
452 EXPECT_FALSE(row->GetRegisterInfo(k_r10, regloc));
453 EXPECT_FALSE(row->GetRegisterInfo(k_r11, regloc));
454 EXPECT_FALSE(row->GetRegisterInfo(k_r12, regloc));
455 EXPECT_FALSE(row->GetRegisterInfo(k_r13, regloc));
456 EXPECT_FALSE(row->GetRegisterInfo(k_r14, regloc));
457 EXPECT_FALSE(row->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::AbstractRegisterLocation regloc;
654 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 10);
661 EXPECT_EQ(10, row->GetOffset());
662 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
663 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
664 EXPECT_EQ(14464, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 15);
669 EXPECT_EQ(15, row->GetOffset());
670 EXPECT_EQ(14468, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 16);
675 EXPECT_EQ(16, row->GetOffset());
676 EXPECT_EQ(14464, row->GetCFAValue().GetOffset());
677
678 // Check that the row for offset 16 has the registers saved that we expect
679
680 EXPECT_TRUE(row->GetRegisterInfo(k_eip, regloc));
681 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
682 EXPECT_EQ(-4, regloc.GetOffset());
683
684 EXPECT_TRUE(row->GetRegisterInfo(k_ebp, regloc));
685 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
686 EXPECT_EQ(-8, regloc.GetOffset());
687
688 EXPECT_TRUE(row->GetRegisterInfo(k_ebx, regloc));
689 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
690 EXPECT_EQ(-12, regloc.GetOffset());
691
692 EXPECT_TRUE(row->GetRegisterInfo(k_edi, regloc));
693 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
694 EXPECT_EQ(-16, regloc.GetOffset());
695
696 EXPECT_TRUE(row->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 = unwind_plan.GetRowForFunctionOffset(offset: 23);
706 EXPECT_EQ(23, row->GetOffset());
707 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
708 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
709 EXPECT_EQ(14472, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 24);
714 EXPECT_EQ(24, row->GetOffset());
715 EXPECT_EQ(14476, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 28);
720 EXPECT_EQ(28, row->GetOffset());
721 EXPECT_EQ(14480, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 36);
726 EXPECT_EQ(36, row->GetOffset());
727 EXPECT_EQ(14464, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 47);
733 EXPECT_EQ(47, row->GetOffset());
734 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
735 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
736 EXPECT_EQ(4, row->GetCFAValue().GetOffset());
737
738 EXPECT_TRUE(row->GetRegisterInfo(k_eip, regloc));
739 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
740 EXPECT_EQ(-4, regloc.GetOffset());
741
742 EXPECT_TRUE(row->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->GetRegisterInfo(k_eax, regloc));
749 EXPECT_FALSE(row->GetRegisterInfo(k_ebx, regloc));
750 EXPECT_FALSE(row->GetRegisterInfo(k_ecx, regloc));
751 EXPECT_FALSE(row->GetRegisterInfo(k_edx, regloc));
752 EXPECT_FALSE(row->GetRegisterInfo(k_esi, regloc));
753 EXPECT_FALSE(row->GetRegisterInfo(k_edi, regloc));
754 EXPECT_FALSE(row->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::AbstractRegisterLocation 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 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(offset: 13);
811
812 EXPECT_EQ(1, row->GetOffset());
813 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
814 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
815 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
816
817 EXPECT_TRUE(row->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->GetRegisterInfo(k_rax, regloc));
824 EXPECT_FALSE(row->GetRegisterInfo(k_rbx, regloc));
825 EXPECT_FALSE(row->GetRegisterInfo(k_rcx, regloc));
826 EXPECT_FALSE(row->GetRegisterInfo(k_rdx, regloc));
827 EXPECT_FALSE(row->GetRegisterInfo(k_rbp, regloc));
828 EXPECT_FALSE(row->GetRegisterInfo(k_rsi, regloc));
829 EXPECT_FALSE(row->GetRegisterInfo(k_rdi, regloc));
830 EXPECT_FALSE(row->GetRegisterInfo(k_r8, regloc));
831 EXPECT_FALSE(row->GetRegisterInfo(k_r9, regloc));
832 EXPECT_FALSE(row->GetRegisterInfo(k_r10, regloc));
833 EXPECT_FALSE(row->GetRegisterInfo(k_r11, regloc));
834 EXPECT_FALSE(row->GetRegisterInfo(k_r12, regloc));
835 EXPECT_FALSE(row->GetRegisterInfo(k_r13, regloc));
836 EXPECT_FALSE(row->GetRegisterInfo(k_r14, regloc));
837 EXPECT_FALSE(row->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 = unwind_plan.GetRowForFunctionOffset(offset: 22);
843
844 EXPECT_EQ(22, row->GetOffset());
845 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
846 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
847 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
848
849 EXPECT_TRUE(row->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::AbstractRegisterLocation 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 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(offset: 3);
920
921 EXPECT_EQ(3, row->GetOffset());
922 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
923 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
924 EXPECT_EQ(16, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 8);
930 EXPECT_EQ(8, row->GetOffset());
931 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
932 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
933 EXPECT_EQ(20, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 9);
939 EXPECT_EQ(9, row->GetOffset());
940 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
941 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
942 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
943
944 // Check that no unexpected registers were saved
945
946 EXPECT_FALSE(row->GetRegisterInfo(k_eax, regloc));
947 EXPECT_FALSE(row->GetRegisterInfo(k_ebx, regloc));
948 EXPECT_FALSE(row->GetRegisterInfo(k_ecx, regloc));
949 EXPECT_FALSE(row->GetRegisterInfo(k_edx, regloc));
950 EXPECT_FALSE(row->GetRegisterInfo(k_esi, regloc));
951 EXPECT_FALSE(row->GetRegisterInfo(k_edi, regloc));
952 EXPECT_FALSE(row->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 = unwind_plan.GetRowForFunctionOffset(offset: 34);
958 EXPECT_EQ(34, row->GetOffset());
959 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
960 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
961 EXPECT_EQ(4, row->GetCFAValue().GetOffset());
962}
963
964TEST_F(Testx86AssemblyInspectionEngine, TestPushRBP) {
965 UnwindPlan::Row::AbstractRegisterLocation regloc;
966 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 1);
981
982 EXPECT_EQ(1, row->GetOffset());
983 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
984 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
985 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
986
987 EXPECT_TRUE(row->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 = unwind_plan.GetRowForFunctionOffset(offset: 1);
996
997 EXPECT_EQ(1, row->GetOffset());
998 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
999 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1000 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1001
1002 EXPECT_TRUE(row->GetRegisterInfo(k_rbp, regloc));
1003 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1004 EXPECT_EQ(-8, regloc.GetOffset());
1005}
1006
1007TEST_F(Testx86AssemblyInspectionEngine, TestPushImm) {
1008 UnwindPlan::Row::AbstractRegisterLocation regloc;
1009 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 5);
1025 EXPECT_EQ(5, row->GetOffset());
1026 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1027 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1028 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
1029
1030 row = unwind_plan.GetRowForFunctionOffset(offset: 7);
1031 EXPECT_EQ(7, row->GetOffset());
1032 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1033 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1034 EXPECT_EQ(24, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 5);
1041 EXPECT_EQ(5, row->GetOffset());
1042 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1043 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1044 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1045
1046 row = unwind_plan.GetRowForFunctionOffset(offset: 7);
1047 EXPECT_EQ(7, row->GetOffset());
1048 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1049 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1050 EXPECT_EQ(12, row->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::AbstractRegisterLocation regloc;
1058 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 2);
1073
1074 // We're verifying that no row was created for the 'pushq $0'
1075 EXPECT_EQ(0, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 2);
1082
1083 // We're verifying that no row was created for the 'pushq $0'
1084 EXPECT_EQ(0, row->GetOffset());
1085}
1086
1087TEST_F(Testx86AssemblyInspectionEngine, TestPushExtended) {
1088 UnwindPlan::Row::AbstractRegisterLocation regloc;
1089 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 4);
1106
1107 EXPECT_EQ(4, row->GetOffset());
1108 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1109 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1110 EXPECT_EQ(16, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 4);
1117 EXPECT_EQ(4, row->GetOffset());
1118 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1119 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1120 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1121
1122 row = unwind_plan.GetRowForFunctionOffset(offset: 10);
1123 EXPECT_EQ(10, row->GetOffset());
1124 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1125 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1126 EXPECT_EQ(12, row->GetCFAValue().GetOffset());
1127
1128 row = unwind_plan.GetRowForFunctionOffset(offset: 12);
1129 EXPECT_EQ(12, row->GetOffset());
1130 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1131 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1132 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
1133}
1134
1135TEST_F(Testx86AssemblyInspectionEngine, TestPushR15) {
1136 UnwindPlan::Row::AbstractRegisterLocation regloc;
1137 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 2);
1152
1153 EXPECT_EQ(2, row->GetOffset());
1154 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1155 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1156 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
1157
1158 EXPECT_TRUE(row->GetRegisterInfo(k_r15, regloc));
1159 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1160 EXPECT_EQ(-16, regloc.GetOffset());
1161}
1162
1163TEST_F(Testx86AssemblyInspectionEngine, TestPushR14) {
1164 UnwindPlan::Row::AbstractRegisterLocation regloc;
1165 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 2);
1180
1181 EXPECT_EQ(2, row->GetOffset());
1182 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1183 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1184 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
1185
1186 EXPECT_TRUE(row->GetRegisterInfo(k_r14, regloc));
1187 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1188 EXPECT_EQ(-16, regloc.GetOffset());
1189}
1190
1191TEST_F(Testx86AssemblyInspectionEngine, TestPushR13) {
1192 UnwindPlan::Row::AbstractRegisterLocation regloc;
1193 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 2);
1208
1209 EXPECT_EQ(2, row->GetOffset());
1210 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1211 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1212 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
1213
1214 EXPECT_TRUE(row->GetRegisterInfo(k_r13, regloc));
1215 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1216 EXPECT_EQ(-16, regloc.GetOffset());
1217}
1218
1219TEST_F(Testx86AssemblyInspectionEngine, TestPushR12) {
1220 UnwindPlan::Row::AbstractRegisterLocation regloc;
1221 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 2);
1236
1237 EXPECT_EQ(2, row->GetOffset());
1238 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1239 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1240 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
1241
1242 EXPECT_TRUE(row->GetRegisterInfo(k_r12, regloc));
1243 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1244 EXPECT_EQ(-16, regloc.GetOffset());
1245}
1246
1247TEST_F(Testx86AssemblyInspectionEngine, TestPushRBX) {
1248 UnwindPlan::Row::AbstractRegisterLocation regloc;
1249 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 1);
1264
1265 EXPECT_EQ(1, row->GetOffset());
1266 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1267 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1268 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
1269
1270 EXPECT_TRUE(row->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::AbstractRegisterLocation regloc;
1280 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 1);
1296 EXPECT_EQ(1, row->GetOffset());
1297 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
1298 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1299 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1300
1301 EXPECT_FALSE(row->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::AbstractRegisterLocation regloc;
1309 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 1);
1325 EXPECT_EQ(1, row->GetOffset());
1326 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
1327 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1328 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1329
1330 EXPECT_FALSE(row->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::AbstractRegisterLocation regloc;
1338 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 1);
1354 EXPECT_EQ(1, row->GetOffset());
1355 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
1356 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1357 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1358
1359 EXPECT_FALSE(row->GetRegisterInfo(k_edx, regloc));
1360}
1361
1362TEST_F(Testx86AssemblyInspectionEngine, TestPushEBX) {
1363 UnwindPlan::Row::AbstractRegisterLocation regloc;
1364 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 1);
1380 EXPECT_EQ(1, row->GetOffset());
1381 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
1382 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1383 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1384
1385 EXPECT_TRUE(row->GetRegisterInfo(k_ebx, regloc));
1386 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1387 EXPECT_EQ(-8, regloc.GetOffset());
1388}
1389
1390TEST_F(Testx86AssemblyInspectionEngine, TestPushEBP) {
1391 UnwindPlan::Row::AbstractRegisterLocation regloc;
1392 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 1);
1408 EXPECT_EQ(1, row->GetOffset());
1409 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
1410 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1411 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1412
1413 EXPECT_TRUE(row->GetRegisterInfo(k_ebp, regloc));
1414 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1415 EXPECT_EQ(-8, regloc.GetOffset());
1416}
1417
1418TEST_F(Testx86AssemblyInspectionEngine, TestPushRBPWithREX) {
1419 UnwindPlan::Row::AbstractRegisterLocation regloc;
1420 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 2);
1435
1436 EXPECT_EQ(2, row->GetOffset());
1437 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1438 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1439 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
1440
1441 EXPECT_TRUE(row->GetRegisterInfo(k_rbp, regloc));
1442 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1443 EXPECT_EQ(-16, regloc.GetOffset());
1444}
1445
1446TEST_F(Testx86AssemblyInspectionEngine, TestPushESI) {
1447 UnwindPlan::Row::AbstractRegisterLocation regloc;
1448 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 1);
1464 EXPECT_EQ(1, row->GetOffset());
1465 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
1466 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1467 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1468
1469 EXPECT_TRUE(row->GetRegisterInfo(k_esi, regloc));
1470 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1471 EXPECT_EQ(-8, regloc.GetOffset());
1472}
1473
1474TEST_F(Testx86AssemblyInspectionEngine, TestPushEDI) {
1475 UnwindPlan::Row::AbstractRegisterLocation regloc;
1476 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 1);
1492 EXPECT_EQ(1, row->GetOffset());
1493 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
1494 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1495 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1496
1497 EXPECT_TRUE(row->GetRegisterInfo(k_edi, regloc));
1498 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
1499 EXPECT_EQ(-8, regloc.GetOffset());
1500}
1501
1502TEST_F(Testx86AssemblyInspectionEngine, TestMovRSPtoRBP) {
1503 UnwindPlan::Row::AbstractRegisterLocation regloc;
1504 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 3);
1519
1520 EXPECT_EQ(3, row->GetOffset());
1521 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);
1522 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1523 EXPECT_EQ(8, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 3);
1536 EXPECT_EQ(3, row->GetOffset());
1537 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);
1538 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1539 EXPECT_EQ(8, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 2);
1552 EXPECT_EQ(2, row->GetOffset());
1553 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_ebp);
1554 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1555 EXPECT_EQ(8, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 2);
1568 EXPECT_EQ(2, row->GetOffset());
1569 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_ebp);
1570 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1571 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1572}
1573
1574TEST_F(Testx86AssemblyInspectionEngine, TestSubRSP) {
1575 UnwindPlan::Row::AbstractRegisterLocation regloc;
1576 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 7);
1592 EXPECT_EQ(7, row->GetOffset());
1593 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1594 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1595 EXPECT_EQ(264, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 4);
1608 EXPECT_EQ(4, row->GetOffset());
1609 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1610 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1611 EXPECT_EQ(24, row->GetCFAValue().GetOffset());
1612}
1613
1614TEST_F(Testx86AssemblyInspectionEngine, TestSubESP) {
1615 UnwindPlan::Row::AbstractRegisterLocation regloc;
1616 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 6);
1632 EXPECT_EQ(6, row->GetOffset());
1633 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1634 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1635 EXPECT_EQ(260, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 3);
1648 EXPECT_EQ(3, row->GetOffset());
1649 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1650 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1651 EXPECT_EQ(20, row->GetCFAValue().GetOffset());
1652}
1653
1654TEST_F(Testx86AssemblyInspectionEngine, TestAddRSP) {
1655 UnwindPlan::Row::AbstractRegisterLocation regloc;
1656 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 7);
1672 EXPECT_EQ(7, row->GetOffset());
1673 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1674 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1675 EXPECT_EQ(8 - 256, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 4);
1688 EXPECT_EQ(4, row->GetOffset());
1689 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1690 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1691 EXPECT_EQ(8 - 16, row->GetCFAValue().GetOffset());
1692}
1693
1694TEST_F(Testx86AssemblyInspectionEngine, TestAddESP) {
1695 UnwindPlan::Row::AbstractRegisterLocation regloc;
1696 const UnwindPlan::Row *row;
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 = unwind_plan.GetRowForFunctionOffset(offset: 6);
1712 EXPECT_EQ(6, row->GetOffset());
1713 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1714 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1715 EXPECT_EQ(4 - 256, row->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 = unwind_plan.GetRowForFunctionOffset(offset: 3);
1728 EXPECT_EQ(3, row->GetOffset());
1729 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1730 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1731 EXPECT_EQ(4 - 16, row->GetCFAValue().GetOffset());
1732}
1733
1734TEST_F(Testx86AssemblyInspectionEngine, TestLEA_RSP_Pattern) {
1735 UnwindPlan::Row::AbstractRegisterLocation regloc;
1736 const UnwindPlan::Row *row;
1737 AddressRange sample_range;
1738 UnwindPlan unwind_plan(eRegisterKindLLDB);
1739 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1740
1741 uint8_t data[] = {
1742 0x8d, 0x64, 0x24, 0x10, // lea rsp, [rsp + 0x10]
1743 0x90 // nop
1744 };
1745
1746 sample_range = AddressRange(0x1000, sizeof(data));
1747
1748 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1749 data, sizeof(data), sample_range, unwind_plan));
1750
1751 row = unwind_plan.GetRowForFunctionOffset(offset: 0);
1752 EXPECT_EQ(0, row->GetOffset());
1753 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1754 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1755 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1756}
1757
1758TEST_F(Testx86AssemblyInspectionEngine, TestPopRBX) {
1759 UnwindPlan::Row::AbstractRegisterLocation regloc;
1760 const UnwindPlan::Row *row;
1761 AddressRange sample_range;
1762 UnwindPlan unwind_plan(eRegisterKindLLDB);
1763 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1764
1765 uint8_t data[] = {
1766 0x53, // pushq %rbx
1767 0x5b, // popq %rbx
1768 0x90 // nop
1769 };
1770
1771 sample_range = AddressRange(0x1000, sizeof(data));
1772
1773 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1774 data, sizeof(data), sample_range, unwind_plan));
1775
1776 row = unwind_plan.GetRowForFunctionOffset(offset: 2);
1777 EXPECT_EQ(2, row->GetOffset());
1778 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1779 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1780 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1781 EXPECT_FALSE(row->GetRegisterInfo(k_rbx, regloc));
1782}
1783
1784TEST_F(Testx86AssemblyInspectionEngine, TestPopRBP) {
1785 UnwindPlan::Row::AbstractRegisterLocation regloc;
1786 const UnwindPlan::Row *row;
1787 AddressRange sample_range;
1788 UnwindPlan unwind_plan(eRegisterKindLLDB);
1789 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1790
1791 uint8_t data[] = {
1792 0x55, // pushq %rbp
1793 0x5d, // popq %rbp
1794 0x90 // nop
1795 };
1796
1797 sample_range = AddressRange(0x1000, sizeof(data));
1798
1799 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1800 data, sizeof(data), sample_range, unwind_plan));
1801
1802 row = unwind_plan.GetRowForFunctionOffset(offset: 2);
1803 EXPECT_EQ(2, row->GetOffset());
1804 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1805 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1806 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1807 EXPECT_FALSE(row->GetRegisterInfo(k_rbp, regloc));
1808}
1809
1810TEST_F(Testx86AssemblyInspectionEngine, TestPopR12) {
1811 UnwindPlan::Row::AbstractRegisterLocation regloc;
1812 const UnwindPlan::Row *row;
1813 AddressRange sample_range;
1814 UnwindPlan unwind_plan(eRegisterKindLLDB);
1815 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1816
1817 uint8_t data[] = {
1818 0x41, 0x54, // pushq %r12
1819 0x41, 0x5c, // popq %r12
1820 0x90 // nop
1821 };
1822
1823 sample_range = AddressRange(0x1000, sizeof(data));
1824
1825 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1826 data, sizeof(data), sample_range, unwind_plan));
1827
1828 row = unwind_plan.GetRowForFunctionOffset(offset: 4);
1829 EXPECT_EQ(4, row->GetOffset());
1830 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1831 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1832 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1833 EXPECT_FALSE(row->GetRegisterInfo(k_r12, regloc));
1834}
1835
1836TEST_F(Testx86AssemblyInspectionEngine, TestPopR13) {
1837 UnwindPlan::Row::AbstractRegisterLocation regloc;
1838 const UnwindPlan::Row *row;
1839 AddressRange sample_range;
1840 UnwindPlan unwind_plan(eRegisterKindLLDB);
1841 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1842
1843 uint8_t data[] = {
1844 0x41, 0x55, // pushq %r13
1845 0x41, 0x5d, // popq %r13
1846 0x90 // nop
1847 };
1848
1849 sample_range = AddressRange(0x1000, sizeof(data));
1850
1851 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1852 data, sizeof(data), sample_range, unwind_plan));
1853
1854 row = unwind_plan.GetRowForFunctionOffset(offset: 4);
1855 EXPECT_EQ(4, row->GetOffset());
1856 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1857 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1858 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1859 EXPECT_FALSE(row->GetRegisterInfo(k_r13, regloc));
1860}
1861
1862TEST_F(Testx86AssemblyInspectionEngine, TestPopR14) {
1863 UnwindPlan::Row::AbstractRegisterLocation regloc;
1864 const UnwindPlan::Row *row;
1865 AddressRange sample_range;
1866 UnwindPlan unwind_plan(eRegisterKindLLDB);
1867 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1868
1869 uint8_t data[] = {
1870 0x41, 0x56, // pushq %r14
1871 0x41, 0x5e, // popq %r14
1872 0x90 // nop
1873 };
1874
1875 sample_range = AddressRange(0x1000, sizeof(data));
1876
1877 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1878 data, sizeof(data), sample_range, unwind_plan));
1879
1880 row = unwind_plan.GetRowForFunctionOffset(offset: 4);
1881 EXPECT_EQ(4, row->GetOffset());
1882 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1883 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1884 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1885 EXPECT_FALSE(row->GetRegisterInfo(k_r14, regloc));
1886}
1887
1888TEST_F(Testx86AssemblyInspectionEngine, TestPopR15) {
1889 UnwindPlan::Row::AbstractRegisterLocation regloc;
1890 const UnwindPlan::Row *row;
1891 AddressRange sample_range;
1892 UnwindPlan unwind_plan(eRegisterKindLLDB);
1893 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1894
1895 uint8_t data[] = {
1896 0x41, 0x57, // pushq %r15
1897 0x41, 0x5f, // popq %r15
1898 0x90 // nop
1899 };
1900
1901 sample_range = AddressRange(0x1000, sizeof(data));
1902
1903 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1904 data, sizeof(data), sample_range, unwind_plan));
1905
1906 row = unwind_plan.GetRowForFunctionOffset(offset: 4);
1907 EXPECT_EQ(4, row->GetOffset());
1908 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1909 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1910 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1911 EXPECT_FALSE(row->GetRegisterInfo(k_r15, regloc));
1912}
1913
1914TEST_F(Testx86AssemblyInspectionEngine, TestPopEBX) {
1915 UnwindPlan::Row::AbstractRegisterLocation regloc;
1916 const UnwindPlan::Row *row;
1917 AddressRange sample_range;
1918 UnwindPlan unwind_plan(eRegisterKindLLDB);
1919 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1920
1921 uint8_t data[] = {
1922 0x53, // pushl %ebx
1923 0x5b, // popl %ebx
1924 0x90 // nop
1925 };
1926
1927 sample_range = AddressRange(0x1000, sizeof(data));
1928
1929 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1930 data, sizeof(data), sample_range, unwind_plan));
1931
1932 row = unwind_plan.GetRowForFunctionOffset(offset: 2);
1933 EXPECT_EQ(2, row->GetOffset());
1934 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1935 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1936 EXPECT_EQ(4, row->GetCFAValue().GetOffset());
1937 EXPECT_FALSE(row->GetRegisterInfo(k_ebx, regloc));
1938}
1939
1940TEST_F(Testx86AssemblyInspectionEngine, TestPopEBP) {
1941 UnwindPlan::Row::AbstractRegisterLocation regloc;
1942 const UnwindPlan::Row *row;
1943 AddressRange sample_range;
1944 UnwindPlan unwind_plan(eRegisterKindLLDB);
1945 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1946
1947 uint8_t data[] = {
1948 0x55, // pushl %ebp
1949 0x5d, // popl %ebp
1950 0x90 // nop
1951 };
1952
1953 sample_range = AddressRange(0x1000, sizeof(data));
1954
1955 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1956 data, sizeof(data), sample_range, unwind_plan));
1957
1958 row = unwind_plan.GetRowForFunctionOffset(offset: 2);
1959 EXPECT_EQ(2, row->GetOffset());
1960 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1961 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1962 EXPECT_EQ(4, row->GetCFAValue().GetOffset());
1963 EXPECT_FALSE(row->GetRegisterInfo(k_ebp, regloc));
1964}
1965
1966TEST_F(Testx86AssemblyInspectionEngine, TestPopRBPWithREX) {
1967 UnwindPlan::Row::AbstractRegisterLocation regloc;
1968 const UnwindPlan::Row *row;
1969 AddressRange sample_range;
1970 UnwindPlan unwind_plan(eRegisterKindLLDB);
1971 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
1972
1973 uint8_t data[] = {
1974 0x40, 0x55, // pushq %rbp
1975 0x40, 0x5d, // popq %rbp
1976 0x90 // nop
1977 };
1978
1979 sample_range = AddressRange(0x1000, sizeof(data));
1980
1981 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
1982 data, sizeof(data), sample_range, unwind_plan));
1983
1984 row = unwind_plan.GetRowForFunctionOffset(offset: 4);
1985 EXPECT_EQ(4, row->GetOffset());
1986 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
1987 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
1988 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
1989 EXPECT_FALSE(row->GetRegisterInfo(k_rbp, regloc));
1990}
1991
1992TEST_F(Testx86AssemblyInspectionEngine, TestPopESI) {
1993 UnwindPlan::Row::AbstractRegisterLocation regloc;
1994 const UnwindPlan::Row *row;
1995 AddressRange sample_range;
1996 UnwindPlan unwind_plan(eRegisterKindLLDB);
1997 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
1998
1999 uint8_t data[] = {
2000 0x56, // pushl %esi
2001 0x5e, // popl %esi
2002 0x90 // nop
2003 };
2004
2005 sample_range = AddressRange(0x1000, sizeof(data));
2006
2007 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
2008 data, sizeof(data), sample_range, unwind_plan));
2009
2010 row = unwind_plan.GetRowForFunctionOffset(offset: 2);
2011 EXPECT_EQ(2, row->GetOffset());
2012 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2013 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2014 EXPECT_EQ(4, row->GetCFAValue().GetOffset());
2015 EXPECT_FALSE(row->GetRegisterInfo(k_esi, regloc));
2016}
2017
2018TEST_F(Testx86AssemblyInspectionEngine, TestPopEDI) {
2019 UnwindPlan::Row::AbstractRegisterLocation regloc;
2020 const UnwindPlan::Row *row;
2021 AddressRange sample_range;
2022 UnwindPlan unwind_plan(eRegisterKindLLDB);
2023 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2024
2025 uint8_t data[] = {
2026 0x57, // pushl %edi
2027 0x5f, // popl %edi
2028 0x90 // nop
2029 };
2030
2031 sample_range = AddressRange(0x1000, sizeof(data));
2032
2033 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
2034 data, sizeof(data), sample_range, unwind_plan));
2035
2036 row = unwind_plan.GetRowForFunctionOffset(offset: 2);
2037 EXPECT_EQ(2, row->GetOffset());
2038 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2039 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2040 EXPECT_EQ(4, row->GetCFAValue().GetOffset());
2041 EXPECT_FALSE(row->GetRegisterInfo(k_edi, regloc));
2042}
2043
2044// We don't track these registers, but make sure the CFA address is updated
2045// if we're defining the CFA in term of esp.
2046TEST_F(Testx86AssemblyInspectionEngine, Testi386IgnoredRegisters) {
2047 UnwindPlan::Row::AbstractRegisterLocation regloc;
2048 const UnwindPlan::Row *row;
2049 AddressRange sample_range;
2050 UnwindPlan unwind_plan(eRegisterKindLLDB);
2051 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2052
2053 uint8_t data[] = {
2054 0x0e, // push cs
2055 0x16, // push ss
2056 0x1e, // push ds
2057 0x06, // push es
2058
2059 0x07, // pop es
2060 0x1f, // pop ds
2061 0x17, // pop ss
2062
2063 0x90 // nop
2064 };
2065
2066 sample_range = AddressRange(0x1000, sizeof(data));
2067
2068 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
2069 data, sizeof(data), sample_range, unwind_plan));
2070
2071 row = unwind_plan.GetRowForFunctionOffset(offset: 4);
2072 EXPECT_EQ(4, row->GetOffset());
2073 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2074 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2075 EXPECT_EQ(20, row->GetCFAValue().GetOffset());
2076
2077 row = unwind_plan.GetRowForFunctionOffset(offset: 7);
2078 EXPECT_EQ(7, row->GetOffset());
2079 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2080 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2081 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
2082}
2083
2084TEST_F(Testx86AssemblyInspectionEngine, TestLEAVE) {
2085 UnwindPlan::Row::AbstractRegisterLocation regloc;
2086 const UnwindPlan::Row *row;
2087 AddressRange sample_range;
2088 UnwindPlan unwind_plan(eRegisterKindLLDB);
2089 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2090 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2091
2092 uint8_t data[] = {
2093 0x55, // push %rbp/ebp
2094 0xc9, // leave
2095 0x90 // nop
2096 };
2097
2098 sample_range = AddressRange(0x1000, sizeof(data));
2099
2100 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2101 data, sizeof(data), sample_range, unwind_plan));
2102
2103 row = unwind_plan.GetRowForFunctionOffset(offset: 2);
2104 EXPECT_EQ(2, row->GetOffset());
2105 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2106 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2107 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
2108 EXPECT_FALSE(row->GetRegisterInfo(k_rbp, regloc));
2109
2110 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2111 data, sizeof(data), sample_range, unwind_plan));
2112
2113 row = unwind_plan.GetRowForFunctionOffset(offset: 2);
2114 EXPECT_EQ(2, row->GetOffset());
2115 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2116 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2117 EXPECT_EQ(4, row->GetCFAValue().GetOffset());
2118 EXPECT_FALSE(row->GetRegisterInfo(k_ebp, regloc));
2119}
2120
2121// In i386, which lacks pc-relative addressing, a common code sequence
2122// is to call the next instruction (i.e. call imm32, value of 0) which
2123// pushes the addr of the next insn on the stack, and then pop that value
2124// into a register (the "pic base" register).
2125TEST_F(Testx86AssemblyInspectionEngine, TestCALLNextInsn) {
2126 UnwindPlan::Row::AbstractRegisterLocation regloc;
2127 const UnwindPlan::Row *row;
2128 AddressRange sample_range;
2129 UnwindPlan unwind_plan(eRegisterKindLLDB);
2130 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2131
2132 uint8_t data[] = {
2133 0xe8, 0x00, 0x00, 0x00, 0x00, // call 0
2134 0x90 // nop
2135 };
2136
2137 sample_range = AddressRange(0x1000, sizeof(data));
2138
2139 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2140 data, sizeof(data), sample_range, unwind_plan));
2141
2142 row = unwind_plan.GetRowForFunctionOffset(offset: 5);
2143 EXPECT_EQ(5, row->GetOffset());
2144 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2145 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2146 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
2147 EXPECT_FALSE(row->GetRegisterInfo(k_ebp, regloc));
2148}
2149
2150TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVx86_64) {
2151 UnwindPlan::Row::AbstractRegisterLocation regloc;
2152 const UnwindPlan::Row *row;
2153 AddressRange sample_range;
2154 UnwindPlan unwind_plan(eRegisterKindLLDB);
2155 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2156
2157 uint8_t data[] = {
2158 0x55, // pushq %rbp
2159 0x48, 0x89, 0xe5, // movq %rsp, %rbp
2160 0x4c, 0x89, 0x75, 0xc0, // movq %r14, -0x40(%rbp)
2161 0x4c, 0x89, 0xbd, 0x28, 0xfa, 0xff, 0xff, // movq %r15, -0x5d8(%rbp)
2162 0x48, 0x89, 0x5d, 0xb8, // movq %rbx, -0x48(%rbp)
2163 0x90 // nop
2164 };
2165
2166 sample_range = AddressRange(0x1000, sizeof(data));
2167
2168 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2169 data, sizeof(data), sample_range, unwind_plan));
2170
2171 row = unwind_plan.GetRowForFunctionOffset(offset: 19);
2172 EXPECT_EQ(19, row->GetOffset());
2173 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);
2174 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
2175
2176 EXPECT_TRUE(row->GetRegisterInfo(k_r14, regloc));
2177 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2178 EXPECT_EQ(-80, regloc.GetOffset());
2179
2180 EXPECT_TRUE(row->GetRegisterInfo(k_r15, regloc));
2181 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2182 EXPECT_EQ(-1512, regloc.GetOffset());
2183
2184 EXPECT_TRUE(row->GetRegisterInfo(k_rbx, regloc));
2185 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2186 EXPECT_EQ(-88, regloc.GetOffset());
2187}
2188
2189TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVi386) {
2190 UnwindPlan::Row::AbstractRegisterLocation regloc;
2191 const UnwindPlan::Row *row;
2192 AddressRange sample_range;
2193 UnwindPlan unwind_plan(eRegisterKindLLDB);
2194 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2195
2196 uint8_t data[] = {
2197 0x55, // pushl %ebp
2198 0x89, 0xe5, // movl %esp, %ebp
2199 0x89, 0x9d, 0xb0, 0xfe, 0xff, 0xff, // movl %ebx, -0x150(%ebp)
2200 0x89, 0x75, 0xe0, // movl %esi, -0x20(%ebp)
2201 0x90 // nop
2202 };
2203
2204 sample_range = AddressRange(0x1000, sizeof(data));
2205
2206 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2207 data, sizeof(data), sample_range, unwind_plan));
2208
2209 row = unwind_plan.GetRowForFunctionOffset(offset: 12);
2210 EXPECT_EQ(12, row->GetOffset());
2211 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);
2212 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
2213
2214 EXPECT_TRUE(row->GetRegisterInfo(k_ebx, regloc));
2215 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2216 EXPECT_EQ(-344, regloc.GetOffset());
2217
2218 EXPECT_TRUE(row->GetRegisterInfo(k_esi, regloc));
2219 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2220 EXPECT_EQ(-40, regloc.GetOffset());
2221}
2222
2223TEST_F(Testx86AssemblyInspectionEngine, TestSpArithx86_64Augmented) {
2224 UnwindPlan::Row::AbstractRegisterLocation regloc;
2225 AddressRange sample_range;
2226 UnwindPlan unwind_plan(eRegisterKindLLDB);
2227 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2228
2229 uint8_t data[] = {
2230 0x55, // pushq %rbp
2231 0x48, 0x89, 0xe5, // movq %rsp, %rbp
2232
2233 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2234 // has a bug where it can't augment a function that is just
2235 // prologue+epilogue - it needs at least one other instruction
2236 // in between.
2237
2238 0x90, // nop
2239 0x48, 0x81, 0xec, 0x88, 0, 0, 0, // subq $0x88, %rsp
2240 0x90, // nop
2241 0x48, 0x81, 0xc4, 0x88, 0, 0, 0, // addq $0x88, %rsp
2242
2243 0x5d, // popq %rbp
2244 0xc3 // retq
2245 };
2246
2247 sample_range = AddressRange(0x1000, sizeof(data));
2248
2249 unwind_plan.SetSourceName("unit testing hand-created unwind plan");
2250 unwind_plan.SetPlanValidAddressRanges({sample_range});
2251 unwind_plan.SetRegisterKind(eRegisterKindLLDB);
2252
2253 {
2254 UnwindPlan::Row row;
2255
2256 // Describe offset 0
2257 row.SetOffset(0);
2258 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_rsp, offset: 8);
2259 regloc.SetAtCFAPlusOffset(-8);
2260 row.SetRegisterInfo(reg_num: k_rip, register_location: regloc);
2261 unwind_plan.AppendRow(row);
2262
2263 // Describe offset 1
2264 row.SetOffset(1);
2265 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_rsp, offset: 16);
2266 regloc.SetAtCFAPlusOffset(-16);
2267 row.SetRegisterInfo(reg_num: k_rbp, register_location: regloc);
2268 unwind_plan.AppendRow(row);
2269
2270 // Describe offset 4
2271 row.SetOffset(4);
2272 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_rsp, offset: 16);
2273 unwind_plan.AppendRow(row);
2274 }
2275
2276 RegisterContextSP reg_ctx_sp;
2277 EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite(
2278 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
2279
2280 // Before we touch the stack pointer, we should still refer to the
2281 // row from after the prologue.
2282 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(offset: 5);
2283 EXPECT_EQ(4, row->GetOffset());
2284
2285 // Check the first stack pointer update.
2286 row = unwind_plan.GetRowForFunctionOffset(offset: 12);
2287 EXPECT_EQ(12, row->GetOffset());
2288 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2289 EXPECT_EQ(152, row->GetCFAValue().GetOffset());
2290
2291 // After the nop, we should still refer to the same row.
2292 row = unwind_plan.GetRowForFunctionOffset(offset: 13);
2293 EXPECT_EQ(12, row->GetOffset());
2294
2295 // Check that the second stack pointer update is reflected in the
2296 // unwind plan.
2297 row = unwind_plan.GetRowForFunctionOffset(offset: 20);
2298 EXPECT_EQ(20, row->GetOffset());
2299 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2300 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
2301}
2302
2303TEST_F(Testx86AssemblyInspectionEngine, TestSimplex86_64Augmented) {
2304 UnwindPlan::Row::AbstractRegisterLocation regloc;
2305 AddressRange sample_range;
2306 UnwindPlan unwind_plan(eRegisterKindLLDB);
2307 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2308
2309 uint8_t data[] = {
2310 0x55, // pushq %rbp
2311 0x48, 0x89, 0xe5, // movq %rsp, %rbp
2312
2313 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2314 // has a bug where it can't augment a function that is just
2315 // prologue+epilogue - it needs at least one other instruction
2316 // in between.
2317 0x90, // nop
2318
2319 0x5d, // popq %rbp
2320 0xc3 // retq
2321 };
2322
2323 sample_range = AddressRange(0x1000, sizeof(data));
2324
2325 unwind_plan.SetSourceName("unit testing hand-created unwind plan");
2326 unwind_plan.SetPlanValidAddressRanges({sample_range});
2327 unwind_plan.SetRegisterKind(eRegisterKindLLDB);
2328
2329 {
2330 UnwindPlan::Row row;
2331
2332 // Describe offset 0
2333 row.SetOffset(0);
2334 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_rsp, offset: 8);
2335 regloc.SetAtCFAPlusOffset(-8);
2336 row.SetRegisterInfo(reg_num: k_rip, register_location: regloc);
2337 unwind_plan.AppendRow(row);
2338
2339 // Describe offset 1
2340 row.SetOffset(1);
2341 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_rsp, offset: 16);
2342 regloc.SetAtCFAPlusOffset(-16);
2343 row.SetRegisterInfo(reg_num: k_rbp, register_location: regloc);
2344 unwind_plan.AppendRow(row);
2345
2346 // Describe offset 4
2347 row.SetOffset(4);
2348 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_rbp, offset: 16);
2349 unwind_plan.AppendRow(row);
2350 }
2351
2352 RegisterContextSP reg_ctx_sp;
2353 EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite(
2354 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
2355
2356 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(offset: 6);
2357 EXPECT_EQ(6, row->GetOffset());
2358 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2359 EXPECT_EQ(8, row->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->GetRegisterInfo(k_rbp, regloc));
2368}
2369
2370TEST_F(Testx86AssemblyInspectionEngine, TestSimplei386ugmented) {
2371 UnwindPlan::Row::AbstractRegisterLocation regloc;
2372 AddressRange sample_range;
2373 UnwindPlan unwind_plan(eRegisterKindLLDB);
2374 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2375
2376 uint8_t data[] = {
2377 0x55, // pushl %ebp
2378 0x89, 0xe5, // movl %esp, %ebp
2379
2380 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2381 // has a bug where it can't augment a function that is just
2382 // prologue+epilogue - it needs at least one other instruction
2383 // in between.
2384 0x90, // nop
2385
2386 0x5d, // popl %ebp
2387 0xc3 // retl
2388 };
2389
2390 sample_range = AddressRange(0x1000, sizeof(data));
2391
2392 unwind_plan.SetSourceName("unit testing hand-created unwind plan");
2393 unwind_plan.SetPlanValidAddressRanges({sample_range});
2394 unwind_plan.SetRegisterKind(eRegisterKindLLDB);
2395
2396 {
2397 UnwindPlan::Row row;
2398
2399 // Describe offset 0
2400 row.SetOffset(0);
2401 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_esp, offset: 4);
2402 regloc.SetAtCFAPlusOffset(-4);
2403 row.SetRegisterInfo(reg_num: k_eip, register_location: regloc);
2404 unwind_plan.AppendRow(row);
2405
2406 // Describe offset 1
2407 row.SetOffset(1);
2408 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_esp, offset: 8);
2409 regloc.SetAtCFAPlusOffset(-8);
2410 row.SetRegisterInfo(reg_num: k_ebp, register_location: regloc);
2411 unwind_plan.AppendRow(row);
2412
2413 // Describe offset 3
2414 row.SetOffset(3);
2415 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: k_ebp, offset: 8);
2416 unwind_plan.AppendRow(row);
2417 }
2418
2419 RegisterContextSP reg_ctx_sp;
2420 EXPECT_TRUE(engine32->AugmentUnwindPlanFromCallSite(
2421 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
2422
2423 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(offset: 5);
2424 EXPECT_EQ(5, row->GetOffset());
2425 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
2426 EXPECT_EQ(4, row->GetCFAValue().GetOffset());
2427
2428 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
2429 // doesn't track register restores (pop'ing a reg value back from
2430 // the stack) - it was just written to make stepping work correctly.
2431 // Technically we should be able to do the following test, but it
2432 // won't work today - the unwind plan will still say that the caller's
2433 // ebp is on the stack.
2434 // EXPECT_FALSE(row->GetRegisterInfo(k_ebp, regloc));
2435}
2436
2437// Check that the i386 disassembler disassembles past an opcode that
2438// is only valid in 32-bit mode (non-long mode), and the x86_64 disassembler
2439// stops
2440// disassembling at that point (long-mode).
2441TEST_F(Testx86AssemblyInspectionEngine, Test32BitOnlyInstruction) {
2442 UnwindPlan::Row::AbstractRegisterLocation regloc;
2443 const UnwindPlan::Row *row;
2444 AddressRange sample_range;
2445 UnwindPlan unwind_plan(eRegisterKindLLDB);
2446 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2447 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2448
2449 uint8_t data[] = {
2450 0x43, // incl $ebx --- an invalid opcode in 64-bit mode
2451 0x55, // pushl %ebp
2452 0x90 // nop
2453 };
2454
2455 sample_range = AddressRange(0x1000, sizeof(data));
2456
2457 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2458 data, sizeof(data), sample_range, unwind_plan));
2459
2460 row = unwind_plan.GetRowForFunctionOffset(offset: 2);
2461 EXPECT_EQ(2, row->GetOffset());
2462 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
2463 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2464 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
2465
2466 EXPECT_TRUE(row->GetRegisterInfo(k_ebp, regloc));
2467 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2468 EXPECT_EQ(-8, regloc.GetOffset());
2469
2470 unwind_plan.Clear();
2471
2472 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2473 data, sizeof(data), sample_range, unwind_plan));
2474
2475 row = unwind_plan.GetRowForFunctionOffset(offset: 2);
2476 EXPECT_EQ(0, row->GetOffset());
2477 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2478 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2479 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
2480
2481 EXPECT_FALSE(row->GetRegisterInfo(k_rbp, regloc));
2482}
2483
2484TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign8BitDisp_i386) {
2485 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2486
2487 uint8_t data[] = {
2488 0x55, // pushl %ebp
2489 0x89, 0xe5, // movl %esp, %ebp
2490 0x53, // pushl %ebx
2491 0x83, 0xe4, 0xf0, // andl $-16, %esp
2492 0x83, 0xec, 0x10, // subl $16, %esp
2493 0x8d, 0x65, 0xfc, // leal -4(%ebp), %esp
2494 0x5b, // popl %ebx
2495 0x5d, // popl %ebp
2496 0xc3, // retl
2497 };
2498
2499 AddressRange sample_range(0x1000, sizeof(data));
2500 UnwindPlan plan(eRegisterKindLLDB);
2501 ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
2502 sample_range, plan));
2503
2504 UnwindPlan::Row::FAValue esp_plus_4, esp_plus_8, ebp_plus_8;
2505 esp_plus_4.SetIsRegisterPlusOffset(reg_num: k_esp, offset: 4);
2506 esp_plus_8.SetIsRegisterPlusOffset(reg_num: k_esp, offset: 8);
2507 ebp_plus_8.SetIsRegisterPlusOffset(reg_num: k_ebp, offset: 8);
2508
2509 EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue());
2510 EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue());
2511 for (size_t i = 3; i < sizeof(data) - 2; ++i)
2512 EXPECT_EQ(ebp_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue())
2513 << "i: " << i;
2514 EXPECT_EQ(esp_plus_4,
2515 plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());
2516}
2517
2518TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign32BitDisp_x86_64) {
2519 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
2520
2521 uint8_t data[] = {
2522 0x55, // pushq %rbp
2523 0x48, 0x89, 0xe5, // movq %rsp, %rbp
2524 0x53, // pushl %rbx
2525 0x48, 0x83, 0xe4, 0xf0, // andq $-16, %rsp
2526 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $256, %rsp
2527 0x48, 0x8d, 0x65, 0xf8, // leaq -8(%rbp), %rsp
2528 0x5b, // popq %rbx
2529 0x5d, // popq %rbp
2530 0xc3, // retq
2531 };
2532
2533 AddressRange sample_range(0x1000, sizeof(data));
2534 UnwindPlan plan(eRegisterKindLLDB);
2535 ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
2536 sample_range, plan));
2537
2538 UnwindPlan::Row::FAValue rsp_plus_8, rsp_plus_16, rbp_plus_16;
2539 rsp_plus_8.SetIsRegisterPlusOffset(reg_num: k_rsp, offset: 8);
2540 rsp_plus_16.SetIsRegisterPlusOffset(reg_num: k_rsp, offset: 16);
2541 rbp_plus_16.SetIsRegisterPlusOffset(reg_num: k_rbp, offset: 16);
2542
2543 EXPECT_EQ(rsp_plus_8, plan.GetRowForFunctionOffset(0)->GetCFAValue());
2544 EXPECT_EQ(rsp_plus_16, plan.GetRowForFunctionOffset(1)->GetCFAValue());
2545 for (size_t i = 4; i < sizeof(data) - 2; ++i)
2546 EXPECT_EQ(rbp_plus_16, plan.GetRowForFunctionOffset(i)->GetCFAValue())
2547 << "i: " << i;
2548 EXPECT_EQ(rsp_plus_8,
2549 plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());
2550}
2551
2552TEST_F(Testx86AssemblyInspectionEngine, TestStackRealignMSVC_i386) {
2553 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
2554
2555 uint8_t data[] = {
2556 0x53, // offset 00 -- pushl %ebx
2557 0x8b, 0xdc, // offset 01 -- movl %esp, %ebx
2558 0x83, 0xec, 0x08, // offset 03 -- subl $8, %esp
2559 0x81, 0xe4, 0x00, 0xff, 0xff, 0xff, // offset 06 -- andl $-256, %esp
2560 0x83, 0xc4, 0x04, // offset 12 -- addl $4, %esp
2561 0x55, // offset 15 -- pushl %ebp
2562 0x8b, 0xec, // offset 16 -- movl %esp, %ebp
2563 0x81, 0xec, 0x00, 0x02, 0x00, 0x00, // offset 18 -- subl $512, %esp
2564 0x89, 0x7d, 0xfc, // offset 24 -- movl %edi, -4(%ebp)
2565 0x8b, 0xe5, // offset 27 -- movl %ebp, %esp
2566 0x5d, // offset 29 -- popl %ebp
2567 0x8b, 0xe3, // offset 30 -- movl %ebx, %esp
2568 0x5b, // offset 32 -- popl %ebx
2569 0xc3 // offset 33 -- retl
2570 };
2571
2572 AddressRange sample_range(0x1000, sizeof(data));
2573 UnwindPlan plan(eRegisterKindLLDB);
2574 ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
2575 sample_range, plan));
2576
2577 UnwindPlan::Row::FAValue esp_minus_4, esp_plus_0, esp_plus_4, esp_plus_8,
2578 ebx_plus_8, ebp_plus_0;
2579 esp_minus_4.SetIsRegisterPlusOffset(reg_num: k_esp, offset: -4);
2580 esp_plus_0.SetIsRegisterPlusOffset(reg_num: k_esp, offset: 0);
2581 esp_plus_4.SetIsRegisterPlusOffset(reg_num: k_esp, offset: 4);
2582 esp_plus_8.SetIsRegisterPlusOffset(reg_num: k_esp, offset: 8);
2583 ebx_plus_8.SetIsRegisterPlusOffset(reg_num: k_ebx, offset: 8);
2584 ebp_plus_0.SetIsRegisterPlusOffset(reg_num: k_ebp, offset: 0);
2585
2586 // Test CFA
2587 EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue());
2588 EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue());
2589 for (size_t i = 3; i < 33; ++i)
2590 EXPECT_EQ(ebx_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue())
2591 << "i: " << i;
2592 EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(33)->GetCFAValue());
2593
2594 // Test AFA
2595 EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(12)->GetAFAValue());
2596 EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(15)->GetAFAValue());
2597 EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(16)->GetAFAValue());
2598 for (size_t i = 18; i < 30; ++i)
2599 EXPECT_EQ(ebp_plus_0, plan.GetRowForFunctionOffset(i)->GetAFAValue())
2600 << "i: " << i;
2601 EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(30)->GetAFAValue());
2602
2603 // Test saved register
2604 UnwindPlan::Row::AbstractRegisterLocation reg_loc;
2605 EXPECT_TRUE(
2606 plan.GetRowForFunctionOffset(27)->GetRegisterInfo(k_edi, reg_loc));
2607 EXPECT_TRUE(reg_loc.IsAtAFAPlusOffset());
2608 EXPECT_EQ(-4, reg_loc.GetOffset());
2609}
2610
2611// Give the disassembler random bytes to test that it doesn't exceed
2612// the bounds of the array when run under clang's address sanitizer.
2613TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyJunkBytes) {
2614 AddressRange sample_range;
2615 UnwindPlan unwind_plan(eRegisterKindLLDB);
2616 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2617 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2618
2619 uint8_t data[] = {
2620 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
2621 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
2622
2623 sample_range = AddressRange(0x1000, sizeof(data));
2624
2625 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2626 data, sizeof(data), sample_range, unwind_plan));
2627
2628 unwind_plan.Clear();
2629
2630 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2631 data, sizeof(data), sample_range, unwind_plan));
2632
2633}
2634
2635TEST_F(Testx86AssemblyInspectionEngine, TestReturnDetect) {
2636 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
2637
2638 // Single fragment with all four return forms.
2639 // We want to verify that the unwind state is reset after each ret.
2640 uint8_t data[] = {
2641 0x55, // offset 0 -- pushq %rbp
2642 0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp
2643 0x31, 0xc0, // offset 4 -- xorl %eax, %eax
2644 0x5d, // offset 6 -- popq %rbp
2645 0xc3, // offset 7 -- retq
2646 0x31, 0xc0, // offset 8 -- xorl %eax, %eax
2647 0x5d, // offset 10 -- popq %rbp
2648 0xcb, // offset 11 -- retf
2649 0x31, 0xc0, // offset 12 -- xorl %eax, %eax
2650 0x5d, // offset 14 -- popq %rbp
2651 0xc2, 0x22, 0x11, // offset 15 -- retq 0x1122
2652 0x31, 0xc0, // offset 18 -- xorl %eax, %eax
2653 0x5d, // offset 20 -- popq %rbp
2654 0xca, 0x44, 0x33, // offset 21 -- retf 0x3344
2655 0x31, 0xc0, // offset 24 -- xorl %eax, %eax
2656 };
2657
2658 AddressRange sample_range(0x1000, sizeof(data));
2659
2660 UnwindPlan unwind_plan(eRegisterKindLLDB);
2661 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
2662 data, sizeof(data), sample_range, unwind_plan));
2663
2664 // Expect following unwind rows:
2665 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2666 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2667 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2668 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2669 // 8: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2670 // 11: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2671 // 12: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2672 // 15: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2673 // 18: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2674 // 21: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2675 // 24: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2676
2677 EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp);
2678 EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
2679 eLazyBoolYes);
2680 EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
2681
2682 UnwindPlan::Row::AbstractRegisterLocation regloc;
2683
2684 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2685 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(offset: 0);
2686 EXPECT_EQ(0, row->GetOffset());
2687 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2688 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2689 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
2690
2691 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));
2692 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2693 EXPECT_EQ(-8, regloc.GetOffset());
2694
2695 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2696 row = unwind_plan.GetRowForFunctionOffset(offset: 1);
2697 EXPECT_EQ(1, row->GetOffset());
2698 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2699 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2700 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
2701
2702 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));
2703 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2704 EXPECT_EQ(-8, regloc.GetOffset());
2705
2706 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2707 row = unwind_plan.GetRowForFunctionOffset(offset: 4);
2708 EXPECT_EQ(4, row->GetOffset());
2709 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);
2710 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2711 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
2712
2713 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));
2714 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2715 EXPECT_EQ(-8, regloc.GetOffset());
2716
2717 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2718 row = unwind_plan.GetRowForFunctionOffset(offset: 7);
2719 EXPECT_EQ(7, row->GetOffset());
2720 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2721 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2722 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
2723
2724 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));
2725 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2726 EXPECT_EQ(-8, regloc.GetOffset());
2727
2728 // 8: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2729 row = unwind_plan.GetRowForFunctionOffset(offset: 8);
2730 EXPECT_EQ(8, row->GetOffset());
2731 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);
2732 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2733 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
2734
2735 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));
2736 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2737 EXPECT_EQ(-8, regloc.GetOffset());
2738
2739 // 11: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2740 row = unwind_plan.GetRowForFunctionOffset(offset: 11);
2741 EXPECT_EQ(11, row->GetOffset());
2742 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2743 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2744 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
2745
2746 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));
2747 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2748 EXPECT_EQ(-8, regloc.GetOffset());
2749
2750 // 12: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2751 row = unwind_plan.GetRowForFunctionOffset(offset: 12);
2752 EXPECT_EQ(12, row->GetOffset());
2753 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);
2754 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2755 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
2756
2757 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));
2758 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2759 EXPECT_EQ(-8, regloc.GetOffset());
2760
2761 // 15: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2762 row = unwind_plan.GetRowForFunctionOffset(offset: 15);
2763 EXPECT_EQ(15, row->GetOffset());
2764 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2765 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2766 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
2767
2768 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));
2769 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2770 EXPECT_EQ(-8, regloc.GetOffset());
2771
2772 // 18: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2773 row = unwind_plan.GetRowForFunctionOffset(offset: 18);
2774 EXPECT_EQ(18, row->GetOffset());
2775 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);
2776 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2777 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
2778
2779 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));
2780 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2781 EXPECT_EQ(-8, regloc.GetOffset());
2782
2783 // 21: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2784 row = unwind_plan.GetRowForFunctionOffset(offset: 21);
2785 EXPECT_EQ(21, row->GetOffset());
2786 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2787 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2788 EXPECT_EQ(8, row->GetCFAValue().GetOffset());
2789
2790 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));
2791 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2792 EXPECT_EQ(-8, regloc.GetOffset());
2793
2794 // 24: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
2795 row = unwind_plan.GetRowForFunctionOffset(offset: 24);
2796 EXPECT_EQ(24, row->GetOffset());
2797 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);
2798 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2799 EXPECT_EQ(16, row->GetCFAValue().GetOffset());
2800
2801 EXPECT_TRUE(row->GetRegisterInfo(k_rip, regloc));
2802 EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
2803 EXPECT_EQ(-8, regloc.GetOffset());
2804}
2805
2806
2807// Test mid-function epilogues - the unwind state post-prologue
2808// should be re-instated.
2809
2810TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyMidFunctionEpilogues) {
2811 AddressRange sample_range;
2812 UnwindPlan unwind_plan(eRegisterKindLLDB);
2813 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
2814 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
2815
2816 uint8_t data[] = {
2817 0x55, // <+0>: pushq %rbp
2818 0x48, 0x89, 0xe5, // <+1>: movq %rsp, %rbp
2819 0x48, 0x83, 0xec, 0x70, // <+4>: subq $0x70, %rsp
2820 0x90, // <+8>: nop // prologue set up
2821
2822 0x74, 0x7, // <+9>: je 7 <+18>
2823 0x48, 0x83, 0xc4, 0x70, // <+11>: addq $0x70, %rsp
2824 0x5d, // <+15>: popq %rbp
2825 0xff, 0xe0, // <+16>: jmpq *%rax // epilogue completed
2826
2827 0x90, // <+18>: nop // prologue setup back
2828
2829 0x74, 0x8, // <+19>: je 7 <+28>
2830 0x48, 0x83, 0xc4, 0x70, // <+21>: addq $0x70, %rsp
2831 0x5d, // <+25>: popq %rbp
2832 0x90, // <+26>: nop // mid-epilogue non-epilogue
2833 0xc3, // <+27>: retq // epilogue completed
2834
2835 0x90, // <+28>: nop // prologue setup back
2836
2837 0x48, 0x83, 0xc4, 0x70, // <+29>: addq $0x70, %rsp
2838 0x5d, // <+33>: popq %rbp
2839 0xc3, // <+34>: retq // epilogue completed
2840
2841 };
2842
2843 sample_range = AddressRange(0x1000, sizeof(data));
2844
2845 int wordsize = 4;
2846 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
2847 data, sizeof(data), sample_range, unwind_plan));
2848
2849 // Check that we've unwound the stack after the first mid-function epilogue
2850 // row: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
2851 const UnwindPlan::Row *row = unwind_plan.GetRowForFunctionOffset(offset: 16);
2852 EXPECT_EQ(16, row->GetOffset());
2853 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
2854 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2855 EXPECT_EQ(wordsize, row->GetCFAValue().GetOffset());
2856
2857 // Check that we've reinstated the stack frame setup
2858 // unwind instructions after a jmpq *%eax
2859 // row: CFA=ebp +8 => esp=CFA+0 eip=[CFA-8]
2860 row = unwind_plan.GetRowForFunctionOffset(offset: 18);
2861 EXPECT_EQ(18, row->GetOffset());
2862 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_ebp);
2863 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2864 EXPECT_EQ(wordsize * 2, row->GetCFAValue().GetOffset());
2865
2866 // Check that we've reinstated the stack frame setup
2867 // unwind instructions after a mid-function retq
2868 // row: CFA=ebp +8 => esp=CFA+0 eip=[CFA-8]
2869 row = unwind_plan.GetRowForFunctionOffset(offset: 28);
2870 EXPECT_EQ(28, row->GetOffset());
2871 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_ebp);
2872 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2873 EXPECT_EQ(wordsize * 2, row->GetCFAValue().GetOffset());
2874
2875 // After last instruction in the function, verify that
2876 // the stack frame has been unwound
2877 // row: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
2878 row = unwind_plan.GetRowForFunctionOffset(offset: 34);
2879 EXPECT_EQ(34, row->GetOffset());
2880 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_esp);
2881 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2882 EXPECT_EQ(wordsize, row->GetCFAValue().GetOffset());
2883
2884 unwind_plan.Clear();
2885
2886 wordsize = 8;
2887 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
2888 data, sizeof(data), sample_range, unwind_plan));
2889
2890 // Check that we've unwound the stack after the first mid-function epilogue
2891 // row: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
2892 row = unwind_plan.GetRowForFunctionOffset(offset: 16);
2893 EXPECT_EQ(16, row->GetOffset());
2894 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2895 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2896 EXPECT_EQ(wordsize, row->GetCFAValue().GetOffset());
2897
2898 // Check that we've reinstated the stack frame setup
2899 // unwind instructions after a jmpq *%eax
2900 // row: CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16]
2901 row = unwind_plan.GetRowForFunctionOffset(offset: 18);
2902 EXPECT_EQ(18, row->GetOffset());
2903 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);
2904 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2905 EXPECT_EQ(wordsize * 2, row->GetCFAValue().GetOffset());
2906
2907 // Check that we've reinstated the stack frame setup
2908 // unwind instructions after a mid-function retq
2909 // row: CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16]
2910 row = unwind_plan.GetRowForFunctionOffset(offset: 28);
2911 EXPECT_EQ(28, row->GetOffset());
2912 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rbp);
2913 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2914 EXPECT_EQ(wordsize * 2, row->GetCFAValue().GetOffset());
2915
2916 // After last instruction in the function, verify that
2917 // the stack frame has been unwound
2918 // row: CFA=rsp +8 => esp=CFA+0 rip=[CFA-8]
2919 row = unwind_plan.GetRowForFunctionOffset(offset: 34);
2920 EXPECT_EQ(34, row->GetOffset());
2921 EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == k_rsp);
2922 EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
2923 EXPECT_EQ(wordsize, row->GetCFAValue().GetOffset());
2924}
2925

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