Skip to content

Commit f6d525f

Browse files
authored
[JITLink][AArch32] Unittest for error paths of readAddend and applyFixup functionality (#69636)
This test checks for error paths in relocation dependent functions of readAddend and applyFixup. It is useful to check these to avoid unexpected assert errors. Currently opcode errors are triggered in most of the cases in AArch32 but there might be further checks to look for in the future. Different backends can also implement a similar test.
1 parent fbc6520 commit f6d525f

File tree

3 files changed

+188
-2
lines changed

3 files changed

+188
-2
lines changed

llvm/include/llvm/ExecutionEngine/JITLink/aarch32.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,8 @@ template <> struct FixupInfo<Arm_MovwAbsNC> : public FixupInfo<Arm_MovtAbs> {
200200
};
201201

202202
template <> struct FixupInfo<Thumb_Jump24> {
203-
static constexpr HalfWords Opcode{0xf000, 0x8000};
204-
static constexpr HalfWords OpcodeMask{0xf800, 0x8000};
203+
static constexpr HalfWords Opcode{0xf000, 0x9000};
204+
static constexpr HalfWords OpcodeMask{0xf800, 0x9000};
205205
static constexpr HalfWords ImmMask{0x07ff, 0x2fff};
206206
};
207207

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
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-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include <llvm/ExecutionEngine/JITLink/aarch32.h>
10+
11+
#include "llvm/Testing/Support/Error.h"
12+
#include "gtest/gtest.h"
13+
14+
using namespace llvm;
15+
using namespace llvm::jitlink;
16+
using namespace llvm::jitlink::aarch32;
17+
using namespace llvm::support;
18+
using namespace llvm::support::endian;
19+
20+
constexpr unsigned PointerSize = 4;
21+
auto G = std::make_unique<LinkGraph>("foo", Triple("armv7-linux-gnueabi"),
22+
PointerSize, llvm::endianness::little,
23+
getGenericEdgeKindName);
24+
auto &Sec =
25+
G->createSection("__data", orc::MemProt::Read | orc::MemProt::Write);
26+
27+
auto ArmCfg = getArmConfigForCPUArch(ARMBuildAttrs::v7);
28+
29+
constexpr uint64_t ArmAlignment = 4;
30+
constexpr uint64_t ThumbAlignment = 2;
31+
constexpr uint64_t AlignmentOffset = 0;
32+
33+
constexpr orc::ExecutorAddrDiff SymbolOffset = 0;
34+
constexpr orc::ExecutorAddrDiff SymbolSize = 4;
35+
36+
TEST(AArch32_ELF, readAddendArmErrors) {
37+
38+
constexpr orc::ExecutorAddr B1DummyAddr(0x1000);
39+
40+
// Permanently undefined instruction in ARM
41+
// udf #0
42+
uint8_t ArmWord[] = {0xf0, 0x00, 0xf0, 0xe7};
43+
ArrayRef<char> ArmContent(reinterpret_cast<const char *>(&ArmWord),
44+
sizeof(ArmWord));
45+
auto &BArm = G->createContentBlock(Sec, ArmContent, B1DummyAddr, ArmAlignment,
46+
AlignmentOffset);
47+
Symbol &TargetSymbol =
48+
G->addAnonymousSymbol(BArm, SymbolOffset, SymbolSize, false, false);
49+
Edge InvalidEdge(Edge::GenericEdgeKind::Invalid, 0 /*Offset*/, TargetSymbol,
50+
0 /*Addend*/);
51+
52+
// Edge kind is tested, block itself is not significant here. So it is tested
53+
// once in Arm
54+
EXPECT_THAT_EXPECTED(readAddendData(*G, BArm, InvalidEdge),
55+
FailedWithMessage(testing::HasSubstr(
56+
"can not read implicit addend for aarch32 edge kind "
57+
"INVALID RELOCATION")));
58+
59+
EXPECT_THAT_EXPECTED(readAddendArm(*G, BArm, InvalidEdge),
60+
FailedWithMessage(testing::HasSubstr(
61+
"can not read implicit addend for aarch32 edge kind "
62+
"INVALID RELOCATION")));
63+
64+
EXPECT_THAT_EXPECTED(readAddendThumb(*G, BArm, InvalidEdge, ArmCfg),
65+
FailedWithMessage(testing::HasSubstr(
66+
"can not read implicit addend for aarch32 edge kind "
67+
"INVALID RELOCATION")));
68+
69+
for (Edge::Kind K = FirstArmRelocation; K < LastArmRelocation; K += 1) {
70+
Edge E(K, 0, TargetSymbol, 0);
71+
EXPECT_THAT_EXPECTED(
72+
readAddendArm(*G, BArm, E),
73+
FailedWithMessage(testing::StartsWith("Invalid opcode")));
74+
}
75+
}
76+
77+
TEST(AArch32_ELF, readAddendThumbErrors) {
78+
79+
constexpr orc::ExecutorAddr B2DummyAddr(0x2000);
80+
81+
// Permanently undefined instruction in Thumb
82+
// udf #0
83+
//
84+
// 11110:op:imm4:1:op1:imm12
85+
// op = 1111111 Permanent undefined
86+
// op1 = 010
87+
//
88+
constexpr HalfWords ThumbHalfWords{0xf7f0, 0xa000};
89+
ArrayRef<char> ThumbContent(reinterpret_cast<const char *>(&ThumbHalfWords),
90+
sizeof(ThumbHalfWords));
91+
auto &BThumb = G->createContentBlock(Sec, ThumbContent, B2DummyAddr,
92+
ThumbAlignment, AlignmentOffset);
93+
Symbol &TargetSymbol =
94+
G->addAnonymousSymbol(BThumb, SymbolOffset, SymbolSize, false, false);
95+
Edge InvalidEdge(Edge::GenericEdgeKind::Invalid, 0 /*Offset*/, TargetSymbol,
96+
0 /*Addend*/);
97+
98+
for (Edge::Kind K = FirstThumbRelocation; K < LastThumbRelocation; K += 1) {
99+
Edge E(K, 0, TargetSymbol, 0);
100+
EXPECT_THAT_EXPECTED(
101+
readAddendThumb(*G, BThumb, E, ArmCfg),
102+
FailedWithMessage(testing::StartsWith("Invalid opcode")));
103+
}
104+
}
105+
106+
TEST(AArch32_ELF, applyFixupArmErrors) {
107+
108+
constexpr orc::ExecutorAddr B3DummyAddr(0x5000);
109+
110+
uint8_t ArmWord[] = {0xf0, 0x00, 0xf0, 0xe7};
111+
MutableArrayRef<char> MutableArmContent(reinterpret_cast<char *>(ArmWord),
112+
sizeof(ArmWord));
113+
114+
auto &BArm = G->createMutableContentBlock(Sec, MutableArmContent, B3DummyAddr,
115+
ArmAlignment, AlignmentOffset);
116+
117+
Symbol &TargetSymbol =
118+
G->addAnonymousSymbol(BArm, SymbolOffset, SymbolSize, false, false);
119+
Edge InvalidEdge(Edge::GenericEdgeKind::Invalid, 0 /*Offset*/, TargetSymbol,
120+
0 /*Addend*/);
121+
122+
// Edge kind is tested, block itself is not significant here. So it is tested
123+
// once in Arm
124+
EXPECT_THAT_ERROR(
125+
applyFixupData(*G, BArm, InvalidEdge),
126+
FailedWithMessage(testing::HasSubstr(
127+
"encountered unfixable aarch32 edge kind INVALID RELOCATION")));
128+
EXPECT_THAT_ERROR(
129+
applyFixupArm(*G, BArm, InvalidEdge),
130+
FailedWithMessage(testing::HasSubstr(
131+
"encountered unfixable aarch32 edge kind INVALID RELOCATION")));
132+
EXPECT_THAT_ERROR(
133+
applyFixupThumb(*G, BArm, InvalidEdge, ArmCfg),
134+
FailedWithMessage(testing::HasSubstr(
135+
"encountered unfixable aarch32 edge kind INVALID RELOCATION")));
136+
137+
for (Edge::Kind K = FirstArmRelocation; K < LastArmRelocation; K += 1) {
138+
Edge E(K, 0, TargetSymbol, 0);
139+
EXPECT_THAT_ERROR(applyFixupArm(*G, BArm, E),
140+
FailedWithMessage(testing::AllOf(
141+
testing::StartsWith("Invalid opcode"),
142+
testing::EndsWith(G->getEdgeKindName(K)))));
143+
}
144+
}
145+
146+
TEST(AArch32_ELF, applyFixupThumbErrors) {
147+
148+
struct MutableHalfWords {
149+
constexpr MutableHalfWords(HalfWords Preset)
150+
: Hi(Preset.Hi), Lo(Preset.Lo) {}
151+
152+
uint16_t Hi; // First halfword
153+
uint16_t Lo; // Second halfword
154+
};
155+
156+
constexpr orc::ExecutorAddr B4DummyAddr(0x6000);
157+
158+
// Permanently undefined instruction in Thumb
159+
// udf #0
160+
//
161+
// 11110:op:imm4:1:op1:imm12
162+
// op = 1111111 Permanent undefined
163+
// op1 = 010
164+
//
165+
constexpr HalfWords ThumbHalfWords{0xf7f0, 0xa000};
166+
MutableHalfWords MutableThumbHalfWords{ThumbHalfWords};
167+
MutableArrayRef<char> MutableThumbContent(
168+
reinterpret_cast<char *>(&MutableThumbHalfWords),
169+
sizeof(MutableThumbHalfWords));
170+
171+
auto &BThumb = G->createMutableContentBlock(
172+
Sec, MutableThumbContent, B4DummyAddr, ThumbAlignment, AlignmentOffset);
173+
Symbol &TargetSymbol =
174+
G->addAnonymousSymbol(BThumb, SymbolOffset, SymbolSize, false, false);
175+
Edge InvalidEdge(Edge::GenericEdgeKind::Invalid, 0 /*Offset*/, TargetSymbol,
176+
0 /*Addend*/);
177+
178+
for (Edge::Kind K = FirstThumbRelocation; K < LastThumbRelocation; K += 1) {
179+
Edge E(K, 0, TargetSymbol, 0);
180+
EXPECT_THAT_ERROR(applyFixupThumb(*G, BThumb, E, ArmCfg),
181+
FailedWithMessage(testing::AllOf(
182+
testing::StartsWith("Invalid opcode"),
183+
testing::EndsWith(G->getEdgeKindName(K)))));
184+
}
185+
}

llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ set(LLVM_LINK_COMPONENTS
99

1010
add_llvm_unittest(JITLinkTests
1111
AArch32Tests.cpp
12+
AArch32ErrorTests.cpp
1213
EHFrameSupportTests.cpp
1314
JITLinkMocks.cpp
1415
LinkGraphTests.cpp

0 commit comments

Comments
 (0)