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/TextAPI/ELF/ELFStub.h"
11 #include "llvm/TextAPI/ELF/TBEHandler.h"
12 #include "llvm/Support/Error.h"
13 #include "llvm/Testing/Support/Error.h"
14 #include "gtest/gtest.h"
18 using namespace llvm::ELF
;
19 using namespace llvm::elfabi
;
21 void compareByLine(StringRef LHS
, StringRef RHS
) {
24 while (LHS
.size() > 0 && RHS
.size() > 0) {
25 std::tie(Line1
, LHS
) = LHS
.split('\n');
26 std::tie(Line2
, RHS
) = RHS
.split('\n');
27 // Comparing StringRef objects works, but has messy output when not equal.
28 // Using STREQ on StringRef.data() doesn't work since these substrings are
29 // not null terminated.
30 // This is inefficient, but forces null terminated strings that can be
32 EXPECT_STREQ(Line1
.str().data(), Line2
.str().data());
36 TEST(ElfYamlTextAPI
, YAMLReadableTBE
) {
37 const char Data
[] = "--- !tapi-tbe\n"
40 "NeededLibs: [libc.so, libfoo.so, libbar.so]\n"
42 " foo: { Type: Func, Undefined: true }\n"
44 Expected
<std::unique_ptr
<ELFStub
>> StubOrErr
= readTBEFromBuffer(Data
);
45 ASSERT_THAT_ERROR(StubOrErr
.takeError(), Succeeded());
46 std::unique_ptr
<ELFStub
> Stub
= std::move(StubOrErr
.get());
47 EXPECT_NE(Stub
.get(), nullptr);
48 EXPECT_FALSE(Stub
->SoName
.hasValue());
49 EXPECT_EQ(Stub
->Arch
, (uint16_t)llvm::ELF::EM_X86_64
);
50 EXPECT_EQ(Stub
->NeededLibs
.size(), 3u);
51 EXPECT_STREQ(Stub
->NeededLibs
[0].c_str(), "libc.so");
52 EXPECT_STREQ(Stub
->NeededLibs
[1].c_str(), "libfoo.so");
53 EXPECT_STREQ(Stub
->NeededLibs
[2].c_str(), "libbar.so");
56 TEST(ElfYamlTextAPI
, YAMLReadsTBESymbols
) {
57 const char Data
[] = "--- !tapi-tbe\n"
62 " bar: { Type: Object, Size: 42 }\n"
63 " baz: { Type: TLS, Size: 3 }\n"
64 " foo: { Type: Func, Warning: \"Deprecated!\" }\n"
65 " nor: { Type: NoType, Undefined: true }\n"
66 " not: { Type: File, Undefined: true, Size: 111, "
67 "Weak: true, Warning: \'All fields populated!\' }\n"
69 Expected
<std::unique_ptr
<ELFStub
>> StubOrErr
= readTBEFromBuffer(Data
);
70 ASSERT_THAT_ERROR(StubOrErr
.takeError(), Succeeded());
71 std::unique_ptr
<ELFStub
> Stub
= std::move(StubOrErr
.get());
72 EXPECT_NE(Stub
.get(), nullptr);
73 EXPECT_TRUE(Stub
->SoName
.hasValue());
74 EXPECT_STREQ(Stub
->SoName
->c_str(), "test.so");
75 EXPECT_EQ(Stub
->Symbols
.size(), 5u);
77 auto Iterator
= Stub
->Symbols
.begin();
78 ELFSymbol
const &SymBar
= *Iterator
++;
79 EXPECT_STREQ(SymBar
.Name
.c_str(), "bar");
80 EXPECT_EQ(SymBar
.Size
, 42u);
81 EXPECT_EQ(SymBar
.Type
, ELFSymbolType::Object
);
82 EXPECT_FALSE(SymBar
.Undefined
);
83 EXPECT_FALSE(SymBar
.Weak
);
84 EXPECT_FALSE(SymBar
.Warning
.hasValue());
86 ELFSymbol
const &SymBaz
= *Iterator
++;
87 EXPECT_STREQ(SymBaz
.Name
.c_str(), "baz");
88 EXPECT_EQ(SymBaz
.Size
, 3u);
89 EXPECT_EQ(SymBaz
.Type
, ELFSymbolType::TLS
);
90 EXPECT_FALSE(SymBaz
.Undefined
);
91 EXPECT_FALSE(SymBaz
.Weak
);
92 EXPECT_FALSE(SymBaz
.Warning
.hasValue());
94 ELFSymbol
const &SymFoo
= *Iterator
++;
95 EXPECT_STREQ(SymFoo
.Name
.c_str(), "foo");
96 EXPECT_EQ(SymFoo
.Size
, 0u);
97 EXPECT_EQ(SymFoo
.Type
, ELFSymbolType::Func
);
98 EXPECT_FALSE(SymFoo
.Undefined
);
99 EXPECT_FALSE(SymFoo
.Weak
);
100 EXPECT_TRUE(SymFoo
.Warning
.hasValue());
101 EXPECT_STREQ(SymFoo
.Warning
->c_str(), "Deprecated!");
103 ELFSymbol
const &SymNor
= *Iterator
++;
104 EXPECT_STREQ(SymNor
.Name
.c_str(), "nor");
105 EXPECT_EQ(SymNor
.Size
, 0u);
106 EXPECT_EQ(SymNor
.Type
, ELFSymbolType::NoType
);
107 EXPECT_TRUE(SymNor
.Undefined
);
108 EXPECT_FALSE(SymNor
.Weak
);
109 EXPECT_FALSE(SymNor
.Warning
.hasValue());
111 ELFSymbol
const &SymNot
= *Iterator
++;
112 EXPECT_STREQ(SymNot
.Name
.c_str(), "not");
113 EXPECT_EQ(SymNot
.Size
, 111u);
114 EXPECT_EQ(SymNot
.Type
, ELFSymbolType::Unknown
);
115 EXPECT_TRUE(SymNot
.Undefined
);
116 EXPECT_TRUE(SymNot
.Weak
);
117 EXPECT_TRUE(SymNot
.Warning
.hasValue());
118 EXPECT_STREQ(SymNot
.Warning
->c_str(), "All fields populated!");
121 TEST(ElfYamlTextAPI
, YAMLReadsNoTBESyms
) {
122 const char Data
[] = "--- !tapi-tbe\n"
128 Expected
<std::unique_ptr
<ELFStub
>> StubOrErr
= readTBEFromBuffer(Data
);
129 ASSERT_THAT_ERROR(StubOrErr
.takeError(), Succeeded());
130 std::unique_ptr
<ELFStub
> Stub
= std::move(StubOrErr
.get());
131 EXPECT_NE(Stub
.get(), nullptr);
132 EXPECT_EQ(0u, Stub
->Symbols
.size());
135 TEST(ElfYamlTextAPI
, YAMLUnreadableTBE
) {
136 // Can't read: wrong format/version.
137 const char Data
[] = "--- !tapi-tbz\n"
142 " foo: { Type: Func, Undefined: true }\n";
143 Expected
<std::unique_ptr
<ELFStub
>> StubOrErr
= readTBEFromBuffer(Data
);
144 ASSERT_THAT_ERROR(StubOrErr
.takeError(), Failed());
147 TEST(ElfYamlTextAPI
, YAMLWritesTBESymbols
) {
148 const char Expected
[] =
153 " bar: { Type: Func, Weak: true }\n"
154 " foo: { Type: NoType, Size: 99, Warning: Does nothing }\n"
155 " nor: { Type: Func, Undefined: true }\n"
156 " not: { Type: Unknown, Size: 12345678901234 }\n"
159 Stub
.TbeVersion
= VersionTuple(1, 0);
160 Stub
.Arch
= ELF::EM_AARCH64
;
162 ELFSymbol
SymFoo("foo");
164 SymFoo
.Type
= ELFSymbolType::NoType
;
165 SymFoo
.Undefined
= false;
167 SymFoo
.Warning
= "Does nothing";
169 ELFSymbol
SymBar("bar");
171 SymBar
.Type
= ELFSymbolType::Func
;
172 SymBar
.Undefined
= false;
175 ELFSymbol
SymNor("nor");
177 SymNor
.Type
= ELFSymbolType::Func
;
178 SymNor
.Undefined
= true;
181 ELFSymbol
SymNot("not");
182 SymNot
.Size
= 12345678901234u;
183 SymNot
.Type
= ELFSymbolType::Unknown
;
184 SymNot
.Undefined
= false;
187 // Deliberately not in order to check that result is sorted.
188 Stub
.Symbols
.insert(SymNot
);
189 Stub
.Symbols
.insert(SymBar
);
190 Stub
.Symbols
.insert(SymFoo
);
191 Stub
.Symbols
.insert(SymNor
);
193 // Ensure move constructor works as expected.
194 ELFStub Moved
= std::move(Stub
);
197 raw_string_ostream
OS(Result
);
198 ASSERT_THAT_ERROR(writeTBEToOutputStream(OS
, Moved
), Succeeded());
200 compareByLine(Result
.c_str(), Expected
);
203 TEST(ElfYamlTextAPI
, YAMLWritesNoTBESyms
) {
204 const char Expected
[] = "--- !tapi-tbe\n"
206 "SoName: nosyms.so\n"
215 Stub
.TbeVersion
= VersionTuple(1, 0);
216 Stub
.SoName
= "nosyms.so";
217 Stub
.Arch
= ELF::EM_X86_64
;
218 Stub
.NeededLibs
.push_back("libc.so");
219 Stub
.NeededLibs
.push_back("libfoo.so");
220 Stub
.NeededLibs
.push_back("libbar.so");
223 raw_string_ostream
OS(Result
);
224 ASSERT_THAT_ERROR(writeTBEToOutputStream(OS
, Stub
), Succeeded());
226 compareByLine(Result
.c_str(), Expected
);