summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/lldb/unittests/Process
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/llvm/lldb/unittests/Process')
-rw-r--r--gnu/llvm/lldb/unittests/Process/CMakeLists.txt6
-rw-r--r--gnu/llvm/lldb/unittests/Process/Linux/CMakeLists.txt8
-rw-r--r--gnu/llvm/lldb/unittests/Process/Linux/ProcessorTraceTest.cpp147
-rw-r--r--gnu/llvm/lldb/unittests/Process/POSIX/CMakeLists.txt8
-rw-r--r--gnu/llvm/lldb/unittests/Process/POSIX/NativeProcessELFTest.cpp155
-rw-r--r--gnu/llvm/lldb/unittests/Process/gdb-remote/CMakeLists.txt19
-rw-r--r--gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp361
-rw-r--r--gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp554
-rw-r--r--gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationServerTest.cpp73
-rw-r--r--gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp67
-rw-r--r--gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp23
-rw-r--r--gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteTestUtils.h91
-rw-r--r--gnu/llvm/lldb/unittests/Process/minidump/CMakeLists.txt25
-rw-r--r--gnu/llvm/lldb/unittests/Process/minidump/Inputs/fizzbuzz_no_heap.dmpbin0 -> 6297 bytes
-rw-r--r--gnu/llvm/lldb/unittests/Process/minidump/Inputs/fizzbuzz_wow64.dmpbin0 -> 9280561 bytes
-rw-r--r--gnu/llvm/lldb/unittests/Process/minidump/Inputs/linux-x86_64.cpp28
-rw-r--r--gnu/llvm/lldb/unittests/Process/minidump/Inputs/linux-x86_64.dmpbin0 -> 38320 bytes
-rw-r--r--gnu/llvm/lldb/unittests/Process/minidump/Inputs/regions-memlist64.dmpbin0 -> 260 bytes
-rw-r--r--gnu/llvm/lldb/unittests/Process/minidump/MinidumpParserTest.cpp724
-rw-r--r--gnu/llvm/lldb/unittests/Process/minidump/RegisterContextMinidumpTest.cpp201
20 files changed, 2490 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/unittests/Process/CMakeLists.txt b/gnu/llvm/lldb/unittests/Process/CMakeLists.txt
new file mode 100644
index 00000000000..a4045692eb5
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_subdirectory(gdb-remote)
+if (CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
+ add_subdirectory(Linux)
+ add_subdirectory(POSIX)
+endif()
+add_subdirectory(minidump)
diff --git a/gnu/llvm/lldb/unittests/Process/Linux/CMakeLists.txt b/gnu/llvm/lldb/unittests/Process/Linux/CMakeLists.txt
new file mode 100644
index 00000000000..3b55b5c8430
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/Linux/CMakeLists.txt
@@ -0,0 +1,8 @@
+include_directories(${LLDB_SOURCE_DIR}/source/Plugins/Process/Linux)
+
+add_lldb_unittest(ProcessorTraceTest
+ ProcessorTraceTest.cpp
+
+ LINK_LIBS
+ lldbPluginProcessLinux
+ ) \ No newline at end of file
diff --git a/gnu/llvm/lldb/unittests/Process/Linux/ProcessorTraceTest.cpp b/gnu/llvm/lldb/unittests/Process/Linux/ProcessorTraceTest.cpp
new file mode 100644
index 00000000000..d3165a1db9c
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/Linux/ProcessorTraceTest.cpp
@@ -0,0 +1,147 @@
+//===-- ProcessorTraceMonitorTest.cpp ------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "ProcessorTrace.h"
+#include "llvm/ADT/ArrayRef.h"
+
+
+using namespace lldb_private;
+using namespace process_linux;
+
+size_t ReadCylicBufferWrapper(void *buf, size_t buf_size, void *cyc_buf,
+ size_t cyc_buf_size, size_t cyc_start,
+ size_t offset) {
+ llvm::MutableArrayRef<uint8_t> dst(reinterpret_cast<uint8_t *>(buf),
+ buf_size);
+ llvm::MutableArrayRef<uint8_t> src(reinterpret_cast<uint8_t *>(cyc_buf),
+ cyc_buf_size);
+ ProcessorTraceMonitor::ReadCyclicBuffer(dst, src, cyc_start, offset);
+ return dst.size();
+}
+
+TEST(CyclicBuffer, EdgeCases) {
+ size_t bytes_read;
+ uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
+
+ // We will always leave the last bytes untouched
+ // so that string comparisions work.
+ char smaller_buffer[4] = {};
+
+ // empty buffer to read into
+ bytes_read = ReadCylicBufferWrapper(smaller_buffer, 0, cyclic_buffer,
+ sizeof(cyclic_buffer), 3, 0);
+ ASSERT_EQ(0u, bytes_read);
+
+ // empty cyclic buffer
+ bytes_read = ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
+ cyclic_buffer, 0, 3, 0);
+ ASSERT_EQ(0u, bytes_read);
+
+ // bigger offset
+ bytes_read =
+ ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
+ cyclic_buffer, sizeof(cyclic_buffer), 3, 6);
+ ASSERT_EQ(0u, bytes_read);
+
+ // wrong offset
+ bytes_read =
+ ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
+ cyclic_buffer, sizeof(cyclic_buffer), 3, 7);
+ ASSERT_EQ(0u, bytes_read);
+
+ // wrong start
+ bytes_read =
+ ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
+ cyclic_buffer, sizeof(cyclic_buffer), 3, 7);
+ ASSERT_EQ(0u, bytes_read);
+}
+
+TEST(CyclicBuffer, EqualSizeBuffer) {
+ size_t bytes_read = 0;
+ uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
+
+ char cyclic[] = "cyclic";
+ for (size_t i = 0; i < sizeof(cyclic); i++) {
+ // We will always leave the last bytes untouched
+ // so that string comparisions work.
+ char equal_size_buffer[7] = {};
+ bytes_read =
+ ReadCylicBufferWrapper(equal_size_buffer, sizeof(cyclic_buffer),
+ cyclic_buffer, sizeof(cyclic_buffer), 3, i);
+ ASSERT_EQ((sizeof(cyclic) - i - 1), bytes_read);
+ ASSERT_STREQ(equal_size_buffer, (cyclic + i));
+ }
+}
+
+TEST(CyclicBuffer, SmallerSizeBuffer) {
+ size_t bytes_read;
+ uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
+
+ // We will always leave the last bytes untouched
+ // so that string comparisions work.
+ char smaller_buffer[4] = {};
+ bytes_read =
+ ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
+ cyclic_buffer, sizeof(cyclic_buffer), 3, 0);
+ ASSERT_EQ(3u, bytes_read);
+ ASSERT_STREQ(smaller_buffer, "cyc");
+
+ bytes_read =
+ ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
+ cyclic_buffer, sizeof(cyclic_buffer), 3, 1);
+ ASSERT_EQ(3u, bytes_read);
+ ASSERT_STREQ(smaller_buffer, "ycl");
+
+ bytes_read =
+ ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
+ cyclic_buffer, sizeof(cyclic_buffer), 3, 2);
+ ASSERT_EQ(3u, bytes_read);
+ ASSERT_STREQ(smaller_buffer, "cli");
+
+ bytes_read =
+ ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
+ cyclic_buffer, sizeof(cyclic_buffer), 3, 3);
+ ASSERT_EQ(3u, bytes_read);
+ ASSERT_STREQ(smaller_buffer, "lic");
+
+ {
+ char smaller_buffer[4] = {};
+ bytes_read =
+ ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
+ cyclic_buffer, sizeof(cyclic_buffer), 3, 4);
+ ASSERT_EQ(2u, bytes_read);
+ ASSERT_STREQ(smaller_buffer, "ic");
+ }
+ {
+ char smaller_buffer[4] = {};
+ bytes_read =
+ ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
+ cyclic_buffer, sizeof(cyclic_buffer), 3, 5);
+ ASSERT_EQ(1u, bytes_read);
+ ASSERT_STREQ(smaller_buffer, "c");
+ }
+}
+
+TEST(CyclicBuffer, BiggerSizeBuffer) {
+ size_t bytes_read = 0;
+ uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
+
+ char cyclic[] = "cyclic";
+ for (size_t i = 0; i < sizeof(cyclic); i++) {
+ // We will always leave the last bytes untouched
+ // so that string comparisions work.
+ char bigger_buffer[10] = {};
+ bytes_read =
+ ReadCylicBufferWrapper(bigger_buffer, (sizeof(bigger_buffer) - 1),
+ cyclic_buffer, sizeof(cyclic_buffer), 3, i);
+ ASSERT_EQ((sizeof(cyclic) - i - 1), bytes_read);
+ ASSERT_STREQ(bigger_buffer, (cyclic + i));
+ }
+}
diff --git a/gnu/llvm/lldb/unittests/Process/POSIX/CMakeLists.txt b/gnu/llvm/lldb/unittests/Process/POSIX/CMakeLists.txt
new file mode 100644
index 00000000000..53318d908da
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/POSIX/CMakeLists.txt
@@ -0,0 +1,8 @@
+include_directories(${LLDB_SOURCE_DIR}/source/Plugins/Process/POSIX)
+
+add_lldb_unittest(ProcessPOSIXTest
+ NativeProcessELFTest.cpp
+
+ LINK_LIBS
+ lldbPluginProcessPOSIX
+ )
diff --git a/gnu/llvm/lldb/unittests/Process/POSIX/NativeProcessELFTest.cpp b/gnu/llvm/lldb/unittests/Process/POSIX/NativeProcessELFTest.cpp
new file mode 100644
index 00000000000..9e91464c441
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/POSIX/NativeProcessELFTest.cpp
@@ -0,0 +1,155 @@
+//===-- NativeProcessELFTest.cpp --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestingSupport/Host/NativeProcessTestUtils.h"
+
+#include "Plugins/Process/POSIX/NativeProcessELF.h"
+#include "Plugins/Process/Utility/AuxVector.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataEncoder.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include "gmock/gmock.h"
+
+using namespace lldb_private;
+using namespace lldb;
+using namespace testing;
+
+namespace {
+class MockProcessELF : public MockProcess<NativeProcessELF> {
+public:
+ using MockProcess::MockProcess;
+ using NativeProcessELF::GetAuxValue;
+ using NativeProcessELF::GetELFImageInfoAddress;
+};
+
+std::unique_ptr<llvm::MemoryBuffer> CreateAuxvData(
+ MockProcessELF &process,
+ llvm::ArrayRef<std::pair<AuxVector::EntryType, uint32_t>> auxv_data) {
+ auto addr_size = process.GetAddressByteSize();
+ DataBufferSP buffer_sp(
+ new DataBufferHeap(auxv_data.size() * addr_size * 2, 0));
+ DataEncoder encoder(buffer_sp, process.GetByteOrder(), addr_size);
+ uint32_t offset = 0;
+ for (auto &pair : auxv_data) {
+ offset = encoder.PutAddress(offset, pair.first);
+ offset = encoder.PutAddress(offset, pair.second);
+ }
+ return llvm::MemoryBuffer::getMemBufferCopy(
+ llvm::toStringRef(buffer_sp->GetData()), "");
+}
+
+} // namespace
+
+TEST(NativeProcessELFTest, GetAuxValue) {
+ NiceMock<MockDelegate> DummyDelegate;
+ MockProcessELF process(DummyDelegate, ArchSpec("i386-pc-linux"));
+
+ uint64_t phdr_addr = 0x42;
+ auto auxv_buffer = CreateAuxvData(
+ process, {std::make_pair(AuxVector::AUXV_AT_PHDR, phdr_addr)});
+ EXPECT_CALL(process, GetAuxvData())
+ .WillOnce(Return(ByMove(std::move(auxv_buffer))));
+
+ ASSERT_EQ(phdr_addr, process.GetAuxValue(AuxVector::AUXV_AT_PHDR));
+}
+
+TEST(NativeProcessELFTest, GetELFImageInfoAddress) {
+ NiceMock<MockDelegate> DummyDelegate;
+ MockProcessELF process(DummyDelegate, ArchSpec("i386-pc-linux"));
+
+ uint32_t load_base = 0x1000;
+ uint32_t info_addr = 0x3741;
+ uint32_t phdr_addr = load_base + sizeof(llvm::ELF::Elf32_Ehdr);
+
+ auto auxv_buffer = CreateAuxvData(
+ process,
+ {std::make_pair(AuxVector::AUXV_AT_PHDR, phdr_addr),
+ std::make_pair(AuxVector::AUXV_AT_PHENT, sizeof(llvm::ELF::Elf32_Phdr)),
+ std::make_pair(AuxVector::AUXV_AT_PHNUM, 2)});
+ EXPECT_CALL(process, GetAuxvData())
+ .WillOnce(Return(ByMove(std::move(auxv_buffer))));
+
+ // We're going to set up a fake memory with 2 program headers and 1 entry in
+ // the dynamic section. For simplicity sake they will be contiguous in memory.
+ struct MemoryContents {
+ llvm::ELF::Elf32_Phdr phdr_load;
+ llvm::ELF::Elf32_Phdr phdr_dynamic;
+ llvm::ELF::Elf32_Dyn dyn_debug;
+ } MC;
+ // Setup the 2 program header entries
+ MC.phdr_load.p_type = llvm::ELF::PT_PHDR;
+ MC.phdr_load.p_vaddr = phdr_addr - load_base;
+
+ MC.phdr_dynamic.p_type = llvm::ELF::PT_DYNAMIC;
+ MC.phdr_dynamic.p_vaddr =
+ (phdr_addr + 2 * sizeof(llvm::ELF::Elf32_Phdr)) - load_base;
+ MC.phdr_dynamic.p_memsz = sizeof(llvm::ELF::Elf32_Dyn);
+
+ // Setup the single entry in the .dynamic section
+ MC.dyn_debug.d_tag = llvm::ELF::DT_DEBUG;
+ MC.dyn_debug.d_un.d_ptr = info_addr;
+
+ FakeMemory M(&MC, sizeof(MC), phdr_addr);
+ EXPECT_CALL(process, ReadMemory(_, _))
+ .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
+
+ lldb::addr_t elf_info_addr = process.GetELFImageInfoAddress<
+ llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
+
+ // Read the address at the elf_info_addr location to make sure we're reading
+ // the correct one.
+ lldb::offset_t info_addr_offset = elf_info_addr - phdr_addr;
+ DataExtractor mem_extractor(&MC, sizeof(MC), process.GetByteOrder(),
+ process.GetAddressByteSize());
+ ASSERT_EQ(mem_extractor.GetAddress(&info_addr_offset), info_addr);
+}
+
+TEST(NativeProcessELFTest, GetELFImageInfoAddress_NoDebugEntry) {
+ NiceMock<MockDelegate> DummyDelegate;
+ MockProcessELF process(DummyDelegate, ArchSpec("i386-pc-linux"));
+
+ uint32_t phdr_addr = sizeof(llvm::ELF::Elf32_Ehdr);
+
+ auto auxv_buffer = CreateAuxvData(
+ process,
+ {std::make_pair(AuxVector::AUXV_AT_PHDR, phdr_addr),
+ std::make_pair(AuxVector::AUXV_AT_PHENT, sizeof(llvm::ELF::Elf32_Phdr)),
+ std::make_pair(AuxVector::AUXV_AT_PHNUM, 2)});
+ EXPECT_CALL(process, GetAuxvData())
+ .WillOnce(Return(ByMove(std::move(auxv_buffer))));
+
+ // We're going to set up a fake memory with 2 program headers and 1 entry in
+ // the dynamic section. For simplicity sake they will be contiguous in memory.
+ struct MemoryContents {
+ llvm::ELF::Elf32_Phdr phdr_load;
+ llvm::ELF::Elf32_Phdr phdr_dynamic;
+ llvm::ELF::Elf32_Dyn dyn_notdebug;
+ } MC;
+ // Setup the 2 program header entries
+ MC.phdr_load.p_type = llvm::ELF::PT_PHDR;
+ MC.phdr_load.p_vaddr = phdr_addr;
+
+ MC.phdr_dynamic.p_type = llvm::ELF::PT_DYNAMIC;
+ MC.phdr_dynamic.p_vaddr = (phdr_addr + 2 * sizeof(llvm::ELF::Elf32_Phdr));
+ MC.phdr_dynamic.p_memsz = sizeof(llvm::ELF::Elf32_Dyn);
+
+ // Setup the single entry in the .dynamic section
+ MC.dyn_notdebug.d_tag = llvm::ELF::DT_NULL;
+
+ FakeMemory M(&MC, sizeof(MC), phdr_addr);
+ EXPECT_CALL(process, ReadMemory(_, _))
+ .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
+
+ lldb::addr_t elf_info_addr = process.GetELFImageInfoAddress<
+ llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
+
+ ASSERT_EQ(elf_info_addr, LLDB_INVALID_ADDRESS);
+}
diff --git a/gnu/llvm/lldb/unittests/Process/gdb-remote/CMakeLists.txt b/gnu/llvm/lldb/unittests/Process/gdb-remote/CMakeLists.txt
new file mode 100644
index 00000000000..abb30e022e4
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/gdb-remote/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_lldb_unittest(ProcessGdbRemoteTests
+ GDBRemoteClientBaseTest.cpp
+ GDBRemoteCommunicationClientTest.cpp
+ GDBRemoteCommunicationServerTest.cpp
+ GDBRemoteCommunicationTest.cpp
+ GDBRemoteTestUtils.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbHost
+ lldbPluginPlatformMacOSX
+ lldbPluginProcessUtility
+ lldbPluginProcessGDBRemote
+
+ LLVMTestingSupport
+
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp
new file mode 100644
index 00000000000..d56e9cf81bc
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp
@@ -0,0 +1,361 @@
+//===-- GDBRemoteClientBaseTest.cpp -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include <future>
+
+#include "GDBRemoteTestUtils.h"
+
+#include "Plugins/Process/Utility/LinuxSignals.h"
+#include "Plugins/Process/gdb-remote/GDBRemoteClientBase.h"
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"
+#include "lldb/Utility/GDBRemote.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Testing/Support/Error.h"
+
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private;
+using namespace lldb;
+typedef GDBRemoteCommunication::PacketResult PacketResult;
+
+namespace {
+
+struct MockDelegate : public GDBRemoteClientBase::ContinueDelegate {
+ std::string output;
+ std::string misc_data;
+ unsigned stop_reply_called = 0;
+ std::vector<std::string> structured_data_packets;
+
+ void HandleAsyncStdout(llvm::StringRef out) override { output += out; }
+ void HandleAsyncMisc(llvm::StringRef data) override { misc_data += data; }
+ void HandleStopReply() override { ++stop_reply_called; }
+
+ void HandleAsyncStructuredDataPacket(llvm::StringRef data) override {
+ structured_data_packets.push_back(data);
+ }
+};
+
+struct TestClient : public GDBRemoteClientBase {
+ TestClient() : GDBRemoteClientBase("test.client", "test.client.listener") {
+ m_send_acks = false;
+ }
+};
+
+class GDBRemoteClientBaseTest : public GDBRemoteTest {
+public:
+ void SetUp() override {
+ ASSERT_THAT_ERROR(GDBRemoteCommunication::ConnectLocally(client, server),
+ llvm::Succeeded());
+ ASSERT_EQ(TestClient::eBroadcastBitRunPacketSent,
+ listener_sp->StartListeningForEvents(
+ &client, TestClient::eBroadcastBitRunPacketSent));
+ }
+
+protected:
+ TestClient client;
+ MockServer server;
+ MockDelegate delegate;
+ ListenerSP listener_sp = Listener::MakeListener("listener");
+
+ StateType SendCPacket(StringExtractorGDBRemote &response) {
+ return client.SendContinuePacketAndWaitForResponse(delegate, LinuxSignals(),
+ "c", response);
+ }
+
+ void WaitForRunEvent() {
+ EventSP event_sp;
+ listener_sp->GetEventForBroadcasterWithType(
+ &client, TestClient::eBroadcastBitRunPacketSent, event_sp, llvm::None);
+ }
+};
+
+} // end anonymous namespace
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueAndWait) {
+ StringExtractorGDBRemote response;
+
+ // Continue. The inferior will stop with a signal.
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, SendCPacket(response));
+ ASSERT_EQ("T01", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+
+ // Continue. The inferior will exit.
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("W01"));
+ ASSERT_EQ(eStateExited, SendCPacket(response));
+ ASSERT_EQ("W01", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+
+ // Continue. The inferior will get killed.
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("X01"));
+ ASSERT_EQ(eStateExited, SendCPacket(response));
+ ASSERT_EQ("X01", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+}
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncSignal) {
+ StringExtractorGDBRemote continue_response, response;
+
+ // SendAsyncSignal should do nothing when we are not running.
+ ASSERT_FALSE(client.SendAsyncSignal(0x47));
+
+ // Continue. After the run packet is sent, send an async signal.
+ std::future<StateType> continue_state = std::async(
+ std::launch::async, [&] { return SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+ WaitForRunEvent();
+
+ std::future<bool> async_result = std::async(
+ std::launch::async, [&] { return client.SendAsyncSignal(0x47); });
+
+ // First we'll get interrupted.
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("\x03", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
+
+ // Then we get the signal packet.
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("C47", response.GetStringRef());
+ ASSERT_TRUE(async_result.get());
+
+ // And we report back a signal stop.
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T47"));
+ ASSERT_EQ(eStateStopped, continue_state.get());
+ ASSERT_EQ("T47", continue_response.GetStringRef());
+}
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncPacket) {
+ StringExtractorGDBRemote continue_response, async_response, response;
+ const bool send_async = true;
+
+ // Continue. After the run packet is sent, send an async packet.
+ std::future<StateType> continue_state = std::async(
+ std::launch::async, [&] { return SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+ WaitForRunEvent();
+
+ // Sending without async enabled should fail.
+ ASSERT_EQ(
+ PacketResult::ErrorSendFailed,
+ client.SendPacketAndWaitForResponse("qTest1", response, !send_async));
+
+ std::future<PacketResult> async_result = std::async(std::launch::async, [&] {
+ return client.SendPacketAndWaitForResponse("qTest2", async_response,
+ send_async);
+ });
+
+ // First we'll get interrupted.
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("\x03", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
+
+ // Then we get the async packet.
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("qTest2", response.GetStringRef());
+
+ // Send the response and receive it.
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("QTest2"));
+ ASSERT_EQ(PacketResult::Success, async_result.get());
+ ASSERT_EQ("QTest2", async_response.GetStringRef());
+
+ // And we get resumed again.
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, continue_state.get());
+ ASSERT_EQ("T01", continue_response.GetStringRef());
+}
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt) {
+ StringExtractorGDBRemote continue_response, response;
+
+ // Interrupt should do nothing when we're not running.
+ ASSERT_FALSE(client.Interrupt());
+
+ // Continue. After the run packet is sent, send an interrupt.
+ std::future<StateType> continue_state = std::async(
+ std::launch::async, [&] { return SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+ WaitForRunEvent();
+
+ std::future<bool> async_result =
+ std::async(std::launch::async, [&] { return client.Interrupt(); });
+
+ // We get interrupted.
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("\x03", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
+
+ // And that's it.
+ ASSERT_EQ(eStateStopped, continue_state.get());
+ ASSERT_EQ("T13", continue_response.GetStringRef());
+ ASSERT_TRUE(async_result.get());
+}
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueAndLateInterrupt) {
+ StringExtractorGDBRemote continue_response, response;
+
+ // Continue. After the run packet is sent, send an interrupt.
+ std::future<StateType> continue_state = std::async(
+ std::launch::async, [&] { return SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+ WaitForRunEvent();
+
+ std::future<bool> async_result =
+ std::async(std::launch::async, [&] { return client.Interrupt(); });
+
+ // However, the target stops due to a different reason than the original
+ // interrupt.
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("\x03", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, continue_state.get());
+ ASSERT_EQ("T01", continue_response.GetStringRef());
+ ASSERT_TRUE(async_result.get());
+
+ // The subsequent continue packet should work normally.
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, SendCPacket(response));
+ ASSERT_EQ("T01", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+}
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt2PacketBug) {
+ StringExtractorGDBRemote continue_response, async_response, response;
+ const bool send_async = true;
+
+ // Interrupt should do nothing when we're not running.
+ ASSERT_FALSE(client.Interrupt());
+
+ // Continue. After the run packet is sent, send an async signal.
+ std::future<StateType> continue_state = std::async(
+ std::launch::async, [&] { return SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+ WaitForRunEvent();
+
+ std::future<bool> interrupt_result =
+ std::async(std::launch::async, [&] { return client.Interrupt(); });
+
+ // We get interrupted. We'll send two packets to simulate a buggy stub.
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("\x03", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
+
+ // We should stop.
+ ASSERT_EQ(eStateStopped, continue_state.get());
+ ASSERT_EQ("T13", continue_response.GetStringRef());
+ ASSERT_TRUE(interrupt_result.get());
+
+ // Packet stream should remain synchronized.
+ std::future<PacketResult> send_result = std::async(std::launch::async, [&] {
+ return client.SendPacketAndWaitForResponse("qTest", async_response,
+ !send_async);
+ });
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("qTest", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("QTest"));
+ ASSERT_EQ(PacketResult::Success, send_result.get());
+ ASSERT_EQ("QTest", async_response.GetStringRef());
+}
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateInterface) {
+ StringExtractorGDBRemote response;
+
+ // Continue. We'll have the server send a bunch of async packets before it
+ // stops.
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("O4142"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("Apro"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("O4344"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("Afile"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, SendCPacket(response));
+ ASSERT_EQ("T01", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+
+ EXPECT_EQ("ABCD", delegate.output);
+ EXPECT_EQ("profile", delegate.misc_data);
+ EXPECT_EQ(1u, delegate.stop_reply_called);
+}
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateStructuredDataReceipt) {
+ // Build the plain-text version of the JSON data we will have the
+ // server send.
+ const std::string json_payload =
+ "{ \"type\": \"MyFeatureType\", "
+ " \"elements\": [ \"entry1\", \"entry2\" ] }";
+ const std::string json_packet = "JSON-async:" + json_payload;
+
+ // Escape it properly for transit.
+ StreamGDBRemote stream;
+ stream.PutEscapedBytes(json_packet.c_str(), json_packet.length());
+ stream.Flush();
+
+ StringExtractorGDBRemote response;
+
+ // Send async structured data packet, then stop.
+ ASSERT_EQ(PacketResult::Success, server.SendPacket(stream.GetData()));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, SendCPacket(response));
+ ASSERT_EQ("T01", response.GetStringRef());
+ ASSERT_EQ(1ul, delegate.structured_data_packets.size());
+
+ // Verify the packet contents. It should have been unescaped upon packet
+ // reception.
+ ASSERT_EQ(json_packet, delegate.structured_data_packets[0]);
+}
+
+TEST_F(GDBRemoteClientBaseTest, InterruptNoResponse) {
+ StringExtractorGDBRemote continue_response, response;
+
+ // Continue. After the run packet is sent, send an interrupt.
+ std::future<StateType> continue_state = std::async(
+ std::launch::async, [&] { return SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+ WaitForRunEvent();
+
+ std::future<bool> async_result =
+ std::async(std::launch::async, [&] { return client.Interrupt(); });
+
+ // We get interrupted, but we don't send a stop packet.
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
+ ASSERT_EQ("\x03", response.GetStringRef());
+
+ // The functions should still terminate (after a timeout).
+ ASSERT_TRUE(async_result.get());
+ ASSERT_EQ(eStateInvalid, continue_state.get());
+}
+
+TEST_F(GDBRemoteClientBaseTest, SendPacketAndReceiveResponseWithOutputSupport) {
+ StringExtractorGDBRemote response;
+ StreamString command_output;
+
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("O"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("O48656c6c6f2c"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("O20"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("O"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("O776f726c64"));
+ ASSERT_EQ(PacketResult::Success, server.SendPacket("OK"));
+
+ PacketResult result = client.SendPacketAndReceiveResponseWithOutputSupport(
+ "qRcmd,test", response, true,
+ [&command_output](llvm::StringRef output) { command_output << output; });
+
+ ASSERT_EQ(PacketResult::Success, result);
+ ASSERT_EQ("OK", response.GetStringRef());
+ ASSERT_EQ("Hello, world", command_output.GetString().str());
+}
diff --git a/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
new file mode 100644
index 00000000000..e52f3782437
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
@@ -0,0 +1,554 @@
+//===-- GDBRemoteCommunicationClientTest.cpp --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h"
+#include "GDBRemoteTestUtils.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/XML.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/TraceOptions.h"
+#include "lldb/lldb-enumerations.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gmock/gmock.h"
+#include <future>
+
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private;
+using namespace lldb;
+using namespace llvm;
+
+namespace {
+
+typedef GDBRemoteCommunication::PacketResult PacketResult;
+
+struct TestClient : public GDBRemoteCommunicationClient {
+ TestClient() { m_send_acks = false; }
+};
+
+void Handle_QThreadSuffixSupported(MockServer &server, bool supported) {
+ StringExtractorGDBRemote request;
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(request));
+ ASSERT_EQ("QThreadSuffixSupported", request.GetStringRef());
+ if (supported)
+ ASSERT_EQ(PacketResult::Success, server.SendOKResponse());
+ else
+ ASSERT_EQ(PacketResult::Success, server.SendUnimplementedResponse(nullptr));
+}
+
+void HandlePacket(MockServer &server,
+ const testing::Matcher<const std::string &> &expected,
+ StringRef response) {
+ StringExtractorGDBRemote request;
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(request));
+ ASSERT_THAT(request.GetStringRef(), expected);
+ ASSERT_EQ(PacketResult::Success, server.SendPacket(response));
+}
+
+uint8_t all_registers[] = {'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'};
+std::string all_registers_hex = "404142434445464748494a4b4c4d4e4f";
+uint8_t one_register[] = {'A', 'B', 'C', 'D'};
+std::string one_register_hex = "41424344";
+
+} // end anonymous namespace
+
+class GDBRemoteCommunicationClientTest : public GDBRemoteTest {
+public:
+ void SetUp() override {
+ ASSERT_THAT_ERROR(GDBRemoteCommunication::ConnectLocally(client, server),
+ llvm::Succeeded());
+ }
+
+protected:
+ TestClient client;
+ MockServer server;
+};
+
+TEST_F(GDBRemoteCommunicationClientTest, WriteRegister) {
+ const lldb::tid_t tid = 0x47;
+ const uint32_t reg_num = 4;
+ std::future<bool> write_result = std::async(std::launch::async, [&] {
+ return client.WriteRegister(tid, reg_num, one_register);
+ });
+
+ Handle_QThreadSuffixSupported(server, true);
+
+ HandlePacket(server, "P4=" + one_register_hex + ";thread:0047;", "OK");
+ ASSERT_TRUE(write_result.get());
+
+ write_result = std::async(std::launch::async, [&] {
+ return client.WriteAllRegisters(tid, all_registers);
+ });
+
+ HandlePacket(server, "G" + all_registers_hex + ";thread:0047;", "OK");
+ ASSERT_TRUE(write_result.get());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, WriteRegisterNoSuffix) {
+ const lldb::tid_t tid = 0x47;
+ const uint32_t reg_num = 4;
+ std::future<bool> write_result = std::async(std::launch::async, [&] {
+ return client.WriteRegister(tid, reg_num, one_register);
+ });
+
+ Handle_QThreadSuffixSupported(server, false);
+ HandlePacket(server, "Hg47", "OK");
+ HandlePacket(server, "P4=" + one_register_hex, "OK");
+ ASSERT_TRUE(write_result.get());
+
+ write_result = std::async(std::launch::async, [&] {
+ return client.WriteAllRegisters(tid, all_registers);
+ });
+
+ HandlePacket(server, "G" + all_registers_hex, "OK");
+ ASSERT_TRUE(write_result.get());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, ReadRegister) {
+ const lldb::tid_t tid = 0x47;
+ const uint32_t reg_num = 4;
+ std::future<bool> async_result = std::async(
+ std::launch::async, [&] { return client.GetpPacketSupported(tid); });
+ Handle_QThreadSuffixSupported(server, true);
+ HandlePacket(server, "p0;thread:0047;", one_register_hex);
+ ASSERT_TRUE(async_result.get());
+
+ std::future<DataBufferSP> read_result = std::async(
+ std::launch::async, [&] { return client.ReadRegister(tid, reg_num); });
+ HandlePacket(server, "p4;thread:0047;", "41424344");
+ auto buffer_sp = read_result.get();
+ ASSERT_TRUE(bool(buffer_sp));
+ ASSERT_EQ(0,
+ memcmp(buffer_sp->GetBytes(), one_register, sizeof one_register));
+
+ read_result = std::async(std::launch::async,
+ [&] { return client.ReadAllRegisters(tid); });
+ HandlePacket(server, "g;thread:0047;", all_registers_hex);
+ buffer_sp = read_result.get();
+ ASSERT_TRUE(bool(buffer_sp));
+ ASSERT_EQ(0,
+ memcmp(buffer_sp->GetBytes(), all_registers, sizeof all_registers));
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, SaveRestoreRegistersNoSuffix) {
+ const lldb::tid_t tid = 0x47;
+ uint32_t save_id;
+ std::future<bool> async_result = std::async(std::launch::async, [&] {
+ return client.SaveRegisterState(tid, save_id);
+ });
+ Handle_QThreadSuffixSupported(server, false);
+ HandlePacket(server, "Hg47", "OK");
+ HandlePacket(server, "QSaveRegisterState", "1");
+ ASSERT_TRUE(async_result.get());
+ EXPECT_EQ(1u, save_id);
+
+ async_result = std::async(std::launch::async, [&] {
+ return client.RestoreRegisterState(tid, save_id);
+ });
+ HandlePacket(server, "QRestoreRegisterState:1", "OK");
+ ASSERT_TRUE(async_result.get());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, SyncThreadState) {
+ const lldb::tid_t tid = 0x47;
+ std::future<bool> async_result = std::async(
+ std::launch::async, [&] { return client.SyncThreadState(tid); });
+ HandlePacket(server, "qSyncThreadStateSupported", "OK");
+ HandlePacket(server, "QSyncThreadState:0047;", "OK");
+ ASSERT_TRUE(async_result.get());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo) {
+ llvm::Triple triple("i386-pc-linux");
+
+ FileSpec file_specs[] = {
+ FileSpec("/foo/bar.so", FileSpec::Style::posix),
+ FileSpec("/foo/baz.so", FileSpec::Style::posix),
+
+ // This is a bit dodgy but we currently depend on GetModulesInfo not
+ // performing denormalization. It can go away once the users
+ // (DynamicLoaderPOSIXDYLD, at least) correctly set the path syntax for
+ // the FileSpecs they create.
+ FileSpec("/foo/baw.so", FileSpec::Style::windows),
+ };
+ std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
+ std::async(std::launch::async,
+ [&] { return client.GetModulesInfo(file_specs, triple); });
+ HandlePacket(
+ server, "jModulesInfo:["
+ R"({"file":"/foo/bar.so","triple":"i386-pc-linux"},)"
+ R"({"file":"/foo/baz.so","triple":"i386-pc-linux"},)"
+ R"({"file":"/foo/baw.so","triple":"i386-pc-linux"}])",
+ R"([{"uuid":"404142434445464748494a4b4c4d4e4f","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::fromData("@ABCDEFGHIJKLMNO", 16),
+ result.getValue()[0].GetUUID());
+ EXPECT_EQ(0u, result.getValue()[0].GetObjectOffset());
+ EXPECT_EQ(1234u, result.getValue()[0].GetObjectSize());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo_UUID20) {
+ llvm::Triple triple("i386-pc-linux");
+
+ FileSpec file_spec("/foo/bar.so", FileSpec::Style::posix);
+ 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::fromData("@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", FileSpec::Style::posix);
+
+ const char *invalid_responses[] = {
+ // no UUID
+ R"([{"triple":"i386-pc-linux",)"
+ 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}]])",
+ // no file_path
+ R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
+ 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}]])",
+ // no file_size
+ R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
+ R"("file_path":"/foo/bar.so","file_offset":0}]])",
+ };
+
+ for (const char *response : invalid_responses) {
+ std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
+ std::async(std::launch::async,
+ [&] { return client.GetModulesInfo(file_spec, triple); });
+ HandlePacket(
+ server,
+ R"(jModulesInfo:[{"file":"/foo/bar.so","triple":"i386-pc-linux"}])",
+ response);
+
+ auto result = async_result.get();
+ ASSERT_TRUE(result);
+ ASSERT_EQ(0u, result->size()) << "response was: " << response;
+ }
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, TestPacketSpeedJSON) {
+ std::thread server_thread([this] {
+ for (;;) {
+ StringExtractorGDBRemote request;
+ PacketResult result = server.GetPacket(request);
+ if (result == PacketResult::ErrorDisconnected)
+ return;
+ ASSERT_EQ(PacketResult::Success, result);
+ StringRef ref = request.GetStringRef();
+ ASSERT_TRUE(ref.consume_front("qSpeedTest:response_size:"));
+ int size;
+ ASSERT_FALSE(ref.consumeInteger(10, size)) << "ref: " << ref;
+ std::string response(size, 'X');
+ ASSERT_EQ(PacketResult::Success, server.SendPacket(response));
+ }
+ });
+
+ StreamString ss;
+ client.TestPacketSpeed(10, 32, 32, 4096, true, ss);
+ client.Disconnect();
+ server_thread.join();
+
+ GTEST_LOG_(INFO) << "Formatted output: " << ss.GetData();
+ auto object_sp = StructuredData::ParseJSON(ss.GetString());
+ ASSERT_TRUE(bool(object_sp));
+ auto dict_sp = object_sp->GetAsDictionary();
+ ASSERT_TRUE(bool(dict_sp));
+
+ object_sp = dict_sp->GetValueForKey("packet_speeds");
+ ASSERT_TRUE(bool(object_sp));
+ dict_sp = object_sp->GetAsDictionary();
+ ASSERT_TRUE(bool(dict_sp));
+
+ int num_packets;
+ ASSERT_TRUE(dict_sp->GetValueForKeyAsInteger("num_packets", num_packets))
+ << ss.GetString();
+ ASSERT_EQ(10, num_packets);
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, SendSignalsToIgnore) {
+ std::future<Status> result = std::async(std::launch::async, [&] {
+ return client.SendSignalsToIgnore({2, 3, 5, 7, 0xB, 0xD, 0x11});
+ });
+
+ HandlePacket(server, "QPassSignals:02;03;05;07;0b;0d;11", "OK");
+ EXPECT_TRUE(result.get().Success());
+
+ result = std::async(std::launch::async, [&] {
+ return client.SendSignalsToIgnore(std::vector<int32_t>());
+ });
+
+ HandlePacket(server, "QPassSignals:", "OK");
+ EXPECT_TRUE(result.get().Success());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfo) {
+ const lldb::addr_t addr = 0xa000;
+ MemoryRegionInfo region_info;
+ std::future<Status> result = std::async(std::launch::async, [&] {
+ return client.GetMemoryRegionInfo(addr, region_info);
+ });
+
+ HandlePacket(server,
+ "qMemoryRegionInfo:a000",
+ "start:a000;size:2000;permissions:rx;name:2f666f6f2f6261722e736f;");
+ if (XMLDocument::XMLEnabled()) {
+ // In case we have XML support, this will also do a "qXfer:memory-map".
+ // Preceeded by a query for supported extensions. Pretend we don't support
+ // that.
+ HandlePacket(server, testing::StartsWith("qSupported:"), "");
+ }
+ EXPECT_TRUE(result.get().Success());
+ EXPECT_EQ(addr, region_info.GetRange().GetRangeBase());
+ EXPECT_EQ(0x2000u, region_info.GetRange().GetByteSize());
+ EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetReadable());
+ EXPECT_EQ(MemoryRegionInfo::eNo, region_info.GetWritable());
+ EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetExecutable());
+ EXPECT_EQ("/foo/bar.so", region_info.GetName().GetStringRef());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) {
+ const lldb::addr_t addr = 0x4000;
+ MemoryRegionInfo region_info;
+ std::future<Status> result = std::async(std::launch::async, [&] {
+ return client.GetMemoryRegionInfo(addr, region_info);
+ });
+
+ HandlePacket(server, "qMemoryRegionInfo:4000", "start:4000;size:0000;");
+ if (XMLDocument::XMLEnabled()) {
+ // In case we have XML support, this will also do a "qXfer:memory-map".
+ // Preceeded by a query for supported extensions. Pretend we don't support
+ // that.
+ HandlePacket(server, testing::StartsWith("qSupported:"), "");
+ }
+ EXPECT_FALSE(result.get().Success());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, SendStartTracePacket) {
+ TraceOptions options;
+ Status error;
+
+ options.setType(lldb::TraceType::eTraceTypeProcessorTrace);
+ options.setMetaDataBufferSize(8192);
+ options.setTraceBufferSize(8192);
+ options.setThreadID(0x23);
+
+ StructuredData::DictionarySP custom_params =
+ std::make_shared<StructuredData::Dictionary>();
+ custom_params->AddStringItem("tracetech", "intel-pt");
+ custom_params->AddIntegerItem("psb", 0x01);
+
+ options.setTraceParams(custom_params);
+
+ std::future<lldb::user_id_t> result = std::async(std::launch::async, [&] {
+ return client.SendStartTracePacket(options, error);
+ });
+
+ // Since the line is exceeding 80 characters.
+ std::string expected_packet1 =
+ R"(jTraceStart:{"buffersize":8192,"metabuffersize":8192,"params":)";
+ std::string expected_packet2 =
+ R"({"psb":1,"tracetech":"intel-pt"},"threadid":35,"type":1})";
+ HandlePacket(server, (expected_packet1 + expected_packet2), "1");
+ ASSERT_TRUE(error.Success());
+ ASSERT_EQ(result.get(), 1u);
+
+ error.Clear();
+ result = std::async(std::launch::async, [&] {
+ return client.SendStartTracePacket(options, error);
+ });
+
+ HandlePacket(server, (expected_packet1 + expected_packet2), "E23");
+ ASSERT_EQ(result.get(), LLDB_INVALID_UID);
+ ASSERT_FALSE(error.Success());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, SendStopTracePacket) {
+ lldb::tid_t thread_id = 0x23;
+ lldb::user_id_t trace_id = 3;
+
+ std::future<Status> result = std::async(std::launch::async, [&] {
+ return client.SendStopTracePacket(trace_id, thread_id);
+ });
+
+ const char *expected_packet = R"(jTraceStop:{"threadid":35,"traceid":3})";
+ HandlePacket(server, expected_packet, "OK");
+ ASSERT_TRUE(result.get().Success());
+
+ result = std::async(std::launch::async, [&] {
+ return client.SendStopTracePacket(trace_id, thread_id);
+ });
+
+ HandlePacket(server, expected_packet, "E23");
+ ASSERT_FALSE(result.get().Success());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, SendGetDataPacket) {
+ lldb::tid_t thread_id = 0x23;
+ lldb::user_id_t trace_id = 3;
+
+ uint8_t buf[32] = {};
+ llvm::MutableArrayRef<uint8_t> buffer(buf, 32);
+ size_t offset = 0;
+
+ std::future<Status> result = std::async(std::launch::async, [&] {
+ return client.SendGetDataPacket(trace_id, thread_id, buffer, offset);
+ });
+
+ std::string expected_packet1 =
+ R"(jTraceBufferRead:{"buffersize":32,"offset":0,"threadid":35,)";
+ std::string expected_packet2 = R"("traceid":3})";
+ HandlePacket(server, expected_packet1+expected_packet2, "123456");
+ ASSERT_TRUE(result.get().Success());
+ ASSERT_EQ(buffer.size(), 3u);
+ ASSERT_EQ(buf[0], 0x12);
+ ASSERT_EQ(buf[1], 0x34);
+ ASSERT_EQ(buf[2], 0x56);
+
+ llvm::MutableArrayRef<uint8_t> buffer2(buf, 32);
+ result = std::async(std::launch::async, [&] {
+ return client.SendGetDataPacket(trace_id, thread_id, buffer2, offset);
+ });
+
+ HandlePacket(server, expected_packet1+expected_packet2, "E23");
+ ASSERT_FALSE(result.get().Success());
+ ASSERT_EQ(buffer2.size(), 0u);
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, SendGetMetaDataPacket) {
+ lldb::tid_t thread_id = 0x23;
+ lldb::user_id_t trace_id = 3;
+
+ uint8_t buf[32] = {};
+ llvm::MutableArrayRef<uint8_t> buffer(buf, 32);
+ size_t offset = 0;
+
+ std::future<Status> result = std::async(std::launch::async, [&] {
+ return client.SendGetMetaDataPacket(trace_id, thread_id, buffer, offset);
+ });
+
+ std::string expected_packet1 =
+ R"(jTraceMetaRead:{"buffersize":32,"offset":0,"threadid":35,)";
+ std::string expected_packet2 = R"("traceid":3})";
+ HandlePacket(server, expected_packet1+expected_packet2, "123456");
+ ASSERT_TRUE(result.get().Success());
+ ASSERT_EQ(buffer.size(), 3u);
+ ASSERT_EQ(buf[0], 0x12);
+ ASSERT_EQ(buf[1], 0x34);
+ ASSERT_EQ(buf[2], 0x56);
+
+ llvm::MutableArrayRef<uint8_t> buffer2(buf, 32);
+ result = std::async(std::launch::async, [&] {
+ return client.SendGetMetaDataPacket(trace_id, thread_id, buffer2, offset);
+ });
+
+ HandlePacket(server, expected_packet1+expected_packet2, "E23");
+ ASSERT_FALSE(result.get().Success());
+ ASSERT_EQ(buffer2.size(), 0u);
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, SendGetTraceConfigPacket) {
+ lldb::tid_t thread_id = 0x23;
+ lldb::user_id_t trace_id = 3;
+ TraceOptions options;
+ options.setThreadID(thread_id);
+
+ std::future<Status> result = std::async(std::launch::async, [&] {
+ return client.SendGetTraceConfigPacket(trace_id, options);
+ });
+
+ const char *expected_packet =
+ R"(jTraceConfigRead:{"threadid":35,"traceid":3})";
+ std::string response1 =
+ R"({"buffersize":8192,"params":{"psb":1,"tracetech":"intel-pt"})";
+ std::string response2 = R"(],"metabuffersize":8192,"threadid":35,"type":1}])";
+ HandlePacket(server, expected_packet, response1+response2);
+ ASSERT_TRUE(result.get().Success());
+ ASSERT_EQ(options.getTraceBufferSize(), 8192u);
+ ASSERT_EQ(options.getMetaDataBufferSize(), 8192u);
+ ASSERT_EQ(options.getType(), 1);
+
+ auto custom_params = options.getTraceParams();
+
+ uint64_t psb_value;
+ llvm::StringRef trace_tech_value;
+
+ ASSERT_TRUE(custom_params);
+ ASSERT_EQ(custom_params->GetType(), eStructuredDataTypeDictionary);
+ ASSERT_TRUE(custom_params->GetValueForKeyAsInteger("psb", psb_value));
+ ASSERT_EQ(psb_value, 1u);
+ ASSERT_TRUE(
+ custom_params->GetValueForKeyAsString("tracetech", trace_tech_value));
+ ASSERT_STREQ(trace_tech_value.data(), "intel-pt");
+
+ // Checking error response.
+ std::future<Status> result2 = std::async(std::launch::async, [&] {
+ return client.SendGetTraceConfigPacket(trace_id, options);
+ });
+
+ HandlePacket(server, expected_packet, "E23");
+ ASSERT_FALSE(result2.get().Success());
+
+ // Wrong JSON as response.
+ std::future<Status> result3 = std::async(std::launch::async, [&] {
+ return client.SendGetTraceConfigPacket(trace_id, options);
+ });
+
+ std::string incorrect_json1 =
+ R"("buffersize" : 8192,"params" : {"psb" : 1,"tracetech" : "intel-pt"})";
+ std::string incorrect_json2 =
+ R"(],"metabuffersize" : 8192,"threadid" : 35,"type" : 1}])";
+ HandlePacket(server, expected_packet, incorrect_json1+incorrect_json2);
+ ASSERT_FALSE(result3.get().Success());
+
+ // Wrong JSON as custom_params.
+ std::future<Status> result4 = std::async(std::launch::async, [&] {
+ return client.SendGetTraceConfigPacket(trace_id, options);
+ });
+
+ std::string incorrect_custom_params1 =
+ R"({"buffersize" : 8192,"params" : "psb" : 1,"tracetech" : "intel-pt"})";
+ std::string incorrect_custom_params2 =
+ R"(],"metabuffersize" : 8192,"threadid" : 35,"type" : 1}])";
+ HandlePacket(server, expected_packet, incorrect_custom_params1+
+ incorrect_custom_params2);
+ ASSERT_FALSE(result4.get().Success());
+}
diff --git a/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationServerTest.cpp b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationServerTest.cpp
new file mode 100644
index 00000000000..a73f7b462a8
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationServerTest.cpp
@@ -0,0 +1,73 @@
+//===-- GDBRemoteCommunicationServerTest.cpp --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "GDBRemoteTestUtils.h"
+
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"
+#include "lldb/Utility/Connection.h"
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+TEST(GDBRemoteCommunicationServerTest, SendErrorResponse_ErrorNumber) {
+ MockServerWithMockConnection server;
+ server.SendErrorResponse(0x42);
+
+ EXPECT_THAT(server.GetPackets(), testing::ElementsAre("$E42#ab"));
+}
+
+TEST(GDBRemoteCommunicationServerTest, SendErrorResponse_Status) {
+ MockServerWithMockConnection server;
+ Status status;
+
+ status.SetError(0x42, lldb::eErrorTypeGeneric);
+ status.SetErrorString("Test error message");
+ server.SendErrorResponse(status);
+
+ EXPECT_THAT(
+ server.GetPackets(),
+ testing::ElementsAre("$E42;54657374206572726f72206d657373616765#ad"));
+}
+
+TEST(GDBRemoteCommunicationServerTest, SendErrorResponse_UnimplementedError) {
+ MockServerWithMockConnection server;
+
+ auto error =
+ llvm::make_error<PacketUnimplementedError>("Test unimplemented error");
+ server.SendErrorResponse(std::move(error));
+
+ EXPECT_THAT(server.GetPackets(), testing::ElementsAre("$#00"));
+}
+
+TEST(GDBRemoteCommunicationServerTest, SendErrorResponse_StringError) {
+ MockServerWithMockConnection server;
+
+ auto error = llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "String error test");
+ server.SendErrorResponse(std::move(error));
+
+ EXPECT_THAT(
+ server.GetPackets(),
+ testing::ElementsAre("$Eff;537472696e67206572726f722074657374#b0"));
+}
+
+TEST(GDBRemoteCommunicationServerTest, SendErrorResponse_ErrorList) {
+ MockServerWithMockConnection server;
+
+ auto error = llvm::joinErrors(llvm::make_error<PacketUnimplementedError>(),
+ llvm::make_error<PacketUnimplementedError>());
+
+ server.SendErrorResponse(std::move(error));
+ // Make sure only one packet is sent even when there are multiple errors.
+ EXPECT_EQ(server.GetPackets().size(), 1UL);
+}
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
diff --git a/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp
new file mode 100644
index 00000000000..2039b9e6d8d
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp
@@ -0,0 +1,67 @@
+//===-- GDBRemoteCommunicationTest.cpp --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "GDBRemoteTestUtils.h"
+#include "llvm/Testing/Support/Error.h"
+
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private;
+using namespace lldb;
+typedef GDBRemoteCommunication::PacketResult PacketResult;
+
+namespace {
+
+class TestClient : public GDBRemoteCommunication {
+public:
+ TestClient()
+ : GDBRemoteCommunication("test.client", "test.client.listener") {}
+
+ PacketResult ReadPacket(StringExtractorGDBRemote &response) {
+ return GDBRemoteCommunication::ReadPacket(response, std::chrono::seconds(1),
+ /*sync_on_timeout*/ false);
+ }
+};
+
+class GDBRemoteCommunicationTest : public GDBRemoteTest {
+public:
+ void SetUp() override {
+ ASSERT_THAT_ERROR(GDBRemoteCommunication::ConnectLocally(client, server),
+ llvm::Succeeded());
+ }
+
+protected:
+ TestClient client;
+ MockServer server;
+
+ bool Write(llvm::StringRef packet) {
+ ConnectionStatus status;
+ return server.Write(packet.data(), packet.size(), status, nullptr) ==
+ packet.size();
+ }
+};
+} // end anonymous namespace
+
+TEST_F(GDBRemoteCommunicationTest, ReadPacket_checksum) {
+ struct TestCase {
+ llvm::StringLiteral Packet;
+ llvm::StringLiteral Payload;
+ };
+ static constexpr TestCase Tests[] = {
+ {{"$#00"}, {""}},
+ {{"$foobar#79"}, {"foobar"}},
+ {{"$}}#fa"}, {"]"}},
+ {{"$x*%#c7"}, {"xxxxxxxxx"}},
+ };
+ for (const auto &Test : Tests) {
+ SCOPED_TRACE(Test.Packet + " -> " + Test.Payload);
+ StringExtractorGDBRemote response;
+ ASSERT_TRUE(Write(Test.Packet));
+ ASSERT_EQ(PacketResult::Success, client.ReadPacket(response));
+ ASSERT_EQ(Test.Payload, response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, server.GetAck());
+ }
+}
diff --git a/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp
new file mode 100644
index 00000000000..92e16d981fe
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp
@@ -0,0 +1,23 @@
+//===-- GDBRemoteTestUtils.cpp ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteTestUtils.h"
+#include "lldb/Host/Socket.h"
+#include "llvm/Testing/Support/Error.h"
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+void GDBRemoteTest::SetUpTestCase() {
+ ASSERT_THAT_ERROR(Socket::Initialize(), llvm::Succeeded());
+}
+
+void GDBRemoteTest::TearDownTestCase() { Socket::Terminate(); }
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
diff --git a/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteTestUtils.h b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteTestUtils.h
new file mode 100644
index 00000000000..53e94a39e8b
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteTestUtils.h
@@ -0,0 +1,91 @@
+//===-- GDBRemoteTestUtils.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef lldb_unittests_Process_gdb_remote_GDBRemoteTestUtils_h
+#define lldb_unittests_Process_gdb_remote_GDBRemoteTestUtils_h
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"
+#include "lldb/Utility/Connection.h"
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class GDBRemoteTest : public testing::Test {
+public:
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+};
+
+class MockConnection : public lldb_private::Connection {
+public:
+ MockConnection(std::vector<std::string> &packets) { m_packets = &packets; };
+
+ MOCK_METHOD2(Connect,
+ lldb::ConnectionStatus(llvm::StringRef url, Status *error_ptr));
+ MOCK_METHOD5(Read, size_t(void *dst, size_t dst_len,
+ const Timeout<std::micro> &timeout,
+ lldb::ConnectionStatus &status, Status *error_ptr));
+ MOCK_METHOD0(GetURI, std::string());
+ MOCK_METHOD0(InterruptRead, bool());
+
+ lldb::ConnectionStatus Disconnect(Status *error_ptr) {
+ return lldb::eConnectionStatusSuccess;
+ };
+
+ bool IsConnected() const { return true; };
+ size_t Write(const void *dst, size_t dst_len, lldb::ConnectionStatus &status,
+ Status *error_ptr) {
+ m_packets->emplace_back(static_cast<const char *>(dst), dst_len);
+ return dst_len;
+ };
+
+ lldb::IOObjectSP GetReadObject() { return lldb::IOObjectSP(); }
+
+ std::vector<std::string> *m_packets;
+};
+
+class MockServer : public GDBRemoteCommunicationServer {
+public:
+ MockServer()
+ : GDBRemoteCommunicationServer("mock-server", "mock-server.listener") {
+ m_send_acks = false;
+ m_send_error_strings = true;
+ }
+
+ PacketResult SendPacket(llvm::StringRef payload) {
+ return GDBRemoteCommunicationServer::SendPacketNoLock(payload);
+ }
+
+ PacketResult GetPacket(StringExtractorGDBRemote &response) {
+ const bool sync_on_timeout = false;
+ return WaitForPacketNoLock(response, std::chrono::seconds(1),
+ sync_on_timeout);
+ }
+
+ using GDBRemoteCommunicationServer::SendErrorResponse;
+ using GDBRemoteCommunicationServer::SendOKResponse;
+ using GDBRemoteCommunicationServer::SendUnimplementedResponse;
+};
+
+class MockServerWithMockConnection : public MockServer {
+public:
+ MockServerWithMockConnection() : MockServer() {
+ SetConnection(new MockConnection(m_packets));
+ }
+
+ llvm::ArrayRef<std::string> GetPackets() { return m_packets; };
+
+ std::vector<std::string> m_packets;
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // lldb_unittests_Process_gdb_remote_GDBRemoteTestUtils_h
diff --git a/gnu/llvm/lldb/unittests/Process/minidump/CMakeLists.txt b/gnu/llvm/lldb/unittests/Process/minidump/CMakeLists.txt
new file mode 100644
index 00000000000..ad5f1883147
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/minidump/CMakeLists.txt
@@ -0,0 +1,25 @@
+add_lldb_unittest(LLDBMinidumpTests
+ MinidumpParserTest.cpp
+ RegisterContextMinidumpTest.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbHost
+ lldbTarget
+ lldbPluginProcessUtility
+ lldbPluginProcessMinidump
+ lldbUtilityHelpers
+ LLVMTestingSupport
+ LINK_COMPONENTS
+ ObjectYAML
+ Support
+ )
+
+set(test_inputs
+ fizzbuzz_no_heap.dmp
+ fizzbuzz_wow64.dmp
+ linux-x86_64.dmp
+ regions-memlist64.dmp
+ )
+
+add_unittest_inputs(LLDBMinidumpTests "${test_inputs}")
diff --git a/gnu/llvm/lldb/unittests/Process/minidump/Inputs/fizzbuzz_no_heap.dmp b/gnu/llvm/lldb/unittests/Process/minidump/Inputs/fizzbuzz_no_heap.dmp
new file mode 100644
index 00000000000..19008c91fc3
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/minidump/Inputs/fizzbuzz_no_heap.dmp
Binary files differ
diff --git a/gnu/llvm/lldb/unittests/Process/minidump/Inputs/fizzbuzz_wow64.dmp b/gnu/llvm/lldb/unittests/Process/minidump/Inputs/fizzbuzz_wow64.dmp
new file mode 100644
index 00000000000..3d97186f2cd
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/minidump/Inputs/fizzbuzz_wow64.dmp
Binary files differ
diff --git a/gnu/llvm/lldb/unittests/Process/minidump/Inputs/linux-x86_64.cpp b/gnu/llvm/lldb/unittests/Process/minidump/Inputs/linux-x86_64.cpp
new file mode 100644
index 00000000000..827fe67b503
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/minidump/Inputs/linux-x86_64.cpp
@@ -0,0 +1,28 @@
+// Example source from breakpad's linux tutorial
+// https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/linux_starter_guide.md
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "client/linux/handler/exception_handler.h"
+
+static bool dumpCallback(const google_breakpad::MinidumpDescriptor &descriptor,
+ void *context, bool succeeded) {
+ printf("Dump path: %s\n", descriptor.path());
+ return succeeded;
+}
+
+void crash() {
+ volatile int *a = (int *)(NULL);
+ *a = 1;
+}
+
+int main(int argc, char *argv[]) {
+ google_breakpad::MinidumpDescriptor descriptor("/tmp");
+ google_breakpad::ExceptionHandler eh(descriptor, NULL, dumpCallback, NULL,
+ true, -1);
+ printf("pid: %d\n", getpid());
+ crash();
+ return 0;
+}
diff --git a/gnu/llvm/lldb/unittests/Process/minidump/Inputs/linux-x86_64.dmp b/gnu/llvm/lldb/unittests/Process/minidump/Inputs/linux-x86_64.dmp
new file mode 100644
index 00000000000..29a12d6a2eb
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/minidump/Inputs/linux-x86_64.dmp
Binary files differ
diff --git a/gnu/llvm/lldb/unittests/Process/minidump/Inputs/regions-memlist64.dmp b/gnu/llvm/lldb/unittests/Process/minidump/Inputs/regions-memlist64.dmp
new file mode 100644
index 00000000000..1bb8db8464d
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/minidump/Inputs/regions-memlist64.dmp
Binary files differ
diff --git a/gnu/llvm/lldb/unittests/Process/minidump/MinidumpParserTest.cpp b/gnu/llvm/lldb/unittests/Process/minidump/MinidumpParserTest.cpp
new file mode 100644
index 00000000000..94bb1b395f0
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/minidump/MinidumpParserTest.cpp
@@ -0,0 +1,724 @@
+//===-- MinidumpTypesTest.cpp -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Process/minidump/MinidumpParser.h"
+#include "Plugins/Process/minidump/MinidumpTypes.h"
+#include "Plugins/Process/minidump/RegisterContextMinidump_x86_32.h"
+#include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"
+#include "TestingSupport/SubsystemRAII.h"
+#include "TestingSupport/TestUtilities.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/FileSpec.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ObjectYAML/yaml2obj.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+// C includes
+
+// C++ includes
+#include <memory>
+
+using namespace lldb_private;
+using namespace minidump;
+
+class MinidumpParserTest : public testing::Test {
+public:
+ SubsystemRAII<FileSystem> subsystems;
+
+ void SetUpData(const char *minidump_filename) {
+ std::string filename = GetInputFilePath(minidump_filename);
+ auto BufferPtr = FileSystem::Instance().CreateDataBuffer(filename, -1, 0);
+ ASSERT_NE(BufferPtr, nullptr);
+ llvm::Expected<MinidumpParser> expected_parser =
+ MinidumpParser::Create(BufferPtr);
+ ASSERT_THAT_EXPECTED(expected_parser, llvm::Succeeded());
+ parser = std::move(*expected_parser);
+ ASSERT_GT(parser->GetData().size(), 0UL);
+ }
+
+ llvm::Error SetUpFromYaml(llvm::StringRef yaml) {
+ std::string data;
+ llvm::raw_string_ostream os(data);
+ llvm::yaml::Input YIn(yaml);
+ if (!llvm::yaml::convertYAML(YIn, os, [](const llvm::Twine &Msg) {}))
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "convertYAML() failed");
+
+ os.flush();
+ auto data_buffer_sp =
+ std::make_shared<DataBufferHeap>(data.data(), data.size());
+ auto expected_parser = MinidumpParser::Create(std::move(data_buffer_sp));
+ if (!expected_parser)
+ return expected_parser.takeError();
+ parser = std::move(*expected_parser);
+ return llvm::Error::success();
+ }
+
+ llvm::Optional<MinidumpParser> parser;
+};
+
+TEST_F(MinidumpParserTest, InvalidMinidump) {
+ std::string duplicate_streams;
+ llvm::raw_string_ostream os(duplicate_streams);
+ llvm::yaml::Input YIn(R"(
+--- !minidump
+Streams:
+ - Type: LinuxAuxv
+ Content: DEADBEEFBAADF00D
+ - Type: LinuxAuxv
+ Content: DEADBEEFBAADF00D
+ )");
+
+ ASSERT_TRUE(llvm::yaml::convertYAML(YIn, os, [](const llvm::Twine &Msg){}));
+ os.flush();
+ auto data_buffer_sp = std::make_shared<DataBufferHeap>(
+ duplicate_streams.data(), duplicate_streams.size());
+ ASSERT_THAT_EXPECTED(MinidumpParser::Create(data_buffer_sp), llvm::Failed());
+}
+
+TEST_F(MinidumpParserTest, GetThreadsAndGetThreadContext) {
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+ - Type: ThreadList
+ Threads:
+ - Thread Id: 0x00003E81
+ Stack:
+ Start of Memory Range: 0x00007FFCEB34A000
+ Content: C84D04BCE97F00
+ Context: 00000000000000
+...
+)"),
+ llvm::Succeeded());
+ llvm::ArrayRef<minidump::Thread> thread_list;
+
+ thread_list = parser->GetThreads();
+ ASSERT_EQ(1UL, thread_list.size());
+
+ const minidump::Thread &thread = thread_list[0];
+
+ EXPECT_EQ(0x3e81u, thread.ThreadId);
+
+ llvm::ArrayRef<uint8_t> context = parser->GetThreadContext(thread);
+ EXPECT_EQ(7u, context.size());
+}
+
+TEST_F(MinidumpParserTest, GetArchitecture) {
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+ - Type: SystemInfo
+ Processor Arch: AMD64
+ Processor Level: 6
+ Processor Revision: 16130
+ Number of Processors: 1
+ Platform ID: Linux
+ CPU:
+ Vendor ID: GenuineIntel
+ Version Info: 0x00000000
+ Feature Info: 0x00000000
+...
+)"),
+ llvm::Succeeded());
+ ASSERT_EQ(llvm::Triple::ArchType::x86_64,
+ parser->GetArchitecture().GetMachine());
+ ASSERT_EQ(llvm::Triple::OSType::Linux,
+ parser->GetArchitecture().GetTriple().getOS());
+}
+
+TEST_F(MinidumpParserTest, GetMiscInfo_no_stream) {
+ // Test that GetMiscInfo returns nullptr when the minidump does not contain
+ // this stream.
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+...
+)"),
+ llvm::Succeeded());
+ EXPECT_EQ(nullptr, parser->GetMiscInfo());
+}
+
+TEST_F(MinidumpParserTest, GetLinuxProcStatus) {
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+ - Type: SystemInfo
+ Processor Arch: AMD64
+ Processor Level: 6
+ Processor Revision: 16130
+ Number of Processors: 1
+ Platform ID: Linux
+ CSD Version: 'Linux 3.13.0-91-generic'
+ CPU:
+ Vendor ID: GenuineIntel
+ Version Info: 0x00000000
+ Feature Info: 0x00000000
+ - Type: LinuxProcStatus
+ Text: |
+ Name: a.out
+ State: t (tracing stop)
+ Tgid: 16001
+ Ngid: 0
+ Pid: 16001
+ PPid: 13243
+ TracerPid: 16002
+ Uid: 404696 404696 404696 404696
+ Gid: 5762 5762 5762 5762
+...
+)"),
+ llvm::Succeeded());
+ llvm::Optional<LinuxProcStatus> proc_status = parser->GetLinuxProcStatus();
+ ASSERT_TRUE(proc_status.hasValue());
+ lldb::pid_t pid = proc_status->GetPid();
+ ASSERT_EQ(16001UL, pid);
+}
+
+TEST_F(MinidumpParserTest, GetPid) {
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+ - Type: SystemInfo
+ Processor Arch: AMD64
+ Processor Level: 6
+ Processor Revision: 16130
+ Number of Processors: 1
+ Platform ID: Linux
+ CSD Version: 'Linux 3.13.0-91-generic'
+ CPU:
+ Vendor ID: GenuineIntel
+ Version Info: 0x00000000
+ Feature Info: 0x00000000
+ - Type: LinuxProcStatus
+ Text: |
+ Name: a.out
+ State: t (tracing stop)
+ Tgid: 16001
+ Ngid: 0
+ Pid: 16001
+ PPid: 13243
+ TracerPid: 16002
+ Uid: 404696 404696 404696 404696
+ Gid: 5762 5762 5762 5762
+...
+)"),
+ llvm::Succeeded());
+ llvm::Optional<lldb::pid_t> pid = parser->GetPid();
+ ASSERT_TRUE(pid.hasValue());
+ ASSERT_EQ(16001UL, pid.getValue());
+}
+
+TEST_F(MinidumpParserTest, GetFilteredModuleList) {
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+ - Type: ModuleList
+ Modules:
+ - Base of Image: 0x0000000000400000
+ Size of Image: 0x00001000
+ Module Name: '/tmp/test/linux-x86_64_not_crashed'
+ CodeView Record: 4C4570426CCF3F60FFA7CC4B86AE8FF44DB2576A68983611
+ - Base of Image: 0x0000000000600000
+ Size of Image: 0x00002000
+ Module Name: '/tmp/test/linux-x86_64_not_crashed'
+ CodeView Record: 4C4570426CCF3F60FFA7CC4B86AE8FF44DB2576A68983611
+...
+)"),
+ llvm::Succeeded());
+ llvm::ArrayRef<minidump::Module> modules = parser->GetModuleList();
+ std::vector<const minidump::Module *> filtered_modules =
+ parser->GetFilteredModuleList();
+ EXPECT_EQ(2u, modules.size());
+ ASSERT_EQ(1u, filtered_modules.size());
+ const minidump::Module &M = *filtered_modules[0];
+ EXPECT_THAT_EXPECTED(parser->GetMinidumpFile().getString(M.ModuleNameRVA),
+ llvm::HasValue("/tmp/test/linux-x86_64_not_crashed"));
+}
+
+TEST_F(MinidumpParserTest, GetExceptionStream) {
+ SetUpData("linux-x86_64.dmp");
+ const llvm::minidump::ExceptionStream *exception_stream =
+ parser->GetExceptionStream();
+ ASSERT_NE(nullptr, exception_stream);
+ ASSERT_EQ(11UL, exception_stream->ExceptionRecord.ExceptionCode);
+}
+
+void check_mem_range_exists(MinidumpParser &parser, const uint64_t range_start,
+ const uint64_t range_size) {
+ llvm::Optional<minidump::Range> range = parser.FindMemoryRange(range_start);
+ ASSERT_TRUE(range.hasValue()) << "There is no range containing this address";
+ EXPECT_EQ(range_start, range->start);
+ EXPECT_EQ(range_start + range_size, range->start + range->range_ref.size());
+}
+
+TEST_F(MinidumpParserTest, FindMemoryRange) {
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+ - Type: MemoryList
+ Memory Ranges:
+ - Start of Memory Range: 0x00007FFCEB34A000
+ Content: C84D04BCE9
+ - Start of Memory Range: 0x0000000000401D46
+ Content: 5421
+...
+)"),
+ llvm::Succeeded());
+ EXPECT_EQ(llvm::None, parser->FindMemoryRange(0x00));
+ EXPECT_EQ(llvm::None, parser->FindMemoryRange(0x2a));
+ EXPECT_EQ((minidump::Range{0x401d46, llvm::ArrayRef<uint8_t>{0x54, 0x21}}),
+ parser->FindMemoryRange(0x401d46));
+ EXPECT_EQ(llvm::None, parser->FindMemoryRange(0x401d46 + 2));
+
+ EXPECT_EQ(
+ (minidump::Range{0x7ffceb34a000,
+ llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}}),
+ parser->FindMemoryRange(0x7ffceb34a000 + 2));
+ EXPECT_EQ(llvm::None, parser->FindMemoryRange(0x7ffceb34a000 + 5));
+}
+
+TEST_F(MinidumpParserTest, GetMemory) {
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+ - Type: MemoryList
+ Memory Ranges:
+ - Start of Memory Range: 0x00007FFCEB34A000
+ Content: C84D04BCE9
+ - Start of Memory Range: 0x0000000000401D46
+ Content: 5421
+...
+)"),
+ llvm::Succeeded());
+
+ EXPECT_EQ((llvm::ArrayRef<uint8_t>{0x54}), parser->GetMemory(0x401d46, 1));
+ EXPECT_EQ((llvm::ArrayRef<uint8_t>{0x54, 0x21}),
+ parser->GetMemory(0x401d46, 4));
+
+ EXPECT_EQ((llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}),
+ parser->GetMemory(0x7ffceb34a000, 5));
+ EXPECT_EQ((llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04}),
+ parser->GetMemory(0x7ffceb34a000, 3));
+
+ EXPECT_EQ(llvm::ArrayRef<uint8_t>(), parser->GetMemory(0x500000, 512));
+}
+
+TEST_F(MinidumpParserTest, FindMemoryRangeWithFullMemoryMinidump) {
+ SetUpData("fizzbuzz_wow64.dmp");
+
+ // There are a lot of ranges in the file, just testing with some of them
+ EXPECT_FALSE(parser->FindMemoryRange(0x00).hasValue());
+ EXPECT_FALSE(parser->FindMemoryRange(0x2a).hasValue());
+ check_mem_range_exists(*parser, 0x10000, 65536); // first range
+ check_mem_range_exists(*parser, 0x40000, 4096);
+ EXPECT_FALSE(parser->FindMemoryRange(0x40000 + 4096).hasValue());
+ check_mem_range_exists(*parser, 0x77c12000, 8192);
+ check_mem_range_exists(*parser, 0x7ffe0000, 4096); // last range
+ EXPECT_FALSE(parser->FindMemoryRange(0x7ffe0000 + 4096).hasValue());
+}
+
+constexpr auto yes = MemoryRegionInfo::eYes;
+constexpr auto no = MemoryRegionInfo::eNo;
+constexpr auto unknown = MemoryRegionInfo::eDontKnow;
+
+TEST_F(MinidumpParserTest, GetMemoryRegionInfo) {
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+ - Type: MemoryInfoList
+ Memory Ranges:
+ - Base Address: 0x0000000000000000
+ Allocation Protect: [ ]
+ Region Size: 0x0000000000010000
+ State: [ MEM_FREE ]
+ Protect: [ PAGE_NO_ACCESS ]
+ Type: [ ]
+ - Base Address: 0x0000000000010000
+ Allocation Protect: [ PAGE_READ_WRITE ]
+ Region Size: 0x0000000000021000
+ State: [ MEM_COMMIT ]
+ Type: [ MEM_MAPPED ]
+ - Base Address: 0x0000000000040000
+ Allocation Protect: [ PAGE_EXECUTE_WRITE_COPY ]
+ Region Size: 0x0000000000001000
+ State: [ MEM_COMMIT ]
+ Protect: [ PAGE_READ_ONLY ]
+ Type: [ MEM_IMAGE ]
+ - Base Address: 0x000000007FFE0000
+ Allocation Protect: [ PAGE_READ_ONLY ]
+ Region Size: 0x0000000000001000
+ State: [ MEM_COMMIT ]
+ Type: [ MEM_PRIVATE ]
+ - Base Address: 0x000000007FFE1000
+ Allocation Base: 0x000000007FFE0000
+ Allocation Protect: [ PAGE_READ_ONLY ]
+ Region Size: 0x000000000000F000
+ State: [ MEM_RESERVE ]
+ Protect: [ PAGE_NO_ACCESS ]
+ Type: [ MEM_PRIVATE ]
+...
+)"),
+ llvm::Succeeded());
+
+ EXPECT_THAT(
+ parser->BuildMemoryRegions(),
+ testing::Pair(testing::ElementsAre(
+ MemoryRegionInfo({0x0, 0x10000}, no, no, no, no,
+ ConstString(), unknown, 0),
+ MemoryRegionInfo({0x10000, 0x21000}, yes, yes, no, yes,
+ ConstString(), unknown, 0),
+ MemoryRegionInfo({0x40000, 0x1000}, yes, no, no, yes,
+ ConstString(), unknown, 0),
+ MemoryRegionInfo({0x7ffe0000, 0x1000}, yes, no, no, yes,
+ ConstString(), unknown, 0),
+ MemoryRegionInfo({0x7ffe1000, 0xf000}, no, no, no, yes,
+ ConstString(), unknown, 0)),
+ true));
+}
+
+TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) {
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+ - Type: MemoryList
+ Memory Ranges:
+ - Start of Memory Range: 0x0000000000001000
+ Content: '31313131313131313131313131313131'
+ - Start of Memory Range: 0x0000000000002000
+ Content: '3333333333333333333333333333333333333333333333333333333333333333'
+...
+)"),
+ llvm::Succeeded());
+
+ // Test we can get memory regions from the MINIDUMP_MEMORY_LIST stream when
+ // we don't have a MemoryInfoListStream.
+
+ EXPECT_THAT(
+ parser->BuildMemoryRegions(),
+ testing::Pair(testing::ElementsAre(
+ MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown,
+ yes, ConstString(), unknown, 0),
+ MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown,
+ yes, ConstString(), unknown, 0)),
+ false));
+}
+
+TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) {
+ SetUpData("regions-memlist64.dmp");
+
+ // Test we can get memory regions from the MINIDUMP_MEMORY64_LIST stream when
+ // we don't have a MemoryInfoListStream.
+ EXPECT_THAT(
+ parser->BuildMemoryRegions(),
+ testing::Pair(testing::ElementsAre(
+ MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown,
+ yes, ConstString(), unknown, 0),
+ MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown,
+ yes, ConstString(), unknown, 0)),
+ false));
+}
+
+TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) {
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+ - Type: LinuxMaps
+ Text: |
+ 400d9000-400db000 r-xp 00000000 b3:04 227 /system/bin/app_process
+ 400db000-400dc000 r--p 00001000 b3:04 227 /system/bin/app_process
+ 400dc000-400dd000 rw-p 00000000 00:00 0
+ 400ec000-400ed000 r--p 00000000 00:00 0
+ 400ee000-400ef000 rw-p 00010000 b3:04 300 /system/bin/linker
+ 400fc000-400fd000 rwxp 00001000 b3:04 1096 /system/lib/liblog.so
+
+...
+)"),
+ llvm::Succeeded());
+ // Test we can get memory regions from the linux /proc/<pid>/maps stream when
+ // we don't have a MemoryInfoListStream.
+ ConstString app_process("/system/bin/app_process");
+ ConstString linker("/system/bin/linker");
+ ConstString liblog("/system/lib/liblog.so");
+ EXPECT_THAT(
+ parser->BuildMemoryRegions(),
+ testing::Pair(testing::ElementsAre(
+ MemoryRegionInfo({0x400d9000, 0x2000}, yes, no, yes,
+ yes, app_process, unknown, 0),
+ MemoryRegionInfo({0x400db000, 0x1000}, yes, no, no, yes,
+ app_process, unknown, 0),
+ MemoryRegionInfo({0x400dc000, 0x1000}, yes, yes, no,
+ yes, ConstString(), unknown, 0),
+ MemoryRegionInfo({0x400ec000, 0x1000}, yes, no, no, yes,
+ ConstString(), unknown, 0),
+ MemoryRegionInfo({0x400ee000, 0x1000}, yes, yes, no,
+ yes, linker, unknown, 0),
+ MemoryRegionInfo({0x400fc000, 0x1000}, yes, yes, yes,
+ yes, liblog, unknown, 0)),
+ true));
+}
+
+// Windows Minidump tests
+TEST_F(MinidumpParserTest, GetArchitectureWindows) {
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+ - Type: SystemInfo
+ Processor Arch: X86
+ Processor Level: 6
+ Processor Revision: 15876
+ Number of Processors: 32
+ Product type: 1
+ Major Version: 6
+ Minor Version: 1
+ Build Number: 7601
+ Platform ID: Win32NT
+ CSD Version: Service Pack 1
+ Suite Mask: 0x0100
+ CPU:
+ Vendor ID: GenuineIntel
+ Version Info: 0x000306E4
+ Feature Info: 0xBFEBFBFF
+ AMD Extended Features: 0x771EEC80
+...
+)"),
+ llvm::Succeeded());
+ ASSERT_EQ(llvm::Triple::ArchType::x86,
+ parser->GetArchitecture().GetMachine());
+ ASSERT_EQ(llvm::Triple::OSType::Win32,
+ parser->GetArchitecture().GetTriple().getOS());
+}
+
+TEST_F(MinidumpParserTest, GetLinuxProcStatus_no_stream) {
+ // Test that GetLinuxProcStatus returns nullptr when the minidump does not
+ // contain this stream.
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+...
+)"),
+ llvm::Succeeded());
+ EXPECT_EQ(llvm::None, parser->GetLinuxProcStatus());
+}
+
+TEST_F(MinidumpParserTest, GetMiscInfoWindows) {
+ SetUpData("fizzbuzz_no_heap.dmp");
+ const MinidumpMiscInfo *misc_info = parser->GetMiscInfo();
+ ASSERT_NE(nullptr, misc_info);
+ llvm::Optional<lldb::pid_t> pid = misc_info->GetPid();
+ ASSERT_TRUE(pid.hasValue());
+ ASSERT_EQ(4440UL, pid.getValue());
+}
+
+TEST_F(MinidumpParserTest, GetPidWindows) {
+ SetUpData("fizzbuzz_no_heap.dmp");
+ llvm::Optional<lldb::pid_t> pid = parser->GetPid();
+ ASSERT_TRUE(pid.hasValue());
+ ASSERT_EQ(4440UL, pid.getValue());
+}
+
+// wow64
+TEST_F(MinidumpParserTest, GetPidWow64) {
+ SetUpData("fizzbuzz_wow64.dmp");
+ llvm::Optional<lldb::pid_t> pid = parser->GetPid();
+ ASSERT_TRUE(pid.hasValue());
+ ASSERT_EQ(7836UL, pid.getValue());
+}
+
+// Register tests
+#define REG_VAL32(x) *(reinterpret_cast<uint32_t *>(x))
+#define REG_VAL64(x) *(reinterpret_cast<uint64_t *>(x))
+
+TEST_F(MinidumpParserTest, GetThreadContext_x86_32) {
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+ - Type: ThreadList
+ Threads:
+ - Thread Id: 0x00026804
+ Stack:
+ Start of Memory Range: 0x00000000FF9DD000
+ Content: 68D39DFF
+ Context: 0F0001000000000000000000000000000000000000000000000000007F03FFFF0000FFFFFFFFFFFF09DC62F72300000088E36CF72B00FFFF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063000000000000002B0000002B000000A88204085CD59DFF008077F7A3D49DFF01000000000000003CD59DFFA082040823000000820201002CD59DFF2B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+)"),
+ llvm::Succeeded());
+
+ llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads();
+ const minidump::Thread &thread = thread_list[0];
+ llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread));
+ const MinidumpContext_x86_32 *context;
+ EXPECT_TRUE(consumeObject(registers, context).Success());
+
+ EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)),
+ MinidumpContext_x86_32_Flags::x86_32_Flag |
+ MinidumpContext_x86_32_Flags::Full |
+ MinidumpContext_x86_32_Flags::FloatingPoint);
+
+ EXPECT_EQ(0x00000000u, context->eax);
+ EXPECT_EQ(0xf7778000u, context->ebx);
+ EXPECT_EQ(0x00000001u, context->ecx);
+ EXPECT_EQ(0xff9dd4a3u, context->edx);
+ EXPECT_EQ(0x080482a8u, context->edi);
+ EXPECT_EQ(0xff9dd55cu, context->esi);
+ EXPECT_EQ(0xff9dd53cu, context->ebp);
+ EXPECT_EQ(0xff9dd52cu, context->esp);
+ EXPECT_EQ(0x080482a0u, context->eip);
+ EXPECT_EQ(0x00010282u, context->eflags);
+ EXPECT_EQ(0x0023u, context->cs);
+ EXPECT_EQ(0x0000u, context->fs);
+ EXPECT_EQ(0x0063u, context->gs);
+ EXPECT_EQ(0x002bu, context->ss);
+ EXPECT_EQ(0x002bu, context->ds);
+ EXPECT_EQ(0x002bu, context->es);
+}
+
+TEST_F(MinidumpParserTest, GetThreadContext_x86_64) {
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+ - Type: ThreadList
+ Threads:
+ - Thread Id: 0x00003E81
+ Stack:
+ Start of Memory Range: 0x00007FFCEB34A000
+ Content: C84D04BCE97F00
+ Context: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B0010000000000033000000000000000000000006020100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000010A234EBFC7F000010A234EBFC7F00000000000000000000F09C34EBFC7F0000C0A91ABCE97F00000000000000000000A0163FBCE97F00004602000000000000921C40000000000030A434EBFC7F000000000000000000000000000000000000C61D4000000000007F0300000000000000000000000000000000000000000000801F0000FFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF25252525252525252525252525252525000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+...
+)"),
+ llvm::Succeeded());
+ llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads();
+ const minidump::Thread &thread = thread_list[0];
+ llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread));
+ const MinidumpContext_x86_64 *context;
+ EXPECT_TRUE(consumeObject(registers, context).Success());
+
+ EXPECT_EQ(MinidumpContext_x86_64_Flags(uint32_t(context->context_flags)),
+ MinidumpContext_x86_64_Flags::x86_64_Flag |
+ MinidumpContext_x86_64_Flags::Control |
+ MinidumpContext_x86_64_Flags::FloatingPoint |
+ MinidumpContext_x86_64_Flags::Integer);
+ EXPECT_EQ(0x0000000000000000u, context->rax);
+ EXPECT_EQ(0x0000000000000000u, context->rbx);
+ EXPECT_EQ(0x0000000000000010u, context->rcx);
+ EXPECT_EQ(0x0000000000000000u, context->rdx);
+ EXPECT_EQ(0x00007ffceb349cf0u, context->rdi);
+ EXPECT_EQ(0x0000000000000000u, context->rsi);
+ EXPECT_EQ(0x00007ffceb34a210u, context->rbp);
+ EXPECT_EQ(0x00007ffceb34a210u, context->rsp);
+ EXPECT_EQ(0x00007fe9bc1aa9c0u, context->r8);
+ EXPECT_EQ(0x0000000000000000u, context->r9);
+ EXPECT_EQ(0x00007fe9bc3f16a0u, context->r10);
+ EXPECT_EQ(0x0000000000000246u, context->r11);
+ EXPECT_EQ(0x0000000000401c92u, context->r12);
+ EXPECT_EQ(0x00007ffceb34a430u, context->r13);
+ EXPECT_EQ(0x0000000000000000u, context->r14);
+ EXPECT_EQ(0x0000000000000000u, context->r15);
+ EXPECT_EQ(0x0000000000401dc6u, context->rip);
+ EXPECT_EQ(0x00010206u, context->eflags);
+ EXPECT_EQ(0x0033u, context->cs);
+ EXPECT_EQ(0x0000u, context->ss);
+}
+
+TEST_F(MinidumpParserTest, GetThreadContext_x86_32_wow64) {
+ SetUpData("fizzbuzz_wow64.dmp");
+ llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads();
+ const minidump::Thread &thread = thread_list[0];
+ llvm::ArrayRef<uint8_t> registers(parser->GetThreadContextWow64(thread));
+ const MinidumpContext_x86_32 *context;
+ EXPECT_TRUE(consumeObject(registers, context).Success());
+
+ EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)),
+ MinidumpContext_x86_32_Flags::x86_32_Flag |
+ MinidumpContext_x86_32_Flags::Full |
+ MinidumpContext_x86_32_Flags::FloatingPoint |
+ MinidumpContext_x86_32_Flags::ExtendedRegisters);
+
+ EXPECT_EQ(0x00000000u, context->eax);
+ EXPECT_EQ(0x0037f608u, context->ebx);
+ EXPECT_EQ(0x00e61578u, context->ecx);
+ EXPECT_EQ(0x00000008u, context->edx);
+ EXPECT_EQ(0x00000000u, context->edi);
+ EXPECT_EQ(0x00000002u, context->esi);
+ EXPECT_EQ(0x0037f654u, context->ebp);
+ EXPECT_EQ(0x0037f5b8u, context->esp);
+ EXPECT_EQ(0x77ce01fdu, context->eip);
+ EXPECT_EQ(0x00000246u, context->eflags);
+ EXPECT_EQ(0x0023u, context->cs);
+ EXPECT_EQ(0x0053u, context->fs);
+ EXPECT_EQ(0x002bu, context->gs);
+ EXPECT_EQ(0x002bu, context->ss);
+ EXPECT_EQ(0x002bu, context->ds);
+ EXPECT_EQ(0x002bu, context->es);
+}
+
+TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMinAddress) {
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+ - Type: ModuleList
+ Modules:
+ - Base of Image: 0x0000000000002000
+ Size of Image: 0x00001000
+ Module Name: '/tmp/a'
+ CodeView Record: ''
+ - Base of Image: 0x0000000000001000
+ Size of Image: 0x00001000
+ Module Name: '/tmp/a'
+ CodeView Record: ''
+...
+)"),
+ llvm::Succeeded());
+ // If we have a module mentioned twice in the module list, the filtered
+ // module list should contain the instance with the lowest BaseOfImage.
+ std::vector<const minidump::Module *> filtered_modules =
+ parser->GetFilteredModuleList();
+ ASSERT_EQ(1u, filtered_modules.size());
+ EXPECT_EQ(0x0000000000001000u, filtered_modules[0]->BaseOfImage);
+}
+
+TEST_F(MinidumpParserTest, MinidumpModuleOrder) {
+ ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+ - Type: ModuleList
+ Modules:
+ - Base of Image: 0x0000000000002000
+ Size of Image: 0x00001000
+ Module Name: '/tmp/a'
+ CodeView Record: ''
+ - Base of Image: 0x0000000000001000
+ Size of Image: 0x00001000
+ Module Name: '/tmp/b'
+ CodeView Record: ''
+...
+)"),
+ llvm::Succeeded());
+ // Test module filtering does not affect the overall module order. Previous
+ // versions of the MinidumpParser::GetFilteredModuleList() function would sort
+ // all images by address and modify the order of the modules.
+ std::vector<const minidump::Module *> filtered_modules =
+ parser->GetFilteredModuleList();
+ ASSERT_EQ(2u, filtered_modules.size());
+ EXPECT_EQ(0x0000000000002000u, filtered_modules[0]->BaseOfImage);
+ EXPECT_THAT_EXPECTED(
+ parser->GetMinidumpFile().getString(filtered_modules[0]->ModuleNameRVA),
+ llvm::HasValue("/tmp/a"));
+ EXPECT_EQ(0x0000000000001000u, filtered_modules[1]->BaseOfImage);
+ EXPECT_THAT_EXPECTED(
+ parser->GetMinidumpFile().getString(filtered_modules[1]->ModuleNameRVA),
+ llvm::HasValue("/tmp/b"));
+}
+
diff --git a/gnu/llvm/lldb/unittests/Process/minidump/RegisterContextMinidumpTest.cpp b/gnu/llvm/lldb/unittests/Process/minidump/RegisterContextMinidumpTest.cpp
new file mode 100644
index 00000000000..265da63d33a
--- /dev/null
+++ b/gnu/llvm/lldb/unittests/Process/minidump/RegisterContextMinidumpTest.cpp
@@ -0,0 +1,201 @@
+//===-- RegisterContextMinidumpTest.cpp -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
+#include "Plugins/Process/minidump/RegisterContextMinidump_x86_32.h"
+#include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"
+#include "Plugins/Process/minidump/RegisterContextMinidump_ARM.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "llvm/ADT/StringRef.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+using namespace lldb_private::minidump;
+
+static uint32_t reg32(const DataBuffer &Buf, const RegisterInfo &Info) {
+ return *reinterpret_cast<const uint32_t *>(Buf.GetBytes() + Info.byte_offset);
+}
+
+static uint64_t reg64(const DataBuffer &Buf, const RegisterInfo &Info) {
+ return *reinterpret_cast<const uint64_t *>(Buf.GetBytes() + Info.byte_offset);
+}
+
+TEST(RegisterContextMinidump, ConvertMinidumpContext_x86_32) {
+ MinidumpContext_x86_32 Context;
+ Context.context_flags =
+ static_cast<uint32_t>(MinidumpContext_x86_32_Flags::x86_32_Flag |
+ MinidumpContext_x86_32_Flags::Control |
+ MinidumpContext_x86_32_Flags::Segments |
+ MinidumpContext_x86_32_Flags::Integer);
+ Context.eax = 0x00010203;
+ Context.ebx = 0x04050607;
+ Context.ecx = 0x08090a0b;
+ Context.edx = 0x0c0d0e0f;
+ Context.edi = 0x10111213;
+ Context.esi = 0x14151617;
+ Context.ebp = 0x18191a1b;
+ Context.esp = 0x1c1d1e1f;
+ Context.eip = 0x20212223;
+ Context.eflags = 0x24252627;
+ Context.cs = 0x2829;
+ Context.fs = 0x2a2b;
+ Context.gs = 0x2c2d;
+ Context.ss = 0x2e2f;
+ Context.ds = 0x3031;
+ Context.es = 0x3233;
+ llvm::ArrayRef<uint8_t> ContextRef(reinterpret_cast<uint8_t *>(&Context),
+ sizeof(Context));
+
+ ArchSpec arch("i386-pc-linux");
+ auto RegInterface = std::make_unique<RegisterContextLinux_i386>(arch);
+ lldb::DataBufferSP Buf =
+ ConvertMinidumpContext_x86_32(ContextRef, RegInterface.get());
+ ASSERT_EQ(RegInterface->GetGPRSize(), Buf->GetByteSize());
+
+ const RegisterInfo *Info = RegInterface->GetRegisterInfo();
+ ASSERT_NE(nullptr, Info);
+
+ EXPECT_EQ(Context.eax, reg32(*Buf, Info[lldb_eax_i386]));
+ EXPECT_EQ(Context.ebx, reg32(*Buf, Info[lldb_ebx_i386]));
+ EXPECT_EQ(Context.ecx, reg32(*Buf, Info[lldb_ecx_i386]));
+ EXPECT_EQ(Context.edx, reg32(*Buf, Info[lldb_edx_i386]));
+ EXPECT_EQ(Context.edi, reg32(*Buf, Info[lldb_edi_i386]));
+ EXPECT_EQ(Context.esi, reg32(*Buf, Info[lldb_esi_i386]));
+ EXPECT_EQ(Context.ebp, reg32(*Buf, Info[lldb_ebp_i386]));
+ EXPECT_EQ(Context.esp, reg32(*Buf, Info[lldb_esp_i386]));
+ EXPECT_EQ(Context.eip, reg32(*Buf, Info[lldb_eip_i386]));
+ EXPECT_EQ(Context.eflags, reg32(*Buf, Info[lldb_eflags_i386]));
+ EXPECT_EQ(Context.cs, reg32(*Buf, Info[lldb_cs_i386]));
+ EXPECT_EQ(Context.fs, reg32(*Buf, Info[lldb_fs_i386]));
+ EXPECT_EQ(Context.gs, reg32(*Buf, Info[lldb_gs_i386]));
+ EXPECT_EQ(Context.ss, reg32(*Buf, Info[lldb_ss_i386]));
+ EXPECT_EQ(Context.ds, reg32(*Buf, Info[lldb_ds_i386]));
+ EXPECT_EQ(Context.es, reg32(*Buf, Info[lldb_es_i386]));
+}
+
+TEST(RegisterContextMinidump, ConvertMinidumpContext_x86_64) {
+ MinidumpContext_x86_64 Context;
+ Context.context_flags =
+ static_cast<uint32_t>(MinidumpContext_x86_64_Flags::x86_64_Flag |
+ MinidumpContext_x86_64_Flags::Control |
+ MinidumpContext_x86_64_Flags::Segments |
+ MinidumpContext_x86_64_Flags::Integer);
+ Context.rax = 0x0001020304050607;
+ Context.rbx = 0x08090a0b0c0d0e0f;
+ Context.rcx = 0x1011121314151617;
+ Context.rdx = 0x18191a1b1c1d1e1f;
+ Context.rdi = 0x2021222324252627;
+ Context.rsi = 0x28292a2b2c2d2e2f;
+ Context.rbp = 0x3031323334353637;
+ Context.rsp = 0x38393a3b3c3d3e3f;
+ Context.r8 = 0x4041424344454647;
+ Context.r9 = 0x48494a4b4c4d4e4f;
+ Context.r10 = 0x5051525354555657;
+ Context.r11 = 0x58595a5b5c5d5e5f;
+ Context.r12 = 0x6061626364656667;
+ Context.r13 = 0x68696a6b6c6d6e6f;
+ Context.r14 = 0x7071727374757677;
+ Context.r15 = 0x78797a7b7c7d7e7f;
+ Context.rip = 0x8081828384858687;
+ Context.eflags = 0x88898a8b;
+ Context.cs = 0x8c8d;
+ Context.fs = 0x8e8f;
+ Context.gs = 0x9091;
+ Context.ss = 0x9293;
+ Context.ds = 0x9495;
+ Context.ss = 0x9697;
+ llvm::ArrayRef<uint8_t> ContextRef(reinterpret_cast<uint8_t *>(&Context),
+ sizeof(Context));
+
+ ArchSpec arch("x86_64-pc-linux");
+ auto RegInterface = std::make_unique<RegisterContextLinux_x86_64>(arch);
+ lldb::DataBufferSP Buf =
+ ConvertMinidumpContext_x86_64(ContextRef, RegInterface.get());
+ ASSERT_EQ(RegInterface->GetGPRSize(), Buf->GetByteSize());
+
+ const RegisterInfo *Info = RegInterface->GetRegisterInfo();
+ EXPECT_EQ(Context.rax, reg64(*Buf, Info[lldb_rax_x86_64]));
+ EXPECT_EQ(Context.rbx, reg64(*Buf, Info[lldb_rbx_x86_64]));
+ EXPECT_EQ(Context.rcx, reg64(*Buf, Info[lldb_rcx_x86_64]));
+ EXPECT_EQ(Context.rdx, reg64(*Buf, Info[lldb_rdx_x86_64]));
+ EXPECT_EQ(Context.rdi, reg64(*Buf, Info[lldb_rdi_x86_64]));
+ EXPECT_EQ(Context.rsi, reg64(*Buf, Info[lldb_rsi_x86_64]));
+ EXPECT_EQ(Context.rbp, reg64(*Buf, Info[lldb_rbp_x86_64]));
+ EXPECT_EQ(Context.rsp, reg64(*Buf, Info[lldb_rsp_x86_64]));
+ EXPECT_EQ(Context.r8, reg64(*Buf, Info[lldb_r8_x86_64]));
+ EXPECT_EQ(Context.r9, reg64(*Buf, Info[lldb_r9_x86_64]));
+ EXPECT_EQ(Context.r10, reg64(*Buf, Info[lldb_r10_x86_64]));
+ EXPECT_EQ(Context.r11, reg64(*Buf, Info[lldb_r11_x86_64]));
+ EXPECT_EQ(Context.r12, reg64(*Buf, Info[lldb_r12_x86_64]));
+ EXPECT_EQ(Context.r13, reg64(*Buf, Info[lldb_r13_x86_64]));
+ EXPECT_EQ(Context.r14, reg64(*Buf, Info[lldb_r14_x86_64]));
+ EXPECT_EQ(Context.r15, reg64(*Buf, Info[lldb_r15_x86_64]));
+ EXPECT_EQ(Context.rip, reg64(*Buf, Info[lldb_rip_x86_64]));
+ EXPECT_EQ(Context.eflags, reg64(*Buf, Info[lldb_rflags_x86_64]));
+ EXPECT_EQ(Context.cs, reg64(*Buf, Info[lldb_cs_x86_64]));
+ EXPECT_EQ(Context.fs, reg64(*Buf, Info[lldb_fs_x86_64]));
+ EXPECT_EQ(Context.gs, reg64(*Buf, Info[lldb_gs_x86_64]));
+ EXPECT_EQ(Context.ss, reg64(*Buf, Info[lldb_ss_x86_64]));
+ EXPECT_EQ(Context.ds, reg64(*Buf, Info[lldb_ds_x86_64]));
+ EXPECT_EQ(Context.es, reg64(*Buf, Info[lldb_es_x86_64]));
+}
+
+static void TestARMRegInfo(const lldb_private::RegisterInfo *info) {
+ // Make sure we have valid register numbers for eRegisterKindEHFrame and
+ // eRegisterKindDWARF for GPR registers r0-r15 so that we can unwind
+ // correctly when using this information.
+ llvm::StringRef name(info->name);
+ llvm::StringRef alt_name(info->alt_name);
+ if (name.startswith("r") || alt_name.startswith("r")) {
+ EXPECT_NE(info->kinds[lldb::eRegisterKindEHFrame], LLDB_INVALID_REGNUM);
+ EXPECT_NE(info->kinds[lldb::eRegisterKindDWARF], LLDB_INVALID_REGNUM);
+ }
+ // Verify generic register are set correctly
+ if (name == "r0") {
+ EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
+ (uint32_t)LLDB_REGNUM_GENERIC_ARG1);
+ } else if (name == "r1") {
+ EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
+ (uint32_t)LLDB_REGNUM_GENERIC_ARG2);
+ } else if (name == "r2") {
+ EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
+ (uint32_t)LLDB_REGNUM_GENERIC_ARG3);
+ } else if (name == "r3") {
+ EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
+ (uint32_t)LLDB_REGNUM_GENERIC_ARG4);
+ } else if (name == "sp") {
+ EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
+ (uint32_t)LLDB_REGNUM_GENERIC_SP);
+ } else if (name == "fp") {
+ EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
+ (uint32_t)LLDB_REGNUM_GENERIC_FP);
+ } else if (name == "lr") {
+ EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
+ (uint32_t)LLDB_REGNUM_GENERIC_RA);
+ } else if (name == "pc") {
+ EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
+ (uint32_t)LLDB_REGNUM_GENERIC_PC);
+ } else if (name == "cpsr") {
+ EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
+ (uint32_t)LLDB_REGNUM_GENERIC_FLAGS);
+ }
+}
+
+TEST(RegisterContextMinidump, CheckRegisterContextMinidump_ARM) {
+ size_t num_regs = RegisterContextMinidump_ARM::GetRegisterCountStatic();
+ const lldb_private::RegisterInfo *reg_info;
+ for (size_t reg=0; reg<num_regs; ++reg) {
+ reg_info = RegisterContextMinidump_ARM::GetRegisterInfoAtIndexStatic(reg,
+ true);
+ TestARMRegInfo(reg_info);
+ reg_info = RegisterContextMinidump_ARM::GetRegisterInfoAtIndexStatic(reg,
+ false);
+ TestARMRegInfo(reg_info);
+ }
+}