This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG2c4226f8ac2c: [lldb-server][linux] Add ability to allocate
memory (authored by labath).
Changed prior to commit:
https://reviews.llvm.org/D89124?vs=297876&id=298134#toc
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D89124/new/
https://reviews.llvm.org/D89124
Files:
lldb/include/lldb/Host/common/NativeProcessProtocol.h
lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp
lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h
lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h
lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
lldb/test/API/lang/c/stepping/TestStepAndBreakpoints.py
lldb/test/API/tools/lldb-server/memory-allocation/Makefile
lldb/test/API/tools/lldb-server/memory-allocation/TestGdbRemoteMemoryAllocation.py
lldb/test/API/tools/lldb-server/memory-allocation/main.c
lldb/test/Shell/Expr/nodefaultlib.cpp
lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h
Index: lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h
===================================================================
--- lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h
+++ lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h
@@ -41,9 +41,6 @@
MOCK_METHOD0(Detach, Status());
MOCK_METHOD1(Signal, Status(int Signo));
MOCK_METHOD0(Kill, Status());
- MOCK_METHOD3(AllocateMemory,
- Status(size_t Size, uint32_t Permissions, addr_t &Addr));
- MOCK_METHOD1(DeallocateMemory, Status(addr_t Addr));
MOCK_METHOD0(GetSharedLibraryInfoAddress, addr_t());
MOCK_METHOD0(UpdateThreads, size_t());
MOCK_CONST_METHOD0(GetAuxvData,
@@ -147,4 +144,4 @@
};
} // namespace lldb_private
-#endif
\ No newline at end of file
+#endif
Index: lldb/test/Shell/Expr/nodefaultlib.cpp
===================================================================
--- /dev/null
+++ lldb/test/Shell/Expr/nodefaultlib.cpp
@@ -0,0 +1,16 @@
+// Test that we're able to evaluate expressions in inferiors without the
+// standard library (and mmap-like functions in particular).
+
+// REQUIRES: native
+// XFAIL: system-linux && !(target-x86 || target-x86_64)
+// XFAIL: system-netbsd || system-freebsd
+
+// RUN: %build %s --nodefaultlib -o %t
+// RUN: %lldb %t -o "b main" -o run -o "p call_me(5, 6)" -o exit \
+// RUN: | FileCheck %s
+
+// CHECK: (int) $0 = 30
+
+int call_me(int x, long y) { return x * y; }
+
+int main() { return call_me(4, 5); }
Index: lldb/test/API/tools/lldb-server/memory-allocation/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/tools/lldb-server/memory-allocation/main.c
@@ -0,0 +1 @@
+int main() { return 0; }
Index: lldb/test/API/tools/lldb-server/memory-allocation/TestGdbRemoteMemoryAllocation.py
===================================================================
--- /dev/null
+++ lldb/test/API/tools/lldb-server/memory-allocation/TestGdbRemoteMemoryAllocation.py
@@ -0,0 +1,101 @@
+
+import gdbremote_testcase
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+supported_linux_archs = ["x86_64", "i386"]
+supported_oses = ["linux"]
+
+class TestGdbRemoteMemoryAllocation(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def allocate(self, size, permissions):
+ self.test_sequence.add_log_lines(["read packet: $_M{:x},{}#00".format(size, permissions),
+ {"direction": "send",
+ "regex":
+ r"^\$([0-9a-f]+)#[0-9a-fA-F]{2}$",
+ "capture": {
+ 1: "addr"}},
+ ],
+ True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ addr = int(context.get("addr"), 16)
+ self.test_sequence.add_log_lines(["read packet: $qMemoryRegionInfo:{:x}#00".format(addr),
+ {"direction": "send",
+ "regex":
+ r"^\$start:([0-9a-fA-F]+);size:([0-9a-fA-F]+);permissions:([rwx]*);.*#[0-9a-fA-F]{2}$",
+ "capture": {
+ 1: "addr",
+ 2: "size",
+ 3: "permissions"}},
+ "read packet: $_m{:x}#00".format(addr),
+ "send packet: $OK#00",
+ ],
+ True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ self.assertEqual(addr, int(context.get("addr"), 16))
+ self.assertLessEqual(size, int(context.get("size"), 16))
+ self.assertEqual(permissions, context.get("permissions"))
+
+ @skipIf(oslist=no_match(supported_oses))
+ @skipIf(oslist=["linux"], archs=no_match(supported_linux_archs))
+ @llgs_test
+ def test_supported(self):
+ """Make sure (de)allocation works on platforms where it's supposed to
+ work"""
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ procs = self.prep_debug_monitor_and_inferior()
+
+ self.allocate(0x1000, "r")
+ self.allocate(0x2000, "rw")
+ self.allocate(0x100, "rx")
+ self.allocate(0x1100, "rwx")
+
+ @skipIf(oslist=["linux"], archs=supported_linux_archs)
+ @llgs_test
+ def test_unsupported(self):
+ """Make sure we get an "unsupported" error on platforms where the
+ feature is not implemented."""
+
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ procs = self.prep_debug_monitor_and_inferior()
+
+ self.test_sequence.add_log_lines(["read packet: $_M1000,rw#00",
+ "send packet: $#00",
+ ],
+ True)
+ self.expect_gdbremote_sequence()
+
+ @llgs_test
+ def test_bad_packet(self):
+ """Make sure we get a proper error for malformed packets."""
+
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ procs = self.prep_debug_monitor_and_inferior()
+
+ def e():
+ return {"direction": "send",
+ "regex":
+ r"^\$E([0-9a-fA-F]+){2}#[0-9a-fA-F]{2}$"}
+
+ self.test_sequence.add_log_lines([
+ "read packet: $_M#00", e(),
+ "read packet: $_M1x#00", e(),
+ "read packet: $_M1:#00", e(),
+ "read packet: $_M1,q#00", e(),
+ "read packet: $_m#00", e(),
+ ], True)
+ self.expect_gdbremote_sequence()
Index: lldb/test/API/tools/lldb-server/memory-allocation/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/tools/lldb-server/memory-allocation/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
Index: lldb/test/API/lang/c/stepping/TestStepAndBreakpoints.py
===================================================================
--- lldb/test/API/lang/c/stepping/TestStepAndBreakpoints.py
+++ lldb/test/API/lang/c/stepping/TestStepAndBreakpoints.py
@@ -20,7 +20,7 @@
@add_test_categories(['pyapi', 'basic_process'])
@expectedFailureAll(oslist=['freebsd'], bugnumber='llvm.org/pr17932')
- @expectedFailureAll(oslist=["linux"], bugnumber="llvm.org/pr14437")
+ @expectedFailureAll(oslist=["linux"], archs=no_match(["i386", "x86_64"]))
@expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24777")
@expectedFailureNetBSD
def test_and_python_api(self):
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -138,6 +138,8 @@
PacketResult Handle_memory_read(StringExtractorGDBRemote &packet);
PacketResult Handle_M(StringExtractorGDBRemote &packet);
+ PacketResult Handle__M(StringExtractorGDBRemote &packet);
+ PacketResult Handle__m(StringExtractorGDBRemote &packet);
PacketResult
Handle_qMemoryRegionInfoSupported(StringExtractorGDBRemote &packet);
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -93,6 +93,10 @@
&GDBRemoteCommunicationServerLLGS::Handle_memory_read);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M,
&GDBRemoteCommunicationServerLLGS::Handle_M);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType__M,
+ &GDBRemoteCommunicationServerLLGS::Handle__M);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType__m,
+ &GDBRemoteCommunicationServerLLGS::Handle__m);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_p,
&GDBRemoteCommunicationServerLLGS::Handle_p);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_P,
@@ -2321,6 +2325,84 @@
return SendPacketNoLock(response.GetString());
}
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle__M(StringExtractorGDBRemote &packet) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos(strlen("_M"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short _M packet");
+
+ const lldb::addr_t size = packet.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ if (size == LLDB_INVALID_ADDRESS)
+ return SendIllFormedResponse(packet, "Address not valid");
+ if (packet.GetChar() != ',')
+ return SendIllFormedResponse(packet, "Bad packet");
+ Permissions perms = {};
+ while (packet.GetBytesLeft() > 0) {
+ switch (packet.GetChar()) {
+ case 'r':
+ perms |= ePermissionsReadable;
+ break;
+ case 'w':
+ perms |= ePermissionsWritable;
+ break;
+ case 'x':
+ perms |= ePermissionsExecutable;
+ break;
+ default:
+ return SendIllFormedResponse(packet, "Bad permissions");
+ }
+ }
+
+ llvm::Expected<addr_t> addr =
+ m_debugged_process_up->AllocateMemory(size, perms);
+ if (!addr)
+ return SendErrorResponse(addr.takeError());
+
+ StreamGDBRemote response;
+ response.PutHex64(*addr);
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle__m(StringExtractorGDBRemote &packet) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos(strlen("_m"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short m packet");
+
+ const lldb::addr_t addr = packet.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ if (addr == LLDB_INVALID_ADDRESS)
+ return SendIllFormedResponse(packet, "Address not valid");
+
+ if (llvm::Error Err = m_debugged_process_up->DeallocateMemory(addr))
+ return SendErrorResponse(std::move(Err));
+
+ return SendOKResponse();
+}
+
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
Index: lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h
===================================================================
--- lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h
+++ lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h
@@ -65,10 +65,10 @@
Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
size_t &bytes_written) override;
- Status AllocateMemory(size_t size, uint32_t permissions,
- lldb::addr_t &addr) override;
+ llvm::Expected<lldb::addr_t> AllocateMemory(size_t size,
+ uint32_t permissions) override;
- Status DeallocateMemory(lldb::addr_t addr) override;
+ llvm::Error DeallocateMemory(lldb::addr_t addr) override;
lldb::addr_t GetSharedLibraryInfoAddress() override;
Index: lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
===================================================================
--- lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
+++ lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
@@ -217,13 +217,17 @@
return ProcessDebugger::WriteMemory(addr, buf, size, bytes_written);
}
-Status NativeProcessWindows::AllocateMemory(size_t size, uint32_t permissions,
- lldb::addr_t &addr) {
- return ProcessDebugger::AllocateMemory(size, permissions, addr);
+llvm::Expected<lldb::addr_t>
+NativeProcessWindows::AllocateMemory(size_t size, uint32_t permissions) {
+ lldb::addr_t addr;
+ Status ST = ProcessDebugger::AllocateMemory(size, permissions, addr);
+ if (ST.Success())
+ return addr;
+ return ST.ToError();
}
-Status NativeProcessWindows::DeallocateMemory(lldb::addr_t addr) {
- return ProcessDebugger::DeallocateMemory(addr);
+llvm::Error NativeProcessWindows::DeallocateMemory(lldb::addr_t addr) {
+ return ProcessDebugger::DeallocateMemory(addr).ToError();
}
lldb::addr_t NativeProcessWindows::GetSharedLibraryInfoAddress() { return 0; }
Index: lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
===================================================================
--- lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
+++ lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
@@ -60,11 +60,6 @@
Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
size_t &bytes_written) override;
- Status AllocateMemory(size_t size, uint32_t permissions,
- lldb::addr_t &addr) override;
-
- Status DeallocateMemory(lldb::addr_t addr) override;
-
lldb::addr_t GetSharedLibraryInfoAddress() override;
size_t UpdateThreads() override;
Index: lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
===================================================================
--- lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
+++ lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
@@ -684,15 +684,6 @@
return Status();
}
-Status NativeProcessNetBSD::AllocateMemory(size_t size, uint32_t permissions,
- lldb::addr_t &addr) {
- return Status("Unimplemented");
-}
-
-Status NativeProcessNetBSD::DeallocateMemory(lldb::addr_t addr) {
- return Status("Unimplemented");
-}
-
lldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() {
// punt on this for now
return LLDB_INVALID_ADDRESS;
Index: lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
+++ lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
@@ -64,6 +64,10 @@
uint32_t NumSupportedHardwareWatchpoints() override;
+ llvm::Optional<SyscallData> GetSyscallData() override;
+
+ llvm::Optional<MmapData> GetMmapData() override;
+
protected:
void *GetGPRBuffer() override { return &m_gpr_x86_64; }
Index: lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
+++ lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
@@ -1220,4 +1220,38 @@
(IsMPX(reg_index) ? 128 : 0);
}
+llvm::Optional<NativeRegisterContextLinux::SyscallData>
+NativeRegisterContextLinux_x86_64::GetSyscallData() {
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86: {
+ static const uint8_t Int80[] = {0xcd, 0x80};
+ static const uint32_t Args[] = {lldb_eax_i386, lldb_ebx_i386, lldb_ecx_i386,
+ lldb_edx_i386, lldb_esi_i386, lldb_edi_i386,
+ lldb_ebp_i386};
+ return SyscallData{Int80, Args, lldb_eax_i386};
+ }
+ case llvm::Triple::x86_64: {
+ static const uint8_t Syscall[] = {0x0f, 0x05};
+ static const uint32_t Args[] = {
+ lldb_rax_x86_64, lldb_rdi_x86_64, lldb_rsi_x86_64, lldb_rdx_x86_64,
+ lldb_r10_x86_64, lldb_r8_x86_64, lldb_r9_x86_64};
+ return SyscallData{Syscall, Args, lldb_rax_x86_64};
+ }
+ default:
+ llvm_unreachable("Unhandled architecture!");
+ }
+}
+
+llvm::Optional<NativeRegisterContextLinux::MmapData>
+NativeRegisterContextLinux_x86_64::GetMmapData() {
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ return MmapData{192, 91};
+ case llvm::Triple::x86_64:
+ return MmapData{9, 11};
+ default:
+ llvm_unreachable("Unhandled architecture!");
+ }
+}
+
#endif // defined(__i386__) || defined(__x86_64__)
Index: lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h
+++ lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h
@@ -31,6 +31,32 @@
// Invalidates cached values in register context data structures
virtual void InvalidateAllRegisters(){}
+ struct SyscallData {
+ /// The syscall instruction. If the architecture uses software
+ /// single-stepping, the instruction should also be followed by a trap to
+ /// ensure the process is stopped after the syscall.
+ llvm::ArrayRef<uint8_t> Insn;
+
+ /// Registers used for syscall arguments. The first register is used to
+ /// store the syscall number.
+ llvm::ArrayRef<uint32_t> Args;
+
+ uint32_t Result; ///< Register containing the syscall result.
+ };
+ /// Return architecture-specific data needed to make inferior syscalls, if
+ /// they are supported.
+ virtual llvm::Optional<SyscallData> GetSyscallData() { return llvm::None; }
+
+ struct MmapData {
+ // Syscall numbers can be found (e.g.) in /usr/include/asm/unistd.h for the
+ // relevant architecture.
+ unsigned SysMmap; ///< mmap syscall number.
+ unsigned SysMunmap; ///< munmap syscall number
+ };
+ /// Return the architecture-specific data needed to make mmap syscalls, if
+ /// they are supported.
+ virtual llvm::Optional<MmapData> GetMmapData() { return llvm::None; }
+
protected:
lldb::ByteOrder GetByteOrder() const;
Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
+++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
@@ -71,10 +71,10 @@
Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
size_t &bytes_written) override;
- Status AllocateMemory(size_t size, uint32_t permissions,
- lldb::addr_t &addr) override;
+ llvm::Expected<lldb::addr_t> AllocateMemory(size_t size,
+ uint32_t permissions) override;
- Status DeallocateMemory(lldb::addr_t addr) override;
+ llvm::Error DeallocateMemory(lldb::addr_t addr) override;
size_t UpdateThreads() override;
@@ -94,6 +94,7 @@
lldb::addr_t &load_addr) override;
NativeThreadLinux *GetThreadByID(lldb::tid_t id);
+ NativeThreadLinux *GetCurrentThread();
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
GetAuxvData() const override {
@@ -127,6 +128,8 @@
llvm::Expected<llvm::ArrayRef<uint8_t>>
GetSoftwareBreakpointTrapOpcode(size_t size_hint) override;
+ llvm::Expected<uint64_t> Syscall(llvm::ArrayRef<uint64_t> args);
+
private:
MainLoop::SignalHandleUP m_sigchld_handle;
ArchSpec m_arch;
@@ -140,6 +143,9 @@
// the relevan breakpoint
std::map<lldb::tid_t, lldb::addr_t> m_threads_stepping_with_breakpoint;
+ /// Inferior memory (allocated by us) and its size.
+ llvm::DenseMap<lldb::addr_t, lldb::addr_t> m_allocated_memory;
+
// Private Instance Methods
NativeProcessLinux(::pid_t pid, int terminal_fd, NativeDelegate &delegate,
const ArchSpec &arch, MainLoop &mainloop,
Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -19,6 +19,10 @@
#include <string>
#include <unordered_map>
+#include "NativeThreadLinux.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "Plugins/Process/Utility/LinuxProcMaps.h"
+#include "Procfs.h"
#include "lldb/Core/EmulateInstruction.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/Host.h"
@@ -38,15 +42,11 @@
#include "lldb/Utility/State.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StringExtractor.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/Errno.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Threading.h"
-#include "NativeThreadLinux.h"
-#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
-#include "Plugins/Process/Utility/LinuxProcMaps.h"
-#include "Procfs.h"
-
#include <linux/unistd.h>
#include <sys/socket.h>
#include <sys/syscall.h>
@@ -1347,43 +1347,134 @@
m_mem_region_cache.clear();
}
-Status NativeProcessLinux::AllocateMemory(size_t size, uint32_t permissions,
- lldb::addr_t &addr) {
-// FIXME implementing this requires the equivalent of
-// InferiorCallPOSIX::InferiorCallMmap, which depends on functional ThreadPlans
-// working with Native*Protocol.
-#if 1
- return Status("not implemented yet");
-#else
- addr = LLDB_INVALID_ADDRESS;
-
- unsigned prot = 0;
- if (permissions & lldb::ePermissionsReadable)
- prot |= eMmapProtRead;
- if (permissions & lldb::ePermissionsWritable)
- prot |= eMmapProtWrite;
- if (permissions & lldb::ePermissionsExecutable)
- prot |= eMmapProtExec;
-
- // TODO implement this directly in NativeProcessLinux
- // (and lift to NativeProcessPOSIX if/when that class is refactored out).
- if (InferiorCallMmap(this, addr, 0, size, prot,
- eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) {
- m_addr_to_mmap_size[addr] = size;
- return Status();
- } else {
- addr = LLDB_INVALID_ADDRESS;
- return Status("unable to allocate %" PRIu64
- " bytes of memory with permissions %s",
- size, GetPermissionsAsCString(permissions));
+llvm::Expected<uint64_t>
+NativeProcessLinux::Syscall(llvm::ArrayRef<uint64_t> args) {
+ PopulateMemoryRegionCache();
+ auto region_it = llvm::find_if(m_mem_region_cache, [](const auto &pair) {
+ return pair.first.GetExecutable() == MemoryRegionInfo::eYes;
+ });
+ if (region_it == m_mem_region_cache.end())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No executable memory region found!");
+
+ addr_t exe_addr = region_it->first.GetRange().GetRangeBase();
+
+ NativeThreadLinux &thread = *GetThreadByID(GetID());
+ assert(thread.GetState() == eStateStopped);
+ NativeRegisterContextLinux ®_ctx = thread.GetRegisterContext();
+
+ NativeRegisterContextLinux::SyscallData syscall_data =
+ *reg_ctx.GetSyscallData();
+
+ DataBufferSP registers_sp;
+ if (llvm::Error Err = reg_ctx.ReadAllRegisterValues(registers_sp).ToError())
+ return std::move(Err);
+ auto restore_regs = llvm::make_scope_exit(
+ [&] { reg_ctx.WriteAllRegisterValues(registers_sp); });
+
+ llvm::SmallVector<uint8_t, 8> memory(syscall_data.Insn.size());
+ size_t bytes_read;
+ if (llvm::Error Err =
+ ReadMemory(exe_addr, memory.data(), memory.size(), bytes_read)
+ .ToError()) {
+ return std::move(Err);
}
-#endif
+
+ auto restore_mem = llvm::make_scope_exit(
+ [&] { WriteMemory(exe_addr, memory.data(), memory.size(), bytes_read); });
+
+ if (llvm::Error Err = reg_ctx.SetPC(exe_addr).ToError())
+ return std::move(Err);
+
+ for (const auto &zip : llvm::zip_first(args, syscall_data.Args)) {
+ if (llvm::Error Err =
+ reg_ctx
+ .WriteRegisterFromUnsigned(std::get<1>(zip), std::get<0>(zip))
+ .ToError()) {
+ return std::move(Err);
+ }
+ }
+ if (llvm::Error Err = WriteMemory(exe_addr, syscall_data.Insn.data(),
+ syscall_data.Insn.size(), bytes_read)
+ .ToError())
+ return std::move(Err);
+
+ m_mem_region_cache.clear();
+
+ // With software single stepping the syscall insn buffer must also include a
+ // trap instruction to stop the process.
+ int req = SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP : PTRACE_CONT;
+ if (llvm::Error Err =
+ PtraceWrapper(req, thread.GetID(), nullptr, nullptr).ToError())
+ return std::move(Err);
+
+ int status;
+ ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, thread.GetID(),
+ &status, __WALL);
+ if (wait_pid == -1) {
+ return llvm::errorCodeToError(
+ std::error_code(errno, std::generic_category()));
+ }
+ assert((unsigned)wait_pid == thread.GetID());
+
+ uint64_t result = reg_ctx.ReadRegisterAsUnsigned(syscall_data.Result, -ESRCH);
+
+ // Values larger than this are actually negative errno numbers.
+ uint64_t errno_threshold =
+ (uint64_t(-1) >> (64 - 8 * m_arch.GetAddressByteSize())) - 0x1000;
+ if (result > errno_threshold) {
+ return llvm::errorCodeToError(
+ std::error_code(-result & 0xfff, std::generic_category()));
+ }
+
+ return result;
}
-Status NativeProcessLinux::DeallocateMemory(lldb::addr_t addr) {
- // FIXME see comments in AllocateMemory - required lower-level
- // bits not in place yet (ThreadPlans)
- return Status("not implemented");
+llvm::Expected<addr_t>
+NativeProcessLinux::AllocateMemory(size_t size, uint32_t permissions) {
+
+ llvm::Optional<NativeRegisterContextLinux::MmapData> mmap_data =
+ GetCurrentThread()->GetRegisterContext().GetMmapData();
+ if (!mmap_data)
+ return llvm::make_error<UnimplementedError>();
+
+ unsigned prot = PROT_NONE;
+ assert((permissions & (ePermissionsReadable | ePermissionsWritable |
+ ePermissionsExecutable)) == permissions &&
+ "Unknown permission!");
+ if (permissions & ePermissionsReadable)
+ prot |= PROT_READ;
+ if (permissions & ePermissionsWritable)
+ prot |= PROT_WRITE;
+ if (permissions & ePermissionsExecutable)
+ prot |= PROT_EXEC;
+
+ llvm::Expected<uint64_t> Result =
+ Syscall({mmap_data->SysMmap, 0, size, prot, MAP_ANONYMOUS | MAP_PRIVATE,
+ uint64_t(-1), 0});
+ if (Result)
+ m_allocated_memory.try_emplace(*Result, size);
+ return Result;
+}
+
+llvm::Error NativeProcessLinux::DeallocateMemory(lldb::addr_t addr) {
+ llvm::Optional<NativeRegisterContextLinux::MmapData> mmap_data =
+ GetCurrentThread()->GetRegisterContext().GetMmapData();
+ if (!mmap_data)
+ return llvm::make_error<UnimplementedError>();
+
+ auto it = m_allocated_memory.find(addr);
+ if (it == m_allocated_memory.end())
+ return llvm::createStringError(llvm::errc::invalid_argument,
+ "Memory not allocated by the debugger.");
+
+ llvm::Expected<uint64_t> Result =
+ Syscall({mmap_data->SysMunmap, addr, it->second});
+ if (!Result)
+ return Result.takeError();
+
+ m_allocated_memory.erase(it);
+ return llvm::Error::success();
}
size_t NativeProcessLinux::UpdateThreads() {
@@ -1652,6 +1743,11 @@
NativeProcessProtocol::GetThreadByID(tid));
}
+NativeThreadLinux *NativeProcessLinux::GetCurrentThread() {
+ return static_cast<NativeThreadLinux *>(
+ NativeProcessProtocol::GetCurrentThread());
+}
+
Status NativeProcessLinux::ResumeThread(NativeThreadLinux &thread,
lldb::StateType state, int signo) {
Log *const log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD);
Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h
===================================================================
--- lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h
+++ lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h
@@ -60,11 +60,6 @@
Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
size_t &bytes_written) override;
- Status AllocateMemory(size_t size, uint32_t permissions,
- lldb::addr_t &addr) override;
-
- Status DeallocateMemory(lldb::addr_t addr) override;
-
lldb::addr_t GetSharedLibraryInfoAddress() override;
size_t UpdateThreads() override;
Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp
===================================================================
--- lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp
+++ lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp
@@ -543,15 +543,6 @@
return Status();
}
-Status NativeProcessFreeBSD::AllocateMemory(size_t size, uint32_t permissions,
- lldb::addr_t &addr) {
- return Status("Unimplemented");
-}
-
-Status NativeProcessFreeBSD::DeallocateMemory(lldb::addr_t addr) {
- return Status("Unimplemented");
-}
-
lldb::addr_t NativeProcessFreeBSD::GetSharedLibraryInfoAddress() {
// punt on this for now
return LLDB_INVALID_ADDRESS;
Index: lldb/include/lldb/Host/common/NativeProcessProtocol.h
===================================================================
--- lldb/include/lldb/Host/common/NativeProcessProtocol.h
+++ lldb/include/lldb/Host/common/NativeProcessProtocol.h
@@ -17,6 +17,7 @@
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/TraceOptions.h"
+#include "lldb/Utility/UnimplementedError.h"
#include "lldb/lldb-private-forward.h"
#include "lldb/lldb-types.h"
#include "llvm/ADT/ArrayRef.h"
@@ -112,10 +113,14 @@
virtual Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
size_t &bytes_written) = 0;
- virtual Status AllocateMemory(size_t size, uint32_t permissions,
- lldb::addr_t &addr) = 0;
+ virtual llvm::Expected<lldb::addr_t> AllocateMemory(size_t size,
+ uint32_t permissions) {
+ return llvm::make_error<UnimplementedError>();
+ }
- virtual Status DeallocateMemory(lldb::addr_t addr) = 0;
+ virtual llvm::Error DeallocateMemory(lldb::addr_t addr) {
+ return llvm::make_error<UnimplementedError>();
+ }
virtual lldb::addr_t GetSharedLibraryInfoAddress() = 0;
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits