summaryrefslogtreecommitdiff
path: root/unittests
diff options
context:
space:
mode:
Diffstat (limited to 'unittests')
-rw-r--r--unittests/CMakeLists.txt7
-rw-r--r--unittests/Core/CMakeLists.txt1
-rw-r--r--unittests/Core/DataExtractorTest.cpp117
-rw-r--r--unittests/Editline/EditlineTest.cpp4
-rw-r--r--unittests/Host/CMakeLists.txt2
-rw-r--r--unittests/Host/HostInfoTest.cpp45
-rw-r--r--unittests/Host/MainLoopTest.cpp20
-rw-r--r--unittests/Host/TaskPoolTest.cpp (renamed from unittests/Utility/TaskPoolTest.cpp)4
-rw-r--r--unittests/Interpreter/CMakeLists.txt1
-rw-r--r--unittests/Interpreter/TestArgs.cpp11
-rw-r--r--unittests/Interpreter/TestCompletion.cpp2
-rw-r--r--unittests/ObjectFile/ELF/TestObjectFileELF.cpp7
-rw-r--r--unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp42
-rw-r--r--unittests/Process/minidump/MinidumpParserTest.cpp8
-rw-r--r--unittests/Symbol/TestClangASTContext.cpp56
-rw-r--r--unittests/Symbol/TestDWARFCallFrameInfo.cpp5
-rw-r--r--unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp4
-rw-r--r--unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp4
-rw-r--r--unittests/Target/ModuleCacheTest.cpp2
-rw-r--r--unittests/TestingSupport/CMakeLists.txt (renamed from unittests/Utility/Helpers/CMakeLists.txt)0
-rw-r--r--unittests/TestingSupport/MockTildeExpressionResolver.cpp (renamed from unittests/Utility/Helpers/MockTildeExpressionResolver.cpp)0
-rw-r--r--unittests/TestingSupport/MockTildeExpressionResolver.h (renamed from unittests/Utility/Helpers/MockTildeExpressionResolver.h)0
-rw-r--r--unittests/TestingSupport/TestUtilities.cpp (renamed from unittests/Utility/Helpers/TestUtilities.cpp)0
-rw-r--r--unittests/TestingSupport/TestUtilities.h (renamed from unittests/Utility/Helpers/TestUtilities.h)0
-rw-r--r--unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp12
-rw-r--r--unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp6
-rw-r--r--unittests/Utility/ArchSpecTest.cpp (renamed from unittests/Core/ArchSpecTest.cpp)3
-rw-r--r--unittests/Utility/CMakeLists.txt5
-rw-r--r--unittests/Utility/JSONTest.cpp26
-rw-r--r--unittests/Utility/StructuredDataTest.cpp2
-rw-r--r--unittests/Utility/TildeExpressionResolverTest.cpp2
-rw-r--r--unittests/Utility/VASprintfTest.cpp12
-rw-r--r--unittests/debugserver/CMakeLists.txt19
-rw-r--r--unittests/tools/CMakeLists.txt2
-rw-r--r--unittests/tools/lldb-server/CMakeLists.txt18
-rw-r--r--unittests/tools/lldb-server/inferior/environment_check.cpp20
-rw-r--r--unittests/tools/lldb-server/tests/CMakeLists.txt8
-rw-r--r--unittests/tools/lldb-server/tests/LLGSTest.cpp36
-rw-r--r--unittests/tools/lldb-server/tests/MessageObjects.cpp152
-rw-r--r--unittests/tools/lldb-server/tests/MessageObjects.h85
-rw-r--r--unittests/tools/lldb-server/tests/TestBase.cpp36
-rw-r--r--unittests/tools/lldb-server/tests/TestBase.h48
-rw-r--r--unittests/tools/lldb-server/tests/TestClient.cpp291
-rw-r--r--unittests/tools/lldb-server/tests/TestClient.h74
-rw-r--r--unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp46
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 &registers, 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());
}