xref: /llvm-project/llvm/unittests/MC/X86/X86MCDisassemblerTest.cpp (revision 8f6512fea000c3a0d394864bb94e524bee375069)
1 //===- X86MCDisassemblerTest.cpp - Tests for X86 MCDisassembler -----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/MC/MCAsmInfo.h"
10 #include "llvm/MC/MCContext.h"
11 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
12 #include "llvm/MC/MCDisassembler/MCSymbolizer.h"
13 #include "llvm/MC/MCInst.h"
14 #include "llvm/MC/MCRegisterInfo.h"
15 #include "llvm/MC/MCSubtargetInfo.h"
16 #include "llvm/MC/MCTargetOptions.h"
17 #include "llvm/MC/TargetRegistry.h"
18 #include "llvm/Support/TargetSelect.h"
19 #include "gtest/gtest.h"
20 
21 using namespace llvm;
22 
23 namespace {
24 
25 struct Context {
26   const char *TripleName = "x86_64-unknown-elf";
27   std::unique_ptr<MCRegisterInfo> MRI;
28   std::unique_ptr<MCAsmInfo> MAI;
29   std::unique_ptr<MCContext> Ctx;
30   std::unique_ptr<MCSubtargetInfo> STI;
31   std::unique_ptr<MCDisassembler> DisAsm;
32 
Context__anon1bc103070111::Context33   Context() {
34     LLVMInitializeX86TargetInfo();
35     LLVMInitializeX86TargetMC();
36     LLVMInitializeX86Disassembler();
37 
38     // If we didn't build x86, do not run the test.
39     std::string Error;
40     const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
41     if (!TheTarget)
42       return;
43 
44     MRI.reset(TheTarget->createMCRegInfo(TripleName));
45     MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCTargetOptions()));
46     STI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
47     Ctx = std::make_unique<MCContext>(Triple(TripleName), MAI.get(), MRI.get(),
48                                       STI.get());
49 
50     DisAsm.reset(TheTarget->createMCDisassembler(*STI, *Ctx));
51   }
52 
operator MCContext&__anon1bc103070111::Context53   operator MCContext &() { return *Ctx; };
54 };
55 
getContext()56 Context &getContext() {
57   static Context Ctxt;
58   return Ctxt;
59 }
60 
61 class X86MCSymbolizerTest : public MCSymbolizer {
62 public:
X86MCSymbolizerTest(MCContext & MC)63   X86MCSymbolizerTest(MCContext &MC) : MCSymbolizer(MC, nullptr) {}
~X86MCSymbolizerTest()64   ~X86MCSymbolizerTest() {}
65 
66   struct OpInfo {
67     int64_t Value = 0;
68     uint64_t Offset = 0;
69     uint64_t Size;
70   };
71   std::vector<OpInfo> Operands;
72   uint64_t InstructionSize = 0;
73 
reset()74   void reset() {
75     Operands.clear();
76     InstructionSize = 0;
77   }
78 
tryAddingSymbolicOperand(MCInst & Inst,raw_ostream & CStream,int64_t Value,uint64_t Address,bool IsBranch,uint64_t Offset,uint64_t OpSize,uint64_t InstSize)79   bool tryAddingSymbolicOperand(MCInst &Inst, raw_ostream &CStream,
80                                 int64_t Value, uint64_t Address, bool IsBranch,
81                                 uint64_t Offset, uint64_t OpSize,
82                                 uint64_t InstSize) override {
83     Operands.push_back({Value, Offset, OpSize});
84     InstructionSize = InstSize;
85     return false;
86   }
87 
tryAddingPcLoadReferenceComment(raw_ostream & cStream,int64_t Value,uint64_t Address)88   void tryAddingPcLoadReferenceComment(raw_ostream &cStream, int64_t Value,
89                                        uint64_t Address) override {}
90 };
91 
92 } // namespace
93 
TEST(X86Disassembler,X86MCSymbolizerTest)94 TEST(X86Disassembler, X86MCSymbolizerTest) {
95   X86MCSymbolizerTest *TestSymbolizer = new X86MCSymbolizerTest(getContext());
96   getContext().DisAsm->setSymbolizer(
97       std::unique_ptr<MCSymbolizer>(TestSymbolizer));
98 
99   MCDisassembler::DecodeStatus Status;
100   MCInst Inst;
101   uint64_t InstSize;
102 
103   auto checkBytes = [&](ArrayRef<uint8_t> Bytes) {
104     TestSymbolizer->reset();
105     Status =
106         getContext().DisAsm->getInstruction(Inst, InstSize, Bytes, 0, nulls());
107     ASSERT_TRUE(Status == MCDisassembler::Success);
108     EXPECT_EQ(TestSymbolizer->InstructionSize, InstSize);
109   };
110 
111   auto checkOperand = [&](size_t OpNo, int64_t Value, uint64_t Offset,
112                           uint64_t Size) {
113     ASSERT_TRUE(TestSymbolizer->Operands.size() > OpNo);
114     EXPECT_EQ(TestSymbolizer->Operands[OpNo].Value, Value);
115     EXPECT_EQ(TestSymbolizer->Operands[OpNo].Offset, Offset);
116     EXPECT_EQ(TestSymbolizer->Operands[OpNo].Size, Size);
117   };
118 
119   // movq    $0x80000, 0x80000
120   checkBytes(
121       {0x48, 0xc7, 0x04, 0x25, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00});
122   checkOperand(0, 0x80000, 4, 4);
123   checkOperand(1, 0x80000, 8, 4);
124 
125   // movq   $0x2a, 0x123(%rax,%r14,8)
126   checkBytes(
127       {0x4a, 0xc7, 0x84, 0xf0, 0x23, 0x01, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00});
128   checkOperand(0, 291, 4, 4);
129   checkOperand(1, 42, 8, 4);
130 
131   // movq   $0xffffffffffffefe8, -0x1(%rip)
132   // Test that the value of the rip-relative operand is set correctly.
133   // The instruction address is 0 and the size is 12 bytes.
134   checkBytes(
135       {0x48, 0xc7, 0x05, 0xff, 0xff, 0xff, 0xff, 0xe8, 0xef, 0xff, 0xff});
136   checkOperand(0, /*next instr address*/ 11 - /*disp*/ 1, 3, 4);
137   checkOperand(1, 0xffffffffffffefe8, 7, 4);
138 
139   // movq   $0xfffffffffffffef5, (%r12)
140   // Test that the displacement operand has a size of 0, since it is not
141   // explicitly specified in the instruction.
142   checkBytes({0x49, 0xc7, 0x04, 0x24, 0xf5, 0xfe, 0xff, 0xff});
143   checkOperand(0, 0, 4, 0);
144   checkOperand(1, 0xfffffffffffffef5, 4, 4);
145 
146   // mov    %ax, 0x1568179(%rbx)
147   // Test that the displacement operand size is not affected by the operand
148   // size override prefix.
149   checkBytes({0x66, 0x89, 0x83, 0x79, 0x81, 0x56, 0x01});
150   checkOperand(0, 0x1568179, 3, 4);
151 }
152