xref: /llvm-project/lldb/unittests/Disassembler/x86/TestGetControlFlowKindx86.cpp (revision f109517d153609d4a8a3a3d3d3cc06da1b629364)
1 //===-- TestX86GetControlFlowKind.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 "llvm/Support/TargetSelect.h"
11 #include "gtest/gtest.h"
12 
13 #include "lldb/Core/Address.h"
14 #include "lldb/Core/Disassembler.h"
15 #include "lldb/Target/ExecutionContext.h"
16 #include "lldb/Utility/ArchSpec.h"
17 
18 #include "Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h"
19 
20 using namespace lldb;
21 using namespace lldb_private;
22 
23 namespace {
24 class TestGetControlFlowKindx86 : public testing::Test {
25 public:
26   static void SetUpTestCase();
27   static void TearDownTestCase();
28 
29 protected:
30 };
31 
32 void TestGetControlFlowKindx86::SetUpTestCase() {
33   llvm::InitializeAllTargets();
34   llvm::InitializeAllAsmPrinters();
35   llvm::InitializeAllTargetMCs();
36   llvm::InitializeAllDisassemblers();
37   DisassemblerLLVMC::Initialize();
38 }
39 
40 void TestGetControlFlowKindx86::TearDownTestCase() {
41   DisassemblerLLVMC::Terminate();
42 }
43 } // namespace
44 
45 TEST_F(TestGetControlFlowKindx86, TestX86_64Instruction) {
46   ArchSpec arch("x86_64-*-linux");
47 
48   const unsigned num_of_instructions = 29;
49   uint8_t data[] = {
50       0x55,                               // other -- pushq %rbp
51       0x48, 0x89, 0xe5,                   // other -- movq %rsp, %rbp
52 
53       0xe8, 0xfc, 0xfe, 0xff, 0xff,       // call -- callq 0x4004c0
54       0x41, 0xff, 0x14, 0xdc,             // call -- callq *(%r12,%rbx,8)
55       0xff, 0x50, 0x18,                   // call -- callq *0x18(%rax)
56       0xe8, 0x48, 0x0d, 0x00, 0x00,       // call -- callq 0x94fe0
57 
58       0xc3,                               // return -- retq
59 
60       0xeb, 0xd3,                         // jump -- jmp 0x92dab
61       0xe9, 0x22, 0xff, 0xff, 0xff,       // jump -- jmp 0x933ae
62       0xff, 0xe0,                         // jump -- jmpq *%rax
63       0xf2, 0xff, 0x25, 0x75, 0xe7, 0x39, 0x00, // jump -- repne jmpq *0x39e775
64 
65       0x73, 0xc2,                         // cond jump -- jae 0x9515c
66       0x74, 0x1f,                         // cond jump -- je 0x400626
67       0x75, 0xea,                         // cond jump -- jne 0x400610
68       0x76, 0x10,                         // cond jump -- jbe 0x94d10
69       0x77, 0x58,                         // cond jump -- ja 0x1208c8
70       0x7e, 0x67,                         // cond jump -- jle 0x92180
71       0x78, 0x0b,                         // cond jump -- js 0x92dc3
72       0x0f, 0x82, 0x17, 0x01, 0x00, 0x00, // cond jump -- jb 0x9c7b0
73       0x0f, 0x83, 0xa7, 0x00, 0x00, 0x00, // cond jump -- jae 0x895c8
74       0x0f, 0x84, 0x8c, 0x00, 0x00, 0x00, // cond jump -- je 0x941f0
75       0x0f, 0x85, 0x51, 0xff, 0xff, 0xff, // cond jump -- jne 0x8952c
76       0x0f, 0x86, 0xa3, 0x02, 0x00, 0x00, // cond jump -- jbe 0x9ae10
77       0x0f, 0x87, 0xff, 0x00, 0x00, 0x00, // cond jump -- ja 0x9ab60
78       0x0f, 0x8e, 0x7e, 0x00, 0x00, 0x00, // cond jump -- jle 0x92dd8
79       0x0f, 0x86, 0xdf, 0x00, 0x00, 0x00, // cond jump -- jbe 0x921b0
80 
81       0x0f, 0x05,                         // far call -- syscall
82 
83       0x0f, 0x07,                         // far return -- sysret
84       0xcf,                               // far return -- interrupt ret
85   };
86 
87   InstructionControlFlowKind result[] = {
88       eInstructionControlFlowKindOther,
89       eInstructionControlFlowKindOther,
90 
91       eInstructionControlFlowKindCall,
92       eInstructionControlFlowKindCall,
93       eInstructionControlFlowKindCall,
94       eInstructionControlFlowKindCall,
95 
96       eInstructionControlFlowKindReturn,
97 
98       eInstructionControlFlowKindJump,
99       eInstructionControlFlowKindJump,
100       eInstructionControlFlowKindJump,
101       eInstructionControlFlowKindJump,
102 
103       eInstructionControlFlowKindCondJump,
104       eInstructionControlFlowKindCondJump,
105       eInstructionControlFlowKindCondJump,
106       eInstructionControlFlowKindCondJump,
107       eInstructionControlFlowKindCondJump,
108       eInstructionControlFlowKindCondJump,
109       eInstructionControlFlowKindCondJump,
110       eInstructionControlFlowKindCondJump,
111       eInstructionControlFlowKindCondJump,
112       eInstructionControlFlowKindCondJump,
113       eInstructionControlFlowKindCondJump,
114       eInstructionControlFlowKindCondJump,
115       eInstructionControlFlowKindCondJump,
116       eInstructionControlFlowKindCondJump,
117       eInstructionControlFlowKindCondJump,
118 
119       eInstructionControlFlowKindFarCall,
120 
121       eInstructionControlFlowKindFarReturn,
122       eInstructionControlFlowKindFarReturn,
123   };
124 
125   DisassemblerSP disass_sp;
126   Address start_addr(0x100);
127   disass_sp = Disassembler::DisassembleBytes(
128       arch, nullptr, nullptr, nullptr, nullptr, start_addr, &data, sizeof(data),
129       num_of_instructions, false);
130 
131   // If we failed to get a disassembler, we can assume it is because
132   // the llvm we linked against was not built with the i386 target,
133   // and we should skip these tests without marking anything as failing.
134   if (!disass_sp)
135     return;
136 
137   const InstructionList inst_list(disass_sp->GetInstructionList());
138   EXPECT_EQ(num_of_instructions, inst_list.GetSize());
139 
140   for (size_t i = 0; i < num_of_instructions; ++i) {
141     InstructionSP inst_sp;
142     inst_sp = inst_list.GetInstructionAtIndex(i);
143     ExecutionContext exe_ctx(nullptr, nullptr, nullptr);
144     InstructionControlFlowKind kind = inst_sp->GetControlFlowKind(&exe_ctx);
145     EXPECT_EQ(kind, result[i]);
146 
147     // Also, test the DisassemblerLLVMC::MCDisasmInstance methods.
148     if (kind == eInstructionControlFlowKindReturn) {
149       EXPECT_FALSE(inst_sp->IsCall());
150     }
151 
152     if (kind == eInstructionControlFlowKindCall) {
153       EXPECT_TRUE(inst_sp->IsCall());
154     }
155 
156     if (kind == eInstructionControlFlowKindCall ||
157         kind == eInstructionControlFlowKindJump ||
158         kind == eInstructionControlFlowKindCondJump ||
159         kind == eInstructionControlFlowKindReturn) {
160       EXPECT_TRUE(inst_sp->DoesBranch());
161     }
162   }
163 }
164