labath updated this revision to Diff 297523.
labath added a comment.

address review comments


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/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/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 uint8_t Int80[] = {0xcd, 0x80};
+    static 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 uint8_t Syscall[] = {0x0f, 0x05};
+    static 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;
 
@@ -127,6 +127,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 +142,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 &reg_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
-}
 
-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");
+  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;
+}
+
+llvm::Expected<addr_t>
+NativeProcessLinux::AllocateMemory(size_t size, uint32_t permissions) {
+
+  llvm::Optional<NativeRegisterContextLinux::MmapData> mmap_data =
+      GetThreadByID(GetID())->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 =
+      GetThreadByID(GetID())->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() {
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
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to