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