diff options
author | Armando Montanez <amontanez@google.com> | 2018-12-03 19:30:52 +0000 |
---|---|---|
committer | Armando Montanez <amontanez@google.com> | 2018-12-03 19:30:52 +0000 |
commit | 1e4b3709bb7d8a67a3382bf1e72364b0a9bd7429 (patch) | |
tree | f7b20de517b562360b7669b670e156d1dbc7875d /llvm/unittests/TextAPI/ELFYAMLTest.cpp | |
parent | 00f1d76738a50374019a47d30d09ee1829fe4a65 (diff) | |
download | bcm5719-llvm-1e4b3709bb7d8a67a3382bf1e72364b0a9bd7429.tar.gz bcm5719-llvm-1e4b3709bb7d8a67a3382bf1e72364b0a9bd7429.zip |
[llvm-tapi] initial commit, supports ELF text stubs
http://lists.llvm.org/pipermail/llvm-dev/2018-September/126472.html
TextAPI is a library and accompanying tool that allows conversion between binary shared object stubs and textual counterparts. The motivations and uses cases for this are explained thoroughly in the llvm-dev proposal [1]. This initial commit proposes a potential structure for the TAPI library, also including support for reading/writing text-based ELF stubs (.tbe) in addition to preliminary support for reading binary ELF files. The goal for this patch is to ensure the project architecture appropriately welcomes integration of Mach-O stubbing from Apple's TAPI [2].
Added:
- TextAPI library
- .tbe read support
- .tbe write (to raw_ostream) support
[1] http://lists.llvm.org/pipermail/llvm-dev/2018-September/126472.html
[2] https://github.com/ributzka/tapi
Differential Revision: https://reviews.llvm.org/D53051
llvm-svn: 348170
Diffstat (limited to 'llvm/unittests/TextAPI/ELFYAMLTest.cpp')
-rw-r--r-- | llvm/unittests/TextAPI/ELFYAMLTest.cpp | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/llvm/unittests/TextAPI/ELFYAMLTest.cpp b/llvm/unittests/TextAPI/ELFYAMLTest.cpp new file mode 100644 index 00000000000..4616531de98 --- /dev/null +++ b/llvm/unittests/TextAPI/ELFYAMLTest.cpp @@ -0,0 +1,216 @@ +//===- llvm/unittests/TextAPI/YAMLTest.cpp --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===-----------------------------------------------------------------------===/ + +#include "llvm/ADT/StringRef.h" +#include "llvm/TextAPI/ELF/ELFStub.h" +#include "llvm/TextAPI/ELF/TBEHandler.h" +#include "llvm/Support/Error.h" +#include "gtest/gtest.h" +#include <string> + +using namespace llvm; +using namespace llvm::ELF; +using namespace llvm::elfabi; + +std::unique_ptr<ELFStub> readFromBuffer(const char Data[]) { + TBEHandler Handler; + + StringRef Buf(Data); + + std::unique_ptr<ELFStub> Stub = Handler.readFile(Buf); + EXPECT_NE(Stub.get(), nullptr); + return Stub; +} + +void compareByLine(StringRef LHS, StringRef RHS) { + StringRef Line1; + StringRef Line2; + while (LHS.size() > 0 && RHS.size() > 0) { + std::tie(Line1, LHS) = LHS.split('\n'); + std::tie(Line2, RHS) = RHS.split('\n'); + // Comparing StringRef objects works, but has messy output when not equal. + // Using STREQ on StringRef.data() doesn't work since these substrings are + // not null terminated. + // This is inefficient, but forces null terminated strings that can be + // cleanly compared. + EXPECT_STREQ(Line1.str().data(), Line2.str().data()); + } +} + +TEST(ElfYamlTextAPI, YAMLReadableTBE) { + const char Data[] = "--- !tapi-tbe\n" + "TbeVersion: 1.0\n" + "SoName: test.so\n" + "Arch: x86_64\n" + "NeededLibs: [libc.so, libfoo.so, libbar.so]\n" + "Symbols:\n" + " foo: { Type: Func, Undefined: true }\n" + "...\n"; + StringRef Buf = StringRef(Data); + TBEHandler Handler; + std::unique_ptr<ELFStub> Stub = Handler.readFile(Buf); + EXPECT_NE(Stub.get(), nullptr); + EXPECT_EQ(Stub->Arch, (uint16_t)llvm::ELF::EM_X86_64); + EXPECT_STREQ(Stub->SoName.c_str(), "test.so"); + EXPECT_EQ(Stub->NeededLibs.size(), 3u); + EXPECT_STREQ(Stub->NeededLibs[0].c_str(), "libc.so"); + EXPECT_STREQ(Stub->NeededLibs[1].c_str(), "libfoo.so"); + EXPECT_STREQ(Stub->NeededLibs[2].c_str(), "libbar.so"); +} + +TEST(ElfYamlTextAPI, YAMLReadsTBESymbols) { + const char Data[] = "--- !tapi-tbe\n" + "TbeVersion: 1.0\n" + "SoName: test.so\n" + "Arch: x86_64\n" + "Symbols:\n" + " bar: { Type: Object, Size: 42 }\n" + " baz: { Type: TLS, Size: 3 }\n" + " foo: { Type: Func, Warning: \"Deprecated!\" }\n" + " nor: { Type: NoType, Undefined: true }\n" + " not: { Type: File, Undefined: true, Size: 111, " + "Warning: \'All fields populated!\' }\n" + "...\n"; + std::unique_ptr<ELFStub> Stub = readFromBuffer(Data); + EXPECT_EQ(Stub->Symbols.size(), 5u); + + auto Iterator = Stub->Symbols.begin(); + ELFSymbol const &SymBar = *Iterator++; + EXPECT_STREQ(SymBar.Name.c_str(), "bar"); + EXPECT_EQ(SymBar.Size, 42u); + EXPECT_EQ(SymBar.Type, ELFSymbolType::Object); + EXPECT_FALSE(SymBar.Undefined); + EXPECT_FALSE(SymBar.Warning.hasValue()); + + ELFSymbol const &SymBaz = *Iterator++; + EXPECT_STREQ(SymBaz.Name.c_str(), "baz"); + EXPECT_EQ(SymBaz.Size, 3u); + EXPECT_EQ(SymBaz.Type, ELFSymbolType::TLS); + EXPECT_FALSE(SymBaz.Undefined); + EXPECT_FALSE(SymBaz.Warning.hasValue()); + + ELFSymbol const &SymFoo = *Iterator++; + EXPECT_STREQ(SymFoo.Name.c_str(), "foo"); + EXPECT_EQ(SymFoo.Size, 0u); + EXPECT_EQ(SymFoo.Type, ELFSymbolType::Func); + EXPECT_FALSE(SymFoo.Undefined); + EXPECT_TRUE(SymFoo.Warning.hasValue()); + EXPECT_STREQ(SymFoo.Warning->c_str(), "Deprecated!"); + + ELFSymbol const &SymNor = *Iterator++; + EXPECT_STREQ(SymNor.Name.c_str(), "nor"); + EXPECT_EQ(SymNor.Size, 0u); + EXPECT_EQ(SymNor.Type, ELFSymbolType::NoType); + EXPECT_TRUE(SymNor.Undefined); + EXPECT_FALSE(SymNor.Warning.hasValue()); + + ELFSymbol const &SymNot = *Iterator++; + EXPECT_STREQ(SymNot.Name.c_str(), "not"); + EXPECT_EQ(SymNot.Size, 111u); + EXPECT_EQ(SymNot.Type, ELFSymbolType::Unknown); + EXPECT_TRUE(SymNot.Undefined); + EXPECT_TRUE(SymNot.Warning.hasValue()); + EXPECT_STREQ(SymNot.Warning->c_str(), "All fields populated!"); +} + +TEST(ElfYamlTextAPI, YAMLReadsNoTBESyms) { + const char Data[] = "--- !tapi-tbe\n" + "TbeVersion: 1.0\n" + "SoName: test.so\n" + "Arch: x86_64\n" + "Symbols: {}\n" + "...\n"; + std::unique_ptr<ELFStub> Stub = readFromBuffer(Data); + EXPECT_EQ(0u, Stub->Symbols.size()); +} + +TEST(ElfYamlTextAPI, YAMLUnreadableTBE) { + TBEHandler Handler; + // Can't read: wrong format/version. + const char Data[] = "--- !tapi-tbz\n" + "TbeVersion: z.3\n" + "SoName: test.so\n" + "Arch: x86_64\n" + "Symbols:\n" + " foo: { Type: Func, Undefined: true }\n"; + StringRef Buf = StringRef(Data); + std::unique_ptr<ELFStub> Stub = Handler.readFile(Buf); + EXPECT_EQ(Stub.get(), nullptr); +} + +TEST(ElfYamlTextAPI, YAMLWritesTBESymbols) { + const char Expected[] = + "--- !tapi-tbe\n" + "TbeVersion: 1.0\n" + "SoName: test.so\n" + "Arch: AArch64\n" + "Symbols: \n" + " foo: { Type: NoType, Size: 99, Warning: Does nothing }\n" + " nor: { Type: Func, Undefined: true }\n" + " not: { Type: Unknown, Size: 12345678901234 }\n" + "...\n"; + ELFStub Stub; + Stub.TbeVersion = VersionTuple(1, 0); + Stub.SoName = "test.so"; + Stub.Arch = ELF::EM_AARCH64; + + ELFSymbol SymFoo("foo"); + SymFoo.Size = 99u; + SymFoo.Type = ELFSymbolType::NoType; + SymFoo.Undefined = false; + SymFoo.Warning = "Does nothing"; + + ELFSymbol SymNor("nor"); + SymNor.Type = ELFSymbolType::Func; + SymNor.Undefined = true; + + ELFSymbol SymNot("not"); + SymNot.Size = 12345678901234u; + SymNot.Type = ELFSymbolType::Unknown; + SymNot.Undefined = false; + + // Deliberately not in order to check that result is sorted. + Stub.Symbols.insert(SymNot); + Stub.Symbols.insert(SymFoo); + Stub.Symbols.insert(SymNor); + + // Ensure move constructor works as expected. + ELFStub Moved = std::move(Stub); + + std::string Result; + raw_string_ostream OS(Result); + TBEHandler Handler; + EXPECT_FALSE(Handler.writeFile(OS, Moved)); + Result = OS.str(); + compareByLine(Result.c_str(), Expected); +} + +TEST(ElfYamlTextAPI, YAMLWritesNoTBESyms) { + const char Expected[] = "--- !tapi-tbe\n" + "TbeVersion: 1.0\n" + "SoName: nosyms.so\n" + "Arch: x86_64\n" + "NeededLibs: [ libc.so, libfoo.so, libbar.so ]\n" + "Symbols: {}\n" + "...\n"; + ELFStub Stub; + Stub.TbeVersion = VersionTuple(1, 0); + Stub.SoName = "nosyms.so"; + Stub.Arch = ELF::EM_X86_64; + Stub.NeededLibs.push_back("libc.so"); + Stub.NeededLibs.push_back("libfoo.so"); + Stub.NeededLibs.push_back("libbar.so"); + + std::string Result; + raw_string_ostream OS(Result); + TBEHandler Handler; + EXPECT_FALSE(Handler.writeFile(OS, Stub)); + Result = OS.str(); + compareByLine(Result.c_str(), Expected); +} |