1//===- llvm/unittests/TextAPI/YAMLTest.cpp --------------------------------===//
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/ADT/StringRef.h"
10#include "llvm/BinaryFormat/ELF.h"
11#include "llvm/InterfaceStub/IFSHandler.h"
12#include "llvm/InterfaceStub/IFSStub.h"
13#include "llvm/Support/Error.h"
14#include "llvm/Testing/Support/Error.h"
15#include "gtest/gtest.h"
16#include <string>
17
18using namespace llvm;
19using namespace llvm::ELF;
20using namespace llvm::ifs;
21
22void compareByLine(StringRef LHS, StringRef RHS) {
23 StringRef Line1;
24 StringRef Line2;
25 while (LHS.size() > 0 && RHS.size() > 0) {
26 std::tie(args&: Line1, args&: LHS) = LHS.split(Separator: '\n');
27 std::tie(args&: Line2, args&: RHS) = RHS.split(Separator: '\n');
28 // Comparing StringRef objects works, but has messy output when not equal.
29 // Using STREQ on StringRef.data() doesn't work since these substrings are
30 // not null terminated.
31 // This is inefficient, but forces null terminated strings that can be
32 // cleanly compared.
33 EXPECT_STREQ(Line1.str().data(), Line2.str().data());
34 }
35}
36
37TEST(ElfYamlTextAPI, YAMLReadableTBE) {
38 const char Data[] = "--- !ifs-v1\n"
39 "IfsVersion: 1.0\n"
40 "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: "
41 "little, BitWidth: 64 }\n"
42 "NeededLibs: [libc.so, libfoo.so, libbar.so]\n"
43 "Symbols:\n"
44 " - { Name: foo, Type: Func, Undefined: true }\n"
45 "...\n";
46 Expected<std::unique_ptr<IFSStub>> StubOrErr = readIFSFromBuffer(Buf: Data);
47 ASSERT_THAT_ERROR(StubOrErr.takeError(), Succeeded());
48 std::unique_ptr<IFSStub> Stub = std::move(StubOrErr.get());
49 EXPECT_NE(Stub.get(), nullptr);
50 EXPECT_FALSE(Stub->SoName.has_value());
51 EXPECT_TRUE(Stub->Target.Arch.has_value());
52 EXPECT_EQ(*Stub->Target.Arch, (uint16_t)llvm::ELF::EM_X86_64);
53 EXPECT_EQ(Stub->NeededLibs.size(), 3u);
54 EXPECT_STREQ(Stub->NeededLibs[0].c_str(), "libc.so");
55 EXPECT_STREQ(Stub->NeededLibs[1].c_str(), "libfoo.so");
56 EXPECT_STREQ(Stub->NeededLibs[2].c_str(), "libbar.so");
57}
58
59TEST(ElfYamlTextAPI, YAMLReadsInvalidSymbols) {
60 const char Data[] =
61 "--- !ifs-v1\n"
62 "IfsVersion: 1.0\n"
63 "SoName: test.so\n"
64 "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: little, "
65 "BitWidth: 64 }\n"
66 "Symbols:\n"
67 " - { Name: not, Type: File, Undefined: true, Size: 111, "
68 "Weak: true, Warning: \'All fields populated!\' }\n"
69 "...\n";
70 Expected<std::unique_ptr<IFSStub>> StubOrErr = readIFSFromBuffer(Buf: Data);
71 ASSERT_THAT_ERROR(
72 StubOrErr.takeError(),
73 FailedWithMessage("IFS symbol type for symbol 'not' is unsupported"));
74}
75
76TEST(ElfYamlTextAPI, YAMLReadsTBESymbols) {
77 const char Data[] =
78 "--- !ifs-v1\n"
79 "IfsVersion: 1.0\n"
80 "SoName: test.so\n"
81 "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: little, "
82 "BitWidth: 64 }\n"
83 "Symbols:\n"
84 " - { Name: bar, Type: Object, Size: 42 }\n"
85 " - { Name: baz, Type: TLS, Size: 3 }\n"
86 " - { Name: foo, Type: Func, Warning: \"Deprecated!\" }\n"
87 " - { Name: nor, Type: NoType, Undefined: true }\n"
88 " - { Name: not, Type: NoType, Undefined: true, Size: 111, "
89 "Weak: true, Warning: \'All fields populated!\' }\n"
90 "...\n";
91 Expected<std::unique_ptr<IFSStub>> StubOrErr = readIFSFromBuffer(Buf: Data);
92 ASSERT_THAT_ERROR(StubOrErr.takeError(), Succeeded());
93 std::unique_ptr<IFSStub> Stub = std::move(StubOrErr.get());
94 EXPECT_NE(Stub.get(), nullptr);
95 EXPECT_TRUE(Stub->SoName);
96 EXPECT_STREQ(Stub->SoName->c_str(), "test.so");
97 EXPECT_EQ(Stub->Symbols.size(), 5u);
98
99 auto Iterator = Stub->Symbols.begin();
100 IFSSymbol const &SymBar = *Iterator++;
101 EXPECT_STREQ(SymBar.Name.c_str(), "bar");
102 EXPECT_EQ(*SymBar.Size, 42u);
103 EXPECT_EQ(SymBar.Type, IFSSymbolType::Object);
104 EXPECT_FALSE(SymBar.Undefined);
105 EXPECT_FALSE(SymBar.Weak);
106 EXPECT_FALSE(SymBar.Warning);
107
108 IFSSymbol const &SymBaz = *Iterator++;
109 EXPECT_STREQ(SymBaz.Name.c_str(), "baz");
110 EXPECT_EQ(*SymBaz.Size, 3u);
111 EXPECT_EQ(SymBaz.Type, IFSSymbolType::TLS);
112 EXPECT_FALSE(SymBaz.Undefined);
113 EXPECT_FALSE(SymBaz.Weak);
114 EXPECT_FALSE(SymBaz.Warning.has_value());
115
116 IFSSymbol const &SymFoo = *Iterator++;
117 EXPECT_STREQ(SymFoo.Name.c_str(), "foo");
118 EXPECT_FALSE(SymFoo.Size.has_value());
119 EXPECT_EQ(SymFoo.Type, IFSSymbolType::Func);
120 EXPECT_FALSE(SymFoo.Undefined);
121 EXPECT_FALSE(SymFoo.Weak);
122 EXPECT_TRUE(SymFoo.Warning.has_value());
123 EXPECT_STREQ(SymFoo.Warning->c_str(), "Deprecated!");
124
125 IFSSymbol const &SymNor = *Iterator++;
126 EXPECT_STREQ(SymNor.Name.c_str(), "nor");
127 EXPECT_FALSE(SymNor.Size.has_value());
128 EXPECT_EQ(SymNor.Type, IFSSymbolType::NoType);
129 EXPECT_TRUE(SymNor.Undefined);
130 EXPECT_FALSE(SymNor.Weak);
131 EXPECT_FALSE(SymNor.Warning.has_value());
132
133 IFSSymbol const &SymNot = *Iterator++;
134 EXPECT_STREQ(SymNot.Name.c_str(), "not");
135 EXPECT_EQ(*SymNot.Size, 111u);
136 EXPECT_EQ(SymNot.Type, IFSSymbolType::NoType);
137 EXPECT_TRUE(SymNot.Undefined);
138 EXPECT_TRUE(SymNot.Weak);
139 EXPECT_TRUE(SymNot.Warning);
140 EXPECT_STREQ(SymNot.Warning->c_str(), "All fields populated!");
141}
142
143TEST(ElfYamlTextAPI, YAMLReadsNoTBESyms) {
144 const char Data[] = "--- !ifs-v1\n"
145 "IfsVersion: 1.0\n"
146 "SoName: test.so\n"
147 "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: "
148 "little, BitWidth: 64 }\n"
149 "Symbols: []\n"
150 "...\n";
151 Expected<std::unique_ptr<IFSStub>> StubOrErr = readIFSFromBuffer(Buf: Data);
152 ASSERT_THAT_ERROR(StubOrErr.takeError(), Succeeded());
153 std::unique_ptr<IFSStub> Stub = std::move(StubOrErr.get());
154 EXPECT_NE(Stub.get(), nullptr);
155 EXPECT_EQ(0u, Stub->Symbols.size());
156}
157
158TEST(ElfYamlTextAPI, YAMLUnreadableTBE) {
159 // Can't read: wrong format/version.
160 const char Data[] = "--- !tapi-tbz\n"
161 "IfsVersion: z.3\n"
162 "SoName: test.so\n"
163 "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: "
164 "little, BitWidth: 64 }\n"
165 "Symbols:\n"
166 " foo: { Type: Func, Undefined: true }\n";
167 Expected<std::unique_ptr<IFSStub>> StubOrErr = readIFSFromBuffer(Buf: Data);
168 ASSERT_THAT_ERROR(StubOrErr.takeError(), Failed());
169}
170
171TEST(ElfYamlTextAPI, YAMLUnsupportedVersion) {
172 const char Data[] = "--- !ifs-v1\n"
173 "IfsVersion: 9.9.9\n"
174 "SoName: test.so\n"
175 "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: "
176 "little, BitWidth: 64 }\n"
177 "Symbols: []\n"
178 "...\n";
179 Expected<std::unique_ptr<IFSStub>> StubOrErr = readIFSFromBuffer(Buf: Data);
180 std::string ErrorMessage = toString(E: StubOrErr.takeError());
181 EXPECT_EQ("IFS version 9.9.9 is unsupported.", ErrorMessage);
182}
183
184TEST(ElfYamlTextAPI, YAMLWritesTBESymbols) {
185 const char Expected[] =
186 "--- !ifs-v1\n"
187 "IfsVersion: 1.0\n"
188 "Target: { ObjectFormat: ELF, Arch: AArch64, Endianness: "
189 "little, BitWidth: 64 }\n"
190 "Symbols:\n"
191 " - { Name: bar, Type: Func, Weak: true }\n"
192 " - { Name: foo, Type: NoType, Size: 99, Warning: Does nothing }\n"
193 " - { Name: nor, Type: Func, Undefined: true }\n"
194 " - { Name: not, Type: Unknown, Size: 12345678901234 }\n"
195 "...\n";
196 IFSStub Stub;
197 Stub.IfsVersion = VersionTuple(1, 0);
198 Stub.Target.Arch = ELF::EM_AARCH64;
199 Stub.Target.BitWidth = IFSBitWidthType::IFS64;
200 Stub.Target.Endianness = IFSEndiannessType::Little;
201 Stub.Target.ObjectFormat = "ELF";
202
203 IFSSymbol SymBar("bar");
204 SymBar.Size = 128u;
205 SymBar.Type = IFSSymbolType::Func;
206 SymBar.Undefined = false;
207 SymBar.Weak = true;
208
209 IFSSymbol SymFoo("foo");
210 SymFoo.Size = 99u;
211 SymFoo.Type = IFSSymbolType::NoType;
212 SymFoo.Undefined = false;
213 SymFoo.Weak = false;
214 SymFoo.Warning = "Does nothing";
215
216 IFSSymbol SymNor("nor");
217 SymNor.Size = 1234u;
218 SymNor.Type = IFSSymbolType::Func;
219 SymNor.Undefined = true;
220 SymNor.Weak = false;
221
222 IFSSymbol SymNot("not");
223 SymNot.Size = 12345678901234u;
224 SymNot.Type = IFSSymbolType::Unknown;
225 SymNot.Undefined = false;
226 SymNot.Weak = false;
227
228 // Symbol order is preserved instead of being sorted.
229 Stub.Symbols.push_back(x: SymBar);
230 Stub.Symbols.push_back(x: SymFoo);
231 Stub.Symbols.push_back(x: SymNor);
232 Stub.Symbols.push_back(x: SymNot);
233
234 // Ensure move constructor works as expected.
235 IFSStub Moved = std::move(Stub);
236
237 std::string Result;
238 raw_string_ostream OS(Result);
239 ASSERT_THAT_ERROR(writeIFSToOutputStream(OS, Moved), Succeeded());
240 Result = OS.str();
241 compareByLine(LHS: Result.c_str(), RHS: Expected);
242}
243
244TEST(ElfYamlTextAPI, YAMLWritesNoTBESyms) {
245 const char Expected[] = "--- !ifs-v1\n"
246 "IfsVersion: 1.0\n"
247 "SoName: nosyms.so\n"
248 "Target: { ObjectFormat: ELF, Arch: x86_64, "
249 "Endianness: little, BitWidth: 64 }\n"
250 "NeededLibs:\n"
251 " - libc.so\n"
252 " - libfoo.so\n"
253 " - libbar.so\n"
254 "Symbols: []\n"
255 "...\n";
256 IFSStub Stub;
257 Stub.IfsVersion = VersionTuple(1, 0);
258 Stub.SoName = "nosyms.so";
259 Stub.Target.Arch = ELF::EM_X86_64;
260 Stub.Target.BitWidth = IFSBitWidthType::IFS64;
261 Stub.Target.Endianness = IFSEndiannessType::Little;
262 Stub.Target.ObjectFormat = "ELF";
263 Stub.NeededLibs.push_back(x: "libc.so");
264 Stub.NeededLibs.push_back(x: "libfoo.so");
265 Stub.NeededLibs.push_back(x: "libbar.so");
266
267 std::string Result;
268 raw_string_ostream OS(Result);
269 ASSERT_THAT_ERROR(writeIFSToOutputStream(OS, Stub), Succeeded());
270 Result = OS.str();
271 compareByLine(LHS: Result.c_str(), RHS: Expected);
272}
273

source code of llvm/unittests/InterfaceStub/ELFYAMLTest.cpp