[Lldb-commits] [lldb] 8244fc5 - [lldb] [Process/FreeBSDRemote] Introduce mips64 support

Michał Górny via lldb-commits lldb-commits at lists.llvm.org
Mon Feb 8 09:27:41 PST 2021


Author: Michał Górny
Date: 2021-02-08T18:27:26+01:00
New Revision: 8244fc505def67f1094713202a2345f0c39d33dd

URL: https://github.com/llvm/llvm-project/commit/8244fc505def67f1094713202a2345f0c39d33dd
DIFF: https://github.com/llvm/llvm-project/commit/8244fc505def67f1094713202a2345f0c39d33dd.diff

LOG: [lldb] [Process/FreeBSDRemote] Introduce mips64 support

Introduce mips64 support to match the legacy FreeBSD plugin. Similarly
to the legacy plugin, the code does not support FPU registers at the
moment.  The support for them will be submitted separately as it
requires changes to the register context shared by both plugins.

This also includes software single-stepping support that is moved from
the Linux plugin into a common Utility class.  The FreeBSD code also
starts explicitly ignoring EINVAL from PT_CLEARSTEP since this is easier
to implement than checking whether hardware single-stepping were used.

Differential Revision: https://reviews.llvm.org/D95802

Added: 
    lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_mips64.cpp
    lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_mips64.h
    lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp
    lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h

Modified: 
    lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
    lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt
    lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp
    lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h
    lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp
    lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
    lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
    lldb/source/Plugins/Process/Utility/CMakeLists.txt
    lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
index 40fef595752b..7994e602703a 100644
--- a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
+++ b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
@@ -255,6 +255,7 @@ bool PlatformFreeBSD::CanDebugProcess() {
     switch (host_triple.getArch()) {
       case llvm::Triple::aarch64:
       case llvm::Triple::arm:
+      case llvm::Triple::mips64:
       case llvm::Triple::x86:
       case llvm::Triple::x86_64:
         use_legacy_plugin = !!getenv("FREEBSD_LEGACY_PLUGIN");

diff  --git a/lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt b/lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt
index 9d102bee24b6..826d7162967a 100644
--- a/lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt
@@ -3,6 +3,7 @@ add_lldb_library(lldbPluginProcessFreeBSDRemote
   NativeRegisterContextFreeBSD.cpp
   NativeRegisterContextFreeBSD_arm.cpp
   NativeRegisterContextFreeBSD_arm64.cpp
+  NativeRegisterContextFreeBSD_mips64.cpp
   NativeRegisterContextFreeBSD_x86_64.cpp
   NativeThreadFreeBSD.cpp
 

diff  --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp
index 139313bb5310..10fafe675221 100644
--- a/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp
+++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp
@@ -265,7 +265,17 @@ void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) {
     switch (info.pl_siginfo.si_code) {
     case TRAP_BRKPT:
       if (thread) {
-        thread->SetStoppedByBreakpoint();
+        auto thread_info =
+            m_threads_stepping_with_breakpoint.find(thread->GetID());
+        if (thread_info != m_threads_stepping_with_breakpoint.end()) {
+          thread->SetStoppedByTrace();
+          Status brkpt_error = RemoveBreakpoint(thread_info->second);
+          if (brkpt_error.Fail())
+            LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}",
+                     thread_info->first, brkpt_error);
+          m_threads_stepping_with_breakpoint.erase(thread_info);
+        } else
+          thread->SetStoppedByBreakpoint();
         FixupBreakpointPCAsNeeded(*thread);
       }
       SetState(StateType::eStateStopped, true);
@@ -899,3 +909,7 @@ Status NativeProcessFreeBSD::ReinitializeThreads() {
 
   return error;
 }
+
+bool NativeProcessFreeBSD::SupportHardwareSingleStepping() const {
+  return !m_arch.IsMIPS();
+}

diff  --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h
index 99123d598186..ceffc370ca33 100644
--- a/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h
+++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h
@@ -10,6 +10,8 @@
 #define liblldb_NativeProcessFreeBSD_H_
 
 #include "Plugins/Process/POSIX/NativeProcessELF.h"
+#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h"
+
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Utility/ArchSpec.h"
 #include "lldb/Utility/FileSpec.h"
@@ -25,7 +27,8 @@ namespace process_freebsd {
 /// for debugging.
 ///
 /// Changes in the inferior process state are broadcasted.
-class NativeProcessFreeBSD : public NativeProcessELF {
+class NativeProcessFreeBSD : public NativeProcessELF,
+                             private NativeProcessSoftwareSingleStep {
 public:
   class Factory : public NativeProcessProtocol::Factory {
   public:
@@ -84,6 +87,8 @@ class NativeProcessFreeBSD : public NativeProcessELF {
   static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
                               int data = 0, int *result = nullptr);
 
+  bool SupportHardwareSingleStepping() const;
+
 protected:
   llvm::Expected<llvm::ArrayRef<uint8_t>>
   GetSoftwareBreakpointTrapOpcode(size_t size_hint) override;

diff  --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_mips64.cpp b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_mips64.cpp
new file mode 100644
index 000000000000..b6d9d64256cf
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_mips64.cpp
@@ -0,0 +1,186 @@
+//===-- NativeRegisterContextFreeBSD_mips64.cpp ---------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__mips64__)
+
+#include "NativeRegisterContextFreeBSD_mips64.h"
+
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Status.h"
+
+#include "Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h"
+
+// clang-format off
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+// clang-format on
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+
+NativeRegisterContextFreeBSD *
+NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
+    const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
+  return new NativeRegisterContextFreeBSD_mips64(target_arch, native_thread);
+}
+
+NativeRegisterContextFreeBSD_mips64::NativeRegisterContextFreeBSD_mips64(
+    const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
+    : NativeRegisterContextRegisterInfo(
+          native_thread, new RegisterContextFreeBSD_mips64(target_arch)) {}
+
+RegisterContextFreeBSD_mips64 &
+NativeRegisterContextFreeBSD_mips64::GetRegisterInfo() const {
+  return static_cast<RegisterContextFreeBSD_mips64 &>(
+      *m_register_info_interface_up);
+}
+
+uint32_t NativeRegisterContextFreeBSD_mips64::GetRegisterSetCount() const {
+  return GetRegisterInfo().GetRegisterSetCount();
+}
+
+const RegisterSet *
+NativeRegisterContextFreeBSD_mips64::GetRegisterSet(uint32_t set_index) const {
+  return GetRegisterInfo().GetRegisterSet(set_index);
+}
+
+uint32_t NativeRegisterContextFreeBSD_mips64::GetUserRegisterCount() const {
+  uint32_t count = 0;
+  for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
+    count += GetRegisterSet(set_index)->num_registers;
+  return count;
+}
+
+Status NativeRegisterContextFreeBSD_mips64::ReadRegisterSet(RegSetKind set) {
+  switch (set) {
+  case GPRegSet:
+    return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
+                                               m_reg_data.data());
+  }
+  llvm_unreachable("NativeRegisterContextFreeBSD_mips64::ReadRegisterSet");
+}
+
+Status NativeRegisterContextFreeBSD_mips64::WriteRegisterSet(RegSetKind set) {
+  switch (set) {
+  case GPRegSet:
+    return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
+                                               m_reg_data.data());
+  }
+  llvm_unreachable("NativeRegisterContextFreeBSD_mips64::WriteRegisterSet");
+}
+
+Status
+NativeRegisterContextFreeBSD_mips64::ReadRegister(const RegisterInfo *reg_info,
+                                                  RegisterValue &reg_value) {
+  Status error;
+
+  if (!reg_info) {
+    error.SetErrorString("reg_info NULL");
+    return error;
+  }
+
+  const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+  if (reg == LLDB_INVALID_REGNUM)
+    return Status("no lldb regnum for %s", reg_info && reg_info->name
+                                               ? reg_info->name
+                                               : "<unknown register>");
+
+  RegSetKind set = GPRegSet;
+  error = ReadRegisterSet(set);
+  if (error.Fail())
+    return error;
+
+  assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
+  reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset,
+                     reg_info->byte_size, endian::InlHostByteOrder());
+  return error;
+}
+
+Status NativeRegisterContextFreeBSD_mips64::WriteRegister(
+    const RegisterInfo *reg_info, const RegisterValue &reg_value) {
+  Status error;
+
+  if (!reg_info)
+    return Status("reg_info NULL");
+
+  const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+  if (reg == LLDB_INVALID_REGNUM)
+    return Status("no lldb regnum for %s", reg_info && reg_info->name
+                                               ? reg_info->name
+                                               : "<unknown register>");
+
+  RegSetKind set = GPRegSet;
+  error = ReadRegisterSet(set);
+  if (error.Fail())
+    return error;
+
+  assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
+  ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(),
+           reg_info->byte_size);
+
+  return WriteRegisterSet(set);
+}
+
+Status NativeRegisterContextFreeBSD_mips64::ReadAllRegisterValues(
+    lldb::DataBufferSP &data_sp) {
+  Status error;
+
+  error = ReadRegisterSet(GPRegSet);
+  if (error.Fail())
+    return error;
+
+  data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0));
+  uint8_t *dst = data_sp->GetBytes();
+  ::memcpy(dst, m_reg_data.data(), m_reg_data.size());
+
+  return error;
+}
+
+Status NativeRegisterContextFreeBSD_mips64::WriteAllRegisterValues(
+    const lldb::DataBufferSP &data_sp) {
+  Status error;
+
+  if (!data_sp) {
+    error.SetErrorStringWithFormat(
+        "NativeRegisterContextFreeBSD_mips64::%s invalid data_sp provided",
+        __FUNCTION__);
+    return error;
+  }
+
+  if (data_sp->GetByteSize() != m_reg_data.size()) {
+    error.SetErrorStringWithFormat(
+        "NativeRegisterContextFreeBSD_mips64::%s data_sp contained mismatched "
+        "data size, expected %" PRIu64 ", actual %" PRIu64,
+        __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize());
+    return error;
+  }
+
+  uint8_t *src = data_sp->GetBytes();
+  if (src == nullptr) {
+    error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_mips64::%s "
+                                   "DataBuffer::GetBytes() returned a null "
+                                   "pointer",
+                                   __FUNCTION__);
+    return error;
+  }
+  ::memcpy(m_reg_data.data(), src, m_reg_data.size());
+
+  return WriteRegisterSet(GPRegSet);
+}
+
+llvm::Error NativeRegisterContextFreeBSD_mips64::CopyHardwareWatchpointsFrom(
+    NativeRegisterContextFreeBSD &source) {
+  return llvm::Error::success();
+}
+
+#endif // defined (__mips64__)

diff  --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_mips64.h b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_mips64.h
new file mode 100644
index 000000000000..b6e1848bf346
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_mips64.h
@@ -0,0 +1,71 @@
+//===-- NativeRegisterContextFreeBSD_mips64.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
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__mips64__)
+
+#ifndef lldb_NativeRegisterContextFreeBSD_mips64_h
+#define lldb_NativeRegisterContextFreeBSD_mips64_h
+
+// clang-format off
+#include <sys/types.h>
+#include <machine/reg.h>
+// clang-format on
+
+#include "Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
+
+#include <array>
+
+namespace lldb_private {
+namespace process_freebsd {
+
+class NativeProcessFreeBSD;
+
+class NativeRegisterContextFreeBSD_mips64
+    : public NativeRegisterContextFreeBSD {
+public:
+  NativeRegisterContextFreeBSD_mips64(const ArchSpec &target_arch,
+                                      NativeThreadProtocol &native_thread);
+
+  uint32_t GetRegisterSetCount() const override;
+
+  uint32_t GetUserRegisterCount() const override;
+
+  const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
+
+  Status ReadRegister(const RegisterInfo *reg_info,
+                      RegisterValue &reg_value) override;
+
+  Status WriteRegister(const RegisterInfo *reg_info,
+                       const RegisterValue &reg_value) override;
+
+  Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
+
+  Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+  llvm::Error
+  CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override;
+
+private:
+  enum RegSetKind {
+    GPRegSet,
+  };
+  std::array<uint8_t, sizeof(reg)> m_reg_data;
+
+  Status ReadRegisterSet(RegSetKind set);
+  Status WriteRegisterSet(RegSetKind set);
+
+  RegisterContextFreeBSD_mips64 &GetRegisterInfo() const;
+};
+
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextFreeBSD_mips64_h
+
+#endif // defined (__mips64__)

diff  --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp
index 43494871be07..63be12fc7b2b 100644
--- a/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp
+++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp
@@ -46,6 +46,11 @@ Status NativeThreadFreeBSD::Resume() {
   if (!ret.Success())
     return ret;
   ret = NativeProcessFreeBSD::PtraceWrapper(PT_CLEARSTEP, GetID());
+  // we can get EINVAL if the architecture in question does not support
+  // hardware single-stepping -- that's fine, we have nothing to clear
+  // then
+  if (ret.GetError() == EINVAL)
+    ret.Clear();
   if (ret.Success())
     SetRunning();
   return ret;

diff  --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index e07d763c2de7..aed0d32f2364 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -23,7 +23,6 @@
 #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"
 #include "lldb/Host/HostProcess.h"
@@ -38,7 +37,6 @@
 #include "lldb/Target/Process.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Utility/LLDBAssert.h"
-#include "lldb/Utility/RegisterValue.h"
 #include "lldb/Utility/State.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/StringExtractor.h"
@@ -860,169 +858,6 @@ void NativeProcessLinux::MonitorSignal(const siginfo_t &info,
   StopRunningThreads(thread.GetID());
 }
 
-namespace {
-
-struct EmulatorBaton {
-  NativeProcessLinux &m_process;
-  NativeRegisterContext &m_reg_context;
-
-  // eRegisterKindDWARF -> RegsiterValue
-  std::unordered_map<uint32_t, RegisterValue> m_register_values;
-
-  EmulatorBaton(NativeProcessLinux &process, NativeRegisterContext &reg_context)
-      : m_process(process), m_reg_context(reg_context) {}
-};
-
-} // anonymous namespace
-
-static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton,
-                                 const EmulateInstruction::Context &context,
-                                 lldb::addr_t addr, void *dst, size_t length) {
-  EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
-
-  size_t bytes_read;
-  emulator_baton->m_process.ReadMemory(addr, dst, length, bytes_read);
-  return bytes_read;
-}
-
-static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton,
-                                 const RegisterInfo *reg_info,
-                                 RegisterValue &reg_value) {
-  EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
-
-  auto it = emulator_baton->m_register_values.find(
-      reg_info->kinds[eRegisterKindDWARF]);
-  if (it != emulator_baton->m_register_values.end()) {
-    reg_value = it->second;
-    return true;
-  }
-
-  // The emulator only fill in the dwarf regsiter numbers (and in some case the
-  // generic register numbers). Get the full register info from the register
-  // context based on the dwarf register numbers.
-  const RegisterInfo *full_reg_info =
-      emulator_baton->m_reg_context.GetRegisterInfo(
-          eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]);
-
-  Status error =
-      emulator_baton->m_reg_context.ReadRegister(full_reg_info, reg_value);
-  if (error.Success())
-    return true;
-
-  return false;
-}
-
-static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton,
-                                  const EmulateInstruction::Context &context,
-                                  const RegisterInfo *reg_info,
-                                  const RegisterValue &reg_value) {
-  EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
-  emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] =
-      reg_value;
-  return true;
-}
-
-static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton,
-                                  const EmulateInstruction::Context &context,
-                                  lldb::addr_t addr, const void *dst,
-                                  size_t length) {
-  return length;
-}
-
-static lldb::addr_t ReadFlags(NativeRegisterContext &regsiter_context) {
-  const RegisterInfo *flags_info = regsiter_context.GetRegisterInfo(
-      eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
-  return regsiter_context.ReadRegisterAsUnsigned(flags_info,
-                                                 LLDB_INVALID_ADDRESS);
-}
-
-Status
-NativeProcessLinux::SetupSoftwareSingleStepping(NativeThreadLinux &thread) {
-  Status error;
-  NativeRegisterContext& register_context = thread.GetRegisterContext();
-
-  std::unique_ptr<EmulateInstruction> emulator_up(
-      EmulateInstruction::FindPlugin(m_arch, eInstructionTypePCModifying,
-                                     nullptr));
-
-  if (emulator_up == nullptr)
-    return Status("Instruction emulator not found!");
-
-  EmulatorBaton baton(*this, register_context);
-  emulator_up->SetBaton(&baton);
-  emulator_up->SetReadMemCallback(&ReadMemoryCallback);
-  emulator_up->SetReadRegCallback(&ReadRegisterCallback);
-  emulator_up->SetWriteMemCallback(&WriteMemoryCallback);
-  emulator_up->SetWriteRegCallback(&WriteRegisterCallback);
-
-  if (!emulator_up->ReadInstruction())
-    return Status("Read instruction failed!");
-
-  bool emulation_result =
-      emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC);
-
-  const RegisterInfo *reg_info_pc = register_context.GetRegisterInfo(
-      eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
-  const RegisterInfo *reg_info_flags = register_context.GetRegisterInfo(
-      eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
-
-  auto pc_it =
-      baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]);
-  auto flags_it =
-      baton.m_register_values.find(reg_info_flags->kinds[eRegisterKindDWARF]);
-
-  lldb::addr_t next_pc;
-  lldb::addr_t next_flags;
-  if (emulation_result) {
-    assert(pc_it != baton.m_register_values.end() &&
-           "Emulation was successfull but PC wasn't updated");
-    next_pc = pc_it->second.GetAsUInt64();
-
-    if (flags_it != baton.m_register_values.end())
-      next_flags = flags_it->second.GetAsUInt64();
-    else
-      next_flags = ReadFlags(register_context);
-  } else if (pc_it == baton.m_register_values.end()) {
-    // Emulate instruction failed and it haven't changed PC. Advance PC with
-    // the size of the current opcode because the emulation of all
-    // PC modifying instruction should be successful. The failure most
-    // likely caused by a not supported instruction which don't modify PC.
-    next_pc = register_context.GetPC() + emulator_up->GetOpcode().GetByteSize();
-    next_flags = ReadFlags(register_context);
-  } else {
-    // The instruction emulation failed after it modified the PC. It is an
-    // unknown error where we can't continue because the next instruction is
-    // modifying the PC but we don't  know how.
-    return Status("Instruction emulation failed unexpectedly.");
-  }
-
-  if (m_arch.GetMachine() == llvm::Triple::arm) {
-    if (next_flags & 0x20) {
-      // Thumb mode
-      error = SetSoftwareBreakpoint(next_pc, 2);
-    } else {
-      // Arm mode
-      error = SetSoftwareBreakpoint(next_pc, 4);
-    }
-  } else if (m_arch.IsMIPS() || m_arch.GetTriple().isPPC64())
-    error = SetSoftwareBreakpoint(next_pc, 4);
-  else {
-    // No size hint is given for the next breakpoint
-    error = SetSoftwareBreakpoint(next_pc, 0);
-  }
-
-  // If setting the breakpoint fails because next_pc is out of the address
-  // space, ignore it and let the debugee segfault.
-  if (error.GetError() == EIO || error.GetError() == EFAULT) {
-    return Status();
-  } else if (error.Fail())
-    return error;
-
-  m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc});
-
-  return Status();
-}
-
 bool NativeProcessLinux::SupportHardwareSingleStepping() const {
   if (m_arch.GetMachine() == llvm::Triple::arm || m_arch.IsMIPS())
     return false;

diff  --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
index b7d70a604144..077c62d36234 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
@@ -22,6 +22,7 @@
 
 #include "NativeThreadLinux.h"
 #include "Plugins/Process/POSIX/NativeProcessELF.h"
+#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h"
 #include "ProcessorTrace.h"
 
 namespace lldb_private {
@@ -36,7 +37,8 @@ namespace process_linux {
 /// for debugging.
 ///
 /// Changes in the inferior process state are broadcasted.
-class NativeProcessLinux : public NativeProcessELF {
+class NativeProcessLinux : public NativeProcessELF,
+                           private NativeProcessSoftwareSingleStep {
 public:
   class Factory : public NativeProcessProtocol::Factory {
   public:
@@ -141,10 +143,6 @@ class NativeProcessLinux : public NativeProcessELF {
 
   lldb::tid_t m_pending_notification_tid = LLDB_INVALID_THREAD_ID;
 
-  // List of thread ids stepping with a breakpoint with the address of
-  // 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;
 
@@ -173,8 +171,6 @@ class NativeProcessLinux : public NativeProcessELF {
   void MonitorSignal(const siginfo_t &info, NativeThreadLinux &thread,
                      bool exited);
 
-  Status SetupSoftwareSingleStepping(NativeThreadLinux &thread);
-
   bool HasThreadNoLock(lldb::tid_t thread_id);
 
   bool StopTrackingThread(lldb::tid_t thread_id);

diff  --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
index 9965d89f4c4b..af0f576eb984 100644
--- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
@@ -9,6 +9,7 @@ add_lldb_library(lldbPluginProcessUtility
   LinuxProcMaps.cpp
   LinuxSignals.cpp
   MipsLinuxSignals.cpp
+  NativeProcessSoftwareSingleStep.cpp
   NativeRegisterContextRegisterInfo.cpp
   NativeRegisterContextWatchpoint_x86.cpp
   NetBSDSignals.cpp

diff  --git a/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp b/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp
new file mode 100644
index 000000000000..ee5295bf6565
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp
@@ -0,0 +1,182 @@
+//===-- NativeProcessSoftwareSingleStep.cpp -------------------------------===//
+//
+// 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 "NativeProcessSoftwareSingleStep.h"
+
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Host/common/NativeRegisterContext.h"
+#include "lldb/Utility/RegisterValue.h"
+
+#include <unordered_map>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+struct EmulatorBaton {
+  NativeProcessProtocol &m_process;
+  NativeRegisterContext &m_reg_context;
+
+  // eRegisterKindDWARF -> RegsiterValue
+  std::unordered_map<uint32_t, RegisterValue> m_register_values;
+
+  EmulatorBaton(NativeProcessProtocol &process,
+                NativeRegisterContext &reg_context)
+      : m_process(process), m_reg_context(reg_context) {}
+};
+
+} // anonymous namespace
+
+static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton,
+                                 const EmulateInstruction::Context &context,
+                                 lldb::addr_t addr, void *dst, size_t length) {
+  EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
+
+  size_t bytes_read;
+  emulator_baton->m_process.ReadMemory(addr, dst, length, bytes_read);
+  return bytes_read;
+}
+
+static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton,
+                                 const RegisterInfo *reg_info,
+                                 RegisterValue &reg_value) {
+  EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
+
+  auto it = emulator_baton->m_register_values.find(
+      reg_info->kinds[eRegisterKindDWARF]);
+  if (it != emulator_baton->m_register_values.end()) {
+    reg_value = it->second;
+    return true;
+  }
+
+  // The emulator only fill in the dwarf regsiter numbers (and in some case the
+  // generic register numbers). Get the full register info from the register
+  // context based on the dwarf register numbers.
+  const RegisterInfo *full_reg_info =
+      emulator_baton->m_reg_context.GetRegisterInfo(
+          eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]);
+
+  Status error =
+      emulator_baton->m_reg_context.ReadRegister(full_reg_info, reg_value);
+  if (error.Success())
+    return true;
+
+  return false;
+}
+
+static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton,
+                                  const EmulateInstruction::Context &context,
+                                  const RegisterInfo *reg_info,
+                                  const RegisterValue &reg_value) {
+  EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
+  emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] =
+      reg_value;
+  return true;
+}
+
+static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton,
+                                  const EmulateInstruction::Context &context,
+                                  lldb::addr_t addr, const void *dst,
+                                  size_t length) {
+  return length;
+}
+
+static lldb::addr_t ReadFlags(NativeRegisterContext &regsiter_context) {
+  const RegisterInfo *flags_info = regsiter_context.GetRegisterInfo(
+      eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+  return regsiter_context.ReadRegisterAsUnsigned(flags_info,
+                                                 LLDB_INVALID_ADDRESS);
+}
+
+Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping(
+    NativeThreadProtocol &thread) {
+  Status error;
+  NativeProcessProtocol &process = thread.GetProcess();
+  NativeRegisterContext &register_context = thread.GetRegisterContext();
+  const ArchSpec &arch = process.GetArchitecture();
+
+  std::unique_ptr<EmulateInstruction> emulator_up(
+      EmulateInstruction::FindPlugin(arch, eInstructionTypePCModifying,
+                                     nullptr));
+
+  if (emulator_up == nullptr)
+    return Status("Instruction emulator not found!");
+
+  EmulatorBaton baton(process, register_context);
+  emulator_up->SetBaton(&baton);
+  emulator_up->SetReadMemCallback(&ReadMemoryCallback);
+  emulator_up->SetReadRegCallback(&ReadRegisterCallback);
+  emulator_up->SetWriteMemCallback(&WriteMemoryCallback);
+  emulator_up->SetWriteRegCallback(&WriteRegisterCallback);
+
+  if (!emulator_up->ReadInstruction())
+    return Status("Read instruction failed!");
+
+  bool emulation_result =
+      emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC);
+
+  const RegisterInfo *reg_info_pc = register_context.GetRegisterInfo(
+      eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+  const RegisterInfo *reg_info_flags = register_context.GetRegisterInfo(
+      eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+
+  auto pc_it =
+      baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]);
+  auto flags_it =
+      baton.m_register_values.find(reg_info_flags->kinds[eRegisterKindDWARF]);
+
+  lldb::addr_t next_pc;
+  lldb::addr_t next_flags;
+  if (emulation_result) {
+    assert(pc_it != baton.m_register_values.end() &&
+           "Emulation was successfull but PC wasn't updated");
+    next_pc = pc_it->second.GetAsUInt64();
+
+    if (flags_it != baton.m_register_values.end())
+      next_flags = flags_it->second.GetAsUInt64();
+    else
+      next_flags = ReadFlags(register_context);
+  } else if (pc_it == baton.m_register_values.end()) {
+    // Emulate instruction failed and it haven't changed PC. Advance PC with
+    // the size of the current opcode because the emulation of all
+    // PC modifying instruction should be successful. The failure most
+    // likely caused by a not supported instruction which don't modify PC.
+    next_pc = register_context.GetPC() + emulator_up->GetOpcode().GetByteSize();
+    next_flags = ReadFlags(register_context);
+  } else {
+    // The instruction emulation failed after it modified the PC. It is an
+    // unknown error where we can't continue because the next instruction is
+    // modifying the PC but we don't  know how.
+    return Status("Instruction emulation failed unexpectedly.");
+  }
+
+  int size_hint = 0;
+  if (arch.GetMachine() == llvm::Triple::arm) {
+    if (next_flags & 0x20) {
+      // Thumb mode
+      size_hint = 2;
+    } else {
+      // Arm mode
+      size_hint = 4;
+    }
+  } else if (arch.IsMIPS() || arch.GetTriple().isPPC64())
+    size_hint = 4;
+  error = process.SetBreakpoint(next_pc, size_hint, /*hardware=*/false);
+
+  // If setting the breakpoint fails because next_pc is out of the address
+  // space, ignore it and let the debugee segfault.
+  if (error.GetError() == EIO || error.GetError() == EFAULT) {
+    return Status();
+  } else if (error.Fail())
+    return error;
+
+  m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc});
+
+  return Status();
+}

diff  --git a/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h b/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h
new file mode 100644
index 000000000000..f9435b7a84ba
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h
@@ -0,0 +1,31 @@
+//===-- NativeProcessSoftwareSingleStep.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_NativeProcessSoftwareSingleStep_h
+#define lldb_NativeProcessSoftwareSingleStep_h
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include <map>
+
+namespace lldb_private {
+
+class NativeProcessSoftwareSingleStep {
+public:
+  Status SetupSoftwareSingleStepping(NativeThreadProtocol &thread);
+
+protected:
+  // List of thread ids stepping with a breakpoint with the address of
+  // the relevan breakpoint
+  std::map<lldb::tid_t, lldb::addr_t> m_threads_stepping_with_breakpoint;
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeProcessSoftwareSingleStep_h

diff  --git a/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp b/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp
index 145b8b25059f..ed0b2275c4ba 100644
--- a/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp
+++ b/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp
@@ -17,13 +17,15 @@
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
-#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
 #include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
 #include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
 #include "Plugins/Process/Utility/lldb-arm-register-enums.h"
 #include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
+#include "Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -398,3 +400,61 @@ TEST(RegisterContextFreeBSDTest, arm64) {
 }
 
 #endif // defined(__aarch64__)
+
+#if defined(__mips64__)
+
+#define EXPECT_GPR_MIPS64(lldb_reg, fbsd_regno)                                \
+  EXPECT_THAT(GetRegParams(reg_ctx, gpr_##lldb_reg##_mips64),                  \
+              ::testing::Pair(offsetof(reg, r_regs[fbsd_regno]),               \
+                              sizeof(reg::r_regs[fbsd_regno])))
+
+TEST(RegisterContextFreeBSDTest, mips64) {
+  ArchSpec arch{"mips64-unknown-freebsd"};
+  RegisterContextFreeBSD_mips64 reg_ctx{arch};
+
+  // we can not use aliases from <machine/regnum.h> because macros defined
+  // there are not namespaced and collide a lot, e.g. 'A1'
+
+  EXPECT_GPR_MIPS64(zero, 0);
+  EXPECT_GPR_MIPS64(r1, 1);
+  EXPECT_GPR_MIPS64(r2, 2);
+  EXPECT_GPR_MIPS64(r3, 3);
+  EXPECT_GPR_MIPS64(r4, 4);
+  EXPECT_GPR_MIPS64(r5, 5);
+  EXPECT_GPR_MIPS64(r6, 6);
+  EXPECT_GPR_MIPS64(r7, 7);
+  EXPECT_GPR_MIPS64(r8, 8);
+  EXPECT_GPR_MIPS64(r9, 9);
+  EXPECT_GPR_MIPS64(r10, 10);
+  EXPECT_GPR_MIPS64(r11, 11);
+  EXPECT_GPR_MIPS64(r12, 12);
+  EXPECT_GPR_MIPS64(r13, 13);
+  EXPECT_GPR_MIPS64(r14, 14);
+  EXPECT_GPR_MIPS64(r15, 15);
+  EXPECT_GPR_MIPS64(r16, 16);
+  EXPECT_GPR_MIPS64(r17, 17);
+  EXPECT_GPR_MIPS64(r18, 18);
+  EXPECT_GPR_MIPS64(r19, 19);
+  EXPECT_GPR_MIPS64(r20, 20);
+  EXPECT_GPR_MIPS64(r21, 21);
+  EXPECT_GPR_MIPS64(r22, 22);
+  EXPECT_GPR_MIPS64(r23, 23);
+  EXPECT_GPR_MIPS64(r24, 24);
+  EXPECT_GPR_MIPS64(r25, 25);
+  EXPECT_GPR_MIPS64(r26, 26);
+  EXPECT_GPR_MIPS64(r27, 27);
+  EXPECT_GPR_MIPS64(gp, 28);
+  EXPECT_GPR_MIPS64(sp, 29);
+  EXPECT_GPR_MIPS64(r30, 30);
+  EXPECT_GPR_MIPS64(ra, 31);
+  EXPECT_GPR_MIPS64(sr, 32);
+  EXPECT_GPR_MIPS64(mullo, 33);
+  EXPECT_GPR_MIPS64(mulhi, 34);
+  EXPECT_GPR_MIPS64(badvaddr, 35);
+  EXPECT_GPR_MIPS64(cause, 36);
+  EXPECT_GPR_MIPS64(pc, 37);
+  EXPECT_GPR_MIPS64(ic, 38);
+  EXPECT_GPR_MIPS64(dummy, 39);
+}
+
+#endif // defined(__mips64__)


        


More information about the lldb-commits mailing list