[Lldb-commits] [lldb] f0f3395 - [LLDB][LoongArch] Make software single stepping work
Weining Lu via lldb-commits
lldb-commits at lists.llvm.org
Thu Dec 8 04:00:15 PST 2022
Author: Hui Li
Date: 2022-12-08T19:59:39+08:00
New Revision: f0f33957d03444eefc8264cbfe7f5cfe7bee6f3d
URL: https://github.com/llvm/llvm-project/commit/f0f33957d03444eefc8264cbfe7f5cfe7bee6f3d
DIFF: https://github.com/llvm/llvm-project/commit/f0f33957d03444eefc8264cbfe7f5cfe7bee6f3d.diff
LOG: [LLDB][LoongArch] Make software single stepping work
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.
Reviewed By: SixWeining, DavidSpickett
Differential Revision: https://reviews.llvm.org/D139158
Added:
lldb/source/Plugins/Instruction/LoongArch/CMakeLists.txt
lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.cpp
lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h
Modified:
lldb/source/Plugins/Instruction/CMakeLists.txt
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
Removed:
################################################################################
diff --git a/lldb/source/Plugins/Instruction/CMakeLists.txt b/lldb/source/Plugins/Instruction/CMakeLists.txt
index 631c0b307cac4..46d610f261e0d 100644
--- a/lldb/source/Plugins/Instruction/CMakeLists.txt
+++ b/lldb/source/Plugins/Instruction/CMakeLists.txt
@@ -1,5 +1,6 @@
add_subdirectory(ARM)
add_subdirectory(ARM64)
+add_subdirectory(LoongArch)
add_subdirectory(MIPS)
add_subdirectory(MIPS64)
add_subdirectory(PPC64)
diff --git a/lldb/source/Plugins/Instruction/LoongArch/CMakeLists.txt b/lldb/source/Plugins/Instruction/LoongArch/CMakeLists.txt
new file mode 100644
index 0000000000000..59802ee8fa9ad
--- /dev/null
+++ b/lldb/source/Plugins/Instruction/LoongArch/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_lldb_library(lldbPluginInstructionLoongArch PLUGIN
+ EmulateInstructionLoongArch.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbInterpreter
+ lldbPluginProcessUtility
+ lldbSymbol
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.cpp b/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.cpp
new file mode 100644
index 0000000000000..14ac993d9ac0f
--- /dev/null
+++ b/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.cpp
@@ -0,0 +1,181 @@
+//===---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) {
+ // TODO: Add the mask of jump instruction.
+ static EmulateInstructionLoongArch::Opcode g_opcodes[] = {
+ {0x00000000, 0x00000000, &EmulateInstructionLoongArch::EmulateNonJMP,
+ "NonJMP"}};
+ static const size_t num_loongarch_opcodes = std::size(g_opcodes);
+
+ for (size_t i = 0; i < num_loongarch_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.
+ if (!(this->*opcode_data->callback)(inst))
+ return false;
+
+ if (increase_pc) {
+ lldb::addr_t new_pc = ReadPC(&success);
+ if (!success)
+ return false;
+
+ if (new_pc == old_pc && !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
diff --git a/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h b/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h
new file mode 100644
index 0000000000000..06abc99d1ee92
--- /dev/null
+++ b/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h
@@ -0,0 +1,76 @@
+//===---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) {
+ return inst_type == eInstructionTypePCModifying;
+ }
+
+ 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_EMULATEINSTRUCTIONLOONGARCH_H
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index ffa15f4023dba..5485d8c7f327c 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -883,7 +883,7 @@ bool NativeProcessLinux::MonitorClone(NativeThreadLinux &parent,
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;
}
diff --git a/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp b/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp
index b8bf30f3b6de4..6bf8a0dc28b22 100644
--- a/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp
+++ b/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp
@@ -168,7 +168,7 @@ Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping(
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);
diff --git a/lldb/tools/lldb-server/CMakeLists.txt b/lldb/tools/lldb-server/CMakeLists.txt
index 833563b5a0fe5..67103e87a1d4a 100644
--- a/lldb/tools/lldb-server/CMakeLists.txt
+++ b/lldb/tools/lldb-server/CMakeLists.txt
@@ -51,6 +51,7 @@ add_lldb_tool(lldb-server
lldbVersion
${LLDB_PLUGINS}
lldbPluginInstructionARM
+ lldbPluginInstructionLoongArch
lldbPluginInstructionMIPS
lldbPluginInstructionMIPS64
lldbPluginInstructionRISCV
diff --git a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp
index a8bdcdf0e77c9..4233252a84dfc 100644
--- a/lldb/tools/lldb-server/SystemInitializerLLGS.cpp
+++ b/lldb/tools/lldb-server/SystemInitializerLLGS.cpp
@@ -29,6 +29,11 @@ using HostObjectFile = ObjectFileELF;
#include "Plugins/Instruction/ARM/EmulateInstructionARM.h"
#endif
+#if defined(__loongarch__)
+#define LLDB_TARGET_LoongArch
+#include "Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h"
+#endif
+
#if defined(__mips64__) || defined(mips64) || defined(__mips64) || \
defined(__MIPS64__) || defined(_M_MIPS64)
#define LLDB_TARGET_MIPS64
@@ -57,6 +62,9 @@ llvm::Error SystemInitializerLLGS::Initialize() {
#if defined(LLDB_TARGET_ARM) || defined(LLDB_TARGET_ARM64)
EmulateInstructionARM::Initialize();
#endif
+#if defined(LLDB_TARGET_LoongArch)
+ EmulateInstructionLoongArch::Initialize();
+#endif
#if defined(LLDB_TARGET_MIPS) || defined(LLDB_TARGET_MIPS64)
EmulateInstructionMIPS::Initialize();
#endif
@@ -76,6 +84,9 @@ void SystemInitializerLLGS::Terminate() {
#if defined(LLDB_TARGET_ARM) || defined(LLDB_TARGET_ARM64)
EmulateInstructionARM::Terminate();
#endif
+#if defined(LLDB_TARGET_LoongArch)
+ EmulateInstructionLoongArch::Terminate();
+#endif
#if defined(LLDB_TARGET_MIPS) || defined(LLDB_TARGET_MIPS64)
EmulateInstructionMIPS::Terminate();
#endif
More information about the lldb-commits
mailing list