lh03061238 created this revision.
lh03061238 added reviewers: SixWeining, wangleiat, xen0n, xry111, MaskRay, 
DavidSpickett.
Herald added subscribers: StephenFan, s.egerton, simoncook.
Herald added a project: All.
lh03061238 requested review of this revision.
Herald added subscribers: lldb-commits, pcwang-thead.
Herald added a project: LLDB.

Hardware single stepping is not currently supported by the linux kernel. 
In order to support single step debugging, add EmulateInstructionLoongArch 
to implement the software Single Stepping. This patch only support the 
simplest single step execution of non-jump instructions.

Here is a simple test:

  loongson@linux:~$ cat test.c
  #include<stdio.h>
  
  int main()
  {
        int i = 1;
  
        i = i + 2;
  
        return 0;
  }
  loongson@linux:~$ clang -g test.c  -o test

Without this patch:

  loongson@linux:~$ llvm-project/llvm/build/bin/lldb test
  (lldb) target create "test"
  Current executable set to '/home/loongson/test' (loongarch64).
  (lldb) b main
  Breakpoint 1: where = test`main + 24 at test.c:5:6, address = 
0x0000000120000628
  (lldb) r
  Process 43090 launched: '/home/loongson/test' (loongarch64)
  Process 43090 exited with status = -1 (0xffffffff) lost connection
  (lldb)

With this patch:

  loongson@linux:~$ llvm-project/llvm/build/bin/lldb test
  (lldb) target create "test"
  Current executable set to '/home/loongson/test' (loongarch64).
  (lldb) b main
  Breakpoint 1: where = test`main + 24 at test.c:5:6, address = 
0x0000000120000628
  (lldb) r
  Process 42467 launched: '/home/loongson/test' (loongarch64)
  Process 42467 stopped
  * thread #1, name = 'test', stop reason = breakpoint 1.1
      frame #0: 0x0000000120000628 test`main at test.c:5:6
     2          
     3          int main()
     4          {
  -> 5                  int i = 1;
     6          
     7                  i = i + 2;
     8          
  (lldb) n
  Process 42467 stopped
  * thread #1, name = 'test', stop reason = step over
      frame #0: 0x000000012000062c test`main at test.c:7:6
     4          {
     5                  int i = 1;
     6          
  -> 7                  i = i + 2;
     8          
     9                  return 0;
     10         }
  (lldb) var i
  (int) i = 1
  (lldb) n
  Process 42467 stopped
  * thread #1, name = 'test', stop reason = step over
      frame #0: 0x000000012000063c test`main at test.c:9:2
     6          
     7                  i = i + 2;
     8          
  -> 9                  return 0;
     10         }
  (lldb) var i
  (int) i = 3
  (lldb) n
  Process 42467 exited with status = 0 (0x00000000) 
  (lldb) q
  loongson@linux:~$


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D139158

Files:
  lldb/source/Plugins/Instruction/CMakeLists.txt
  lldb/source/Plugins/Instruction/LoongArch/CMakeLists.txt
  lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.cpp
  lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h
  lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
  lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp
  lldb/tools/lldb-server/CMakeLists.txt
  lldb/tools/lldb-server/SystemInitializerLLGS.cpp

Index: lldb/tools/lldb-server/SystemInitializerLLGS.cpp
===================================================================
--- lldb/tools/lldb-server/SystemInitializerLLGS.cpp
+++ lldb/tools/lldb-server/SystemInitializerLLGS.cpp
@@ -46,6 +46,11 @@
 #include "Plugins/Instruction/RISCV/EmulateInstructionRISCV.h"
 #endif
 
+#if defined(__loongarch) || defined(__loongarch64)
+#define LLDB_TARGET_LoongArch
+#include "Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h"
+#endif
+
 using namespace lldb_private;
 
 llvm::Error SystemInitializerLLGS::Initialize() {
@@ -66,6 +71,9 @@
 #if defined(LLDB_TARGET_RISCV)
   EmulateInstructionRISCV::Initialize();
 #endif
+#if defined(LLDB_TARGET_LoongArch)
+  EmulateInstructionLoongArch::Initialize();
+#endif
 
   return llvm::Error::success();
 }
@@ -85,6 +93,9 @@
 #if defined(LLDB_TARGET_RISCV)
   EmulateInstructionRISCV::Terminate();
 #endif
+#if defined(LLDB_TARGET_LoongArch)
+  EmulateInstructionLoongArch::Terminate();
+#endif
 
   SystemInitializerCommon::Terminate();
 }
Index: lldb/tools/lldb-server/CMakeLists.txt
===================================================================
--- lldb/tools/lldb-server/CMakeLists.txt
+++ lldb/tools/lldb-server/CMakeLists.txt
@@ -54,6 +54,7 @@
       lldbPluginInstructionMIPS
       lldbPluginInstructionMIPS64
       lldbPluginInstructionRISCV
+      lldbPluginInstructionLoongArch
       ${LLDB_SYSTEM_LIBS}
 
     LINK_COMPONENTS
Index: lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp
===================================================================
--- lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp
+++ lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp
@@ -168,7 +168,7 @@
       size_hint = 4;
     }
   } else if (arch.IsMIPS() || arch.GetTriple().isPPC64() ||
-             arch.GetTriple().isRISCV())
+             arch.GetTriple().isRISCV() || arch.GetTriple().isLoongArch())
     size_hint = 4;
   error = process.SetBreakpoint(next_pc, size_hint, /*hardware=*/false);
 
Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -883,7 +883,7 @@
 
 bool NativeProcessLinux::SupportHardwareSingleStepping() const {
   if (m_arch.IsMIPS() || m_arch.GetMachine() == llvm::Triple::arm ||
-      m_arch.GetTriple().isRISCV())
+      m_arch.GetTriple().isRISCV() || m_arch.GetTriple().isLoongArch())
     return false;
   return true;
 }
Index: lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h
@@ -0,0 +1,84 @@
+//===---EmulateInstructionLoongArch.h--------------------------------------===//
+//
+// 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_SOURCE_PLUGINS_INSTRUCTION_LoongArch_EMULATEINSTRUCTIONLoongArch_H
+#define LLDB_SOURCE_PLUGINS_INSTRUCTION_LoongArch_EMULATEINSTRUCTIONLoongArch_H
+
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Interpreter/OptionValue.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+
+namespace lldb_private {
+
+class EmulateInstructionLoongArch : public EmulateInstruction {
+public:
+  static llvm::StringRef GetPluginNameStatic() { return "loongarch"; }
+
+  static llvm::StringRef GetPluginDescriptionStatic() {
+    return "Emulate instructions for the loongarch architecture.";
+  }
+
+  static bool SupportsThisInstructionType(InstructionType inst_type) {
+    switch (inst_type) {
+    case eInstructionTypePCModifying:
+      return true;
+    case eInstructionTypeAny:
+    case eInstructionTypePrologueEpilogue:
+    case eInstructionTypeAll:
+      return false;
+    }
+    return false;
+  }
+
+  static bool SupportsThisArch(const ArchSpec &arch);
+
+  static lldb_private::EmulateInstruction *
+  CreateInstance(const lldb_private::ArchSpec &arch, InstructionType inst_type);
+
+  static void Initialize();
+
+  static void Terminate();
+
+public:
+  EmulateInstructionLoongArch(const ArchSpec &arch)
+      : EmulateInstruction(arch) {}
+
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+  bool SupportsEmulatingInstructionsOfType(InstructionType inst_type) override {
+    return SupportsThisInstructionType(inst_type);
+  }
+
+  bool SetTargetTriple(const ArchSpec &arch) override;
+  bool ReadInstruction() override;
+  bool EvaluateInstruction(uint32_t options) override;
+  bool TestEmulation(Stream *out_stream, ArchSpec &arch,
+                     OptionValueDictionary *test_data) override;
+
+  llvm::Optional<RegisterInfo> GetRegisterInfo(lldb::RegisterKind reg_kind,
+                                               uint32_t reg_num) override;
+  lldb::addr_t ReadPC(bool *success);
+  bool WritePC(lldb::addr_t pc);
+
+private:
+  struct Opcode {
+    uint32_t mask;
+    uint32_t value;
+    bool (EmulateInstructionLoongArch::*callback)(uint32_t opcode);
+    const char *name;
+  };
+
+  Opcode *GetOpcodeForInstruction(uint32_t inst);
+
+  bool EmulateNonJMP(uint32_t inst);
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_INSTRUCTION_LoongArch_EMULATEINSTRUCTIONRISCV_H
Index: lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.cpp
@@ -0,0 +1,187 @@
+//===---EmulateInstructionLoongArch.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 <cstdlib>
+
+#include "EmulateInstructionLoongArch.h"
+#include "Plugins/Process/Utility/InstructionUtils.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.h"
+#include "Plugins/Process/Utility/lldb-loongarch-register-enums.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Interpreter/OptionValueArray.h"
+#include "lldb/Interpreter/OptionValueDictionary.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Stream.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/MathExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionLoongArch, InstructionLoongArch)
+
+namespace lldb_private {
+
+EmulateInstructionLoongArch::Opcode *
+EmulateInstructionLoongArch::GetOpcodeForInstruction(uint32_t inst) {
+  static EmulateInstructionLoongArch::Opcode g_opcodes[] = {
+      {0x00000000, 0x00000000, &EmulateInstructionLoongArch::EmulateNonJMP,
+       "NonJMP"}};
+  static const size_t num_ppc_opcodes = std::size(g_opcodes);
+
+  for (size_t i = 0; i < num_ppc_opcodes; ++i) {
+    if ((g_opcodes[i].mask & inst) == g_opcodes[i].value)
+      return &g_opcodes[i];
+  }
+  return nullptr;
+}
+
+bool EmulateInstructionLoongArch::EvaluateInstruction(uint32_t options) {
+  uint32_t inst_size = m_opcode.GetByteSize();
+  uint32_t inst = m_opcode.GetOpcode32();
+  bool increase_pc = options & eEmulateInstructionOptionAutoAdvancePC;
+  bool success = false;
+
+  Opcode *opcode_data = GetOpcodeForInstruction(inst);
+  if (!opcode_data)
+    return false;
+
+  lldb::addr_t old_pc = 0;
+  if (increase_pc) {
+    old_pc = ReadPC(&success);
+    if (!success)
+      return false;
+  }
+
+  // Call the Emulate... function.
+  success = (this->*opcode_data->callback)(inst);
+  if (!success)
+    return false;
+
+  if (increase_pc) {
+    lldb::addr_t new_pc = ReadPC(&success);
+    if (!success)
+      return false;
+
+    if (new_pc == old_pc) {
+      if (!WritePC(old_pc + inst_size))
+        return false;
+    }
+  }
+  return true;
+}
+
+bool EmulateInstructionLoongArch::ReadInstruction() {
+
+  bool success = false;
+  m_addr = ReadPC(&success);
+  if (!success) {
+    m_addr = LLDB_INVALID_ADDRESS;
+    return false;
+  }
+
+  Context ctx;
+  ctx.type = eContextReadOpcode;
+  ctx.SetNoArgs();
+  uint32_t inst = (uint32_t)ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success);
+  m_opcode.SetOpcode32(inst, GetByteOrder());
+
+  return true;
+}
+
+lldb::addr_t EmulateInstructionLoongArch::ReadPC(bool *success) {
+  return ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
+                              LLDB_INVALID_ADDRESS, success);
+}
+
+bool EmulateInstructionLoongArch::WritePC(lldb::addr_t pc) {
+  EmulateInstruction::Context ctx;
+  ctx.type = eContextAdvancePC;
+  ctx.SetNoArgs();
+  return WriteRegisterUnsigned(ctx, eRegisterKindGeneric,
+                               LLDB_REGNUM_GENERIC_PC, pc);
+}
+
+llvm::Optional<RegisterInfo>
+EmulateInstructionLoongArch::GetRegisterInfo(lldb::RegisterKind reg_kind,
+                                             uint32_t reg_index) {
+  if (reg_kind == eRegisterKindGeneric) {
+    switch (reg_index) {
+    case LLDB_REGNUM_GENERIC_PC:
+      reg_kind = eRegisterKindLLDB;
+      reg_index = gpr_pc_loongarch;
+      break;
+    case LLDB_REGNUM_GENERIC_SP:
+      reg_kind = eRegisterKindLLDB;
+      reg_index = gpr_sp_loongarch;
+      break;
+    case LLDB_REGNUM_GENERIC_FP:
+      reg_kind = eRegisterKindLLDB;
+      reg_index = gpr_fp_loongarch;
+      break;
+    case LLDB_REGNUM_GENERIC_RA:
+      reg_kind = eRegisterKindLLDB;
+      reg_index = gpr_ra_loongarch;
+      break;
+    // We may handle LLDB_REGNUM_GENERIC_ARGx when more instructions are
+    // supported.
+    default:
+      llvm_unreachable("unsupported register");
+    }
+  }
+
+  const RegisterInfo *array =
+      RegisterInfoPOSIX_loongarch64::GetRegisterInfoPtr(m_arch);
+  const uint32_t length =
+      RegisterInfoPOSIX_loongarch64::GetRegisterInfoCount(m_arch);
+
+  if (reg_index >= length || reg_kind != eRegisterKindLLDB)
+    return {};
+  return array[reg_index];
+}
+
+bool EmulateInstructionLoongArch::SetTargetTriple(const ArchSpec &arch) {
+  return SupportsThisArch(arch);
+}
+
+bool EmulateInstructionLoongArch::TestEmulation(
+    Stream *out_stream, ArchSpec &arch, OptionValueDictionary *test_data) {
+  return false;
+}
+
+void EmulateInstructionLoongArch::Initialize() {
+  PluginManager::RegisterPlugin(GetPluginNameStatic(),
+                                GetPluginDescriptionStatic(), CreateInstance);
+}
+
+void EmulateInstructionLoongArch::Terminate() {
+  PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+lldb_private::EmulateInstruction *
+EmulateInstructionLoongArch::CreateInstance(const ArchSpec &arch,
+                                            InstructionType inst_type) {
+  if (EmulateInstructionLoongArch::SupportsThisInstructionType(inst_type) &&
+      SupportsThisArch(arch)) {
+    return new EmulateInstructionLoongArch(arch);
+  }
+
+  return nullptr;
+}
+
+bool EmulateInstructionLoongArch::SupportsThisArch(const ArchSpec &arch) {
+  return arch.GetTriple().isLoongArch();
+}
+
+bool EmulateInstructionLoongArch::EmulateNonJMP(uint32_t inst) { return false; }
+
+} // namespace lldb_private
Index: lldb/source/Plugins/Instruction/LoongArch/CMakeLists.txt
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Instruction/LoongArch/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_lldb_library(lldbPluginInstructionLoongArch PLUGIN
+  EmulateInstructionLoongArch.cpp
+
+  LINK_LIBS
+    lldbCore
+    lldbInterpreter
+    lldbSymbol
+    lldbPluginProcessUtility
+  LINK_COMPONENTS
+    Support
+  )
Index: lldb/source/Plugins/Instruction/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/Instruction/CMakeLists.txt
+++ lldb/source/Plugins/Instruction/CMakeLists.txt
@@ -4,3 +4,4 @@
 add_subdirectory(MIPS64)
 add_subdirectory(PPC64)
 add_subdirectory(RISCV)
+add_subdirectory(LoongArch)
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to