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