aboutsummaryrefslogtreecommitdiff
path: root/lldb
diff options
context:
space:
mode:
Diffstat (limited to 'lldb')
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp1
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp103
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h16
-rw-r--r--lldb/test/API/CMakeLists.txt10
-rw-r--r--lldb/test/API/lang/objc/foundation/TestObjCMethodsNSError.py27
-rw-r--r--lldb/tools/lldb-dap/DAP.cpp7
-rw-r--r--lldb/unittests/Target/MemoryTest.cpp2
7 files changed, 163 insertions, 3 deletions
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 6b121c9..9900745 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -754,7 +754,6 @@ ClangExpressionParser::ClangExpressionParser(
// Make sure clang uses the same VFS as LLDB.
m_compiler->setVirtualFileSystem(
FileSystem::Instance().GetVirtualFileSystem());
- m_compiler->createFileManager();
// 2. Configure the compiler with a set of default options that are
// appropriate for most situations.
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 91f3a6c..b4422a7 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -86,6 +86,7 @@
#include "lldb/Host/Host.h"
#include "lldb/Utility/StringExtractorGDBRemote.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
@@ -2762,6 +2763,108 @@ size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size,
return 0;
}
+llvm::SmallVector<llvm::MutableArrayRef<uint8_t>>
+ProcessGDBRemote::ReadMemoryRanges(
+ llvm::ArrayRef<Range<lldb::addr_t, size_t>> ranges,
+ llvm::MutableArrayRef<uint8_t> buffer) {
+ if (!m_gdb_comm.GetMultiMemReadSupported())
+ return Process::ReadMemoryRanges(ranges, buffer);
+
+ llvm::Expected<StringExtractorGDBRemote> response =
+ SendMultiMemReadPacket(ranges);
+ if (!response) {
+ LLDB_LOG_ERROR(GetLog(GDBRLog::Process), response.takeError(),
+ "MultiMemRead error response: {0}");
+ return Process::ReadMemoryRanges(ranges, buffer);
+ }
+
+ llvm::StringRef response_str = response->GetStringRef();
+ const unsigned expected_num_ranges = ranges.size();
+ llvm::Expected<llvm::SmallVector<llvm::MutableArrayRef<uint8_t>>>
+ parsed_response =
+ ParseMultiMemReadPacket(response_str, buffer, expected_num_ranges);
+ if (!parsed_response) {
+ LLDB_LOG_ERROR(GetLog(GDBRLog::Process), parsed_response.takeError(),
+ "MultiMemRead error parsing response: {0}");
+ return Process::ReadMemoryRanges(ranges, buffer);
+ }
+ return std::move(*parsed_response);
+}
+
+llvm::Expected<StringExtractorGDBRemote>
+ProcessGDBRemote::SendMultiMemReadPacket(
+ llvm::ArrayRef<Range<lldb::addr_t, size_t>> ranges) {
+ std::string packet_str;
+ llvm::raw_string_ostream stream(packet_str);
+ stream << "MultiMemRead:ranges:";
+
+ auto range_to_stream = [&](auto range) {
+ // the "-" marker omits the '0x' prefix.
+ stream << llvm::formatv("{0:x-},{1:x-}", range.base, range.size);
+ };
+ llvm::interleave(ranges, stream, range_to_stream, ",");
+ stream << ";";
+
+ StringExtractorGDBRemote response;
+ GDBRemoteCommunication::PacketResult packet_result =
+ m_gdb_comm.SendPacketAndWaitForResponse(packet_str.data(), response,
+ GetInterruptTimeout());
+ if (packet_result != GDBRemoteCommunication::PacketResult::Success)
+ return llvm::createStringError(
+ llvm::formatv("MultiMemRead failed to send packet: '{0}'", packet_str));
+
+ if (response.IsErrorResponse())
+ return llvm::createStringError(
+ llvm::formatv("MultiMemRead failed: '{0}'", response.GetStringRef()));
+
+ if (!response.IsNormalResponse())
+ return llvm::createStringError(llvm::formatv(
+ "MultiMemRead unexpected response: '{0}'", response.GetStringRef()));
+
+ return response;
+}
+
+llvm::Expected<llvm::SmallVector<llvm::MutableArrayRef<uint8_t>>>
+ProcessGDBRemote::ParseMultiMemReadPacket(llvm::StringRef response_str,
+ llvm::MutableArrayRef<uint8_t> buffer,
+ unsigned expected_num_ranges) {
+ // The sizes and the data are separated by a `;`.
+ auto [sizes_str, memory_data] = response_str.split(';');
+ if (sizes_str.size() == response_str.size())
+ return llvm::createStringError(llvm::formatv(
+ "MultiMemRead response missing field separator ';' in: '{0}'",
+ response_str));
+
+ llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> read_results;
+
+ // Sizes are separated by a `,`.
+ for (llvm::StringRef size_str : llvm::split(sizes_str, ',')) {
+ uint64_t read_size;
+ if (size_str.getAsInteger(16, read_size))
+ return llvm::createStringError(llvm::formatv(
+ "MultiMemRead response has invalid size string: {0}", size_str));
+
+ if (memory_data.size() < read_size)
+ return llvm::createStringError(
+ llvm::formatv("MultiMemRead response did not have enough data, "
+ "requested sizes: {0}",
+ sizes_str));
+
+ llvm::StringRef region_to_read = memory_data.take_front(read_size);
+ memory_data = memory_data.drop_front(read_size);
+
+ assert(buffer.size() >= read_size);
+ llvm::MutableArrayRef<uint8_t> region_to_write =
+ buffer.take_front(read_size);
+ buffer = buffer.drop_front(read_size);
+
+ memcpy(region_to_write.data(), region_to_read.data(), read_size);
+ read_results.push_back(region_to_write);
+ }
+
+ return read_results;
+}
+
bool ProcessGDBRemote::SupportsMemoryTagging() {
return m_gdb_comm.GetMemoryTaggingSupported();
}
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 7c3dfb1..eb33b52 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -137,6 +137,22 @@ public:
size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
Status &error) override;
+ /// Override of ReadMemoryRanges that uses MultiMemRead to optimize this
+ /// operation.
+ llvm::SmallVector<llvm::MutableArrayRef<uint8_t>>
+ ReadMemoryRanges(llvm::ArrayRef<Range<lldb::addr_t, size_t>> ranges,
+ llvm::MutableArrayRef<uint8_t> buf) override;
+
+private:
+ llvm::Expected<StringExtractorGDBRemote>
+ SendMultiMemReadPacket(llvm::ArrayRef<Range<lldb::addr_t, size_t>> ranges);
+
+ llvm::Expected<llvm::SmallVector<llvm::MutableArrayRef<uint8_t>>>
+ ParseMultiMemReadPacket(llvm::StringRef response_str,
+ llvm::MutableArrayRef<uint8_t> buffer,
+ unsigned expected_num_ranges);
+
+public:
Status
WriteObjectFile(std::vector<ObjectFile::LoadableData> entries) override;
diff --git a/lldb/test/API/CMakeLists.txt b/lldb/test/API/CMakeLists.txt
index e3bffbc..c719ac3 100644
--- a/lldb/test/API/CMakeLists.txt
+++ b/lldb/test/API/CMakeLists.txt
@@ -74,6 +74,16 @@ else()
endif()
endif()
+find_program(LLDB_DIRNAME_PATH dirname)
+if(LLDB_DIRNAME_PATH)
+ message(STATUS "Found dirname: ${LLDB_DIRNAME_PATH}")
+else()
+ message(STATUS "Could NOT find 'dirname'")
+ message(WARNING
+ "Many LLDB API tests require the GNU coreutils tools. Please make "
+ "sure they are installed and in PATH.")
+endif()
+
if (TARGET clang)
set(LLDB_DEFAULT_TEST_COMPILER "${LLVM_TOOLS_BINARY_DIR}/clang${CMAKE_EXECUTABLE_SUFFIX}")
else()
diff --git a/lldb/test/API/lang/objc/foundation/TestObjCMethodsNSError.py b/lldb/test/API/lang/objc/foundation/TestObjCMethodsNSError.py
index a14035d..a9fbe54 100644
--- a/lldb/test/API/lang/objc/foundation/TestObjCMethodsNSError.py
+++ b/lldb/test/API/lang/objc/foundation/TestObjCMethodsNSError.py
@@ -45,3 +45,30 @@ class FoundationTestCaseNSError(TestBase):
],
)
self.runCmd("process continue")
+
+ @skipIfOutOfTreeDebugserver
+ def test_runtime_types_efficient_memreads(self):
+ # Test that we use an efficient reading of memory when reading
+ # Objective-C method descriptions.
+ logfile = os.path.join(self.getBuildDir(), "log.txt")
+ self.runCmd(f"log enable -f {logfile} gdb-remote packets process")
+ self.addTearDownHook(lambda: self.runCmd("log disable gdb-remote packets"))
+
+ self.build()
+ self.target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
+ self, "// Break here for NSString tests", lldb.SBFileSpec("main.m", False)
+ )
+
+ self.runCmd(f"proc plugin packet send StartTesting", check=False)
+ self.expect('expression str = [NSString stringWithCString: "new"]')
+ self.runCmd(f"proc plugin packet send EndTesting", check=False)
+
+ self.assertTrue(os.path.exists(logfile))
+ log_text = open(logfile).read()
+ log_text = log_text.split("StartTesting", 1)[-1].split("EndTesting", 1)[0]
+
+ # This test is only checking that the packet it used at all (and that
+ # no errors are produced). It doesn't check that the packet is being
+ # used to solve a problem in an optimal way.
+ self.assertIn("MultiMemRead:", log_text)
+ self.assertNotIn("MultiMemRead error", log_text)
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 52c8c6b..3c4f225 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -26,6 +26,7 @@
#include "lldb/API/SBEvent.h"
#include "lldb/API/SBLanguageRuntime.h"
#include "lldb/API/SBListener.h"
+#include "lldb/API/SBMutex.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBStream.h"
#include "lldb/Host/JSONTransport.h"
@@ -1452,7 +1453,11 @@ void DAP::EventThread() {
const bool remove_module =
event_mask & lldb::SBTarget::eBroadcastBitModulesUnloaded;
- std::lock_guard<std::mutex> guard(modules_mutex);
+ // NOTE: Both mutexes must be acquired to prevent deadlock when
+ // handling `modules_request`, which also requires both locks.
+ lldb::SBMutex api_mutex = GetAPIMutex();
+ const std::scoped_lock<lldb::SBMutex, std::mutex> guard(
+ api_mutex, modules_mutex);
for (uint32_t i = 0; i < num_modules; ++i) {
lldb::SBModule module =
lldb::SBTarget::GetModuleAtIndexFromEvent(i, event);
diff --git a/lldb/unittests/Target/MemoryTest.cpp b/lldb/unittests/Target/MemoryTest.cpp
index f7b4e97..e444f68 100644
--- a/lldb/unittests/Target/MemoryTest.cpp
+++ b/lldb/unittests/Target/MemoryTest.cpp
@@ -245,7 +245,7 @@ public:
if (read_more_than_requested)
size *= 2;
uint8_t *buffer = static_cast<uint8_t *>(buf);
- for (size_t addr = vm_addr; addr < vm_addr + size; addr++)
+ for (lldb::addr_t addr = vm_addr; addr < vm_addr + size; addr++)
buffer[addr - vm_addr] = static_cast<uint8_t>(addr); // LSB of addr.
return size;
}