summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Host/common/NativeProcessProtocol.h25
-rw-r--r--lldb/source/Host/common/NativeProcessProtocol.cpp54
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp2
-rw-r--r--lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp11
-rw-r--r--lldb/unittests/Host/NativeProcessProtocolTest.cpp51
5 files changed, 136 insertions, 7 deletions
diff --git a/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
index b574e57f80c..77bcf788bbd 100644
--- a/lldb/include/lldb/Host/common/NativeProcessProtocol.h
+++ b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
@@ -84,6 +84,31 @@ public:
Status ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size,
size_t &bytes_read);
+ /// Reads a null terminated string from memory.
+ ///
+ /// Reads up to \p max_size bytes of memory until it finds a '\0'.
+ /// If a '\0' is not found then it reads max_size-1 bytes as a string and a
+ /// '\0' is added as the last character of the \p buffer.
+ ///
+ /// \param[in] addr
+ /// The address in memory to read from.
+ ///
+ /// \param[in] buffer
+ /// An allocated buffer with at least \p max_size size.
+ ///
+ /// \param[in] max_size
+ /// The maximum number of bytes to read from memory until it reads the
+ /// string.
+ ///
+ /// \param[out] total_bytes_read
+ /// The number of bytes read from memory into \p buffer.
+ ///
+ /// \return
+ /// Returns a StringRef backed up by the \p buffer passed in.
+ llvm::Expected<llvm::StringRef>
+ ReadCStringFromMemory(lldb::addr_t addr, char *buffer, size_t max_size,
+ size_t &total_bytes_read);
+
virtual Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
size_t &bytes_written) = 0;
diff --git a/lldb/source/Host/common/NativeProcessProtocol.cpp b/lldb/source/Host/common/NativeProcessProtocol.cpp
index 90272cb8d0b..476ab97a490 100644
--- a/lldb/source/Host/common/NativeProcessProtocol.cpp
+++ b/lldb/source/Host/common/NativeProcessProtocol.cpp
@@ -16,6 +16,8 @@
#include "lldb/Utility/State.h"
#include "lldb/lldb-enumerations.h"
+#include "llvm/Support/Process.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -659,6 +661,58 @@ Status NativeProcessProtocol::ReadMemoryWithoutTrap(lldb::addr_t addr,
return Status();
}
+llvm::Expected<llvm::StringRef>
+NativeProcessProtocol::ReadCStringFromMemory(lldb::addr_t addr, char *buffer,
+ size_t max_size,
+ size_t &total_bytes_read) {
+ static const size_t cache_line_size =
+ llvm::sys::Process::getPageSizeEstimate();
+ size_t bytes_read = 0;
+ size_t bytes_left = max_size;
+ addr_t curr_addr = addr;
+ size_t string_size;
+ char *curr_buffer = buffer;
+ total_bytes_read = 0;
+ Status status;
+
+ while (bytes_left > 0 && status.Success()) {
+ addr_t cache_line_bytes_left =
+ cache_line_size - (curr_addr % cache_line_size);
+ addr_t bytes_to_read = std::min<addr_t>(bytes_left, cache_line_bytes_left);
+ status = ReadMemory(curr_addr, reinterpret_cast<void *>(curr_buffer),
+ bytes_to_read, bytes_read);
+
+ if (bytes_read == 0)
+ break;
+
+ void *str_end = std::memchr(curr_buffer, '\0', bytes_read);
+ if (str_end != nullptr) {
+ total_bytes_read =
+ (size_t)(reinterpret_cast<char *>(str_end) - buffer + 1);
+ status.Clear();
+ break;
+ }
+
+ total_bytes_read += bytes_read;
+ curr_buffer += bytes_read;
+ curr_addr += bytes_read;
+ bytes_left -= bytes_read;
+ }
+
+ string_size = total_bytes_read - 1;
+
+ // Make sure we return a null terminated string.
+ if (bytes_left == 0 && max_size > 0 && buffer[max_size - 1] != '\0') {
+ buffer[max_size - 1] = '\0';
+ total_bytes_read--;
+ }
+
+ if (!status.Success())
+ return status.ToError();
+
+ return llvm::StringRef(buffer, string_size);
+}
+
lldb::StateType NativeProcessProtocol::GetState() const {
std::lock_guard<std::recursive_mutex> guard(m_state_mutex);
return m_state;
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index b40b70104ea..7637237aa16 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -2076,4 +2076,4 @@ Status NativeProcessLinux::StopProcessorTracingOnThread(lldb::user_id_t traceid,
m_processor_trace_monitor.erase(iter);
return error;
-} \ No newline at end of file
+}
diff --git a/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp b/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp
index 50b2d05df3e..6470eca7746 100644
--- a/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp
+++ b/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp
@@ -118,14 +118,13 @@ NativeProcessELF::ReadSVR4LibraryInfo(lldb::addr_t link_map_addr) {
return error.ToError();
char name_buffer[PATH_MAX];
- error = ReadMemory(link_map.l_name, &name_buffer, sizeof(name_buffer),
- bytes_read);
- if (bytes_read == 0)
- return error.ToError();
- name_buffer[PATH_MAX - 1] = '\0';
+ llvm::Expected<llvm::StringRef> string_or_error = ReadCStringFromMemory(
+ link_map.l_name, &name_buffer[0], sizeof(name_buffer), bytes_read);
+ if (!string_or_error)
+ return string_or_error.takeError();
SVR4LibraryInfo info;
- info.name = std::string(name_buffer);
+ info.name = string_or_error->str();
info.link_map = link_map_addr;
info.base_addr = link_map.l_addr;
info.ld_addr = link_map.l_ld;
diff --git a/lldb/unittests/Host/NativeProcessProtocolTest.cpp b/lldb/unittests/Host/NativeProcessProtocolTest.cpp
index bf61951be60..c5516b1b1d3 100644
--- a/lldb/unittests/Host/NativeProcessProtocolTest.cpp
+++ b/lldb/unittests/Host/NativeProcessProtocolTest.cpp
@@ -9,6 +9,7 @@
#include "TestingSupport/Host/NativeProcessTestUtils.h"
#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "llvm/Support/Process.h"
#include "llvm/Testing/Support/Error.h"
#include "gmock/gmock.h"
@@ -96,3 +97,53 @@ TEST(NativeProcessProtocolTest, ReadMemoryWithoutTrap) {
EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(4, 2),
llvm::HasValue(std::vector<uint8_t>{4, 5}));
}
+
+TEST(NativeProcessProtocolTest, ReadCStringFromMemory) {
+ NiceMock<MockDelegate> DummyDelegate;
+ MockProcess<NativeProcessProtocol> Process(DummyDelegate,
+ ArchSpec("aarch64-pc-linux"));
+ FakeMemory M({'h', 'e', 'l', 'l', 'o', 0, 'w', 'o'});
+ EXPECT_CALL(Process, ReadMemory(_, _))
+ .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
+
+ char string[1024];
+ size_t bytes_read;
+ EXPECT_THAT_EXPECTED(Process.ReadCStringFromMemory(
+ 0x0, &string[0], sizeof(string), bytes_read),
+ llvm::HasValue(llvm::StringRef("hello")));
+ EXPECT_EQ(bytes_read, 6UL);
+}
+
+TEST(NativeProcessProtocolTest, ReadCStringFromMemory_MaxSize) {
+ NiceMock<MockDelegate> DummyDelegate;
+ MockProcess<NativeProcessProtocol> Process(DummyDelegate,
+ ArchSpec("aarch64-pc-linux"));
+ FakeMemory M({'h', 'e', 'l', 'l', 'o', 0, 'w', 'o'});
+ EXPECT_CALL(Process, ReadMemory(_, _))
+ .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
+
+ char string[4];
+ size_t bytes_read;
+ EXPECT_THAT_EXPECTED(Process.ReadCStringFromMemory(
+ 0x0, &string[0], sizeof(string), bytes_read),
+ llvm::HasValue(llvm::StringRef("hel")));
+ EXPECT_EQ(bytes_read, 3UL);
+}
+
+TEST(NativeProcessProtocolTest, ReadCStringFromMemory_CrossPageBoundary) {
+ NiceMock<MockDelegate> DummyDelegate;
+ MockProcess<NativeProcessProtocol> Process(DummyDelegate,
+ ArchSpec("aarch64-pc-linux"));
+ unsigned string_start = llvm::sys::Process::getPageSizeEstimate() - 3;
+ FakeMemory M({'h', 'e', 'l', 'l', 'o', 0, 'w', 'o'}, string_start);
+ EXPECT_CALL(Process, ReadMemory(_, _))
+ .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
+
+ char string[1024];
+ size_t bytes_read;
+ EXPECT_THAT_EXPECTED(Process.ReadCStringFromMemory(string_start, &string[0],
+ sizeof(string),
+ bytes_read),
+ llvm::HasValue(llvm::StringRef("hello")));
+ EXPECT_EQ(bytes_read, 6UL);
+} \ No newline at end of file
OpenPOWER on IntegriCloud