aboutsummaryrefslogtreecommitdiff
path: root/lldb/unittests/Disassembler/RISCV/TestMCDisasmInstanceRISCV.cpp
blob: 64177a2fac49079b893da28bb4f514b8e17dfbc0 (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
//===-- TestMCDisasmInstanceRISCV.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 "lldb/Utility/StreamString.h"

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

using namespace lldb;
using namespace lldb_private;

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

protected:
};

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

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

TEST_F(TestMCDisasmInstanceRISCV, TestRISCV32Instruction) {
  ArchSpec arch("riscv32-*-linux");

  const unsigned num_of_instructions = 5;
  uint8_t data[] = {
      0xef, 0x00, 0x00, 0x00, // call -- jal x1, 0
      0xe7, 0x00, 0x00, 0x00, // call -- jalr x1, x0, 0
      0x6f, 0x00, 0x00, 0x00, // jump -- jal x0, 0
      0x67, 0x00, 0x00, 0x00, // jump -- jalr x0, x0, 0
      0x67, 0x80, 0x00, 0x00  // ret  -- jalr x0, x1, 0
  };

  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);

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

  InstructionSP inst_sp;
  inst_sp = inst_list.GetInstructionAtIndex(0);
  EXPECT_TRUE(inst_sp->IsCall());
  EXPECT_TRUE(inst_sp->DoesBranch());

  inst_sp = inst_list.GetInstructionAtIndex(1);
  EXPECT_TRUE(inst_sp->IsCall());
  EXPECT_TRUE(inst_sp->DoesBranch());

  inst_sp = inst_list.GetInstructionAtIndex(2);
  EXPECT_FALSE(inst_sp->IsCall());
  EXPECT_TRUE(inst_sp->DoesBranch());

  inst_sp = inst_list.GetInstructionAtIndex(3);
  EXPECT_FALSE(inst_sp->IsCall());
  EXPECT_TRUE(inst_sp->DoesBranch());

  inst_sp = inst_list.GetInstructionAtIndex(4);
  EXPECT_FALSE(inst_sp->IsCall());
  EXPECT_TRUE(inst_sp->DoesBranch());
}

TEST_F(TestMCDisasmInstanceRISCV, TestOpcodeBytePrinter) {
  ArchSpec arch("riscv32-*-linux");

  const unsigned num_of_instructions = 7;
  // clang-format off
  uint8_t data[] = {
      0x41, 0x11,             // addi   sp, sp, -0x10
      0x06, 0xc6,             // sw     ra, 0xc(sp)
      0x23, 0x2a, 0xa4, 0xfe, // sw     a0, -0xc(s0)
      0x23, 0x28, 0xa4, 0xfe, // sw     a0, -0x10(s0)
      0x22, 0x44,             // lw     s0, 0x8(sp)

      0x3f, 0x00, 0x40, 0x09, // Fake 64-bit instruction
      0x20, 0x00, 0x20, 0x00,

      0x1f, 0x02,             // 48 bit xqci.e.li rd=8 imm=0x1000
      0x00, 0x00, 
      0x00, 0x10,
  };
  // clang-format on

  // clang-format off
  const char *expected_outputs[] = {
    "1141",
    "c606",
    "fea42a23",
    "fea42823",
    "4422",
    "0940003f 00200020",
    "021f 0000 1000"
  };
  // clang-format on
  const unsigned num_of_expected_outputs =
      sizeof(expected_outputs) / sizeof(char *);

  EXPECT_EQ(num_of_instructions, num_of_expected_outputs);

  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);

  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;
    StreamString s;
    inst_sp = inst_list.GetInstructionAtIndex(i);
    inst_sp->GetOpcode().Dump(&s, 1);
    ASSERT_STREQ(s.GetString().str().c_str(), expected_outputs[i]);
  }
}