1 //===- llvm/unittests/TextAPI/YAMLTest.cpp --------------------------------===//
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
7 //===-----------------------------------------------------------------------===/
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"
19 using namespace llvm::ELF
;
20 using namespace llvm::ifs
;
22 void compareByLine(StringRef LHS
, StringRef RHS
) {
25 while (LHS
.size() > 0 && RHS
.size() > 0) {
26 std::tie(Line1
, LHS
) = LHS
.split('\n');
27 std::tie(Line2
, RHS
) = RHS
.split('\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
33 EXPECT_STREQ(Line1
.str().data(), Line2
.str().data());
37 TEST(ElfYamlTextAPI
, YAMLReadableTBE
) {
38 const char Data
[] = "--- !ifs-v1\n"
40 "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: "
41 "little, BitWidth: 64 }\n"
42 "NeededLibs: [libc.so, libfoo.so, libbar.so]\n"
44 " - { Name: foo, Type: Func, Undefined: true }\n"
46 Expected
<std::unique_ptr
<IFSStub
>> StubOrErr
= readIFSFromBuffer(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");
59 TEST(ElfYamlTextAPI
, YAMLReadsInvalidSymbols
) {
64 "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: little, "
67 " - { Name: not, Type: File, Undefined: true, Size: 111, "
68 "Weak: true, Warning: \'All fields populated!\' }\n"
70 Expected
<std::unique_ptr
<IFSStub
>> StubOrErr
= readIFSFromBuffer(Data
);
72 StubOrErr
.takeError(),
73 FailedWithMessage("IFS symbol type for symbol 'not' is unsupported"));
76 TEST(ElfYamlTextAPI
, YAMLReadsTBESymbols
) {
81 "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: little, "
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"
91 Expected
<std::unique_ptr
<IFSStub
>> StubOrErr
= readIFSFromBuffer(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);
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
);
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());
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!");
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());
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!");
143 TEST(ElfYamlTextAPI
, YAMLReadsNoTBESyms
) {
144 const char Data
[] = "--- !ifs-v1\n"
147 "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: "
148 "little, BitWidth: 64 }\n"
151 Expected
<std::unique_ptr
<IFSStub
>> StubOrErr
= readIFSFromBuffer(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());
158 TEST(ElfYamlTextAPI
, YAMLUnreadableTBE
) {
159 // Can't read: wrong format/version.
160 const char Data
[] = "--- !tapi-tbz\n"
163 "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: "
164 "little, BitWidth: 64 }\n"
166 " foo: { Type: Func, Undefined: true }\n";
167 Expected
<std::unique_ptr
<IFSStub
>> StubOrErr
= readIFSFromBuffer(Data
);
168 ASSERT_THAT_ERROR(StubOrErr
.takeError(), Failed());
171 TEST(ElfYamlTextAPI
, YAMLUnsupportedVersion
) {
172 const char Data
[] = "--- !ifs-v1\n"
173 "IfsVersion: 9.9.9\n"
175 "Target: { ObjectFormat: ELF, Arch: x86_64, Endianness: "
176 "little, BitWidth: 64 }\n"
179 Expected
<std::unique_ptr
<IFSStub
>> StubOrErr
= readIFSFromBuffer(Data
);
180 std::string ErrorMessage
= toString(StubOrErr
.takeError());
181 EXPECT_EQ("IFS version 9.9.9 is unsupported.", ErrorMessage
);
184 TEST(ElfYamlTextAPI
, YAMLWritesTBESymbols
) {
185 const char Expected
[] =
188 "Target: { ObjectFormat: ELF, Arch: AArch64, Endianness: "
189 "little, BitWidth: 64 }\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"
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";
203 IFSSymbol
SymBar("bar");
205 SymBar
.Type
= IFSSymbolType::Func
;
206 SymBar
.Undefined
= false;
209 IFSSymbol
SymFoo("foo");
211 SymFoo
.Type
= IFSSymbolType::NoType
;
212 SymFoo
.Undefined
= false;
214 SymFoo
.Warning
= "Does nothing";
216 IFSSymbol
SymNor("nor");
218 SymNor
.Type
= IFSSymbolType::Func
;
219 SymNor
.Undefined
= true;
222 IFSSymbol
SymNot("not");
223 SymNot
.Size
= 12345678901234u;
224 SymNot
.Type
= IFSSymbolType::Unknown
;
225 SymNot
.Undefined
= false;
228 // Symbol order is preserved instead of being sorted.
229 Stub
.Symbols
.push_back(SymBar
);
230 Stub
.Symbols
.push_back(SymFoo
);
231 Stub
.Symbols
.push_back(SymNor
);
232 Stub
.Symbols
.push_back(SymNot
);
234 // Ensure move constructor works as expected.
235 IFSStub Moved
= std::move(Stub
);
238 raw_string_ostream
OS(Result
);
239 ASSERT_THAT_ERROR(writeIFSToOutputStream(OS
, Moved
), Succeeded());
241 compareByLine(Result
.c_str(), Expected
);
244 TEST(ElfYamlTextAPI
, YAMLWritesNoTBESyms
) {
245 const char Expected
[] = "--- !ifs-v1\n"
247 "SoName: nosyms.so\n"
248 "Target: { ObjectFormat: ELF, Arch: x86_64, "
249 "Endianness: little, BitWidth: 64 }\n"
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("libc.so");
264 Stub
.NeededLibs
.push_back("libfoo.so");
265 Stub
.NeededLibs
.push_back("libbar.so");
268 raw_string_ostream
OS(Result
);
269 ASSERT_THAT_ERROR(writeIFSToOutputStream(OS
, Stub
), Succeeded());
271 compareByLine(Result
.c_str(), Expected
);