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/InterfaceStub/ELFStub.h" 11 #include "llvm/InterfaceStub/TBEHandler.h" 12 #include "llvm/Support/Error.h" 13 #include "llvm/Testing/Support/Error.h" 14 #include "gtest/gtest.h" 15 #include <string> 16 17 using namespace llvm; 18 using namespace llvm::ELF; 19 using namespace llvm::elfabi; 20 21 void compareByLine(StringRef LHS, StringRef RHS) { 22 StringRef Line1; 23 StringRef Line2; 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 31 // cleanly compared. 32 EXPECT_STREQ(Line1.str().data(), Line2.str().data()); 33 } 34 } 35 36 TEST(ElfYamlTextAPI, YAMLReadableTBE) { 37 const char Data[] = "--- !tapi-tbe\n" 38 "TbeVersion: 1.0\n" 39 "Arch: x86_64\n" 40 "NeededLibs: [libc.so, libfoo.so, libbar.so]\n" 41 "Symbols:\n" 42 " foo: { Type: Func, Undefined: true }\n" 43 "...\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"); 54 } 55 56 TEST(ElfYamlTextAPI, YAMLReadsTBESymbols) { 57 const char Data[] = "--- !tapi-tbe\n" 58 "TbeVersion: 1.0\n" 59 "SoName: test.so\n" 60 "Arch: x86_64\n" 61 "Symbols:\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" 68 "...\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); 76 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()); 85 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()); 93 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!"); 102 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()); 110 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!"); 119 } 120 121 TEST(ElfYamlTextAPI, YAMLReadsNoTBESyms) { 122 const char Data[] = "--- !tapi-tbe\n" 123 "TbeVersion: 1.0\n" 124 "SoName: test.so\n" 125 "Arch: x86_64\n" 126 "Symbols: {}\n" 127 "...\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()); 133 } 134 135 TEST(ElfYamlTextAPI, YAMLUnreadableTBE) { 136 // Can't read: wrong format/version. 137 const char Data[] = "--- !tapi-tbz\n" 138 "TbeVersion: z.3\n" 139 "SoName: test.so\n" 140 "Arch: x86_64\n" 141 "Symbols:\n" 142 " foo: { Type: Func, Undefined: true }\n"; 143 Expected<std::unique_ptr<ELFStub>> StubOrErr = readTBEFromBuffer(Data); 144 ASSERT_THAT_ERROR(StubOrErr.takeError(), Failed()); 145 } 146 147 TEST(ElfYamlTextAPI, YAMLUnsupportedVersion) { 148 const char Data[] = "--- !tapi-tbe\n" 149 "TbeVersion: 9.9.9\n" 150 "SoName: test.so\n" 151 "Arch: x86_64\n" 152 "Symbols: {}\n" 153 "...\n"; 154 Expected<std::unique_ptr<ELFStub>> StubOrErr = readTBEFromBuffer(Data); 155 std::string ErrorMessage = toString(StubOrErr.takeError()); 156 EXPECT_EQ("TBE version 9.9.9 is unsupported.", ErrorMessage); 157 } 158 159 TEST(ElfYamlTextAPI, YAMLWritesTBESymbols) { 160 const char Expected[] = 161 "--- !tapi-tbe\n" 162 "TbeVersion: 1.0\n" 163 "Arch: AArch64\n" 164 "Symbols:\n" 165 " bar: { Type: Func, Weak: true }\n" 166 " foo: { Type: NoType, Size: 99, Warning: Does nothing }\n" 167 " nor: { Type: Func, Undefined: true }\n" 168 " not: { Type: Unknown, Size: 12345678901234 }\n" 169 "...\n"; 170 ELFStub Stub; 171 Stub.TbeVersion = VersionTuple(1, 0); 172 Stub.Arch = ELF::EM_AARCH64; 173 174 ELFSymbol SymFoo("foo"); 175 SymFoo.Size = 99u; 176 SymFoo.Type = ELFSymbolType::NoType; 177 SymFoo.Undefined = false; 178 SymFoo.Weak = false; 179 SymFoo.Warning = "Does nothing"; 180 181 ELFSymbol SymBar("bar"); 182 SymBar.Size = 128u; 183 SymBar.Type = ELFSymbolType::Func; 184 SymBar.Undefined = false; 185 SymBar.Weak = true; 186 187 ELFSymbol SymNor("nor"); 188 SymNor.Size = 1234u; 189 SymNor.Type = ELFSymbolType::Func; 190 SymNor.Undefined = true; 191 SymNor.Weak = false; 192 193 ELFSymbol SymNot("not"); 194 SymNot.Size = 12345678901234u; 195 SymNot.Type = ELFSymbolType::Unknown; 196 SymNot.Undefined = false; 197 SymNot.Weak = false; 198 199 // Deliberately not in order to check that result is sorted. 200 Stub.Symbols.insert(SymNot); 201 Stub.Symbols.insert(SymBar); 202 Stub.Symbols.insert(SymFoo); 203 Stub.Symbols.insert(SymNor); 204 205 // Ensure move constructor works as expected. 206 ELFStub Moved = std::move(Stub); 207 208 std::string Result; 209 raw_string_ostream OS(Result); 210 ASSERT_THAT_ERROR(writeTBEToOutputStream(OS, Moved), Succeeded()); 211 Result = OS.str(); 212 compareByLine(Result.c_str(), Expected); 213 } 214 215 TEST(ElfYamlTextAPI, YAMLWritesNoTBESyms) { 216 const char Expected[] = "--- !tapi-tbe\n" 217 "TbeVersion: 1.0\n" 218 "SoName: nosyms.so\n" 219 "Arch: x86_64\n" 220 "NeededLibs:\n" 221 " - libc.so\n" 222 " - libfoo.so\n" 223 " - libbar.so\n" 224 "Symbols: {}\n" 225 "...\n"; 226 ELFStub Stub; 227 Stub.TbeVersion = VersionTuple(1, 0); 228 Stub.SoName = "nosyms.so"; 229 Stub.Arch = ELF::EM_X86_64; 230 Stub.NeededLibs.push_back("libc.so"); 231 Stub.NeededLibs.push_back("libfoo.so"); 232 Stub.NeededLibs.push_back("libbar.so"); 233 234 std::string Result; 235 raw_string_ostream OS(Result); 236 ASSERT_THAT_ERROR(writeTBEToOutputStream(OS, Stub), Succeeded()); 237 Result = OS.str(); 238 compareByLine(Result.c_str(), Expected); 239 } 240