aboutsummaryrefslogtreecommitdiff
path: root/lldb/unittests/Disassembler/x86/TestGetControlFlowKindx86.cpp
blob: 4b62e5f747529cb4742e6ddb69a8c710e17072ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//===-- TestX86GetControlFlowKind.cpp -------------------------------------===//

//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/TargetSelect.h"
#include "gtest/gtest.h"

#include "lldb/Core/Address.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Utility/ArchSpec.h"

#include "Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h"

using namespace lldb;
using namespace lldb_private;

namespace {
class TestGetControlFlowKindx86 : public testing::Test {
public:
  static void SetUpTestCase();
  static void TearDownTestCase();

protected:
};

void TestGetControlFlowKindx86::SetUpTestCase() {
  llvm::InitializeAllTargets();
  llvm::InitializeAllAsmPrinters();
  llvm::InitializeAllTargetMCs();
  llvm::InitializeAllDisassemblers();
  DisassemblerLLVMC::Initialize();
}

void TestGetControlFlowKindx86::TearDownTestCase() {
  DisassemblerLLVMC::Terminate();
}
} // namespace

TEST_F(TestGetControlFlowKindx86, TestX86_64Instruction) {
  ArchSpec arch("x86_64-*-linux");

  const unsigned num_of_instructions = 29;
  uint8_t data[] = {
      0x55,                               // other -- pushq %rbp
      0x48, 0x89, 0xe5,                   // other -- movq %rsp, %rbp

      0xe8, 0xfc, 0xfe, 0xff, 0xff,       // call -- callq 0x4004c0
      0x41, 0xff, 0x14, 0xdc,             // call -- callq *(%r12,%rbx,8)
      0xff, 0x50, 0x18,                   // call -- callq *0x18(%rax)
      0xe8, 0x48, 0x0d, 0x00, 0x00,       // call -- callq 0x94fe0

      0xc3,                               // return -- retq

      0xeb, 0xd3,                         // jump -- jmp 0x92dab
      0xe9, 0x22, 0xff, 0xff, 0xff,       // jump -- jmp 0x933ae
      0xff, 0xe0,                         // jump -- jmpq *%rax
      0xf2, 0xff, 0x25, 0x75, 0xe7, 0x39, 0x00, // jump -- repne jmpq *0x39e775

      0x73, 0xc2,                         // cond jump -- jae 0x9515c
      0x74, 0x1f,                         // cond jump -- je 0x400626
      0x75, 0xea,                         // cond jump -- jne 0x400610
      0x76, 0x10,                         // cond jump -- jbe 0x94d10
      0x77, 0x58,                         // cond jump -- ja 0x1208c8
      0x7e, 0x67,                         // cond jump -- jle 0x92180
      0x78, 0x0b,                         // cond jump -- js 0x92dc3
      0x0f, 0x82, 0x17, 0x01, 0x00, 0x00, // cond jump -- jb 0x9c7b0
      0x0f, 0x83, 0xa7, 0x00, 0x00, 0x00, // cond jump -- jae 0x895c8
      0x0f, 0x84, 0x8c, 0x00, 0x00, 0x00, // cond jump -- je 0x941f0
      0x0f, 0x85, 0x51, 0xff, 0xff, 0xff, // cond jump -- jne 0x8952c
      0x0f, 0x86, 0xa3, 0x02, 0x00, 0x00, // cond jump -- jbe 0x9ae10
      0x0f, 0x87, 0xff, 0x00, 0x00, 0x00, // cond jump -- ja 0x9ab60
      0x0f, 0x8e, 0x7e, 0x00, 0x00, 0x00, // cond jump -- jle 0x92dd8
      0x0f, 0x86, 0xdf, 0x00, 0x00, 0x00, // cond jump -- jbe 0x921b0

      0x0f, 0x05,                         // far call -- syscall

      0x0f, 0x07,                         // far return -- sysret
      0xcf,                               // far return -- interrupt ret
  };

  InstructionControlFlowKind result[] = {
      eInstructionControlFlowKindOther,
      eInstructionControlFlowKindOther,

      eInstructionControlFlowKindCall,
      eInstructionControlFlowKindCall,
      eInstructionControlFlowKindCall,
      eInstructionControlFlowKindCall,

      eInstructionControlFlowKindReturn,

      eInstructionControlFlowKindJump,
      eInstructionControlFlowKindJump,
      eInstructionControlFlowKindJump,
      eInstructionControlFlowKindJump,

      eInstructionControlFlowKindCondJump,
      eInstructionControlFlowKindCondJump,
      eInstructionControlFlowKindCondJump,
      eInstructionControlFlowKindCondJump,
      eInstructionControlFlowKindCondJump,
      eInstructionControlFlowKindCondJump,
      eInstructionControlFlowKindCondJump,
      eInstructionControlFlowKindCondJump,
      eInstructionControlFlowKindCondJump,
      eInstructionControlFlowKindCondJump,
      eInstructionControlFlowKindCondJump,
      eInstructionControlFlowKindCondJump,
      eInstructionControlFlowKindCondJump,
      eInstructionControlFlowKindCondJump,
      eInstructionControlFlowKindCondJump,

      eInstructionControlFlowKindFarCall,

      eInstructionControlFlowKindFarReturn,
      eInstructionControlFlowKindFarReturn,
  };

  DisassemblerSP disass_sp;
  Address start_addr(0x100);
  disass_sp = Disassembler::DisassembleBytes(
      arch, nullptr, nullptr, nullptr, nullptr, start_addr, &data, sizeof(data),
      num_of_instructions, false);

  // If we failed to get a disassembler, we can assume it is because
  // the llvm we linked against was not built with the i386 target,
  // and we should skip these tests without marking anything as failing.
  if (!disass_sp)
    return;

  const InstructionList inst_list(disass_sp->GetInstructionList());
  EXPECT_EQ(num_of_instructions, inst_list.GetSize());

  for (size_t i = 0; i < num_of_instructions; ++i) {
    InstructionSP inst_sp;
    inst_sp = inst_list.GetInstructionAtIndex(i);
    ExecutionContext exe_ctx(nullptr, nullptr, nullptr);
    InstructionControlFlowKind kind = inst_sp->GetControlFlowKind(&exe_ctx);
    EXPECT_EQ(kind, result[i]);

    // Also, test the DisassemblerLLVMC::MCDisasmInstance methods.
    if (kind == eInstructionControlFlowKindReturn) {
      EXPECT_FALSE(inst_sp->IsCall());
    }

    if (kind == eInstructionControlFlowKindCall) {
      EXPECT_TRUE(inst_sp->IsCall());
    }

    if (kind == eInstructionControlFlowKindCall ||
        kind == eInstructionControlFlowKindJump ||
        kind == eInstructionControlFlowKindCondJump ||
        kind == eInstructionControlFlowKindReturn) {
      EXPECT_TRUE(inst_sp->DoesBranch());
    }
  }
}