1 //===- XCOFFObjectFileTest.cpp - Tests for XCOFFObjectFile ----------------===//
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/Object/ELFObjectFile.h"
10 #include "llvm/Object/XCOFFObjectFile.h"
11 #include "llvm/Testing/Support/Error.h"
12 #include "gtest/gtest.h"
13 
14 using namespace llvm;
15 using namespace llvm::object;
16 using namespace llvm::XCOFF;
17 
TEST(XCOFFObjectFileTest,XCOFFObjectType)18 TEST(XCOFFObjectFileTest, XCOFFObjectType) {
19   // Create an arbitrary object of a non-XCOFF type and test that
20   // dyn_cast<XCOFFObjectFile> returns null for it.
21   char Buf[sizeof(typename ELF64LE::Ehdr)] = {};
22   memcpy(Buf, "\177ELF", 4);
23 
24   auto *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(Buf);
25   EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
26   EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
27 
28   MemoryBufferRef Source(StringRef(Buf, sizeof(Buf)), "non-XCOFF");
29   Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
30       ObjectFile::createObjectFile(Source);
31   ASSERT_THAT_EXPECTED(ObjOrErr, Succeeded());
32 
33   EXPECT_TRUE(dyn_cast<XCOFFObjectFile>((*ObjOrErr).get()) == nullptr);
34 }
35 
TEST(XCOFFObjectFileTest,doesXCOFFTracebackTableBegin)36 TEST(XCOFFObjectFileTest, doesXCOFFTracebackTableBegin) {
37   EXPECT_TRUE(doesXCOFFTracebackTableBegin({0, 0, 0, 0}));
38   EXPECT_TRUE(doesXCOFFTracebackTableBegin({0, 0, 0, 0, 1}));
39   EXPECT_FALSE(doesXCOFFTracebackTableBegin({0, 0, 0, 1}));
40   EXPECT_FALSE(doesXCOFFTracebackTableBegin({0, 0, 0}));
41 }
42 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableAPIGeneral)43 TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIGeneral) {
44   uint8_t V[] = {0x00, 0x00, 0x22, 0x40, 0x80, 0x00, 0x01, 0x05, 0x58, 0x00,
45                  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x07, 0x61, 0x64,
46                  0x64, 0x5f, 0x61, 0x6c, 0x6c, 0x00, 0x00, 0x00};
47   uint64_t Size = sizeof(V);
48   Expected<XCOFFTracebackTable> TTOrErr = XCOFFTracebackTable::create(V, Size);
49   ASSERT_THAT_EXPECTED(TTOrErr, Succeeded());
50   XCOFFTracebackTable TT = *TTOrErr;
51 
52   EXPECT_EQ(TT.getVersion(), 0);
53 
54   EXPECT_EQ(TT.getLanguageID(), 0);
55 
56   EXPECT_FALSE(TT.isGlobalLinkage());
57   EXPECT_FALSE(TT.isOutOfLineEpilogOrPrologue());
58   EXPECT_TRUE(TT.hasTraceBackTableOffset());
59   EXPECT_FALSE(TT.isInternalProcedure());
60   EXPECT_FALSE(TT.hasControlledStorage());
61   EXPECT_FALSE(TT.isTOCless());
62   EXPECT_TRUE(TT.isFloatingPointPresent());
63   EXPECT_FALSE(TT.isFloatingPointOperationLogOrAbortEnabled());
64 
65   EXPECT_FALSE(TT.isInterruptHandler());
66   EXPECT_TRUE(TT.isFuncNamePresent());
67   EXPECT_FALSE(TT.isAllocaUsed());
68   EXPECT_EQ(TT.getOnConditionDirective(), 0);
69   EXPECT_FALSE(TT.isCRSaved());
70   EXPECT_FALSE(TT.isLRSaved());
71 
72   EXPECT_TRUE(TT.isBackChainStored());
73   EXPECT_FALSE(TT.isFixup());
74   EXPECT_EQ(TT.getNumOfFPRsSaved(), 0);
75 
76   EXPECT_FALSE(TT.hasExtensionTable());
77   EXPECT_FALSE(TT.hasVectorInfo());
78   EXPECT_EQ(TT.getNumOfGPRsSaved(), 0);
79 
80   EXPECT_EQ(TT.getNumberOfFixedParms(), 1);
81 
82   EXPECT_EQ(TT.getNumberOfFPParms(), 2);
83   EXPECT_TRUE(TT.hasParmsOnStack());
84 
85   ASSERT_TRUE(TT.getParmsType());
86   EXPECT_EQ(TT.getParmsType().getValue(), "i, f, d");
87 
88   ASSERT_TRUE(TT.getTraceBackTableOffset());
89   EXPECT_EQ(TT.getTraceBackTableOffset().getValue(), 64u);
90 
91   EXPECT_FALSE(TT.getHandlerMask());
92 
93   ASSERT_TRUE(TT.getFunctionName());
94   EXPECT_EQ(TT.getFunctionName().getValue(), "add_all");
95   EXPECT_EQ(TT.getFunctionName().getValue().size(), 7u);
96 
97   EXPECT_FALSE(TT.getAllocaRegister());
98   EXPECT_EQ(Size, 25u);
99 }
100 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableAPIParmsType)101 TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIParmsType) {
102   uint8_t V[] = {0x01, 0x02, 0xA2, 0x40, 0x80, 0x00, 0x02, 0x07, 0x2B, 0x00,
103                  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x07, 0x61, 0x64,
104                  0x64, 0x5f, 0x61, 0x6c, 0x6c, 0x00, 0x00, 0x00};
105   uint64_t Size = sizeof(V);
106   Expected<XCOFFTracebackTable> TTOrErr = XCOFFTracebackTable::create(V, Size);
107 
108   ASSERT_THAT_EXPECTED(TTOrErr, Succeeded());
109   XCOFFTracebackTable TT = *TTOrErr;
110   EXPECT_EQ(TT.getVersion(), 1);
111   EXPECT_EQ(TT.getLanguageID(), 2);
112 
113   EXPECT_TRUE(TT.isGlobalLinkage());
114   EXPECT_EQ(TT.getNumberOfFixedParms(), 2);
115 
116   EXPECT_EQ(TT.getNumberOfFPParms(), 3);
117 
118   ASSERT_TRUE(TT.getParmsType());
119   EXPECT_EQ(TT.getParmsType().getValue(), "i, i, f, f, d");
120 
121   V[8] = 0xAC;
122   Size = sizeof(V);
123   Expected<XCOFFTracebackTable> TTOrErr1 = XCOFFTracebackTable::create(V, Size);
124   ASSERT_THAT_EXPECTED(TTOrErr1, Succeeded());
125   XCOFFTracebackTable TT1 = *TTOrErr1;
126   ASSERT_TRUE(TT1.getParmsType());
127   EXPECT_EQ(TT1.getParmsType().getValue(), "f, f, d, i, i");
128 
129   V[8] = 0xD4;
130   Size = sizeof(V);
131   Expected<XCOFFTracebackTable> TTOrErr2 = XCOFFTracebackTable::create(V, Size);
132   ASSERT_THAT_EXPECTED(TTOrErr2, Succeeded());
133   XCOFFTracebackTable TT2 = *TTOrErr2;
134   ASSERT_TRUE(TT2.getParmsType());
135   EXPECT_EQ(TT2.getParmsType().getValue(), "d, i, f, f, i");
136 
137   V[6] = 0x01;
138   Size = sizeof(V);
139   Expected<XCOFFTracebackTable> TTOrErr3 = XCOFFTracebackTable::create(V, Size);
140   ASSERT_THAT_EXPECTED(TTOrErr3, Succeeded());
141   XCOFFTracebackTable TT3 = *TTOrErr3;
142   ASSERT_TRUE(TT3.getParmsType());
143   EXPECT_EQ(TT3.getParmsType().getValue(), "d, i, f, f");
144 }
145 
146 const uint8_t TBTableData[] = {
147     0x00, 0x00, 0x2A, 0x60, 0x80, 0xc0, 0x03, 0x05, 0x48, 0xc4, 0x00, 0x00,
148     0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x05, 0x05, 0x00, 0x00,
149     0x06, 0x06, 0x00, 0x00, 0x00, 0x07, 0x61, 0x64, 0x64, 0x5f, 0x61, 0x6c,
150     0x6c, 0x1f, 0x02, 0x05, 0xf0, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00};
151 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableAPIControlledStorageInfoDisp)152 TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIControlledStorageInfoDisp) {
153   uint64_t Size = sizeof(TBTableData);
154   Expected<XCOFFTracebackTable> TTOrErr =
155       XCOFFTracebackTable::create(TBTableData, Size);
156   ASSERT_THAT_EXPECTED(TTOrErr, Succeeded());
157   XCOFFTracebackTable TT = *TTOrErr;
158   EXPECT_TRUE(TT.hasControlledStorage());
159   ASSERT_TRUE(TT.getNumOfCtlAnchors());
160   EXPECT_EQ(TT.getNumOfCtlAnchors().getValue(), 2u);
161 
162   ASSERT_TRUE(TT.getControlledStorageInfoDisp());
163 
164   SmallVector<uint32_t, 8> Disp = TT.getControlledStorageInfoDisp().getValue();
165 
166   ASSERT_EQ(Disp.size(), 2UL);
167   EXPECT_EQ(Disp[0], 0x05050000u);
168   EXPECT_EQ(Disp[1], 0x06060000u);
169   EXPECT_EQ(Size, 45u);
170 }
171 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableAPIAllocaRegister)172 TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIAllocaRegister) {
173   uint64_t Size = sizeof(TBTableData);
174   Expected<XCOFFTracebackTable> TTOrErr =
175       XCOFFTracebackTable::create(TBTableData, Size);
176   ASSERT_THAT_EXPECTED(TTOrErr, Succeeded());
177   XCOFFTracebackTable TT = *TTOrErr;
178   ASSERT_TRUE(TT.getAllocaRegister());
179   EXPECT_EQ(TT.getAllocaRegister().getValue(), 31u);
180 }
181 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableAPIHasVectorInfo)182 TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIHasVectorInfo) {
183 
184   uint64_t Size = sizeof(TBTableData);
185   Expected<XCOFFTracebackTable> TTOrErr =
186       XCOFFTracebackTable::create(TBTableData, Size);
187   ASSERT_THAT_EXPECTED(TTOrErr, Succeeded());
188   XCOFFTracebackTable TT = *TTOrErr;
189 
190   EXPECT_EQ(TT.getNumberOfFixedParms(), 3);
191   EXPECT_EQ(TT.getNumberOfFPParms(), 2);
192   EXPECT_TRUE(TT.hasVectorInfo());
193   EXPECT_TRUE(TT.hasExtensionTable());
194 
195   ASSERT_TRUE(TT.getParmsType());
196   EXPECT_EQ(TT.getParmsType().getValue(), "v, i, f, i, d, i, v");
197 
198   ASSERT_TRUE(TT.getVectorExt());
199   TBVectorExt VecExt = TT.getVectorExt().getValue();
200 
201   EXPECT_EQ(VecExt.getNumberOfVRSaved(), 0);
202   EXPECT_TRUE(VecExt.isVRSavedOnStack());
203   EXPECT_FALSE(VecExt.hasVarArgs());
204 
205   EXPECT_EQ(VecExt.getNumberOfVectorParms(), 2u);
206   EXPECT_TRUE(VecExt.hasVMXInstruction());
207 
208   EXPECT_EQ(VecExt.getVectorParmsInfoString(), "vf, vf");
209 
210   ASSERT_TRUE(TT.getExtensionTable());
211   EXPECT_EQ(TT.getExtensionTable().getValue(),
212             ExtendedTBTableFlag::TB_SSP_CANARY);
213 
214   EXPECT_EQ(Size, 45u);
215 }
216 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableAPIHasVectorInfo1)217 TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIHasVectorInfo1) {
218   const uint8_t TBTableData[] = {
219       0x00, 0x00, 0x2A, 0x40, 0x80, 0xc0, 0x03, 0x05, 0x48, 0xc0, 0x00, 0x00,
220       0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x05, 0x05, 0x00, 0x00,
221       0x06, 0x06, 0x00, 0x00, 0x00, 0x07, 0x61, 0x64, 0x64, 0x5f, 0x61, 0x6c,
222       0x6c, 0x11, 0x07, 0x90, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00};
223   uint64_t Size = sizeof(TBTableData);
224   Expected<XCOFFTracebackTable> TTOrErr =
225       XCOFFTracebackTable::create(TBTableData, Size);
226   ASSERT_THAT_EXPECTED(TTOrErr, Succeeded());
227   XCOFFTracebackTable TT = *TTOrErr;
228 
229   ASSERT_TRUE(TT.getParmsType());
230   EXPECT_EQ(TT.getParmsType().getValue(), "v, i, f, i, d, i");
231 
232   ASSERT_TRUE(TT.getVectorExt());
233   TBVectorExt VecExt = TT.getVectorExt().getValue();
234 
235   EXPECT_EQ(VecExt.getNumberOfVRSaved(), 4);
236   EXPECT_FALSE(VecExt.isVRSavedOnStack());
237   EXPECT_TRUE(VecExt.hasVarArgs());
238 
239   EXPECT_EQ(VecExt.getNumberOfVectorParms(), 3u);
240   EXPECT_TRUE(VecExt.hasVMXInstruction());
241 
242   EXPECT_EQ(VecExt.getVectorParmsInfoString(), "vi, vs, vc");
243 
244   ASSERT_TRUE(TT.getExtensionTable());
245   EXPECT_EQ(TT.getExtensionTable().getValue(),
246             ExtendedTBTableFlag::TB_SSP_CANARY);
247 
248   EXPECT_EQ(Size, 44u);
249 }
250 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableTruncatedAtMandatory)251 TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtMandatory) {
252   uint64_t Size = 6;
253   Expected<XCOFFTracebackTable> TTOrErr =
254       XCOFFTracebackTable::create(TBTableData, Size);
255   EXPECT_THAT_ERROR(
256       TTOrErr.takeError(),
257       FailedWithMessage(
258           "unexpected end of data at offset 0x6 while reading [0x0, 0x8)"));
259   EXPECT_EQ(Size, 0u);
260 }
261 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableTruncatedAtParmsType)262 TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtParmsType) {
263   uint64_t Size = 9;
264   Expected<XCOFFTracebackTable> TTOrErr =
265       XCOFFTracebackTable::create(TBTableData, Size);
266   EXPECT_THAT_ERROR(
267       TTOrErr.takeError(),
268       FailedWithMessage(
269           "unexpected end of data at offset 0x9 while reading [0x8, 0xc)"));
270   EXPECT_EQ(Size, 8u);
271 }
272 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableTruncatedAtTBOffset)273 TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtTBOffset) {
274   uint64_t Size = 14;
275   Expected<XCOFFTracebackTable> TTOrErr =
276       XCOFFTracebackTable::create(TBTableData, Size);
277   EXPECT_THAT_ERROR(
278       TTOrErr.takeError(),
279       FailedWithMessage(
280           "unexpected end of data at offset 0xe while reading [0xc, 0x10)"));
281   EXPECT_EQ(Size, 12u);
282 }
283 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableTruncatedAtHandlerMask)284 TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtHandlerMask) {
285   uint8_t V[] = {0x00, 0x00, 0x22, 0xC0, 0x80, 0x00, 0x01, 0x05, 0x58,
286                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x07};
287   uint64_t Size = sizeof(V);
288   Expected<XCOFFTracebackTable> TTOrErr = XCOFFTracebackTable::create(V, Size);
289   EXPECT_THAT_ERROR(
290       TTOrErr.takeError(),
291       FailedWithMessage(
292           "unexpected end of data at offset 0x12 while reading [0x10, 0x14)"));
293   EXPECT_EQ(Size, 16u);
294 }
295 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableTruncatedAtNumOfCtlAnchors)296 TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtNumOfCtlAnchors) {
297   uint64_t Size = 19;
298   Expected<XCOFFTracebackTable> TTOrErr =
299       XCOFFTracebackTable::create(TBTableData, Size);
300   EXPECT_THAT_ERROR(
301       TTOrErr.takeError(),
302       FailedWithMessage(
303           "unexpected end of data at offset 0x13 while reading [0x10, 0x14)"));
304   EXPECT_EQ(Size, 16u);
305 }
306 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableTruncatedAtControlledStorageInfoDisp)307 TEST(XCOFFObjectFileTest,
308      XCOFFTracebackTableTruncatedAtControlledStorageInfoDisp) {
309   uint64_t Size = 21;
310   Expected<XCOFFTracebackTable> TTOrErr =
311       XCOFFTracebackTable::create(TBTableData, Size);
312   EXPECT_THAT_ERROR(
313       TTOrErr.takeError(),
314       FailedWithMessage(
315           "unexpected end of data at offset 0x15 while reading [0x14, 0x18)"));
316   EXPECT_EQ(Size, 20u);
317 }
318 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableTruncatedAtNameLen)319 TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtNameLen) {
320   uint64_t Size = 29;
321   Expected<XCOFFTracebackTable> TTOrErr =
322       XCOFFTracebackTable::create(TBTableData, Size);
323   EXPECT_THAT_ERROR(
324       TTOrErr.takeError(),
325       FailedWithMessage(
326           "unexpected end of data at offset 0x1d while reading [0x1c, 0x1e)"));
327   EXPECT_EQ(Size, 28u);
328 }
329 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableTruncatedAtFunctionName)330 TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtFunctionName) {
331   uint64_t Size = 36;
332   Expected<XCOFFTracebackTable> TTOrErr =
333       XCOFFTracebackTable::create(TBTableData, Size);
334   EXPECT_THAT_ERROR(
335       TTOrErr.takeError(),
336       FailedWithMessage(
337           "unexpected end of data at offset 0x24 while reading [0x1e, 0x25)"));
338   EXPECT_EQ(Size, 30u);
339 }
340 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableTruncatedAtAllocaUsed)341 TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtAllocaUsed) {
342   uint64_t Size = 37;
343   Expected<XCOFFTracebackTable> TTOrErr =
344       XCOFFTracebackTable::create(TBTableData, Size);
345   EXPECT_THAT_ERROR(
346       TTOrErr.takeError(),
347       FailedWithMessage(
348           "unexpected end of data at offset 0x25 while reading [0x25, 0x26)"));
349   EXPECT_EQ(Size, 37u);
350 }
351 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableTruncatedAtVectorInfoData)352 TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtVectorInfoData) {
353   uint64_t Size = 39;
354   Expected<XCOFFTracebackTable> TTOrErr =
355       XCOFFTracebackTable::create(TBTableData, Size);
356 
357   EXPECT_THAT_ERROR(
358       TTOrErr.takeError(),
359       FailedWithMessage(
360           "unexpected end of data at offset 0x27 while reading [0x26, 0x2c)"));
361   EXPECT_EQ(Size, 38u);
362 }
363 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableTruncatedAtVectorInfoParmsInfo)364 TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtVectorInfoParmsInfo) {
365   uint64_t Size = 43;
366   Expected<XCOFFTracebackTable> TTOrErr =
367       XCOFFTracebackTable::create(TBTableData, Size);
368 
369   EXPECT_THAT_ERROR(
370       TTOrErr.takeError(),
371       FailedWithMessage(
372           "unexpected end of data at offset 0x2b while reading [0x26, 0x2c)"));
373   EXPECT_EQ(Size, 38u);
374 }
375 
TEST(XCOFFObjectFileTest,XCOFFTracebackTableTruncatedAtExtLongTBTable)376 TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtExtLongTBTable) {
377   uint64_t Size = 44;
378   Expected<XCOFFTracebackTable> TTOrErr =
379       XCOFFTracebackTable::create(TBTableData, Size);
380 
381   EXPECT_THAT_ERROR(
382       TTOrErr.takeError(),
383       FailedWithMessage(
384           "unexpected end of data at offset 0x2c while reading [0x2c, 0x2d)"));
385   EXPECT_EQ(Size, 44u);
386 }
387