diff options
Diffstat (limited to 'unittests')
45 files changed, 921 insertions, 324 deletions
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index f7b611802fbf9..7b8bc678e5544 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -2,7 +2,7 @@ add_custom_target(LLDBUnitTests) set_target_properties(LLDBUnitTests PROPERTIES FOLDER "LLDB tests") include_directories(${LLDB_SOURCE_ROOT}) -include_directories(${LLDB_PROJECT_ROOT}) +include_directories(${LLDB_PROJECT_ROOT}/unittests) set(LLDB_GTEST_COMMON_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/gtest_common.h) if (MSVC) @@ -11,8 +11,6 @@ else () list(APPEND LLVM_COMPILE_FLAGS -include ${LLDB_GTEST_COMMON_INCLUDE}) endif () -include(${LLDB_PROJECT_ROOT}/cmake/LLDBDependencies.cmake) - if (LLDB_BUILT_STANDALONE) # Build the gtest library needed for unittests, if we have LLVM sources # handy. @@ -46,7 +44,7 @@ function(add_lldb_unittest test_name) POST_BUILD COMMAND "${CMAKE_COMMAND}" -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/Inputs) - target_link_libraries(${test_name} ${ARG_LINK_LIBS} ${LLDB_SYSTEM_LIBS}) + target_link_libraries(${test_name} PRIVATE ${ARG_LINK_LIBS}) endfunction() function(add_unittest_inputs test_name inputs) @@ -59,6 +57,7 @@ function(add_unittest_inputs test_name inputs) endforeach() endfunction() +add_subdirectory(TestingSupport) add_subdirectory(Breakpoint) add_subdirectory(Core) add_subdirectory(Editline) diff --git a/unittests/Core/CMakeLists.txt b/unittests/Core/CMakeLists.txt index 426009661b121..41ace5bcaece5 100644 --- a/unittests/Core/CMakeLists.txt +++ b/unittests/Core/CMakeLists.txt @@ -1,5 +1,4 @@ add_lldb_unittest(LLDBCoreTests - ArchSpecTest.cpp BroadcasterTest.cpp DataExtractorTest.cpp ListenerTest.cpp diff --git a/unittests/Core/DataExtractorTest.cpp b/unittests/Core/DataExtractorTest.cpp index 213d5a7b43fdd..0267f6d140563 100644 --- a/unittests/Core/DataExtractorTest.cpp +++ b/unittests/Core/DataExtractorTest.cpp @@ -49,3 +49,120 @@ TEST(DataExtractorTest, PeekData) { EXPECT_EQ(buffer + 4, E.PeekData(4, 0)); EXPECT_EQ(nullptr, E.PeekData(4, 1)); } + +TEST(DataExtractorTest, GetMaxU64) { + uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle, + sizeof(void *)); + DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, sizeof(void *)); + + lldb::offset_t offset; + + // Check with the minimum allowed byte size. + offset = 0; + EXPECT_EQ(0x01U, LE.GetMaxU64(&offset, 1)); + EXPECT_EQ(1U, offset); + offset = 0; + EXPECT_EQ(0x01U, BE.GetMaxU64(&offset, 1)); + EXPECT_EQ(1U, offset); + + // Check with a non-zero offset. + offset = 1; + EXPECT_EQ(0x0302U, LE.GetMaxU64(&offset, 2)); + EXPECT_EQ(3U, offset); + offset = 1; + EXPECT_EQ(0x0203U, BE.GetMaxU64(&offset, 2)); + EXPECT_EQ(3U, offset); + + // Check with the byte size not being a multiple of 2. + offset = 0; + EXPECT_EQ(0x07060504030201U, LE.GetMaxU64(&offset, 7)); + EXPECT_EQ(7U, offset); + offset = 0; + EXPECT_EQ(0x01020304050607U, BE.GetMaxU64(&offset, 7)); + EXPECT_EQ(7U, offset); + + // Check with the maximum allowed byte size. + offset = 0; + EXPECT_EQ(0x0807060504030201U, LE.GetMaxU64(&offset, 8)); + EXPECT_EQ(8U, offset); + offset = 0; + EXPECT_EQ(0x0102030405060708U, BE.GetMaxU64(&offset, 8)); + EXPECT_EQ(8U, offset); +} + +TEST(DataExtractorTest, GetMaxS64) { + uint8_t buffer[] = {0x01, 0x02, 0x83, 0x04, 0x05, 0x06, 0x07, 0x08}; + DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle, + sizeof(void *)); + DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, sizeof(void *)); + + lldb::offset_t offset; + + // Check with the minimum allowed byte size. + offset = 0; + EXPECT_EQ(0x01, LE.GetMaxS64(&offset, 1)); + EXPECT_EQ(1U, offset); + offset = 0; + EXPECT_EQ(0x01, BE.GetMaxS64(&offset, 1)); + EXPECT_EQ(1U, offset); + + // Check that sign extension works correctly. + offset = 0; + int64_t value = LE.GetMaxS64(&offset, 3); + EXPECT_EQ(0xffffffffff830201U, *reinterpret_cast<uint64_t *>(&value)); + EXPECT_EQ(3U, offset); + offset = 2; + value = BE.GetMaxS64(&offset, 3); + EXPECT_EQ(0xffffffffff830405U, *reinterpret_cast<uint64_t *>(&value)); + EXPECT_EQ(5U, offset); + + // Check with the maximum allowed byte size. + offset = 0; + EXPECT_EQ(0x0807060504830201, LE.GetMaxS64(&offset, 8)); + EXPECT_EQ(8U, offset); + offset = 0; + EXPECT_EQ(0x0102830405060708, BE.GetMaxS64(&offset, 8)); + EXPECT_EQ(8U, offset); +} + +TEST(DataExtractorTest, GetMaxU64_unchecked) { + uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle, + sizeof(void *)); + DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, sizeof(void *)); + + lldb::offset_t offset; + + // Check with the minimum allowed byte size. + offset = 0; + EXPECT_EQ(0x01U, LE.GetMaxU64_unchecked(&offset, 1)); + EXPECT_EQ(1U, offset); + offset = 0; + EXPECT_EQ(0x01U, BE.GetMaxU64_unchecked(&offset, 1)); + EXPECT_EQ(1U, offset); + + // Check with a non-zero offset. + offset = 1; + EXPECT_EQ(0x0302U, LE.GetMaxU64_unchecked(&offset, 2)); + EXPECT_EQ(3U, offset); + offset = 1; + EXPECT_EQ(0x0203U, BE.GetMaxU64_unchecked(&offset, 2)); + EXPECT_EQ(3U, offset); + + // Check with the byte size not being a multiple of 2. + offset = 0; + EXPECT_EQ(0x07060504030201U, LE.GetMaxU64_unchecked(&offset, 7)); + EXPECT_EQ(7U, offset); + offset = 0; + EXPECT_EQ(0x01020304050607U, BE.GetMaxU64_unchecked(&offset, 7)); + EXPECT_EQ(7U, offset); + + // Check with the maximum allowed byte size. + offset = 0; + EXPECT_EQ(0x0807060504030201U, LE.GetMaxU64_unchecked(&offset, 8)); + EXPECT_EQ(8U, offset); + offset = 0; + EXPECT_EQ(0x0102030405060708U, BE.GetMaxU64_unchecked(&offset, 8)); + EXPECT_EQ(8U, offset); +} diff --git a/unittests/Editline/EditlineTest.cpp b/unittests/Editline/EditlineTest.cpp index 668d1f5421288..963d9043e994c 100644 --- a/unittests/Editline/EditlineTest.cpp +++ b/unittests/Editline/EditlineTest.cpp @@ -25,6 +25,8 @@ #include "lldb/Utility/Status.h" #include "lldb/Utility/StringList.h" +using namespace lldb_private; + namespace { const size_t TIMEOUT_MILLIS = 5000; } @@ -81,7 +83,7 @@ private: std::unique_ptr<lldb_private::Editline> _editline_sp; - lldb_utility::PseudoTerminal _pty; + PseudoTerminal _pty; int _pty_master_fd; int _pty_slave_fd; diff --git a/unittests/Host/CMakeLists.txt b/unittests/Host/CMakeLists.txt index 0c42eb533fa0b..238026b64c4da 100644 --- a/unittests/Host/CMakeLists.txt +++ b/unittests/Host/CMakeLists.txt @@ -1,11 +1,13 @@ set (FILES FileSpecTest.cpp FileSystemTest.cpp + HostInfoTest.cpp HostTest.cpp MainLoopTest.cpp SocketAddressTest.cpp SocketTest.cpp SymbolsTest.cpp + TaskPoolTest.cpp ) if (CMAKE_SYSTEM_NAME MATCHES "Linux|Android") diff --git a/unittests/Host/HostInfoTest.cpp b/unittests/Host/HostInfoTest.cpp new file mode 100644 index 0000000000000..75b8c770bbeb9 --- /dev/null +++ b/unittests/Host/HostInfoTest.cpp @@ -0,0 +1,45 @@ +//===-- HostInfoTest.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/HostInfo.h" +#include "lldb/lldb-defines.h" +#include "gtest/gtest.h" + +using namespace lldb_private; +using namespace llvm; + +namespace { +class HostInfoTest: public ::testing::Test { + public: + void SetUp() override { HostInfo::Initialize(); } + void TearDown() override { HostInfo::Terminate(); } +}; +} + +TEST_F(HostInfoTest, GetAugmentedArchSpec) { + // Fully specified triple should not be changed. + ArchSpec spec = HostInfo::GetAugmentedArchSpec("x86_64-pc-linux-gnu"); + EXPECT_EQ(spec.GetTriple().getTriple(), "x86_64-pc-linux-gnu"); + + // Same goes if we specify at least one of (os, vendor, env). + spec = HostInfo::GetAugmentedArchSpec("x86_64-pc"); + EXPECT_EQ(spec.GetTriple().getTriple(), "x86_64-pc"); + + // But if we specify only an arch, we should fill in the rest from the host. + spec = HostInfo::GetAugmentedArchSpec("x86_64"); + Triple triple(sys::getDefaultTargetTriple()); + EXPECT_EQ(spec.GetTriple().getArch(), Triple::x86_64); + EXPECT_EQ(spec.GetTriple().getOS(), triple.getOS()); + EXPECT_EQ(spec.GetTriple().getVendor(), triple.getVendor()); + EXPECT_EQ(spec.GetTriple().getEnvironment(), triple.getEnvironment()); + + // Test LLDB_ARCH_DEFAULT + EXPECT_EQ(HostInfo::GetAugmentedArchSpec(LLDB_ARCH_DEFAULT).GetTriple(), + HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple()); +} diff --git a/unittests/Host/MainLoopTest.cpp b/unittests/Host/MainLoopTest.cpp index 3a39ea1c9ac75..8f2c55c2416df 100644 --- a/unittests/Host/MainLoopTest.cpp +++ b/unittests/Host/MainLoopTest.cpp @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/MainLoop.h" +#include "lldb/Host/ConnectionFileDescriptor.h" +#include "lldb/Host/PseudoTerminal.h" #include "lldb/Host/common/TCPSocket.h" #include "gtest/gtest.h" #include <future> @@ -107,6 +109,24 @@ TEST_F(MainLoopTest, TerminatesImmediately) { } #ifdef LLVM_ON_UNIX +TEST_F(MainLoopTest, DetectsEOF) { + PseudoTerminal term; + ASSERT_TRUE(term.OpenFirstAvailableMaster(O_RDWR, nullptr, 0)); + ASSERT_TRUE(term.OpenSlave(O_RDWR | O_NOCTTY, nullptr, 0)); + auto conn = llvm::make_unique<ConnectionFileDescriptor>( + term.ReleaseMasterFileDescriptor(), true); + + Status error; + MainLoop loop; + auto handle = + loop.RegisterReadObject(conn->GetReadObject(), make_callback(), error); + ASSERT_TRUE(error.Success()); + term.CloseSlaveFileDescriptor(); + + ASSERT_TRUE(loop.Run().Success()); + ASSERT_EQ(1u, callback_count); +} + TEST_F(MainLoopTest, Signal) { MainLoop loop; Status error; diff --git a/unittests/Utility/TaskPoolTest.cpp b/unittests/Host/TaskPoolTest.cpp index e340a81b27dbd..fea5442679575 100644 --- a/unittests/Utility/TaskPoolTest.cpp +++ b/unittests/Host/TaskPoolTest.cpp @@ -1,6 +1,8 @@ #include "gtest/gtest.h" -#include "lldb/Utility/TaskPool.h" +#include "lldb/Host/TaskPool.h" + +using namespace lldb_private; TEST(TaskPoolTest, AddTask) { auto fn = [](int x) { return x * x + 1; }; diff --git a/unittests/Interpreter/CMakeLists.txt b/unittests/Interpreter/CMakeLists.txt index 7be092b24b5e4..40fc45d4d6401 100644 --- a/unittests/Interpreter/CMakeLists.txt +++ b/unittests/Interpreter/CMakeLists.txt @@ -8,5 +8,6 @@ add_lldb_unittest(InterpreterTests ) target_link_libraries(InterpreterTests + PRIVATE ${PYTHON_LIBRARY} ) diff --git a/unittests/Interpreter/TestArgs.cpp b/unittests/Interpreter/TestArgs.cpp index 2aeed0f542b18..2aaaab84e2114 100644 --- a/unittests/Interpreter/TestArgs.cpp +++ b/unittests/Interpreter/TestArgs.cpp @@ -10,6 +10,7 @@ #include "gtest/gtest.h" #include "lldb/Interpreter/Args.h" +#include "lldb/Utility/StringList.h" #include <limits> #include <sstream> @@ -117,6 +118,16 @@ TEST(ArgsTest, TestArgv) { EXPECT_EQ(nullptr, args.GetArgumentVector()[5]); } +TEST(ArgsTest, StringListConstructor) { + StringList list; + list << "foo" << "bar" << "baz"; + Args args(list); + ASSERT_EQ(3u, args.GetArgumentCount()); + EXPECT_EQ("foo", args[0].ref); + EXPECT_EQ("bar", args[1].ref); + EXPECT_EQ("baz", args[2].ref); +} + TEST(ArgsTest, GetQuotedCommandString) { Args args; const char *str = "process launch -o stdout.txt -- \"a b c\""; diff --git a/unittests/Interpreter/TestCompletion.cpp b/unittests/Interpreter/TestCompletion.cpp index 0baf61fdaf34f..5db7f83db0f96 100644 --- a/unittests/Interpreter/TestCompletion.cpp +++ b/unittests/Interpreter/TestCompletion.cpp @@ -12,7 +12,7 @@ #include "lldb/Utility/StringList.h" #include "lldb/Utility/TildeExpressionResolver.h" -#include "unittests/Utility/Helpers/MockTildeExpressionResolver.h" +#include "TestingSupport/MockTildeExpressionResolver.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" diff --git a/unittests/ObjectFile/ELF/TestObjectFileELF.cpp b/unittests/ObjectFile/ELF/TestObjectFileELF.cpp index e9b3e9fcf2377..056799ee9191c 100644 --- a/unittests/ObjectFile/ELF/TestObjectFileELF.cpp +++ b/unittests/ObjectFile/ELF/TestObjectFileELF.cpp @@ -10,11 +10,13 @@ #include "Plugins/ObjectFile/ELF/ObjectFileELF.h" #include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h" +#include "TestingSupport/TestUtilities.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/Section.h" #include "lldb/Host/HostInfo.h" -#include "unittests/Utility/Helpers/TestUtilities.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" @@ -61,7 +63,8 @@ TEST_F(ObjectFileELFTest, SectionsResolveConsistently) { llvm::FileRemover remover(obj); const char *args[] = {YAML2OBJ, yaml.c_str(), nullptr}; llvm::StringRef obj_ref = obj; - const llvm::StringRef *redirects[] = {nullptr, &obj_ref, nullptr}; + const llvm::Optional<llvm::StringRef> redirects[] = {llvm::None, obj_ref, + llvm::None}; ASSERT_EQ(0, llvm::sys::ExecuteAndWait(YAML2OBJ, args, nullptr, redirects)); uint64_t size; ASSERT_NO_ERROR(llvm::sys::fs::file_size(obj, size)); diff --git a/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp b/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp index 90a9c7ea7a0fc..1d7632a67a30e 100644 --- a/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp +++ b/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp @@ -197,27 +197,53 @@ TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo) { EXPECT_EQ(1234u, result.getValue()[0].GetObjectSize()); } +TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo_UUID20) { + llvm::Triple triple("i386-pc-linux"); + + FileSpec file_spec("/foo/bar.so", false, FileSpec::ePathSyntaxPosix); + std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result = + std::async(std::launch::async, + [&] { return client.GetModulesInfo(file_spec, triple); }); + HandlePacket( + server, + "jModulesInfo:[" + R"({"file":"/foo/bar.so","triple":"i386-pc-linux"}])", + R"([{"uuid":"404142434445464748494a4b4c4d4e4f50515253","triple":"i386-pc-linux",)" + R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])"); + + auto result = async_result.get(); + ASSERT_TRUE(result.hasValue()); + ASSERT_EQ(1u, result->size()); + EXPECT_EQ("/foo/bar.so", result.getValue()[0].GetFileSpec().GetPath()); + EXPECT_EQ(triple, result.getValue()[0].GetArchitecture().GetTriple()); + EXPECT_EQ(UUID("@ABCDEFGHIJKLMNOPQRS", 20), result.getValue()[0].GetUUID()); + EXPECT_EQ(0u, result.getValue()[0].GetObjectOffset()); + EXPECT_EQ(1234u, result.getValue()[0].GetObjectSize()); +} + TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfoInvalidResponse) { llvm::Triple triple("i386-pc-linux"); FileSpec file_spec("/foo/bar.so", false, FileSpec::ePathSyntaxPosix); const char *invalid_responses[] = { - "OK", "E47", "[]", // no UUID R"([{"triple":"i386-pc-linux",)" - R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}])", + R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])", + // invalid UUID + R"([{"uuid":"XXXXXX","triple":"i386-pc-linux",)" + R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])", // no triple R"([{"uuid":"404142434445464748494a4b4c4d4e4f",)" - R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}])", + R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])", // no file_path R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)" - R"("file_offset":0,"file_size":1234}])", + R"("file_offset":0,"file_size":1234}]])", // no file_offset R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)" - R"("file_path":"/foo/bar.so","file_size":1234}])", + R"("file_path":"/foo/bar.so","file_size":1234}]])", // no file_size R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)" - R"("file_path":"/foo/bar.so","file_offset":0}])", + R"("file_path":"/foo/bar.so","file_offset":0}]])", }; for (const char *response : invalid_responses) { @@ -229,7 +255,9 @@ TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfoInvalidResponse) { R"(jModulesInfo:[{"file":"/foo/bar.so","triple":"i386-pc-linux"}])", response); - ASSERT_FALSE(async_result.get().hasValue()) << "response was: " << response; + auto result = async_result.get(); + ASSERT_TRUE(result); + ASSERT_EQ(0u, result->size()) << "response was: " << response; } } diff --git a/unittests/Process/minidump/MinidumpParserTest.cpp b/unittests/Process/minidump/MinidumpParserTest.cpp index a029466fc59e4..7aceb0e16dcf9 100644 --- a/unittests/Process/minidump/MinidumpParserTest.cpp +++ b/unittests/Process/minidump/MinidumpParserTest.cpp @@ -15,20 +15,18 @@ #include "Plugins/Process/minidump/RegisterContextMinidump_x86_32.h" #include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h" -// Other libraries and framework includes -#include "gtest/gtest.h" - -#include "lldb/Core/ArchSpec.h" +#include "TestingSupport/TestUtilities.h" #include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/DataBufferLLVM.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/FileSpec.h" -#include "unittests/Utility/Helpers/TestUtilities.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include "gtest/gtest.h" // C includes diff --git a/unittests/Symbol/TestClangASTContext.cpp b/unittests/Symbol/TestClangASTContext.cpp index ed49c2657c7a6..9fe804708378a 100644 --- a/unittests/Symbol/TestClangASTContext.cpp +++ b/unittests/Symbol/TestClangASTContext.cpp @@ -376,3 +376,59 @@ TEST_F(TestClangASTContext, TestRecordHasFields) { EXPECT_TRUE( ClangASTContext::RecordHasFields(empty_derived_non_empty_vbase_decl)); } + +TEST_F(TestClangASTContext, TemplateArguments) { + ClangASTContext::TemplateParameterInfos infos; + infos.names.push_back("T"); + infos.args.push_back(TemplateArgument(m_ast->getASTContext()->IntTy)); + infos.names.push_back("I"); + llvm::APSInt arg(llvm::APInt(8, 47)); + infos.args.push_back(TemplateArgument(*m_ast->getASTContext(), arg, + m_ast->getASTContext()->IntTy)); + + // template<typename T, int I> struct foo; + ClassTemplateDecl *decl = m_ast->CreateClassTemplateDecl( + m_ast->GetTranslationUnitDecl(), eAccessPublic, "foo", TTK_Struct, infos); + ASSERT_NE(decl, nullptr); + + // foo<int, 47> + ClassTemplateSpecializationDecl *spec_decl = + m_ast->CreateClassTemplateSpecializationDecl( + m_ast->GetTranslationUnitDecl(), decl, TTK_Struct, infos); + ASSERT_NE(spec_decl, nullptr); + CompilerType type = m_ast->CreateClassTemplateSpecializationType(spec_decl); + ASSERT_TRUE(type); + m_ast->StartTagDeclarationDefinition(type); + m_ast->CompleteTagDeclarationDefinition(type); + + // typedef foo<int, 47> foo_def; + CompilerType typedef_type = m_ast->CreateTypedefType( + type, "foo_def", + CompilerDeclContext(m_ast.get(), m_ast->GetTranslationUnitDecl())); + + CompilerType auto_type(m_ast->getASTContext(), + m_ast->getASTContext()->getAutoType( + ClangUtil::GetCanonicalQualType(typedef_type), + clang::AutoTypeKeyword::Auto, false)); + + CompilerType int_type(m_ast->getASTContext(), m_ast->getASTContext()->IntTy); + for(CompilerType t: { type, typedef_type, auto_type }) { + SCOPED_TRACE(t.GetTypeName().AsCString()); + + EXPECT_EQ(m_ast->GetTemplateArgumentKind(t.GetOpaqueQualType(), 0), + eTemplateArgumentKindType); + EXPECT_EQ(m_ast->GetTypeTemplateArgument(t.GetOpaqueQualType(), 0), + int_type); + EXPECT_EQ(llvm::None, + m_ast->GetIntegralTemplateArgument(t.GetOpaqueQualType(), 0)); + + EXPECT_EQ(m_ast->GetTemplateArgumentKind(t.GetOpaqueQualType(), 1), + eTemplateArgumentKindIntegral); + EXPECT_EQ(m_ast->GetTypeTemplateArgument(t.GetOpaqueQualType(), 1), + CompilerType()); + auto result = m_ast->GetIntegralTemplateArgument(t.GetOpaqueQualType(), 1); + ASSERT_NE(llvm::None, result); + EXPECT_EQ(arg, result->value); + EXPECT_EQ(int_type, result->type); + } +} diff --git a/unittests/Symbol/TestDWARFCallFrameInfo.cpp b/unittests/Symbol/TestDWARFCallFrameInfo.cpp index 40e3aac5fb378..85cb4a72b95c5 100644 --- a/unittests/Symbol/TestDWARFCallFrameInfo.cpp +++ b/unittests/Symbol/TestDWARFCallFrameInfo.cpp @@ -16,7 +16,7 @@ #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" #include "lldb/Utility/StreamString.h" -#include "unittests/Utility/Helpers/TestUtilities.h" +#include "TestingSupport/TestUtilities.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" @@ -98,7 +98,8 @@ void DWARFCallFrameInfoTest::TestBasic(DWARFCallFrameInfo::Type type, const char *args[] = {YAML2OBJ, yaml.c_str(), nullptr}; llvm::StringRef obj_ref = obj; - const llvm::StringRef *redirects[] = {nullptr, &obj_ref, nullptr}; + const llvm::Optional<llvm::StringRef> redirects[] = {llvm::None, obj_ref, + llvm::None}; ASSERT_EQ(0, llvm::sys::ExecuteAndWait(YAML2OBJ, args, nullptr, redirects)); uint64_t size; diff --git a/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp b/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp index 298bed10f3f81..743b91a287918 100644 --- a/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp +++ b/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp @@ -18,8 +18,8 @@ #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h" +#include "TestingSupport/TestUtilities.h" #include "lldb/Core/Address.h" -#include "lldb/Core/ArchSpec.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/HostInfo.h" @@ -27,8 +27,8 @@ #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/FileSpec.h" -#include "unittests/Utility/Helpers/TestUtilities.h" using namespace lldb_private; diff --git a/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp b/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp index 0e63a4104234c..1e9cf1700642d 100644 --- a/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp +++ b/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp @@ -18,8 +18,8 @@ #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h" +#include "TestingSupport/TestUtilities.h" #include "lldb/Core/Address.h" -#include "lldb/Core/ArchSpec.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/HostInfo.h" @@ -27,8 +27,8 @@ #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/FileSpec.h" -#include "unittests/Utility/Helpers/TestUtilities.h" #if defined(_MSC_VER) #include "lldb/Host/windows/windows.h" diff --git a/unittests/Target/ModuleCacheTest.cpp b/unittests/Target/ModuleCacheTest.cpp index 122d789daf570..de07648ae00b4 100644 --- a/unittests/Target/ModuleCacheTest.cpp +++ b/unittests/Target/ModuleCacheTest.cpp @@ -10,7 +10,7 @@ #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/ModuleCache.h" -#include "unittests/Utility/Helpers/TestUtilities.h" +#include "TestingSupport/TestUtilities.h" using namespace lldb_private; using namespace lldb; diff --git a/unittests/Utility/Helpers/CMakeLists.txt b/unittests/TestingSupport/CMakeLists.txt index 36c774cb68265..36c774cb68265 100644 --- a/unittests/Utility/Helpers/CMakeLists.txt +++ b/unittests/TestingSupport/CMakeLists.txt diff --git a/unittests/Utility/Helpers/MockTildeExpressionResolver.cpp b/unittests/TestingSupport/MockTildeExpressionResolver.cpp index 832836682b500..832836682b500 100644 --- a/unittests/Utility/Helpers/MockTildeExpressionResolver.cpp +++ b/unittests/TestingSupport/MockTildeExpressionResolver.cpp diff --git a/unittests/Utility/Helpers/MockTildeExpressionResolver.h b/unittests/TestingSupport/MockTildeExpressionResolver.h index 18be1102e1fd4..18be1102e1fd4 100644 --- a/unittests/Utility/Helpers/MockTildeExpressionResolver.h +++ b/unittests/TestingSupport/MockTildeExpressionResolver.h diff --git a/unittests/Utility/Helpers/TestUtilities.cpp b/unittests/TestingSupport/TestUtilities.cpp index eacf876614207..eacf876614207 100644 --- a/unittests/Utility/Helpers/TestUtilities.cpp +++ b/unittests/TestingSupport/TestUtilities.cpp diff --git a/unittests/Utility/Helpers/TestUtilities.h b/unittests/TestingSupport/TestUtilities.h index 8d848797b7b2e..8d848797b7b2e 100644 --- a/unittests/Utility/Helpers/TestUtilities.h +++ b/unittests/TestingSupport/TestUtilities.h diff --git a/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp b/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp index d7caf4281d5d2..ab28cb637d8d7 100644 --- a/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp +++ b/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp @@ -17,9 +17,9 @@ #include "lldb/Core/Address.h" #include "lldb/Core/AddressRange.h" -#include "lldb/Core/ArchSpec.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/UnwindAssembly.h" +#include "lldb/Utility/ArchSpec.h" #include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h" #include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h" @@ -55,7 +55,7 @@ void TestArm64InstEmulation::TearDownTestCase() { } TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) { - ArchSpec arch("arm64-apple-ios10", nullptr); + ArchSpec arch("arm64-apple-ios10"); UnwindAssemblyInstEmulation *engine = static_cast<UnwindAssemblyInstEmulation *>( UnwindAssemblyInstEmulation::CreateInstance(arch)); @@ -151,7 +151,7 @@ TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) { } TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) { - ArchSpec arch("arm64-apple-ios10", nullptr); + ArchSpec arch("arm64-apple-ios10"); UnwindAssemblyInstEmulation *engine = static_cast<UnwindAssemblyInstEmulation *>( UnwindAssemblyInstEmulation::CreateInstance(arch)); @@ -313,7 +313,7 @@ TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) { } TEST_F(TestArm64InstEmulation, TestFramelessThreeEpilogueFunction) { - ArchSpec arch("arm64-apple-ios10", nullptr); + ArchSpec arch("arm64-apple-ios10"); UnwindAssemblyInstEmulation *engine = static_cast<UnwindAssemblyInstEmulation *>( UnwindAssemblyInstEmulation::CreateInstance(arch)); @@ -408,7 +408,7 @@ TEST_F(TestArm64InstEmulation, TestFramelessThreeEpilogueFunction) { } TEST_F(TestArm64InstEmulation, TestRegisterSavedTwice) { - ArchSpec arch("arm64-apple-ios10", nullptr); + ArchSpec arch("arm64-apple-ios10"); UnwindAssemblyInstEmulation *engine = static_cast<UnwindAssemblyInstEmulation *>( UnwindAssemblyInstEmulation::CreateInstance(arch)); @@ -510,7 +510,7 @@ TEST_F(TestArm64InstEmulation, TestRegisterSavedTwice) { } TEST_F(TestArm64InstEmulation, TestRegisterDoubleSpills) { - ArchSpec arch("arm64-apple-ios10", nullptr); + ArchSpec arch("arm64-apple-ios10"); UnwindAssemblyInstEmulation *engine = static_cast<UnwindAssemblyInstEmulation *>( UnwindAssemblyInstEmulation::CreateInstance(arch)); diff --git a/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp b/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp index c3591b2d73e1b..f0c9cefeb7b00 100644 --- a/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp +++ b/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp @@ -16,8 +16,8 @@ #include "Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h" #include "lldb/Core/Address.h" #include "lldb/Core/AddressRange.h" -#include "lldb/Core/ArchSpec.h" #include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/StreamString.h" #include "llvm/Support/TargetSelect.h" @@ -95,7 +95,7 @@ enum i386_regs { std::unique_ptr<x86AssemblyInspectionEngine> Getx86_64Inspector() { - ArchSpec arch("x86_64-apple-macosx", nullptr); + ArchSpec arch("x86_64-apple-macosx"); std::unique_ptr<x86AssemblyInspectionEngine> engine( new x86AssemblyInspectionEngine(arch)); @@ -114,7 +114,7 @@ std::unique_ptr<x86AssemblyInspectionEngine> Getx86_64Inspector() { std::unique_ptr<x86AssemblyInspectionEngine> Geti386Inspector() { - ArchSpec arch("i386-apple-macosx", nullptr); + ArchSpec arch("i386-apple-macosx"); std::unique_ptr<x86AssemblyInspectionEngine> engine( new x86AssemblyInspectionEngine(arch)); diff --git a/unittests/Core/ArchSpecTest.cpp b/unittests/Utility/ArchSpecTest.cpp index 98b77e1826b11..a45e28e658b8f 100644 --- a/unittests/Core/ArchSpecTest.cpp +++ b/unittests/Utility/ArchSpecTest.cpp @@ -9,8 +9,7 @@ #include "gtest/gtest.h" -#include "lldb/Core/ArchSpec.h" - +#include "lldb/Utility/ArchSpec.h" #include "llvm/BinaryFormat/MachO.h" using namespace lldb; diff --git a/unittests/Utility/CMakeLists.txt b/unittests/Utility/CMakeLists.txt index 91cdbbda3ec37..13f840af2bb90 100644 --- a/unittests/Utility/CMakeLists.txt +++ b/unittests/Utility/CMakeLists.txt @@ -1,13 +1,12 @@ -add_subdirectory(Helpers) - add_lldb_unittest(UtilityTests + ArchSpecTest.cpp ConstStringTest.cpp + JSONTest.cpp LogTest.cpp NameMatchesTest.cpp StatusTest.cpp StringExtractorTest.cpp StructuredDataTest.cpp - TaskPoolTest.cpp TildeExpressionResolverTest.cpp TimeoutTest.cpp TimerTest.cpp diff --git a/unittests/Utility/JSONTest.cpp b/unittests/Utility/JSONTest.cpp new file mode 100644 index 0000000000000..0c23350517ce6 --- /dev/null +++ b/unittests/Utility/JSONTest.cpp @@ -0,0 +1,26 @@ +#include "gtest/gtest.h" + +#include "lldb/Utility/JSON.h" +#include "lldb/Utility/StreamString.h" + +using namespace lldb_private; + +TEST(JSONTest, Dictionary) { + JSONObject o; + o.SetObject("key", std::make_shared<JSONString>("value")); + + StreamString stream; + o.Write(stream); + + ASSERT_EQ(stream.GetString(), R"({"key":"value"})"); +} + +TEST(JSONTest, Newlines) { + JSONObject o; + o.SetObject("key", std::make_shared<JSONString>("hello\nworld")); + + StreamString stream; + o.Write(stream); + + ASSERT_EQ(stream.GetString(), R"({"key":"hello\nworld"})"); +} diff --git a/unittests/Utility/StructuredDataTest.cpp b/unittests/Utility/StructuredDataTest.cpp index f346dd9e83223..15a2ca6bf70af 100644 --- a/unittests/Utility/StructuredDataTest.cpp +++ b/unittests/Utility/StructuredDataTest.cpp @@ -9,7 +9,7 @@ #include "gtest/gtest.h" -#include "Helpers/TestUtilities.h" +#include "TestingSupport/TestUtilities.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StructuredData.h" diff --git a/unittests/Utility/TildeExpressionResolverTest.cpp b/unittests/Utility/TildeExpressionResolverTest.cpp index a24e998cb81da..bc1ca7a448115 100644 --- a/unittests/Utility/TildeExpressionResolverTest.cpp +++ b/unittests/Utility/TildeExpressionResolverTest.cpp @@ -1,6 +1,6 @@ #include "gtest/gtest.h" -#include "Helpers/MockTildeExpressionResolver.h" +#include "TestingSupport/MockTildeExpressionResolver.h" #include "lldb/Utility/TildeExpressionResolver.h" #include "llvm/ADT/SmallString.h" diff --git a/unittests/Utility/VASprintfTest.cpp b/unittests/Utility/VASprintfTest.cpp index 0b440942eb5a5..cb5b2533688e7 100644 --- a/unittests/Utility/VASprintfTest.cpp +++ b/unittests/Utility/VASprintfTest.cpp @@ -14,6 +14,12 @@ #include <locale.h> +#if defined (_WIN32) +#define TEST_ENCODING ".932" // On Windows, test codepage 932 +#else +#define TEST_ENCODING "C" // ...otherwise, any widely available uni-byte LC +#endif + using namespace lldb_private; using namespace llvm; @@ -46,7 +52,8 @@ TEST(VASprintfTest, EncodingError) { // Save the current locale first. std::string Current(::setlocale(LC_ALL, nullptr)); - setlocale(LC_ALL, ".932"); + // Ensure tested locale is successfully set + ASSERT_TRUE(setlocale(LC_ALL, TEST_ENCODING)); wchar_t Invalid[2]; Invalid[0] = 0x100; @@ -55,5 +62,6 @@ TEST(VASprintfTest, EncodingError) { EXPECT_FALSE(Sprintf(Buffer, "%ls", Invalid)); EXPECT_EQ("<Encoding error>", Buffer); - setlocale(LC_ALL, Current.c_str()); + // Ensure we've restored the original locale once tested + ASSERT_TRUE(setlocale(LC_ALL, Current.c_str())); } diff --git a/unittests/debugserver/CMakeLists.txt b/unittests/debugserver/CMakeLists.txt index cfb520a0dc761..adb8fb00ddaca 100644 --- a/unittests/debugserver/CMakeLists.txt +++ b/unittests/debugserver/CMakeLists.txt @@ -17,3 +17,22 @@ add_lldb_unittest(debugserverTests LINK_COMPONENTS Support ) + +if(IOS) + set_property(TARGET debugserverTests APPEND PROPERTY COMPILE_DEFINITIONS + WITH_LOCKDOWN + WITH_FBS + WITH_BKS + ) + + add_lldb_unittest(debugserverNonUITests + RNBSocketTest.cpp + debugserver_LogCallback.cpp + + LINK_LIBS + lldbDebugserverCommon_NonUI + lldbHost + LINK_COMPONENTS + Support + ) +endif() diff --git a/unittests/tools/CMakeLists.txt b/unittests/tools/CMakeLists.txt index 2d41864d98f42..e3816217bb4ba 100644 --- a/unittests/tools/CMakeLists.txt +++ b/unittests/tools/CMakeLists.txt @@ -1,3 +1,3 @@ -if(CMAKE_SYSTEM_NAME MATCHES "Android|Linux|NetBSD") +if(CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|Linux|NetBSD") add_subdirectory(lldb-server) endif() diff --git a/unittests/tools/lldb-server/CMakeLists.txt b/unittests/tools/lldb-server/CMakeLists.txt index b7113c3d260c5..8641e8ddb5c9d 100644 --- a/unittests/tools/lldb-server/CMakeLists.txt +++ b/unittests/tools/lldb-server/CMakeLists.txt @@ -1,13 +1,25 @@ +set(ALL_LLDB_TEST_EXECUTABLES) + function(add_lldb_test_executable test_name) set(EXCLUDE_FROM_ALL ON) add_llvm_executable(${test_name} NO_INSTALL_RPATH ${ARGN}) set(outdir ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}) set_output_directory(${test_name} BINARY_DIR ${outdir} LIBRARY_DIR ${outdir}) + list(APPEND ALL_LLDB_TEST_EXECUTABLES ${test_name}) + set(ALL_LLDB_TEST_EXECUTABLES ${ALL_LLDB_TEST_EXECUTABLES} PARENT_SCOPE) endfunction() add_lldb_test_executable(thread_inferior inferior/thread_inferior.cpp) +add_lldb_test_executable(environment_check inferior/environment_check.cpp) + +if (CMAKE_SYSTEM_NAME MATCHES "Darwin") + add_definitions(-DLLDB_SERVER="$<TARGET_FILE:debugserver>") +else() + add_definitions(-DLLDB_SERVER="$<TARGET_FILE:lldb-server>") +endif() -add_definitions(-DLLDB_SERVER="$<TARGET_FILE:lldb-server>") -add_definitions(-DTHREAD_INFERIOR="${CMAKE_CURRENT_BINARY_DIR}/thread_inferior") +add_definitions( + -DLLDB_TEST_INFERIOR_PATH="${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" + -DLLDB_TEST_INFERIOR_SUFFIX="${CMAKE_EXECUTABLE_SUFFIX}" + ) add_subdirectory(tests) -add_dependencies(LLDBServerTests thread_inferior) diff --git a/unittests/tools/lldb-server/inferior/environment_check.cpp b/unittests/tools/lldb-server/inferior/environment_check.cpp new file mode 100644 index 0000000000000..d2a5ede0cabf3 --- /dev/null +++ b/unittests/tools/lldb-server/inferior/environment_check.cpp @@ -0,0 +1,20 @@ +//===-- thread_inferior.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <string> +#include <cstdlib> + +int main() { + const char *value = std::getenv("LLDB_TEST_MAGIC_VARIABLE"); + if (!value) + return 1; + if (std::string(value) != "LLDB_TEST_MAGIC_VALUE") + return 2; + return 0; +} diff --git a/unittests/tools/lldb-server/tests/CMakeLists.txt b/unittests/tools/lldb-server/tests/CMakeLists.txt index 4ef4165b27fef..ed5eb88ba5270 100644 --- a/unittests/tools/lldb-server/tests/CMakeLists.txt +++ b/unittests/tools/lldb-server/tests/CMakeLists.txt @@ -1,6 +1,8 @@ add_lldb_unittest(LLDBServerTests - TestClient.cpp + LLGSTest.cpp MessageObjects.cpp + TestBase.cpp + TestClient.cpp ThreadIdsInJstopinfoTest.cpp LINK_LIBS @@ -10,6 +12,10 @@ add_lldb_unittest(LLDBServerTests lldbTarget lldbPluginPlatformLinux lldbPluginProcessGDBRemote + + LLVMTestingSupport LINK_COMPONENTS Support ) + +add_dependencies(LLDBServerTests lldb-server ${ALL_LLDB_TEST_EXECUTABLES}) diff --git a/unittests/tools/lldb-server/tests/LLGSTest.cpp b/unittests/tools/lldb-server/tests/LLGSTest.cpp new file mode 100644 index 0000000000000..75d964ed26f44 --- /dev/null +++ b/unittests/tools/lldb-server/tests/LLGSTest.cpp @@ -0,0 +1,36 @@ +//===-- LLGSTest.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "TestBase.h" +#include "lldb/Host/Host.h" +#include "llvm/Testing/Support/Error.h" + +using namespace llgs_tests; +using namespace lldb_private; +using namespace llvm; + +TEST_F(TestBase, LaunchModePreservesEnvironment) { + if (TestClient::IsDebugServer()) { + GTEST_LOG_(WARNING) << "Test fails with debugserver: llvm.org/pr35671"; + return; + } + + putenv(const_cast<char *>("LLDB_TEST_MAGIC_VARIABLE=LLDB_TEST_MAGIC_VALUE")); + + auto ClientOr = TestClient::launch(getLogFileName(), + {getInferiorPath("environment_check")}); + ASSERT_THAT_EXPECTED(ClientOr, Succeeded()); + auto &Client = **ClientOr; + + ASSERT_THAT_ERROR(Client.ContinueAll(), Succeeded()); + ASSERT_THAT_EXPECTED( + Client.GetLatestStopReplyAs<StopReplyExit>(), + HasValue(testing::Property(&StopReply::getKind, + WaitStatus{WaitStatus::Exit, 0}))); +} diff --git a/unittests/tools/lldb-server/tests/MessageObjects.cpp b/unittests/tools/lldb-server/tests/MessageObjects.cpp index 6ac067bce0621..e5927d037f985 100644 --- a/unittests/tools/lldb-server/tests/MessageObjects.cpp +++ b/unittests/tools/lldb-server/tests/MessageObjects.cpp @@ -19,7 +19,7 @@ namespace llgs_tests { Expected<ProcessInfo> ProcessInfo::Create(StringRef response) { ProcessInfo process_info; - auto elements_or_error = SplitPairList("ProcessInfo", response); + auto elements_or_error = SplitUniquePairList("ProcessInfo", response); if (!elements_or_error) return elements_or_error.takeError(); @@ -65,19 +65,16 @@ StringRef ThreadInfo::ReadRegister(unsigned int register_id) const { return m_registers.lookup(register_id); } -bool ThreadInfo::ReadRegisterAsUint64(unsigned int register_id, - uint64_t &value) const { +Expected<uint64_t> +ThreadInfo::ReadRegisterAsUint64(unsigned int register_id) const { + uint64_t value; std::string value_str(m_registers.lookup(register_id)); - if (!llvm::to_integer(value_str, value, 16)) { - GTEST_LOG_(ERROR) - << formatv("ThreadInfo: Unable to parse register value at {0}.", - register_id) - .str(); - return false; - } + if (!llvm::to_integer(value_str, value, 16)) + return make_parsing_error("ThreadInfo value for register {0}: {1}", + register_id, value_str); sys::swapByteOrder(value); - return true; + return value; } //====== JThreadsInfo ========================================================== @@ -136,60 +133,96 @@ const ThreadInfoMap &JThreadsInfo::GetThreadInfos() const { } //====== StopReply ============================================================= -const U64Map &StopReply::GetThreadPcs() const { return m_thread_pcs; } +Expected<std::unique_ptr<StopReply>> +StopReply::create(StringRef Response, llvm::support::endianness Endian) { + if (Response.size() < 3) + return make_parsing_error("StopReply: Invalid packet"); + if (Response.consume_front("T")) + return StopReplyStop::create(Response, Endian); + if (Response.consume_front("W")) + return StopReplyExit::create(Response); + return make_parsing_error("StopReply: Invalid packet"); +} -Expected<StopReply> StopReply::Create(StringRef response, - llvm::support::endianness endian) { - StopReply stop_reply; +Expected<std::unique_ptr<StopReplyStop>> +StopReplyStop::create(StringRef Response, llvm::support::endianness Endian) { + unsigned int Signal; + StringRef SignalStr = Response.take_front(2); + Response = Response.drop_front(2); + if (!to_integer(SignalStr, Signal, 16)) + return make_parsing_error("StopReply: stop signal"); + + auto Elements = SplitPairList(Response); + for (StringRef Field : + {"name", "reason", "thread", "threads", "thread-pcs"}) { + // This will insert an empty field if there is none. In the future, we + // should probably differentiate between these fields not being present and + // them being empty, but right now no tests depends on this. + if (Elements.insert({Field, {""}}).first->second.size() != 1) + return make_parsing_error( + "StopReply: got multiple responses for the {0} field", Field); + } + StringRef Name = Elements["name"][0]; + StringRef Reason = Elements["reason"][0]; + + lldb::tid_t Thread; + if (!to_integer(Elements["thread"][0], Thread, 16)) + return make_parsing_error("StopReply: thread"); + + SmallVector<StringRef, 20> Threads; + SmallVector<StringRef, 20> Pcs; + Elements["threads"][0].split(Threads, ','); + Elements["thread-pcs"][0].split(Pcs, ','); + if (Threads.size() != Pcs.size()) + return make_parsing_error("StopReply: thread/PC count mismatch"); - auto elements_or_error = SplitPairList("StopReply", response); - if (auto split_error = elements_or_error.takeError()) { - return std::move(split_error); + U64Map ThreadPcs; + for (auto ThreadPc : zip(Threads, Pcs)) { + lldb::tid_t Id; + uint64_t Pc; + if (!to_integer(std::get<0>(ThreadPc), Id, 16)) + return make_parsing_error("StopReply: Thread id '{0}'", + std::get<0>(ThreadPc)); + if (!to_integer(std::get<1>(ThreadPc), Pc, 16)) + return make_parsing_error("StopReply Thread Pc '{0}'", + std::get<1>(ThreadPc)); + + ThreadPcs[Id] = Pc; } - auto elements = *elements_or_error; - stop_reply.m_name = elements["name"]; - stop_reply.m_reason = elements["reason"]; + RegisterMap Registers; + for (const auto &E : Elements) { + StringRef Key = E.getKey(); + const auto &Val = E.getValue(); + if (Key.size() != 2) + continue; - SmallVector<StringRef, 20> threads; - SmallVector<StringRef, 20> pcs; - elements["threads"].split(threads, ','); - elements["thread-pcs"].split(pcs, ','); - if (threads.size() != pcs.size()) - return make_parsing_error("StopReply: thread/PC count mismatch"); + unsigned int Reg; + if (!to_integer(Key, Reg, 16)) + continue; - for (size_t i = 0; i < threads.size(); i++) { - lldb::tid_t thread_id; - uint64_t pc; - if (threads[i].getAsInteger(16, thread_id)) - return make_parsing_error("StopReply: thread ID at [{0}].", i); - if (pcs[i].getAsInteger(16, pc)) - return make_parsing_error("StopReply: thread PC at [{0}].", i); + if (Val.size() != 1) + return make_parsing_error( + "StopReply: multiple entries for register field [{0:x}]", Reg); - stop_reply.m_thread_pcs[thread_id] = pc; + Registers[Reg] = Val[0].str(); } - for (auto i = elements.begin(); i != elements.end(); i++) { - StringRef key = i->getKey(); - StringRef val = i->getValue(); - if (key.size() >= 9 && key[0] == 'T' && key.substr(3, 6) == "thread") { - if (val.getAsInteger(16, stop_reply.m_thread)) - return make_parsing_error("StopReply: thread id"); - if (key.substr(1, 2).getAsInteger(16, stop_reply.m_signal)) - return make_parsing_error("StopReply: stop signal"); - } else if (key.size() == 2) { - unsigned int reg; - if (!key.getAsInteger(16, reg)) { - stop_reply.m_registers[reg] = val.str(); - } - } - } + return llvm::make_unique<StopReplyStop>(Signal, Thread, Name, ThreadPcs, + Registers, Reason); +} - return stop_reply; +Expected<std::unique_ptr<StopReplyExit>> +StopReplyExit::create(StringRef Response) { + uint8_t Status; + if (!to_integer(Response, Status, 16)) + return make_parsing_error("StopReply: exit status"); + return llvm::make_unique<StopReplyExit>(Status); } //====== Globals =============================================================== -Expected<StringMap<StringRef>> SplitPairList(StringRef caller, StringRef str) { +Expected<StringMap<StringRef>> SplitUniquePairList(StringRef caller, + StringRef str) { SmallVector<StringRef, 20> elements; str.split(elements, ';'); @@ -199,7 +232,20 @@ Expected<StringMap<StringRef>> SplitPairList(StringRef caller, StringRef str) { if (pairs.count(pair.first)) return make_parsing_error("{0}: Duplicate Key: {1}", caller, pair.first); - pairs.insert(s.split(':')); + pairs.insert(pair); + } + + return pairs; +} + +StringMap<SmallVector<StringRef, 2>> SplitPairList(StringRef str) { + SmallVector<StringRef, 20> elements; + str.split(elements, ';'); + + StringMap<SmallVector<StringRef, 2>> pairs; + for (StringRef s : elements) { + std::pair<StringRef, StringRef> pair = s.split(':'); + pairs[pair.first].push_back(pair.second); } return pairs; diff --git a/unittests/tools/lldb-server/tests/MessageObjects.h b/unittests/tools/lldb-server/tests/MessageObjects.h index 82551e2bb5490..bbb7f75bafd5c 100644 --- a/unittests/tools/lldb-server/tests/MessageObjects.h +++ b/unittests/tools/lldb-server/tests/MessageObjects.h @@ -7,6 +7,10 @@ // //===----------------------------------------------------------------------===// +#ifndef LLDB_SERVER_TESTS_MESSAGEOBJECTS_H +#define LLDB_SERVER_TESTS_MESSAGEOBJECTS_H + +#include "lldb/Host/Host.h" #include "lldb/lldb-types.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" @@ -48,7 +52,7 @@ public: const RegisterMap ®isters, unsigned int signal); llvm::StringRef ReadRegister(unsigned int register_id) const; - bool ReadRegisterAsUint64(unsigned int register_id, uint64_t &value) const; + llvm::Expected<uint64_t> ReadRegisterAsUint64(unsigned int register_id) const; private: std::string m_name; @@ -71,25 +75,75 @@ private: class StopReply { public: - static llvm::Expected<StopReply> Create(llvm::StringRef response, - llvm::support::endianness endian); - const U64Map &GetThreadPcs() const; + StopReply() = default; + virtual ~StopReply() = default; + + static llvm::Expected<std::unique_ptr<StopReply>> + create(llvm::StringRef response, llvm::support::endianness endian); + + // for llvm::cast<> + virtual lldb_private::WaitStatus getKind() const = 0; + + StopReply(const StopReply &) = delete; + void operator=(const StopReply &) = delete; +}; + +class StopReplyStop : public StopReply { +public: + StopReplyStop(uint8_t Signal, lldb::tid_t ThreadId, llvm::StringRef Name, + U64Map ThreadPcs, RegisterMap Registers, llvm::StringRef Reason) + : Signal(Signal), ThreadId(ThreadId), Name(Name), + ThreadPcs(std::move(ThreadPcs)), Registers(std::move(Registers)), + Reason(Reason) {} + + static llvm::Expected<std::unique_ptr<StopReplyStop>> + create(llvm::StringRef response, llvm::support::endianness endian); + + const U64Map &getThreadPcs() const { return ThreadPcs; } + lldb::tid_t getThreadId() const { return ThreadId; } + + // for llvm::cast<> + lldb_private::WaitStatus getKind() const override { + return lldb_private::WaitStatus{lldb_private::WaitStatus::Stop, Signal}; + } + static bool classof(const StopReply *R) { + return R->getKind().type == lldb_private::WaitStatus::Stop; + } private: - StopReply() = default; - void ParseResponse(llvm::StringRef response, - llvm::support::endianness endian); - unsigned int m_signal; - lldb::tid_t m_thread; - std::string m_name; - U64Map m_thread_pcs; - RegisterMap m_registers; - std::string m_reason; + uint8_t Signal; + lldb::tid_t ThreadId; + std::string Name; + U64Map ThreadPcs; + RegisterMap Registers; + std::string Reason; +}; + +class StopReplyExit : public StopReply { +public: + explicit StopReplyExit(uint8_t Status) : Status(Status) {} + + static llvm::Expected<std::unique_ptr<StopReplyExit>> + create(llvm::StringRef response); + + // for llvm::cast<> + lldb_private::WaitStatus getKind() const override { + return lldb_private::WaitStatus{lldb_private::WaitStatus::Exit, Status}; + } + static bool classof(const StopReply *R) { + return R->getKind().type == lldb_private::WaitStatus::Exit; + } + +private: + uint8_t Status; }; // Common functions for parsing packet data. llvm::Expected<llvm::StringMap<llvm::StringRef>> -SplitPairList(llvm::StringRef caller, llvm::StringRef s); +SplitUniquePairList(llvm::StringRef caller, llvm::StringRef s); + +llvm::StringMap<llvm::SmallVector<llvm::StringRef, 2>> +SplitPairList(llvm::StringRef s); template <typename... Args> llvm::Error make_parsing_error(llvm::StringRef format, Args &&... args) { @@ -99,4 +153,7 @@ llvm::Error make_parsing_error(llvm::StringRef format, Args &&... args) { return llvm::make_error<llvm::StringError>(error, llvm::inconvertibleErrorCode()); } + } // namespace llgs_tests + +#endif // LLDB_SERVER_TESTS_MESSAGEOBJECTS_H diff --git a/unittests/tools/lldb-server/tests/TestBase.cpp b/unittests/tools/lldb-server/tests/TestBase.cpp new file mode 100644 index 0000000000000..b901249dbf4c6 --- /dev/null +++ b/unittests/tools/lldb-server/tests/TestBase.cpp @@ -0,0 +1,36 @@ +//===-- TestBase.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "TestBase.h" +#include <cstdlib> + +using namespace llgs_tests; +using namespace llvm; + +std::string TestBase::getLogFileName() { + const auto *test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + assert(test_info); + + const char *Dir = getenv("LOG_FILE_DIRECTORY"); + if (!Dir) + return ""; + + if (!llvm::sys::fs::is_directory(Dir)) { + GTEST_LOG_(WARNING) << "Cannot access log directory: " << Dir; + return ""; + } + + SmallString<64> DirStr(Dir); + sys::path::append(DirStr, std::string("server-") + + test_info->test_case_name() + "-" + + test_info->name() + ".log"); + return DirStr.str(); +} + diff --git a/unittests/tools/lldb-server/tests/TestBase.h b/unittests/tools/lldb-server/tests/TestBase.h new file mode 100644 index 0000000000000..8956490e945c1 --- /dev/null +++ b/unittests/tools/lldb-server/tests/TestBase.h @@ -0,0 +1,48 @@ +//===-- TestBase.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SERVER_TESTS_TESTBASE_H +#define LLDB_SERVER_TESTS_TESTBASE_H + +#include "TestClient.h" +#include "lldb/Host/HostInfo.h" +#include "llvm/Support/Path.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" + +namespace llgs_tests { + +class TestBase: public ::testing::Test { +public: + static void SetUpTestCase() { lldb_private::HostInfo::Initialize(); } + + static std::string getInferiorPath(llvm::StringRef Name) { + llvm::SmallString<64> Path(LLDB_TEST_INFERIOR_PATH); + llvm::sys::path::append(Path, Name + LLDB_TEST_INFERIOR_SUFFIX); + return Path.str(); + } + + static std::string getLogFileName(); +}; + +class StandardStartupTest: public TestBase { +public: + void SetUp() override { + auto ClientOr = TestClient::launch(getLogFileName()); + ASSERT_THAT_EXPECTED(ClientOr, llvm::Succeeded()); + Client = std::move(*ClientOr); + } + +protected: + std::unique_ptr<TestClient> Client; +}; + +} // namespace llgs_tests + +#endif // LLDB_SERVER_TESTS_TESTBASE_H diff --git a/unittests/tools/lldb-server/tests/TestClient.cpp b/unittests/tools/lldb-server/tests/TestClient.cpp index 9553ddd65fac3..773466abe8553 100644 --- a/unittests/tools/lldb-server/tests/TestClient.cpp +++ b/unittests/tools/lldb-server/tests/TestClient.cpp @@ -8,13 +8,14 @@ //===----------------------------------------------------------------------===// #include "TestClient.h" -#include "lldb/Core/ArchSpec.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/common/TCPSocket.h" #include "lldb/Host/posix/ConnectionFileDescriptorPosix.h" #include "lldb/Interpreter/Args.h" #include "lldb/Target/ProcessLaunchInfo.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Path.h" +#include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" #include <cstdlib> #include <future> @@ -26,67 +27,100 @@ using namespace lldb_private; using namespace llvm; namespace llgs_tests { -void TestClient::Initialize() { HostInfo::Initialize(); } +bool TestClient::IsDebugServer() { + return sys::path::filename(LLDB_SERVER).contains("debugserver"); +} + +bool TestClient::IsLldbServer() { return !IsDebugServer(); } + +TestClient::TestClient(std::unique_ptr<Connection> Conn) { + SetConnection(Conn.release()); + + SendAck(); // Send this as a handshake. +} -TestClient::TestClient(const std::string &test_name, - const std::string &test_case_name) - : m_test_name(test_name), m_test_case_name(test_case_name), - m_pc_register(UINT_MAX) {} +TestClient::~TestClient() { + if (!IsConnected()) + return; -TestClient::~TestClient() {} + std::string response; + // Debugserver (non-conformingly?) sends a reply to the k packet instead of + // simply closing the connection. + PacketResult result = + IsDebugServer() ? PacketResult::Success : PacketResult::ErrorDisconnected; + EXPECT_THAT_ERROR(SendMessage("k", response, result), Succeeded()); +} + +Expected<std::unique_ptr<TestClient>> TestClient::launch(StringRef Log) { + return launch(Log, {}); +} -bool TestClient::StartDebugger() { +Expected<std::unique_ptr<TestClient>> TestClient::launch(StringRef Log, ArrayRef<StringRef> InferiorArgs) { const ArchSpec &arch_spec = HostInfo::GetArchitecture(); Args args; args.AppendArgument(LLDB_SERVER); - args.AppendArgument("gdbserver"); - args.AppendArgument("--log-channels=gdb-remote packets"); + if (IsLldbServer()) + args.AppendArgument("gdbserver"); args.AppendArgument("--reverse-connect"); - std::string log_file_name = GenerateLogFileName(arch_spec); - if (log_file_name.size()) { - args.AppendArgument("--log-file=" + log_file_name); + + if (!Log.empty()) { + args.AppendArgument(("--log-file=" + Log).str()); + if (IsLldbServer()) + args.AppendArgument("--log-channels=gdb-remote packets"); + else + args.AppendArgument("--log-flags=0x800000"); } - Status error; + Status status; TCPSocket listen_socket(true, false); - error = listen_socket.Listen("127.0.0.1:0", 5); - if (error.Fail()) { - GTEST_LOG_(ERROR) << "Unable to open listen socket."; - return false; + status = listen_socket.Listen("127.0.0.1:0", 5); + if (status.Fail()) + return status.ToError(); + + args.AppendArgument( + ("localhost:" + Twine(listen_socket.GetLocalPortNumber())).str()); + + if (!InferiorArgs.empty()) { + args.AppendArgument("--"); + for (StringRef arg : InferiorArgs) + args.AppendArgument(arg); } - char connect_remote_address[64]; - snprintf(connect_remote_address, sizeof(connect_remote_address), - "localhost:%u", listen_socket.GetLocalPortNumber()); + ProcessLaunchInfo Info; + Info.SetArchitecture(arch_spec); + Info.SetArguments(args, true); - args.AppendArgument(connect_remote_address); + StringList Env; + Host::GetEnvironment(Env); + Info.GetEnvironmentEntries() = Args(Env); - m_server_process_info.SetArchitecture(arch_spec); - m_server_process_info.SetArguments(args, true); - Status status = Host::LaunchProcess(m_server_process_info); - if (status.Fail()) { - GTEST_LOG_(ERROR) - << formatv("Failure to launch lldb server: {0}.", status).str(); - return false; - } + status = Host::LaunchProcess(Info); + if (status.Fail()) + return status.ToError(); - char connect_remote_uri[64]; - snprintf(connect_remote_uri, sizeof(connect_remote_uri), "connect://%s", - connect_remote_address); Socket *accept_socket; listen_socket.Accept(accept_socket); - SetConnection(new ConnectionFileDescriptor(accept_socket)); + auto Conn = llvm::make_unique<ConnectionFileDescriptor>(accept_socket); + auto Client = std::unique_ptr<TestClient>(new TestClient(std::move(Conn))); - SendAck(); // Send this as a handshake. - return true; -} + if (!InferiorArgs.empty()) { + if (Error E = Client->QueryProcessInfo()) + return std::move(E); + } -bool TestClient::StopDebugger() { - std::string response; - return SendMessage("k", response, PacketResult::ErrorDisconnected); + return std::move(Client); } -bool TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) { +Error TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) { + StringList env; + Host::GetEnvironment(env); + for (size_t i = 0; i < env.GetSize(); ++i) { + if (SendEnvironmentPacket(env[i].c_str()) != 0) { + return make_error<StringError>( + formatv("Failed to set environment variable: {0}", env[i]).str(), + inconvertibleErrorCode()); + } + } std::stringstream command; command << "A"; for (size_t i = 0; i < inferior_args.size(); i++) { @@ -96,36 +130,26 @@ bool TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) { command << hex_encoded.size() << ',' << i << ',' << hex_encoded; } - if (!SendMessage(command.str())) - return false; - if (!SendMessage("qLaunchSuccess")) - return false; - std::string response; - if (!SendMessage("qProcessInfo", response)) - return false; - auto create_or_error = ProcessInfo::Create(response); - if (auto create_error = create_or_error.takeError()) { - GTEST_LOG_(ERROR) << toString(std::move(create_error)); - return false; - } - - m_process_info = *create_or_error; - return true; + if (Error E = SendMessage(command.str())) + return E; + if (Error E = SendMessage("qLaunchSuccess")) + return E; + if (Error E = QueryProcessInfo()) + return E; + return Error::success(); } -bool TestClient::ListThreadsInStopReply() { +Error TestClient::ListThreadsInStopReply() { return SendMessage("QListThreadsInStopReply"); } -bool TestClient::SetBreakpoint(unsigned long address) { - std::stringstream command; - command << "Z0," << std::hex << address << ",1"; - return SendMessage(command.str()); +Error TestClient::SetBreakpoint(unsigned long address) { + return SendMessage(formatv("Z0,{0:x-},1", address).str()); } -bool TestClient::ContinueAll() { return Continue("vCont;c"); } +Error TestClient::ContinueAll() { return Continue("vCont;c"); } -bool TestClient::ContinueThread(unsigned long thread_id) { +Error TestClient::ContinueThread(unsigned long thread_id) { return Continue(formatv("vCont;c:{0:x-}", thread_id).str()); } @@ -133,7 +157,7 @@ const ProcessInfo &TestClient::GetProcessInfo() { return *m_process_info; } Optional<JThreadsInfo> TestClient::GetJThreadsInfo() { std::string response; - if (!SendMessage("jThreadsInfo", response)) + if (SendMessage("jThreadsInfo", response)) return llvm::None; auto creation = JThreadsInfo::Create(response, m_process_info->GetEndian()); if (auto create_error = creation.takeError()) { @@ -145,39 +169,41 @@ Optional<JThreadsInfo> TestClient::GetJThreadsInfo() { } const StopReply &TestClient::GetLatestStopReply() { - return m_stop_reply.getValue(); + assert(m_stop_reply); + return *m_stop_reply; } -bool TestClient::SendMessage(StringRef message) { +Error TestClient::SendMessage(StringRef message) { std::string dummy_string; return SendMessage(message, dummy_string); } -bool TestClient::SendMessage(StringRef message, std::string &response_string) { - if (!SendMessage(message, response_string, PacketResult::Success)) - return false; - else if (response_string[0] == 'E') { - GTEST_LOG_(ERROR) << "Error " << response_string - << " while sending message: " << message.str(); - return false; +Error TestClient::SendMessage(StringRef message, std::string &response_string) { + if (Error E = SendMessage(message, response_string, PacketResult::Success)) + return E; + if (response_string[0] == 'E') { + return make_error<StringError>( + formatv("Error `{0}` while sending message: {1}", response_string, + message) + .str(), + inconvertibleErrorCode()); } - - return true; + return Error::success(); } -bool TestClient::SendMessage(StringRef message, std::string &response_string, - PacketResult expected_result) { +Error TestClient::SendMessage(StringRef message, std::string &response_string, + PacketResult expected_result) { StringExtractorGDBRemote response; GTEST_LOG_(INFO) << "Send Packet: " << message.str(); PacketResult result = SendPacketAndWaitForResponse(message, response, false); response.GetEscapedBinaryData(response_string); GTEST_LOG_(INFO) << "Read Packet: " << response_string; - if (result != expected_result) { - GTEST_LOG_(ERROR) << FormatFailedResult(message, result); - return false; - } + if (result != expected_result) + return make_error<StringError>( + formatv("Error sending message `{0}`: {1}", message, result).str(), + inconvertibleErrorCode()); - return true; + return Error::success(); } unsigned int TestClient::GetPcRegisterId() { @@ -187,12 +213,12 @@ unsigned int TestClient::GetPcRegisterId() { for (unsigned int register_id = 0;; register_id++) { std::string message = formatv("qRegisterInfo{0:x-}", register_id).str(); std::string response; - if (!SendMessage(message, response)) { + if (SendMessage(message, response)) { GTEST_LOG_(ERROR) << "Unable to query register ID for PC register."; return UINT_MAX; } - auto elements_or_error = SplitPairList("GetPcRegisterId", response); + auto elements_or_error = SplitUniquePairList("GetPcRegisterId", response); if (auto split_error = elements_or_error.takeError()) { GTEST_LOG_(ERROR) << "GetPcRegisterId: Error splitting response: " << response; @@ -209,78 +235,41 @@ unsigned int TestClient::GetPcRegisterId() { return m_pc_register; } -bool TestClient::Continue(StringRef message) { - if (!m_process_info.hasValue()) { - GTEST_LOG_(ERROR) << "Continue() called before m_process_info initialized."; - return false; - } - +llvm::Error TestClient::QueryProcessInfo() { std::string response; - if (!SendMessage(message, response)) - return false; - auto creation = StopReply::Create(response, m_process_info->GetEndian()); - if (auto create_error = creation.takeError()) { - GTEST_LOG_(ERROR) << toString(std::move(create_error)); - return false; - } - - m_stop_reply = std::move(*creation); - return true; + if (Error E = SendMessage("qProcessInfo", response)) + return E; + auto create_or_error = ProcessInfo::Create(response); + if (!create_or_error) + return create_or_error.takeError(); + m_process_info = *create_or_error; + return Error::success(); } -std::string TestClient::GenerateLogFileName(const ArchSpec &arch) const { - char *log_directory = getenv("LOG_FILE_DIRECTORY"); - if (!log_directory) - return ""; +Error TestClient::Continue(StringRef message) { + assert(m_process_info.hasValue()); - if (!llvm::sys::fs::is_directory(log_directory)) { - GTEST_LOG_(WARNING) << "Cannot access log directory: " << log_directory; - return ""; - } - - std::string log_file_name; - raw_string_ostream log_file(log_file_name); - log_file << log_directory << "/lldb-" << m_test_case_name << '-' - << m_test_name << '-' << arch.GetArchitectureName() << ".log"; - return log_file.str(); -} + std::string response; + if (Error E = SendMessage(message, response)) + return E; + auto creation = StopReply::create(response, m_process_info->GetEndian()); + if (Error E = creation.takeError()) + return E; -std::string TestClient::FormatFailedResult(const std::string &message, - PacketResult result) { - std::string formatted_error; - raw_string_ostream error_stream(formatted_error); - error_stream << "Failure sending message: " << message << " Result: "; - - switch (result) { - case PacketResult::ErrorSendFailed: - error_stream << "ErrorSendFailed"; - break; - case PacketResult::ErrorSendAck: - error_stream << "ErrorSendAck"; - break; - case PacketResult::ErrorReplyFailed: - error_stream << "ErrorReplyFailed"; - break; - case PacketResult::ErrorReplyTimeout: - error_stream << "ErrorReplyTimeout"; - break; - case PacketResult::ErrorReplyInvalid: - error_stream << "ErrorReplyInvalid"; - break; - case PacketResult::ErrorReplyAck: - error_stream << "ErrorReplyAck"; - break; - case PacketResult::ErrorDisconnected: - error_stream << "ErrorDisconnected"; - break; - case PacketResult::ErrorNoSequenceLock: - error_stream << "ErrorNoSequenceLock"; - break; - default: - error_stream << "Unknown Error"; + m_stop_reply = std::move(*creation); + if (!isa<StopReplyStop>(m_stop_reply)) { + StringExtractorGDBRemote R; + PacketResult result = ReadPacket(R, GetPacketTimeout(), false); + if (result != PacketResult::ErrorDisconnected) { + return make_error<StringError>( + formatv("Expected connection close after receiving {0}. Got {1}/{2} " + "instead.", + response, result, R.GetStringRef()) + .str(), + inconvertibleErrorCode()); + } } - - error_stream.str(); - return formatted_error; + return Error::success(); } + } // namespace llgs_tests diff --git a/unittests/tools/lldb-server/tests/TestClient.h b/unittests/tools/lldb-server/tests/TestClient.h index ae620cc972078..4fa1bbb8ac935 100644 --- a/unittests/tools/lldb-server/tests/TestClient.h +++ b/unittests/tools/lldb-server/tests/TestClient.h @@ -7,55 +7,75 @@ // //===----------------------------------------------------------------------===// +#ifndef LLDB_SERVER_TESTS_TESTCLIENT_H +#define LLDB_SERVER_TESTS_TESTCLIENT_H + #include "MessageObjects.h" #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h" -#include "lldb/Core/ArchSpec.h" #include "lldb/Target/ProcessLaunchInfo.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/Connection.h" #include "llvm/ADT/Optional.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/FormatVariadic.h" #include <memory> #include <string> namespace llgs_tests { -// TODO: Make the test client an abstract base class, with different children -// for different types of connections: llgs v. debugserver class TestClient : public lldb_private::process_gdb_remote::GDBRemoteCommunicationClient { public: - static void Initialize(); - TestClient(const std::string &test_name, const std::string &test_case_name); - virtual ~TestClient(); - LLVM_NODISCARD bool StartDebugger(); - LLVM_NODISCARD bool StopDebugger(); - LLVM_NODISCARD bool SetInferior(llvm::ArrayRef<std::string> inferior_args); - LLVM_NODISCARD bool ListThreadsInStopReply(); - LLVM_NODISCARD bool SetBreakpoint(unsigned long address); - LLVM_NODISCARD bool ContinueAll(); - LLVM_NODISCARD bool ContinueThread(unsigned long thread_id); + static bool IsDebugServer(); + static bool IsLldbServer(); + + /// Launches the server, connects it to the client and returns the client. If + /// Log is non-empty, the server will write it's log to this file. + static llvm::Expected<std::unique_ptr<TestClient>> launch(llvm::StringRef Log); + + /// Launches the server, while specifying the inferior on its command line. + /// When the client connects, it already has a process ready. + static llvm::Expected<std::unique_ptr<TestClient>> + launch(llvm::StringRef Log, llvm::ArrayRef<llvm::StringRef> InferiorArgs); + + ~TestClient() override; + llvm::Error SetInferior(llvm::ArrayRef<std::string> inferior_args); + llvm::Error ListThreadsInStopReply(); + llvm::Error SetBreakpoint(unsigned long address); + llvm::Error ContinueAll(); + llvm::Error ContinueThread(unsigned long thread_id); const ProcessInfo &GetProcessInfo(); llvm::Optional<JThreadsInfo> GetJThreadsInfo(); const StopReply &GetLatestStopReply(); - LLVM_NODISCARD bool SendMessage(llvm::StringRef message); - LLVM_NODISCARD bool SendMessage(llvm::StringRef message, - std::string &response_string); - LLVM_NODISCARD bool SendMessage(llvm::StringRef message, - std::string &response_string, - PacketResult expected_result); + template <typename T> llvm::Expected<const T &> GetLatestStopReplyAs() { + assert(m_stop_reply); + if (const auto *Reply = llvm::dyn_cast<T>(m_stop_reply.get())) + return *Reply; + return llvm::make_error<llvm::StringError>( + llvm::formatv("Unexpected Stop Reply {0}", m_stop_reply->getKind()), + llvm::inconvertibleErrorCode()); + } + llvm::Error SendMessage(llvm::StringRef message); + llvm::Error SendMessage(llvm::StringRef message, + std::string &response_string); + llvm::Error SendMessage(llvm::StringRef message, std::string &response_string, + PacketResult expected_result); unsigned int GetPcRegisterId(); private: - LLVM_NODISCARD bool Continue(llvm::StringRef message); - LLVM_NODISCARD bool GenerateConnectionAddress(std::string &address); - std::string GenerateLogFileName(const lldb_private::ArchSpec &arch) const; + TestClient(std::unique_ptr<lldb_private::Connection> Conn); + + llvm::Error QueryProcessInfo(); + llvm::Error Continue(llvm::StringRef message); std::string FormatFailedResult( const std::string &message, lldb_private::process_gdb_remote::GDBRemoteCommunication::PacketResult result); llvm::Optional<ProcessInfo> m_process_info; - llvm::Optional<StopReply> m_stop_reply; - lldb_private::ProcessLaunchInfo m_server_process_info; - std::string m_test_name; - std::string m_test_case_name; - unsigned int m_pc_register; + std::unique_ptr<StopReply> m_stop_reply; + unsigned int m_pc_register = UINT_MAX; }; + } // namespace llgs_tests + +#endif // LLDB_SERVER_TESTS_TESTCLIENT_H diff --git a/unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp b/unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp index 961b0a3b3167c..6ff777bd17abf 100644 --- a/unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp +++ b/unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp @@ -7,38 +7,33 @@ // //===----------------------------------------------------------------------===// +#include "TestBase.h" #include "TestClient.h" +#include "llvm/Support/Path.h" +#include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" #include <string> using namespace llgs_tests; +using namespace llvm; -class ThreadsInJstopinfoTest : public ::testing::Test { -protected: - virtual void SetUp() { TestClient::Initialize(); } -}; +TEST_F(StandardStartupTest, TestStopReplyContainsThreadPcs) { + // This inferior spawns 4 threads, then forces a break. + ASSERT_THAT_ERROR( + Client->SetInferior({getInferiorPath("thread_inferior"), "4"}), + Succeeded()); -TEST_F(ThreadsInJstopinfoTest, TestStopReplyContainsThreadPcsLlgs) { - std::vector<std::string> inferior_args; - // This inferior spawns N threads, then forces a break. - inferior_args.push_back(THREAD_INFERIOR); - inferior_args.push_back("4"); - - auto test_info = ::testing::UnitTest::GetInstance()->current_test_info(); - - TestClient client(test_info->name(), test_info->test_case_name()); - ASSERT_TRUE(client.StartDebugger()); - ASSERT_TRUE(client.SetInferior(inferior_args)); - ASSERT_TRUE(client.ListThreadsInStopReply()); - ASSERT_TRUE(client.ContinueAll()); - unsigned int pc_reg = client.GetPcRegisterId(); + ASSERT_THAT_ERROR(Client->ListThreadsInStopReply(), Succeeded()); + ASSERT_THAT_ERROR(Client->ContinueAll(), Succeeded()); + unsigned int pc_reg = Client->GetPcRegisterId(); ASSERT_NE(pc_reg, UINT_MAX); - auto jthreads_info = client.GetJThreadsInfo(); + auto jthreads_info = Client->GetJThreadsInfo(); ASSERT_TRUE(jthreads_info); - auto stop_reply = client.GetLatestStopReply(); - auto stop_reply_pcs = stop_reply.GetThreadPcs(); + auto stop_reply = Client->GetLatestStopReplyAs<StopReplyStop>(); + ASSERT_THAT_EXPECTED(stop_reply, Succeeded()); + auto stop_reply_pcs = stop_reply->getThreadPcs(); auto thread_infos = jthreads_info->GetThreadInfos(); ASSERT_EQ(stop_reply_pcs.size(), thread_infos.size()) << "Thread count mismatch."; @@ -47,12 +42,9 @@ TEST_F(ThreadsInJstopinfoTest, TestStopReplyContainsThreadPcsLlgs) { unsigned long tid = stop_reply_pc.first; ASSERT_TRUE(thread_infos.find(tid) != thread_infos.end()) << "Thread ID: " << tid << " not in JThreadsInfo."; - uint64_t pc_value; - ASSERT_TRUE(thread_infos[tid].ReadRegisterAsUint64(pc_reg, pc_value)) - << "Failure reading ThreadInfo register " << pc_reg; - ASSERT_EQ(stop_reply_pcs[tid], pc_value) + auto pc_value = thread_infos[tid].ReadRegisterAsUint64(pc_reg); + ASSERT_THAT_EXPECTED(pc_value, Succeeded()); + ASSERT_EQ(stop_reply_pcs[tid], *pc_value) << "Mismatched PC for thread: " << tid; } - - ASSERT_TRUE(client.StopDebugger()); } |