1 #ifdef AARCH64_AVAILABLE
2 #include "AArch64Subtarget.h"
3 #endif // AARCH64_AVAILABLE
4 
5 #ifdef X86_AVAILABLE
6 #include "X86Subtarget.h"
7 #endif // X86_AVAILABLE
8 
9 #include "bolt/Core/BinaryBasicBlock.h"
10 #include "bolt/Core/BinaryFunction.h"
11 #include "bolt/Rewrite/RewriteInstance.h"
12 #include "llvm/BinaryFormat/ELF.h"
13 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
14 #include "llvm/Object/ELFObjectFile.h"
15 #include "llvm/Support/TargetSelect.h"
16 #include "gtest/gtest.h"
17 
18 using namespace llvm;
19 using namespace llvm::object;
20 using namespace llvm::ELF;
21 using namespace bolt;
22 
23 namespace {
24 struct MCPlusBuilderTester : public testing::TestWithParam<Triple::ArchType> {
SetUp__anonb58d5c450111::MCPlusBuilderTester25   void SetUp() override {
26     initalizeLLVM();
27     prepareElf();
28     initializeBolt();
29   }
30 
31 protected:
initalizeLLVM__anonb58d5c450111::MCPlusBuilderTester32   void initalizeLLVM() {
33     llvm::InitializeAllTargetInfos();
34     llvm::InitializeAllTargetMCs();
35     llvm::InitializeAllAsmParsers();
36     llvm::InitializeAllDisassemblers();
37     llvm::InitializeAllTargets();
38     llvm::InitializeAllAsmPrinters();
39   }
40 
prepareElf__anonb58d5c450111::MCPlusBuilderTester41   void prepareElf() {
42     memcpy(ElfBuf, "\177ELF", 4);
43     ELF64LE::Ehdr *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(ElfBuf);
44     EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
45     EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
46     EHdr->e_machine = GetParam() == Triple::aarch64 ? EM_AARCH64 : EM_X86_64;
47     MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF");
48     ObjFile = cantFail(ObjectFile::createObjectFile(Source));
49   }
50 
initializeBolt__anonb58d5c450111::MCPlusBuilderTester51   void initializeBolt() {
52     BC = cantFail(BinaryContext::createBinaryContext(
53         ObjFile.get(), true, DWARFContext::create(*ObjFile.get())));
54     ASSERT_FALSE(!BC);
55     BC->initializeTarget(std::unique_ptr<MCPlusBuilder>(createMCPlusBuilder(
56         GetParam(), BC->MIA.get(), BC->MII.get(), BC->MRI.get())));
57   }
58 
testRegAliases__anonb58d5c450111::MCPlusBuilderTester59   void testRegAliases(Triple::ArchType Arch, uint64_t Register,
60                       uint64_t *Aliases, size_t Count,
61                       bool OnlySmaller = false) {
62     if (GetParam() != Arch)
63       GTEST_SKIP();
64 
65     const BitVector &BV = BC->MIB->getAliases(Register, OnlySmaller);
66     ASSERT_EQ(BV.count(), Count);
67     for (size_t I = 0; I < Count; ++I)
68       ASSERT_TRUE(BV[Aliases[I]]);
69   }
70 
71   char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {};
72   std::unique_ptr<ObjectFile> ObjFile;
73   std::unique_ptr<BinaryContext> BC;
74 };
75 } // namespace
76 
77 #ifdef AARCH64_AVAILABLE
78 
79 INSTANTIATE_TEST_SUITE_P(AArch64, MCPlusBuilderTester,
80                          ::testing::Values(Triple::aarch64));
81 
TEST_P(MCPlusBuilderTester,AliasX0)82 TEST_P(MCPlusBuilderTester, AliasX0) {
83   uint64_t AliasesX0[] = {AArch64::W0, AArch64::X0, AArch64::W0_W1,
84                           AArch64::X0_X1, AArch64::X0_X1_X2_X3_X4_X5_X6_X7};
85   size_t AliasesX0Count = sizeof(AliasesX0) / sizeof(*AliasesX0);
86   testRegAliases(Triple::aarch64, AArch64::X0, AliasesX0, AliasesX0Count);
87 }
88 
TEST_P(MCPlusBuilderTester,AliasSmallerX0)89 TEST_P(MCPlusBuilderTester, AliasSmallerX0) {
90   uint64_t AliasesX0[] = {AArch64::W0, AArch64::X0};
91   size_t AliasesX0Count = sizeof(AliasesX0) / sizeof(*AliasesX0);
92   testRegAliases(Triple::aarch64, AArch64::X0, AliasesX0, AliasesX0Count, true);
93 }
94 
95 #endif // AARCH64_AVAILABLE
96 
97 #ifdef X86_AVAILABLE
98 
99 INSTANTIATE_TEST_SUITE_P(X86, MCPlusBuilderTester,
100                          ::testing::Values(Triple::x86_64));
101 
TEST_P(MCPlusBuilderTester,AliasAX)102 TEST_P(MCPlusBuilderTester, AliasAX) {
103   uint64_t AliasesAX[] = {X86::RAX, X86::EAX, X86::AX, X86::AL, X86::AH};
104   size_t AliasesAXCount = sizeof(AliasesAX) / sizeof(*AliasesAX);
105   testRegAliases(Triple::x86_64, X86::AX, AliasesAX, AliasesAXCount);
106 }
107 
TEST_P(MCPlusBuilderTester,AliasSmallerAX)108 TEST_P(MCPlusBuilderTester, AliasSmallerAX) {
109   uint64_t AliasesAX[] = {X86::AX, X86::AL, X86::AH};
110   size_t AliasesAXCount = sizeof(AliasesAX) / sizeof(*AliasesAX);
111   testRegAliases(Triple::x86_64, X86::AX, AliasesAX, AliasesAXCount, true);
112 }
113 
TEST_P(MCPlusBuilderTester,ReplaceRegWithImm)114 TEST_P(MCPlusBuilderTester, ReplaceRegWithImm) {
115   if (GetParam() != Triple::x86_64)
116     GTEST_SKIP();
117   BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
118   std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
119   MCInst Inst; // cmpl    %eax, %ebx
120   Inst.setOpcode(X86::CMP32rr);
121   Inst.addOperand(MCOperand::createReg(X86::EAX));
122   Inst.addOperand(MCOperand::createReg(X86::EBX));
123   auto II = BB->addInstruction(Inst);
124   bool Replaced = BC->MIB->replaceRegWithImm(*II, X86::EBX, 1);
125   ASSERT_TRUE(Replaced);
126   ASSERT_EQ(II->getOpcode(), X86::CMP32ri8);
127   ASSERT_EQ(II->getOperand(0).getReg(), X86::EAX);
128   ASSERT_EQ(II->getOperand(1).getImm(), 1);
129 }
130 
131 #endif // X86_AVAILABLE
132 
TEST_P(MCPlusBuilderTester,Annotation)133 TEST_P(MCPlusBuilderTester, Annotation) {
134   MCInst Inst;
135   bool Success = BC->MIB->createTailCall(Inst, BC->Ctx->createNamedTempSymbol(),
136                                          BC->Ctx.get());
137   ASSERT_TRUE(Success);
138   MCSymbol *LPSymbol = BC->Ctx->createNamedTempSymbol("LP");
139   uint64_t Value = INT32_MIN;
140   // Test encodeAnnotationImm using this indirect way
141   BC->MIB->addEHInfo(Inst, MCPlus::MCLandingPad(LPSymbol, Value));
142   // Round-trip encoding-decoding check for negative values
143   Optional<MCPlus::MCLandingPad> EHInfo = BC->MIB->getEHInfo(Inst);
144   ASSERT_TRUE(EHInfo.hasValue());
145   MCPlus::MCLandingPad LP = EHInfo.getValue();
146   uint64_t DecodedValue = LP.second;
147   ASSERT_EQ(Value, DecodedValue);
148 
149   // Large int64 should trigger an out of range assertion
150   Value = 0x1FF'FFFF'FFFF'FFFFULL;
151   Inst.clear();
152   Success = BC->MIB->createTailCall(Inst, BC->Ctx->createNamedTempSymbol(),
153                                     BC->Ctx.get());
154   ASSERT_TRUE(Success);
155   ASSERT_DEATH(BC->MIB->addEHInfo(Inst, MCPlus::MCLandingPad(LPSymbol, Value)),
156                "annotation value out of range");
157 }
158