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