brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.9 KiB · 6e9957f Raw
305 lines · cpp
1//===------- AArch32ErrorTests.cpp - Test AArch32 error handling ----------===//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/ExecutionEngine/Orc/SymbolStringPool.h"10#include "llvm/TargetParser/Triple.h"11#include "llvm/Testing/Support/Error.h"12#include "gtest/gtest.h"13#include <llvm/ExecutionEngine/JITLink/aarch32.h>14 15using namespace llvm;16using namespace llvm::jitlink;17using namespace llvm::jitlink::aarch32;18using namespace llvm::support;19using namespace llvm::support::endian;20 21auto G = std::make_unique<LinkGraph>(22    "foo", std::make_shared<orc::SymbolStringPool>(),23    Triple("armv7-linux-gnueabi"), SubtargetFeatures(),24    aarch32::getEdgeKindName);25auto &Sec =26    G->createSection("__data", orc::MemProt::Read | orc::MemProt::Write);27 28auto ArmCfg = getArmConfigForCPUArch(ARMBuildAttrs::v7);29 30constexpr uint64_t ArmAlignment = 4;31constexpr uint64_t ThumbAlignment = 2;32constexpr uint64_t AlignmentOffset = 0;33 34constexpr orc::ExecutorAddrDiff SymbolOffset = 0;35constexpr orc::ExecutorAddrDiff SymbolSize = 4;36 37class AArch32Errors : public testing::Test {38protected:39  const ArmConfig Cfg = getArmConfigForCPUArch(ARMBuildAttrs::v7);40  std::unique_ptr<LinkGraph> G;41  Section *S = nullptr;42 43  const uint8_t Zeros[4]{0x00, 0x00, 0x00, 0x00};44  uint8_t MutableZeros[4]{0x00, 0x00, 0x00, 0x00};45 46public:47  static void SetUpTestCase() {}48 49  void SetUp() override {50    G = std::make_unique<LinkGraph>(51        "foo", std::make_shared<orc::SymbolStringPool>(),52        Triple("armv7-linux-gnueabi"), SubtargetFeatures(),53        aarch32::getEdgeKindName);54    S = &G->createSection("__data", orc::MemProt::Read | orc::MemProt::Write);55  }56 57  void TearDown() override {}58 59protected:60  template <size_t Size>61  Block &createBlock(const uint8_t (&Content)[Size], uint64_t Addr,62                     uint64_t Alignment = 4) {63    ArrayRef<char> CharContent{reinterpret_cast<const char *>(&Content),64                               sizeof(Content)};65    return G->createContentBlock(*S, CharContent, orc::ExecutorAddr(Addr),66                                 Alignment, AlignmentOffset);67  }68 69  template <size_t Size>70  Block &createMutableBlock(uint8_t (&Content)[Size], uint64_t Addr,71                            uint64_t Alignment = 4) {72    MutableArrayRef<char> CharContent{reinterpret_cast<char *>(&Content),73                                      sizeof(Content)};74    return G->createMutableContentBlock(75        *S, CharContent, orc::ExecutorAddr(Addr), Alignment, AlignmentOffset);76  }77 78  Symbol &createSymbolWithDistance(Block &Origin, uint64_t Dist) {79    uint64_t TargetAddr = Origin.getAddress().getValue() + Dist;80    return G->addAnonymousSymbol(createBlock(Zeros, TargetAddr), 0 /*Offset*/,81                                 G->getPointerSize(), false, false);82  };83 84  template <endianness Endian> void write(uint8_t *Mem, HalfWords Data) {85    write16<Endian>(Mem, Data.Hi);86    write16<Endian>(Mem + 2, Data.Lo);87  }88};89 90TEST_F(AArch32Errors, readAddendDataGeneric) {91  Block &ZerosBlock = createBlock(Zeros, 0x1000);92  constexpr uint64_t ZerosOffset = 0;93 94  // Invalid edge kind is the only error we can raise here right now.95  Edge::Kind Invalid = Edge::GenericEdgeKind::Invalid;96  EXPECT_THAT_EXPECTED(readAddend(*G, ZerosBlock, ZerosOffset, Invalid, Cfg),97                       FailedWithMessage(testing::HasSubstr(98                           "can not read implicit addend for aarch32 edge kind "99                           "INVALID RELOCATION")));100}101 102TEST(AArch32_ELF, readAddendArmErrors) {103 104  constexpr orc::ExecutorAddr B1DummyAddr(0x1000);105 106  // Permanently undefined instruction in ARM107  //    udf #0108  uint8_t ArmWord[] = {0xf0, 0x00, 0xf0, 0xe7};109  ArrayRef<char> ArmContent(reinterpret_cast<const char *>(&ArmWord),110                            sizeof(ArmWord));111  auto &BArm = G->createContentBlock(Sec, ArmContent, B1DummyAddr, ArmAlignment,112                                     AlignmentOffset);113 114  for (Edge::Kind K = FirstArmRelocation; K < LastArmRelocation; K += 1) {115    EXPECT_THAT_EXPECTED(readAddend(*G, BArm, SymbolOffset, K, ArmCfg),116                         FailedWithMessage(testing::AllOf(117                             testing::StartsWith("Invalid opcode"),118                             testing::EndsWith(aarch32::getEdgeKindName(K)))));119  }120}121 122TEST(AArch32_ELF, readAddendThumbErrors) {123 124  constexpr orc::ExecutorAddr B2DummyAddr(0x2000);125 126  // Permanently undefined instruction in Thumb127  //    udf #0128  //129  //    11110:op:imm4:1:op1:imm12130  //    op  = 1111111 Permanent undefined131  //    op1 = 010132  //133  constexpr HalfWords ThumbHalfWords{0xf7f0, 0xa000};134  ArrayRef<char> ThumbContent(reinterpret_cast<const char *>(&ThumbHalfWords),135                              sizeof(ThumbHalfWords));136  auto &BThumb = G->createContentBlock(Sec, ThumbContent, B2DummyAddr,137                                       ThumbAlignment, AlignmentOffset);138 139  for (Edge::Kind K = FirstThumbRelocation; K < LastThumbRelocation; K += 1) {140    EXPECT_THAT_EXPECTED(readAddend(*G, BThumb, SymbolOffset, K, ArmCfg),141                         FailedWithMessage(testing::AllOf(142                             testing::StartsWith("Invalid opcode"),143                             testing::EndsWith(aarch32::getEdgeKindName(K)))));144  }145}146 147TEST_F(AArch32Errors, applyFixupDataGeneric) {148  Block &OriginBlock = createMutableBlock(MutableZeros, 0x1000);149  Block &TargetBlock = createBlock(Zeros, 0x2000);150 151  constexpr uint64_t OffsetInTarget = 0;152  Symbol &TargetSymbol = G->addAnonymousSymbol(153      TargetBlock, OffsetInTarget, G->getPointerSize(), false, false);154 155  constexpr uint64_t OffsetInOrigin = 0;156  Edge::Kind Invalid = Edge::GenericEdgeKind::Invalid;157  Edge InvalidEdge(Invalid, OffsetInOrigin, TargetSymbol, 0 /*Addend*/);158  EXPECT_THAT_ERROR(159      applyFixup(*G, OriginBlock, InvalidEdge, Cfg),160      FailedWithMessage(testing::HasSubstr(161          "encountered unfixable aarch32 edge kind INVALID RELOCATION")));162}163 164TEST(AArch32_ELF, applyFixupArmErrors) {165 166  constexpr orc::ExecutorAddr B3DummyAddr(0x5000);167 168  uint8_t ArmWord[] = {0xf0, 0x00, 0xf0, 0xe7};169  MutableArrayRef<char> MutableArmContent(reinterpret_cast<char *>(ArmWord),170                                          sizeof(ArmWord));171 172  auto &BArm = G->createMutableContentBlock(Sec, MutableArmContent, B3DummyAddr,173                                            ArmAlignment, AlignmentOffset);174 175  Symbol &TargetSymbol =176      G->addAnonymousSymbol(BArm, SymbolOffset, SymbolSize, false, false);177 178  for (Edge::Kind K = FirstArmRelocation; K < LastArmRelocation; K += 1) {179    Edge E(K, 0, TargetSymbol, 0);180    EXPECT_THAT_ERROR(applyFixup(*G, BArm, E, ArmCfg),181                      FailedWithMessage(testing::AllOf(182                          testing::StartsWith("Invalid opcode"),183                          testing::EndsWith(aarch32::getEdgeKindName(K)))));184  }185}186 187TEST(AArch32_ELF, applyFixupThumbErrors) {188 189  struct MutableHalfWords {190    constexpr MutableHalfWords(HalfWords Preset)191        : Hi(Preset.Hi), Lo(Preset.Lo) {}192 193    uint16_t Hi; // First halfword194    uint16_t Lo; // Second halfword195  };196 197  constexpr orc::ExecutorAddr B4DummyAddr(0x6000);198 199  // Permanently undefined instruction in Thumb200  //    udf #0201  //202  //    11110:op:imm4:1:op1:imm12203  //    op  = 1111111 Permanent undefined204  //    op1 = 010205  //206  constexpr HalfWords ThumbHalfWords{0xf7f0, 0xa000};207  MutableHalfWords MutableThumbHalfWords{ThumbHalfWords};208  MutableArrayRef<char> MutableThumbContent(209      reinterpret_cast<char *>(&MutableThumbHalfWords),210      sizeof(MutableThumbHalfWords));211 212  auto &BThumb = G->createMutableContentBlock(213      Sec, MutableThumbContent, B4DummyAddr, ThumbAlignment, AlignmentOffset);214  Symbol &TargetSymbol =215      G->addAnonymousSymbol(BThumb, SymbolOffset, SymbolSize, false, false);216 217  for (Edge::Kind K = FirstThumbRelocation; K < LastThumbRelocation; K += 1) {218    Edge E(K, 0, TargetSymbol, 0);219    EXPECT_THAT_ERROR(applyFixup(*G, BThumb, E, ArmCfg),220                      FailedWithMessage(testing::AllOf(221                          testing::StartsWith("Invalid opcode"),222                          testing::EndsWith(aarch32::getEdgeKindName(K)))));223  }224}225 226TEST_F(AArch32Errors, applyFixupThumbCall) {227  // Check range of R_ARM_THM_CALL relocation228  constexpr uint64_t Call1Offset = 0; //< first out-of-range229  constexpr uint64_t Call2Offset = 4; //< last in-range230 231  uint8_t TwoCallsMem[8];232  Block &Site = createMutableBlock(TwoCallsMem, 0);233  constexpr HalfWords CallOpcode = FixupInfo<Thumb_Call>::Opcode;234  write<endianness::little>(TwoCallsMem + Call1Offset, CallOpcode);235  write<endianness::little>(TwoCallsMem + Call2Offset, CallOpcode);236 237  // Thumb call with J1J2-encoding has range of 25 bit238  ArmConfig ArmCfg;239  ArmCfg.J1J2BranchEncoding = true;240  Symbol &J1J2Target = createSymbolWithDistance(Site, 0x01ull << 24);241  {242    Edge LastInRange(Thumb_Call, Call2Offset, J1J2Target, 0);243    EXPECT_THAT_ERROR(applyFixup(*G, Site, LastInRange, ArmCfg), Succeeded());244    Edge FirstOutOfRange(Thumb_Call, Call1Offset, J1J2Target, 0);245    EXPECT_THAT_ERROR(applyFixup(*G, Site, FirstOutOfRange, ArmCfg),246                      FailedWithMessage(testing::HasSubstr("out of range")));247  }248 249  // Thumb call without J1J2-encoding has range of 22 bit250  ArmCfg.J1J2BranchEncoding = false;251  Symbol &NonJ1J2Target = createSymbolWithDistance(Site, 0x01ull << 21);252  {253    Edge LastInRange(Thumb_Call, Call2Offset, NonJ1J2Target, 0);254    EXPECT_THAT_ERROR(applyFixup(*G, Site, LastInRange, ArmCfg), Succeeded());255    Edge FirstOutOfRange(Thumb_Call, Call1Offset, NonJ1J2Target, 0);256    EXPECT_THAT_ERROR(applyFixup(*G, Site, FirstOutOfRange, ArmCfg),257                      FailedWithMessage(testing::HasSubstr("out of range")));258  }259}260 261TEST_F(AArch32Errors, applyFixupThumbJump24) {262  // Check range of R_ARM_THM_JUMP24 relocation263  constexpr uint64_t Jump1Offset = 0; //< first out-of-range264  constexpr uint64_t Jump2Offset = 4; //< last in-range265 266  uint8_t TwoJumpsMem[8];267  constexpr HalfWords JumpOpcode = FixupInfo<Thumb_Jump24>::Opcode;268  write<endianness::little>(TwoJumpsMem + Jump1Offset, JumpOpcode);269  write<endianness::little>(TwoJumpsMem + Jump2Offset, JumpOpcode);270  Block &Site = createMutableBlock(TwoJumpsMem, 0);271 272  // Thumb Jump24 with J1J2-encoding has range of 25 bit273  ArmCfg.J1J2BranchEncoding = true;274  Symbol &J1J2Target = createSymbolWithDistance(Site, 0x01ull << 24);275  J1J2Target.setTargetFlags(TargetFlags_aarch32::ThumbSymbol);276  {277    Edge LastInRange(Thumb_Jump24, Jump2Offset, J1J2Target, 0);278    EXPECT_THAT_ERROR(applyFixup(*G, Site, LastInRange, ArmCfg), Succeeded());279    Edge FirstOutOfRange(Thumb_Jump24, Jump1Offset, J1J2Target, 0);280    EXPECT_THAT_ERROR(applyFixup(*G, Site, FirstOutOfRange, ArmCfg),281                      FailedWithMessage(testing::HasSubstr("out of range")));282  }283 284  // Thumb Jump24 without J1J2-encoding has range of 22 bit285  ArmCfg.J1J2BranchEncoding = false;286  Symbol &NonJ1J2Target = createSymbolWithDistance(Site, 0x01ull << 21);287  NonJ1J2Target.setTargetFlags(TargetFlags_aarch32::ThumbSymbol);288  {289    Edge LastInRange(Thumb_Jump24, Jump2Offset, NonJ1J2Target, 0);290    EXPECT_THAT_ERROR(applyFixup(*G, Site, LastInRange, ArmCfg), Succeeded());291    Edge FirstOutOfRange(Thumb_Jump24, Jump1Offset, NonJ1J2Target, 0);292    EXPECT_THAT_ERROR(applyFixup(*G, Site, FirstOutOfRange, ArmCfg),293                      FailedWithMessage(testing::HasSubstr("out of range")));294  }295 296  // Check that branching to an ARM target with Jump24 fails297  Symbol &ArmTarget = createSymbolWithDistance(Site, 0x1000);298  assert((ArmTarget.getTargetFlags() & TargetFlags_aarch32::ThumbSymbol) == 0);299  Edge Interworking(Thumb_Jump24, Jump2Offset, ArmTarget, 0);300  EXPECT_THAT_ERROR(applyFixup(*G, Site, Interworking, ArmCfg),301                    FailedWithMessage(testing::HasSubstr(302                        "Branch relocation needs interworking "303                        "stub when bridging to ARM")));304}305