From ce93763769e32cea1088fba3a77e619d5ff53566 Mon Sep 17 00:00:00 2001 From: wuzx Date: Tue, 2 Dec 2025 03:59:49 -0800 Subject: [PATCH] Add sw_64 support. --- lldb/include/lldb/Utility/ArchSpec.h | 17 + lldb/source/Host/common/HostInfoBase.cpp | 1 + .../Host/common/NativeProcessProtocol.cpp | 5 + lldb/source/Plugins/ABI/CMakeLists.txt | 2 +- lldb/source/Plugins/ABI/Sw64/ABISw64.cpp | 21 + lldb/source/Plugins/ABI/Sw64/ABISw64.h | 17 + .../source/Plugins/ABI/Sw64/ABISysV_sw_64.cpp | 1631 +++++++++++++++++ lldb/source/Plugins/ABI/Sw64/ABISysV_sw_64.h | 104 ++ lldb/source/Plugins/ABI/Sw64/CMakeLists.txt | 13 + .../Plugins/Architecture/CMakeLists.txt | 1 + .../Architecture/Sw64/ArchitectureSw64.cpp | 234 +++ .../Architecture/Sw64/ArchitectureSw64.h | 53 + .../Plugins/Architecture/Sw64/CMakeLists.txt | 10 + .../Disassembler/LLVMC/DisassemblerLLVMC.cpp | 5 + .../ObjectFile/Breakpad/BreakpadRecords.cpp | 3 + .../Plugins/ObjectFile/ELF/ELFHeader.cpp | 5 + .../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 15 + .../Plugins/Platform/Linux/PlatformLinux.cpp | 6 +- .../Plugins/Process/Linux/CMakeLists.txt | 1 + .../NativeRegisterContextLinux_sw_64.cpp | 815 ++++++++ .../Linux/NativeRegisterContextLinux_sw_64.h | 149 ++ .../Plugins/Process/Utility/CMakeLists.txt | 2 + .../Plugins/Process/Utility/LinuxSignals.cpp | 7 + .../Utility/RegisterContextLinux_sw_64.cpp | 180 ++ .../Utility/RegisterContextLinux_sw_64.h | 39 + .../Utility/RegisterContextPOSIX_sw_64.cpp | 186 ++ .../Utility/RegisterContextPOSIX_sw_64.h | 84 + .../Process/Utility/RegisterContext_sw_64.h | 239 +++ .../Process/Utility/RegisterInfos_sw_64.h | 312 ++++ .../Utility/lldb-sw_64-linux-register-enums.h | 206 +++ .../Plugins/Process/elf-core/CMakeLists.txt | 1 + .../Process/elf-core/ProcessElfCore.cpp | 6 + .../RegisterContextPOSIXCore_sw_64.cpp | 107 ++ .../elf-core/RegisterContextPOSIXCore_sw_64.h | 55 + .../Process/elf-core/ThreadElfCore.cpp | 10 + .../GDBRemoteCommunicationServerCommon.cpp | 2 +- lldb/source/Target/Platform.cpp | 8 + lldb/source/Utility/ArchSpec.cpp | 38 + 38 files changed, 4587 insertions(+), 3 deletions(-) create mode 100755 lldb/source/Plugins/ABI/Sw64/ABISw64.cpp create mode 100755 lldb/source/Plugins/ABI/Sw64/ABISw64.h create mode 100755 lldb/source/Plugins/ABI/Sw64/ABISysV_sw_64.cpp create mode 100755 lldb/source/Plugins/ABI/Sw64/ABISysV_sw_64.h create mode 100755 lldb/source/Plugins/ABI/Sw64/CMakeLists.txt create mode 100755 lldb/source/Plugins/Architecture/Sw64/ArchitectureSw64.cpp create mode 100755 lldb/source/Plugins/Architecture/Sw64/ArchitectureSw64.h create mode 100755 lldb/source/Plugins/Architecture/Sw64/CMakeLists.txt create mode 100755 lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_sw_64.cpp create mode 100755 lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_sw_64.h create mode 100755 lldb/source/Plugins/Process/Utility/RegisterContextLinux_sw_64.cpp create mode 100755 lldb/source/Plugins/Process/Utility/RegisterContextLinux_sw_64.h create mode 100755 lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_sw_64.cpp create mode 100755 lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_sw_64.h create mode 100755 lldb/source/Plugins/Process/Utility/RegisterContext_sw_64.h create mode 100755 lldb/source/Plugins/Process/Utility/RegisterInfos_sw_64.h create mode 100755 lldb/source/Plugins/Process/Utility/lldb-sw_64-linux-register-enums.h create mode 100755 lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_sw_64.cpp create mode 100755 lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_sw_64.h diff --git a/lldb/include/lldb/Utility/ArchSpec.h b/lldb/include/lldb/Utility/ArchSpec.h index a226a3a5a9b7..723b326a7ab3 100644 --- a/lldb/include/lldb/Utility/ArchSpec.h +++ b/lldb/include/lldb/Utility/ArchSpec.h @@ -113,6 +113,12 @@ public: eLoongArchSubType_loongarch64, }; +#ifndef LHX20240718 + enum SW64SubType { + eSW64SubType_sw_64, + }; +#endif + enum Core { eCore_arm_generic, eCore_arm_armv4, @@ -150,6 +156,10 @@ public: eCore_arm_arm64_32, eCore_arm_aarch64, +#ifndef LHX20240726 + eCore_sw_64, +#endif + eCore_mips32, eCore_mips32r2, eCore_mips32r3, @@ -256,6 +266,11 @@ public: kCore_hexagon_first = eCore_hexagon_generic, kCore_hexagon_last = eCore_hexagon_hexagonv5, +#ifndef LHX20240718 + kCore_sw_64_first = eCore_sw_64, + kCore_sw_64_last = eCore_sw_64, +#endif + kCore_mips32_first = eCore_mips32, kCore_mips32_last = eCore_mips32r6, @@ -314,6 +329,8 @@ public: /// \return a boolean value. bool IsMIPS() const; + bool IsSw64() const; + /// Returns a string representing current architecture as a target CPU for /// tools like compiler, disassembler etc. /// diff --git a/lldb/source/Host/common/HostInfoBase.cpp b/lldb/source/Host/common/HostInfoBase.cpp index 5c44c2f38b28..094ae1254000 100644 --- a/lldb/source/Host/common/HostInfoBase.cpp +++ b/lldb/source/Host/common/HostInfoBase.cpp @@ -342,6 +342,7 @@ void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, arch_32.SetTriple(triple.get32BitArchVariant()); break; + case llvm::Triple::sw_64: case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::sparcv9: diff --git a/lldb/source/Host/common/NativeProcessProtocol.cpp b/lldb/source/Host/common/NativeProcessProtocol.cpp index b3ef8f027bcf..d111b5ede043 100644 --- a/lldb/source/Host/common/NativeProcessProtocol.cpp +++ b/lldb/source/Host/common/NativeProcessProtocol.cpp @@ -500,6 +500,7 @@ NativeProcessProtocol::EnableSoftwareBreakpoint(lldb::addr_t addr, llvm::Expected> NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x20, 0xd4}; + static const uint8_t g_sw_64_opcode[] = {0x80, 0x00, 0x00, 0x00}; static const uint8_t g_i386_opcode[] = {0xCC}; static const uint8_t g_mips64_opcode[] = {0x00, 0x00, 0x00, 0x0d}; static const uint8_t g_mips64el_opcode[] = {0x0d, 0x00, 0x00, 0x00}; @@ -517,6 +518,9 @@ NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { case llvm::Triple::aarch64_32: return llvm::ArrayRef(g_aarch64_opcode); + case llvm::Triple::sw_64: + return llvm::ArrayRef(g_sw_64_opcode); + case llvm::Triple::x86: case llvm::Triple::x86_64: return llvm::ArrayRef(g_i386_opcode); @@ -563,6 +567,7 @@ size_t NativeProcessProtocol::GetSoftwareBreakpointPCOffset() { case llvm::Triple::x86: case llvm::Triple::x86_64: case llvm::Triple::systemz: + case llvm::Triple::sw_64: // These architectures report increment the PC after breakpoint is hit. return cantFail(GetSoftwareBreakpointTrapOpcode(0)).size(); diff --git a/lldb/source/Plugins/ABI/CMakeLists.txt b/lldb/source/Plugins/ABI/CMakeLists.txt index 828aea674ea6..8986d9cc505f 100644 --- a/lldb/source/Plugins/ABI/CMakeLists.txt +++ b/lldb/source/Plugins/ABI/CMakeLists.txt @@ -1,4 +1,4 @@ -foreach(target AArch64 ARM ARC Hexagon Mips MSP430 PowerPC SystemZ X86) +foreach(target AArch64 ARM ARC Hexagon Mips MSP430 PowerPC Sw64 SystemZ X86) if (${target} IN_LIST LLVM_TARGETS_TO_BUILD) add_subdirectory(${target}) endif() diff --git a/lldb/source/Plugins/ABI/Sw64/ABISw64.cpp b/lldb/source/Plugins/ABI/Sw64/ABISw64.cpp new file mode 100755 index 000000000000..d7de4869f8cb --- /dev/null +++ b/lldb/source/Plugins/ABI/Sw64/ABISw64.cpp @@ -0,0 +1,21 @@ +//===-- Sw64.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 +// +//===----------------------------------------------------------------------===// + +#include "ABISw64.h" +#include "ABISysV_sw_64.h" +#include "lldb/Core/PluginManager.h" + +LLDB_PLUGIN_DEFINE(ABISw64) + +void ABISw64::Initialize() { + ABISysV_sw_64::Initialize(); +} + +void ABISw64::Terminate() { + ABISysV_sw_64::Terminate(); +} diff --git a/lldb/source/Plugins/ABI/Sw64/ABISw64.h b/lldb/source/Plugins/ABI/Sw64/ABISw64.h new file mode 100755 index 000000000000..08a0f8ceccf4 --- /dev/null +++ b/lldb/source/Plugins/ABI/Sw64/ABISw64.h @@ -0,0 +1,17 @@ +//===-- ABISw64.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_SOURCE_PLUGINS_ABI_SW64_ABISW64_H +#define LLDB_SOURCE_PLUGINS_ABI_SW64_ABISW64_H + +class ABISw64 { +public: + static void Initialize(); + static void Terminate(); +}; +#endif diff --git a/lldb/source/Plugins/ABI/Sw64/ABISysV_sw_64.cpp b/lldb/source/Plugins/ABI/Sw64/ABISysV_sw_64.cpp new file mode 100755 index 000000000000..b13f9ed60cd6 --- /dev/null +++ b/lldb/source/Plugins/ABI/Sw64/ABISysV_sw_64.cpp @@ -0,0 +1,1631 @@ +//===-- ABISysV_sw_64.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 "ABISysV_sw_64.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/TargetParser/Triple.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Core/ValueObjectMemory.h" +#include "lldb/Core/ValueObjectRegister.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" +#include + +using namespace lldb; +using namespace lldb_private; + +LLDB_PLUGIN_DEFINE(ABISysV_sw_64) + +enum dwarf_regnums { + dwarf_r0 = 0, + dwarf_r1, + dwarf_r2, + dwarf_r3, + dwarf_r4, + dwarf_r5, + dwarf_r6, + dwarf_r7, + dwarf_r8, + dwarf_r9, + dwarf_r10, + dwarf_r11, + dwarf_r12, + dwarf_r13, + dwarf_r14, + dwarf_r15, + dwarf_r16, + dwarf_r17, + dwarf_r18, + dwarf_r19, + dwarf_r20, + dwarf_r21, + dwarf_r22, + dwarf_r23, + dwarf_r24, + dwarf_r25, + dwarf_r26, + dwarf_r27, + dwarf_r28, + dwarf_r29, + dwarf_r30, + dwarf_r31, + dwarf_pc +}; + +static const RegisterInfo g_register_infos[] = { + // NAME ALT SZ OFF ENCODING FORMAT EH_FRAME + // DWARF GENERIC PROCESS PLUGIN + // LLDB NATIVE + // ======== ====== == === ============= ========== ============= + // ================= ==================== ================= + // ==================== + {"r0", + "v0", + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r0, dwarf_r0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r1", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r1, dwarf_r1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r2", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r2, dwarf_r2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r3", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r3, dwarf_r3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r4", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r4, dwarf_r4, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r5", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r5, dwarf_r5, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r6", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r6, dwarf_r6, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r7", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r7, dwarf_r7, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r8", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r8, dwarf_r8, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r9", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r9, dwarf_r9, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r10", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r10, dwarf_r10, LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r11", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r11, dwarf_r11, LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r12", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r13", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r13, dwarf_r13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r14", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r14, dwarf_r14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r15", + "fp", + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r15, dwarf_r15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r16", + "arg1", + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r16, dwarf_r16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r17", + "arg2", + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r17, dwarf_r17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r18", + "arg3", + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r18, dwarf_r18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r19", + "arg4", + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r19, dwarf_r19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r20", + "arg5", + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r20, dwarf_r20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r21", + "arg6", + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r21, dwarf_r21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r22", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r22, dwarf_r22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r23", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r23, dwarf_r23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r24", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r24, dwarf_r24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r25", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r25, dwarf_r25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r26", + "ra", + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r26, dwarf_r26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r27", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r27, dwarf_r27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r28", + "at", + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r28, dwarf_r28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r29", + "gp", + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r29, dwarf_r29, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r30", + "sp", + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r30, dwarf_r30, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"r31", + "zero", + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_r31, dwarf_r31, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, + {"pc", + nullptr, + 8, + 0, + eEncodingUint, + eFormatHex, + {dwarf_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM}, + nullptr, + nullptr, + nullptr, + }, +}; + +static const uint32_t k_num_register_infos = std::size(g_register_infos); + +const lldb_private::RegisterInfo * +ABISysV_sw_64::GetRegisterInfoArray(uint32_t &count) { + count = k_num_register_infos; + return g_register_infos; +} + +size_t ABISysV_sw_64::GetRedZoneSize() const { return 0; } + +// Static Functions + +ABISP +ABISysV_sw_64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { + if (arch.GetTriple().isSw64()) + return ABISP( + new ABISysV_sw_64(std::move(process_sp), MakeMCRegisterInfo(arch))); + return ABISP(); +} + +bool ABISysV_sw_64::PrepareTrivialCall(Thread &thread, addr_t sp, + addr_t func_addr, addr_t return_addr, + llvm::ArrayRef args) const { + //Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + Log *log = GetLog(LLDBLog::Expressions); + + if (log) { + StreamString s; + s.Printf("ABISysV_sw_64::PrepareTrivialCall (tid = 0x%" PRIx64 + ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 + ", return_addr = 0x%" PRIx64, + thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, + (uint64_t)return_addr); + + for (size_t i = 0; i < args.size(); ++i) + s.Printf(", arg%zd = 0x%" PRIx64, i + 1, args[i]); + s.PutCString(")"); + log->PutString(s.GetString()); + } + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + const RegisterInfo *reg_info = nullptr; + + if (args.size() > 6) // TODO handle more than 8 arguments + return false; + + for (size_t i = 0; i < args.size(); ++i) { + reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG1 + i); + LLDB_LOGF(log, "About to write arg%zd (0x%" PRIx64 ") into %s", i + 1, + args[i], reg_info->name); + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) + return false; + } + + // First, align the SP + + LLDB_LOGF(log, "16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64, + (uint64_t)sp, (uint64_t)(sp & ~0xfull)); + + sp &= ~(0xfull); // 16-byte alignment + + Status error; + const RegisterInfo *pc_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + const RegisterInfo *sp_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + const RegisterInfo *ra_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); + const RegisterInfo *r25_info = reg_ctx->GetRegisterInfoByName("r27", 0); + const RegisterInfo *r0_info = reg_ctx->GetRegisterInfoByName("zero", 0); + + LLDB_LOGF(log, "Writing R0: 0x%" PRIx64, (uint64_t)0); + + /* Write r0 with 0, in case we are stopped in syscall, + * such setting prevents automatic decrement of the PC. + * This clears the bug 23659 for MIPS. + */ + if (!reg_ctx->WriteRegisterFromUnsigned(r0_info, (uint64_t)0)) + return false; + + LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp); + + // Set "sp" to the requested value + if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp)) + return false; + + LLDB_LOGF(log, "Writing RA: 0x%" PRIx64, (uint64_t)return_addr); + + // Set "ra" to the return address + if (!reg_ctx->WriteRegisterFromUnsigned(ra_reg_info, return_addr)) + return false; + + LLDB_LOGF(log, "Writing PC: 0x%" PRIx64, (uint64_t)func_addr); + + // Set pc to the address of the called function. + if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr)) + return false; + + LLDB_LOGF(log, "Writing r25: 0x%" PRIx64, (uint64_t)func_addr); + + // All callers of position independent functions must place the address of + // the called function in t9 (r25) + if (!reg_ctx->WriteRegisterFromUnsigned(r25_info, func_addr)) + return false; + + return true; +} + +bool ABISysV_sw_64::GetArgumentValues(Thread &thread, + ValueList &values) const { + return false; +} + +Status ABISysV_sw_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, + lldb::ValueObjectSP &new_value_sp) { + Status error; + if (!new_value_sp) { + error.SetErrorString("Empty value object for return value."); + return error; + } + + CompilerType compiler_type = new_value_sp->GetCompilerType(); + if (!compiler_type) { + error.SetErrorString("Null clang type for return value."); + return error; + } + + Thread *thread = frame_sp->GetThread().get(); +#if 0 + RegisterContext *reg_ctx = thread->GetRegisterContext().get(); + + if (!reg_ctx) + error.SetErrorString("no registers are available"); + + DataExtractor data; + Status data_error; + size_t num_bytes = new_value_sp->GetData(data, data_error); + if (data_error.Fail()) { + error.SetErrorStringWithFormat( + "Couldn't convert return value to raw data: %s", + data_error.AsCString()); + return error; + } + + const uint32_t type_flags = compiler_type.GetTypeInfo(nullptr); + + if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { + if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) { + lldb::offset_t offset = 0; + + if (num_bytes <= 16) { + const RegisterInfo *r2_info = reg_ctx->GetRegisterInfoByName("r2", 0); + if (num_bytes <= 8) { + uint64_t raw_value = data.GetMaxU64(&offset, num_bytes); + + if (!reg_ctx->WriteRegisterFromUnsigned(r2_info, raw_value)) + error.SetErrorString("failed to write register r2"); + } else { + uint64_t raw_value = data.GetMaxU64(&offset, 8); + if (reg_ctx->WriteRegisterFromUnsigned(r2_info, raw_value)) { + const RegisterInfo *r3_info = + reg_ctx->GetRegisterInfoByName("r3", 0); + raw_value = data.GetMaxU64(&offset, num_bytes - offset); + + if (!reg_ctx->WriteRegisterFromUnsigned(r3_info, raw_value)) + error.SetErrorString("failed to write register r3"); + } else + error.SetErrorString("failed to write register r2"); + } + } else { + error.SetErrorString("We don't support returning longer than 128 bit " + "integer values at present."); + } + } else if (type_flags & eTypeIsFloat) { + error.SetErrorString("TODO: Handle Float Types."); + } + } else if (type_flags & eTypeIsVector) { + error.SetErrorString("returning vector values are not supported"); + } +#endif + +#ifndef LHX20240722 // refer to x86_64 + bool is_signed; + uint32_t count; + bool is_complex; + + RegisterContext *reg_ctx = thread->GetRegisterContext().get(); + + bool set_it_simple = false; + if (compiler_type.IsIntegerOrEnumerationType(is_signed) || + compiler_type.IsPointerType()) { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r0", 0); + + DataExtractor data; + Status data_error; + size_t num_bytes = new_value_sp->GetData(data, data_error); + if (data_error.Fail()) { + error.SetErrorStringWithFormat( + "Couldn't convert return value to raw data: %s", + data_error.AsCString()); + return error; + } + lldb::offset_t offset = 0; + if (num_bytes <= 8) { + uint64_t raw_value = data.GetMaxU64(&offset, num_bytes); + + if (reg_ctx->WriteRegisterFromUnsigned(reg_info, raw_value)) + set_it_simple = true; + } else { + error.SetErrorString("We don't support returning longer than 64 bit " + "integer values at present."); + } + } else if (compiler_type.IsFloatingPointType(count, is_complex)) { + if (is_complex) + error.SetErrorString( + "We don't support returning complex values at present"); + else { + std::optional bit_width = + compiler_type.GetBitSize(frame_sp.get()); + if (!bit_width) { + error.SetErrorString("can't get type size"); + return error; + } + if (*bit_width <= 64) { + const RegisterInfo *xmm0_info = + reg_ctx->GetRegisterInfoByName("f0", 0); + RegisterValue xmm0_value; + DataExtractor data; + Status data_error; + size_t num_bytes = new_value_sp->GetData(data, data_error); + if (data_error.Fail()) { + error.SetErrorStringWithFormat( + "Couldn't convert return value to raw data: %s", + data_error.AsCString()); + return error; + } + + unsigned char buffer[16]; + ByteOrder byte_order = data.GetByteOrder(); + + data.CopyByteOrderedData(0, num_bytes, buffer, 16, byte_order); + xmm0_value.SetBytes(buffer, 16, byte_order); + reg_ctx->WriteRegister(xmm0_info, xmm0_value); + set_it_simple = true; + } else { + // FIXME - don't know how to do 80 bit long doubles yet. + error.SetErrorString( + "We don't support returning float values > 64 bits at present"); + } + } + } + + if (!set_it_simple) { + // Okay we've got a structure or something that doesn't fit in a simple + // register. We should figure out where it really goes, but we don't + // support this yet. + error.SetErrorString("We only support setting simple integer and float " + "return types at present."); + } +#endif + return error; +} + +ValueObjectSP ABISysV_sw_64::GetReturnValueObjectSimple( + Thread &thread, CompilerType &return_compiler_type) const { + ValueObjectSP return_valobj_sp; + return return_valobj_sp; +} + +#ifndef LHX20240722 +ValueObjectSP ABISysV_sw_64::GetReturnValueObjectImpl( + Thread &thread, CompilerType &return_compiler_type) const { + ValueObjectSP return_valobj_sp; + Value value; + Status error; + + ExecutionContext exe_ctx(thread.shared_from_this()); + if (exe_ctx.GetTargetPtr() == nullptr || exe_ctx.GetProcessPtr() == nullptr) + return return_valobj_sp; + value.SetCompilerType(return_compiler_type); + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return return_valobj_sp; + Target *target = exe_ctx.GetTargetPtr(); + const ArchSpec target_arch = target->GetArchitecture(); + ByteOrder target_byte_order = target_arch.GetByteOrder(); + std::optional byte_size = return_compiler_type.GetByteSize(&thread); + if (!byte_size) + return return_valobj_sp; + const uint32_t type_flags = return_compiler_type.GetTypeInfo(nullptr); + //uint32_t fp_flag = + // target_arch.GetFlags() & lldb_private::ArchSpec::eSW64_ABI_FP_mask; + + const RegisterInfo *r0_info = reg_ctx->GetRegisterInfoByName("r0", 0); + if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { + value.SetValueType(Value::ValueType::Scalar); + + bool success = false; + if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) { + // Extract the register context so we can read arguments from registers + // In MIPS register "r2" (v0) holds the integer function return values + // In SW64 register "r0" (v0) ... + uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r0_info, 0); + const bool is_signed = (type_flags & eTypeIsSigned) != 0; + switch (*byte_size) { + default: + break; + + case sizeof(uint64_t): + if (is_signed) + value.GetScalar() = (int64_t)(raw_value); + else + value.GetScalar() = (uint64_t)(raw_value); + success = true; + break; + + case sizeof(uint32_t): + if (is_signed) + value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); + else + value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); + success = true; + break; + + case sizeof(uint16_t): + if (is_signed) + value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); + else + value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); + success = true; + break; + case sizeof(uint8_t): + if (is_signed) + value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); + else + value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); + success = true; + break; + } + } else if (type_flags & eTypeIsFloat) { + if (type_flags & eTypeIsComplex) { + // Don't handle complex yet. + } +/* + else if (IsSoftFloat(fp_flag)) { + uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_info, 0); + switch (*byte_size) { + case 4: + value.GetScalar() = *((float *)(&raw_value)); + success = true; + break; + case 8: + value.GetScalar() = *((double *)(&raw_value)); + success = true; + break; + case 16: + uint64_t result[2]; + if (target_byte_order == eByteOrderLittle) { + result[0] = raw_value; + result[1] = reg_ctx->ReadRegisterAsUnsigned(r3_info, 0); + value.GetScalar() = *((long double *)(result)); + } else { + result[0] = reg_ctx->ReadRegisterAsUnsigned(r3_info, 0); + result[1] = raw_value; + value.GetScalar() = *((long double *)(result)); + } + success = true; + break; + } + } +*/ + else { + if (*byte_size <= sizeof(long double)) { + const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); + + RegisterValue f0_value; + DataExtractor f0_data; + + reg_ctx->ReadRegister(f0_info, f0_value); + + f0_value.GetData(f0_data); + + lldb::offset_t offset = 0; + if (*byte_size == sizeof(float)) { + value.GetScalar() = (float)f0_data.GetFloat(&offset); + success = true; + } else if (*byte_size == sizeof(double)) { + value.GetScalar() = (double)f0_data.GetDouble(&offset); + success = true; + } else if (*byte_size == sizeof(long double)) { + const RegisterInfo *f2_info = + reg_ctx->GetRegisterInfoByName("f1", 0); //lhx: mips is f0,f2 sw_64 is f0,f1 + RegisterValue f2_value; + DataExtractor f2_data; + reg_ctx->ReadRegister(f2_info, f2_value); + DataExtractor *copy_from_extractor = nullptr; + WritableDataBufferSP data_sp(new DataBufferHeap(16, 0)); + DataExtractor return_ext( + data_sp, target_byte_order, + target->GetArchitecture().GetAddressByteSize()); + + if (target_byte_order == eByteOrderLittle) { + copy_from_extractor = &f0_data; + copy_from_extractor->CopyByteOrderedData( + 0, 8, data_sp->GetBytes(), *byte_size - 8, target_byte_order); + f2_value.GetData(f2_data); + copy_from_extractor = &f2_data; + copy_from_extractor->CopyByteOrderedData( + 0, 8, data_sp->GetBytes() + 8, *byte_size - 8, + target_byte_order); + } else { + copy_from_extractor = &f0_data; + copy_from_extractor->CopyByteOrderedData( + 0, 8, data_sp->GetBytes() + 8, *byte_size - 8, + target_byte_order); + f2_value.GetData(f2_data); + copy_from_extractor = &f2_data; + copy_from_extractor->CopyByteOrderedData( + 0, 8, data_sp->GetBytes(), *byte_size - 8, target_byte_order); + } + + return_valobj_sp = ValueObjectConstResult::Create( + &thread, return_compiler_type, ConstString(""), return_ext); + return return_valobj_sp; + } + } + } + } + + if (success) + return_valobj_sp = ValueObjectConstResult::Create( + thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); + } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass || + type_flags & eTypeIsVector) { + // Any structure of up to 16 bytes in size is returned in the registers. + if (*byte_size <= 16) { + WritableDataBufferSP data_sp(new DataBufferHeap(16, 0)); + DataExtractor return_ext(data_sp, target_byte_order, + target->GetArchitecture().GetAddressByteSize()); + + RegisterValue r2_value, r3_value, f0_value, f1_value, f2_value; + // Tracks how much bytes of r2 and r3 registers we've consumed so far + uint32_t integer_bytes = 0; + // True if return values are in FP return registers. + bool use_fp_regs = false; + // True if we found any non floating point field in structure. + bool found_non_fp_field = false; + // True if return values are in r2 register. + bool use_r2 = false; + // True if return values are in r3 register. + bool use_r3 = false; + // True if the result is copied into our data buffer + bool sucess = false; + std::string name; + bool is_complex; + uint32_t count; + const uint32_t num_children = return_compiler_type.GetNumFields(); + + // A structure consisting of one or two FP values (and nothing else) will + // be returned in the two FP return-value registers i.e fp0 and fp2. + if (num_children <= 2) { + uint64_t field_bit_offset = 0; + + // Check if this structure contains only floating point fields + for (uint32_t idx = 0; idx < num_children; idx++) { + CompilerType field_compiler_type = + return_compiler_type.GetFieldAtIndex(idx, name, &field_bit_offset, + nullptr, nullptr); + + if (field_compiler_type.IsFloatingPointType(count, is_complex)) + use_fp_regs = true; + else + found_non_fp_field = true; + } + + if (use_fp_regs && !found_non_fp_field) { + // We have one or two FP-only values in this structure. Get it from + // f0/f2 registers. + DataExtractor f0_data, f1_data, f2_data; + const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); + const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0); + const RegisterInfo *f2_info = reg_ctx->GetRegisterInfoByName("f2", 0); + + reg_ctx->ReadRegister(f0_info, f0_value); + reg_ctx->ReadRegister(f2_info, f2_value); + + f0_value.GetData(f0_data); + + for (uint32_t idx = 0; idx < num_children; idx++) { + CompilerType field_compiler_type = + return_compiler_type.GetFieldAtIndex( + idx, name, &field_bit_offset, nullptr, nullptr); + std::optional field_byte_width = + field_compiler_type.GetByteSize(&thread); + if (!field_byte_width) + return return_valobj_sp; + + DataExtractor *copy_from_extractor = nullptr; + uint64_t return_value[2]; + offset_t offset = 0; + if (idx == 0) { + // This case is for long double type. + if (*field_byte_width == 16) { + + // If structure contains long double type, then it is returned + // in fp0/fp1 registers. + if (target_byte_order == eByteOrderLittle) { + return_value[0] = f0_data.GetU64(&offset); + reg_ctx->ReadRegister(f1_info, f1_value); + f1_value.GetData(f1_data); + offset = 0; + return_value[1] = f1_data.GetU64(&offset); + } else { + return_value[1] = f0_data.GetU64(&offset); + reg_ctx->ReadRegister(f1_info, f1_value); + f1_value.GetData(f1_data); + offset = 0; + return_value[0] = f1_data.GetU64(&offset); + } + + f0_data.SetData(return_value, *field_byte_width, + target_byte_order); + } + copy_from_extractor = &f0_data; // This is in f0, copy from + // register to our result + // structure + } else { + f2_value.GetData(f2_data); + // This is in f2, copy from register to our result structure + copy_from_extractor = &f2_data; + } + + // Sanity check to avoid crash + if (!copy_from_extractor || + *field_byte_width > copy_from_extractor->GetByteSize()) + return return_valobj_sp; + + // copy the register contents into our data buffer + copy_from_extractor->CopyByteOrderedData( + 0, *field_byte_width, + data_sp->GetBytes() + (field_bit_offset / 8), *field_byte_width, + target_byte_order); + } + + // The result is in our data buffer. Create a variable object out of + // it + return_valobj_sp = ValueObjectConstResult::Create( + &thread, return_compiler_type, ConstString(""), return_ext); + + return return_valobj_sp; + } + } + + // If we reach here, it means this structure either contains more than + // two fields or it contains at least one non floating point type. In + // that case, all fields are returned in GP return registers. + for (uint32_t idx = 0; idx < num_children; idx++) { + uint64_t field_bit_offset = 0; + bool is_signed; + uint32_t padding; + CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex( + idx, name, &field_bit_offset, nullptr, nullptr); + std::optional field_byte_width = + field_compiler_type.GetByteSize(nullptr); + + // if we don't know the size of the field (e.g. invalid type), just + // bail out + if (!field_byte_width || *field_byte_width == 0) + break; + + uint32_t field_byte_offset = field_bit_offset / 8; + + if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) || + field_compiler_type.IsPointerType() || + field_compiler_type.IsFloatingPointType(count, is_complex)) { + padding = field_byte_offset - integer_bytes; + + if (integer_bytes < 8) { + // We have not yet consumed r2 completely. + if (integer_bytes + *field_byte_width + padding <= 8) { + // This field fits in r2, copy its value from r2 to our result + // structure + integer_bytes = integer_bytes + *field_byte_width + + padding; // Increase the consumed bytes. + use_r2 = true; + } else { + // There isn't enough space left in r2 for this field, so this + // will be in r3. + integer_bytes = integer_bytes + *field_byte_width + + padding; // Increase the consumed bytes. + use_r3 = true; + } + } + // We already have consumed at-least 8 bytes that means r2 is done, + // and this field will be in r3. Check if this field can fit in r3. + else if (integer_bytes + *field_byte_width + padding <= 16) { + integer_bytes = integer_bytes + *field_byte_width + padding; + use_r3 = true; + } else { + // There isn't any space left for this field, this should not + // happen as we have already checked the overall size is not + // greater than 16 bytes. For now, return a nullptr return value + // object. + return return_valobj_sp; + } + } + } + // Vector types up to 16 bytes are returned in GP return registers + if (type_flags & eTypeIsVector) { + if (*byte_size <= 8) + use_r2 = true; + else { + use_r2 = true; + use_r3 = true; + } + } + if (use_r2) { + reg_ctx->ReadRegister(r0_info, r2_value); + + const size_t bytes_copied = r2_value.GetAsMemoryData( + *r0_info, data_sp->GetBytes(), r0_info->byte_size, target_byte_order, + error); + if (bytes_copied != r0_info->byte_size) + return return_valobj_sp; + sucess = true; + } +#if 0 + if (use_r3) { + reg_ctx->ReadRegister(r3_info, r3_value); + const size_t bytes_copied = r3_value.GetAsMemoryData( + r3_info, data_sp->GetBytes() + r0_info->byte_size, + r3_info->byte_size, target_byte_order, error); + + if (bytes_copied != r3_info->byte_size) + return return_valobj_sp; + sucess = true; + } +#endif + if (sucess) { + // The result is in our data buffer. Create a variable object out of + // it + return_valobj_sp = ValueObjectConstResult::Create( + &thread, return_compiler_type, ConstString(""), return_ext); + } + return return_valobj_sp; + } + uint64_t mem_address = reg_ctx->ReadRegisterAsUnsigned( + reg_ctx->GetRegisterInfoByName("r0", 0), 0); + + // We have got the address. Create a memory object out of it + return_valobj_sp = ValueObjectMemory::Create( + &thread, "", Address(mem_address, nullptr), return_compiler_type); + } + + return return_valobj_sp; +} + +#endif +#if 0 +ValueObjectSP ABISysV_sw_64::GetReturnValueObjectImpl( + Thread &thread, CompilerType &return_compiler_type) const { + ValueObjectSP return_valobj_sp; + Value value; + Status error; + + ExecutionContext exe_ctx(thread.shared_from_this()); + if (exe_ctx.GetTargetPtr() == nullptr || exe_ctx.GetProcessPtr() == nullptr) + return return_valobj_sp; + + value.SetCompilerType(return_compiler_type); + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return return_valobj_sp; + + Target *target = exe_ctx.GetTargetPtr(); + const ArchSpec target_arch = target->GetArchitecture(); + ByteOrder target_byte_order = target_arch.GetByteOrder(); + llvm::Optional byte_size = + return_compiler_type.GetByteSize(&thread); + if (!byte_size) + return return_valobj_sp; + const uint32_t type_flags = return_compiler_type.GetTypeInfo(nullptr); + uint32_t fp_flag = + target_arch.GetFlags() & lldb_private::ArchSpec::eMIPS_ABI_FP_mask; + + const RegisterInfo *r2_info = reg_ctx->GetRegisterInfoByName("r2", 0); + const RegisterInfo *r3_info = reg_ctx->GetRegisterInfoByName("r3", 0); + + if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { + value.SetValueType(Value::ValueType::Scalar); + + bool success = false; + if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) { + // Extract the register context so we can read arguments from registers + // In MIPS register "r2" (v0) holds the integer function return values + + uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_info, 0); + + const bool is_signed = (type_flags & eTypeIsSigned) != 0; + switch (*byte_size) { + default: + break; + + case sizeof(uint64_t): + if (is_signed) + value.GetScalar() = (int64_t)(raw_value); + else + value.GetScalar() = (uint64_t)(raw_value); + success = true; + break; + + case sizeof(uint32_t): + if (is_signed) + value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); + else + value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); + success = true; + break; + + case sizeof(uint16_t): + if (is_signed) + value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); + else + value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); + success = true; + break; + + case sizeof(uint8_t): + if (is_signed) + value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); + else + value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); + success = true; + break; + } + } else if (type_flags & eTypeIsFloat) { + if (type_flags & eTypeIsComplex) { + // Don't handle complex yet. + } else if (IsSoftFloat(fp_flag)) { + uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_info, 0); + switch (*byte_size) { + case 4: + value.GetScalar() = *((float *)(&raw_value)); + success = true; + break; + case 8: + value.GetScalar() = *((double *)(&raw_value)); + success = true; + break; + case 16: + uint64_t result[2]; + if (target_byte_order == eByteOrderLittle) { + result[0] = raw_value; + result[1] = reg_ctx->ReadRegisterAsUnsigned(r3_info, 0); + value.GetScalar() = *((long double *)(result)); + } else { + result[0] = reg_ctx->ReadRegisterAsUnsigned(r3_info, 0); + result[1] = raw_value; + value.GetScalar() = *((long double *)(result)); + } + success = true; + break; + } + + } else { + if (*byte_size <= sizeof(long double)) { + const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); + + RegisterValue f0_value; + DataExtractor f0_data; + + reg_ctx->ReadRegister(f0_info, f0_value); + + f0_value.GetData(f0_data); + + lldb::offset_t offset = 0; + if (*byte_size == sizeof(float)) { + value.GetScalar() = (float)f0_data.GetFloat(&offset); + success = true; + } else if (*byte_size == sizeof(double)) { + value.GetScalar() = (double)f0_data.GetDouble(&offset); + success = true; + } else if (*byte_size == sizeof(long double)) { + const RegisterInfo *f2_info = + reg_ctx->GetRegisterInfoByName("f2", 0); + RegisterValue f2_value; + DataExtractor f2_data; + reg_ctx->ReadRegister(f2_info, f2_value); + DataExtractor *copy_from_extractor = nullptr; + DataBufferSP data_sp(new DataBufferHeap(16, 0)); + DataExtractor return_ext( + data_sp, target_byte_order, + target->GetArchitecture().GetAddressByteSize()); + + if (target_byte_order == eByteOrderLittle) { + copy_from_extractor = &f0_data; + copy_from_extractor->CopyByteOrderedData( + 0, 8, data_sp->GetBytes(), *byte_size - 8, target_byte_order); + f2_value.GetData(f2_data); + copy_from_extractor = &f2_data; + copy_from_extractor->CopyByteOrderedData( + 0, 8, data_sp->GetBytes() + 8, *byte_size - 8, + target_byte_order); + } else { + copy_from_extractor = &f0_data; + copy_from_extractor->CopyByteOrderedData( + 0, 8, data_sp->GetBytes() + 8, *byte_size - 8, + target_byte_order); + f2_value.GetData(f2_data); + copy_from_extractor = &f2_data; + copy_from_extractor->CopyByteOrderedData( + 0, 8, data_sp->GetBytes(), *byte_size - 8, target_byte_order); + } + + return_valobj_sp = ValueObjectConstResult::Create( + &thread, return_compiler_type, ConstString(""), return_ext); + return return_valobj_sp; + } + } + } + } + + if (success) + return_valobj_sp = ValueObjectConstResult::Create( + thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); + } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass || + type_flags & eTypeIsVector) { + // Any structure of up to 16 bytes in size is returned in the registers. + if (*byte_size <= 16) { + DataBufferSP data_sp(new DataBufferHeap(16, 0)); + DataExtractor return_ext(data_sp, target_byte_order, + target->GetArchitecture().GetAddressByteSize()); + + RegisterValue r2_value, r3_value, f0_value, f1_value, f2_value; + // Tracks how much bytes of r2 and r3 registers we've consumed so far + uint32_t integer_bytes = 0; + + // True if return values are in FP return registers. + bool use_fp_regs = false; + // True if we found any non floating point field in structure. + bool found_non_fp_field = false; + // True if return values are in r2 register. + bool use_r2 = false; + // True if return values are in r3 register. + bool use_r3 = false; + // True if the result is copied into our data buffer + bool sucess = false; + std::string name; + bool is_complex; + uint32_t count; + const uint32_t num_children = return_compiler_type.GetNumFields(); + + // A structure consisting of one or two FP values (and nothing else) will + // be returned in the two FP return-value registers i.e fp0 and fp2. + if (num_children <= 2) { + uint64_t field_bit_offset = 0; + + // Check if this structure contains only floating point fields + for (uint32_t idx = 0; idx < num_children; idx++) { + CompilerType field_compiler_type = + return_compiler_type.GetFieldAtIndex(idx, name, &field_bit_offset, + nullptr, nullptr); + + if (field_compiler_type.IsFloatingPointType(count, is_complex)) + use_fp_regs = true; + else + found_non_fp_field = true; + } + + if (use_fp_regs && !found_non_fp_field) { + // We have one or two FP-only values in this structure. Get it from + // f0/f2 registers. + DataExtractor f0_data, f1_data, f2_data; + const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); + const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0); + const RegisterInfo *f2_info = reg_ctx->GetRegisterInfoByName("f2", 0); + + reg_ctx->ReadRegister(f0_info, f0_value); + reg_ctx->ReadRegister(f2_info, f2_value); + + f0_value.GetData(f0_data); + + for (uint32_t idx = 0; idx < num_children; idx++) { + CompilerType field_compiler_type = + return_compiler_type.GetFieldAtIndex( + idx, name, &field_bit_offset, nullptr, nullptr); + std::optional field_byte_width = + field_compiler_type.GetByteSize(&thread); + if (!field_byte_width) + return return_valobj_sp; + + DataExtractor *copy_from_extractor = nullptr; + uint64_t return_value[2]; + offset_t offset = 0; + + if (idx == 0) { + // This case is for long double type. + if (*field_byte_width == 16) { + + // If structure contains long double type, then it is returned + // in fp0/fp1 registers. + if (target_byte_order == eByteOrderLittle) { + return_value[0] = f0_data.GetU64(&offset); + reg_ctx->ReadRegister(f1_info, f1_value); + f1_value.GetData(f1_data); + offset = 0; + return_value[1] = f1_data.GetU64(&offset); + } else { + return_value[1] = f0_data.GetU64(&offset); + reg_ctx->ReadRegister(f1_info, f1_value); + f1_value.GetData(f1_data); + offset = 0; + return_value[0] = f1_data.GetU64(&offset); + } + + f0_data.SetData(return_value, *field_byte_width, + target_byte_order); + } + copy_from_extractor = &f0_data; // This is in f0, copy from + // register to our result + // structure + } else { + f2_value.GetData(f2_data); + // This is in f2, copy from register to our result structure + copy_from_extractor = &f2_data; + } + + // Sanity check to avoid crash + if (!copy_from_extractor || + *field_byte_width > copy_from_extractor->GetByteSize()) + return return_valobj_sp; + + // copy the register contents into our data buffer + copy_from_extractor->CopyByteOrderedData( + 0, *field_byte_width, + data_sp->GetBytes() + (field_bit_offset / 8), *field_byte_width, + target_byte_order); + } + + // The result is in our data buffer. Create a variable object out of + // it + return_valobj_sp = ValueObjectConstResult::Create( + &thread, return_compiler_type, ConstString(""), return_ext); + + return return_valobj_sp; + } + } + + // If we reach here, it means this structure either contains more than + // two fields or it contains at least one non floating point type. In + // that case, all fields are returned in GP return registers. + for (uint32_t idx = 0; idx < num_children; idx++) { + uint64_t field_bit_offset = 0; + bool is_signed; + uint32_t padding; + + CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex( + idx, name, &field_bit_offset, nullptr, nullptr); + std::optional field_byte_width = + field_compiler_type.GetByteSize(&thread); + + // if we don't know the size of the field (e.g. invalid type), just + // bail out + if (!field_byte_width || *field_byte_width == 0) + break; + + uint32_t field_byte_offset = field_bit_offset / 8; + + if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) || + field_compiler_type.IsPointerType() || + field_compiler_type.IsFloatingPointType(count, is_complex)) { + padding = field_byte_offset - integer_bytes; + + if (integer_bytes < 8) { + // We have not yet consumed r2 completely. + if (integer_bytes + *field_byte_width + padding <= 8) { + // This field fits in r2, copy its value from r2 to our result + // structure + integer_bytes = integer_bytes + *field_byte_width + + padding; // Increase the consumed bytes. + use_r2 = true; + } else { + // There isn't enough space left in r2 for this field, so this + // will be in r3. + integer_bytes = integer_bytes + *field_byte_width + + padding; // Increase the consumed bytes. + use_r3 = true; + } + } + // We already have consumed at-least 8 bytes that means r2 is done, + // and this field will be in r3. Check if this field can fit in r3. + else if (integer_bytes + *field_byte_width + padding <= 16) { + integer_bytes = integer_bytes + *field_byte_width + padding; + use_r3 = true; + } else { + // There isn't any space left for this field, this should not + // happen as we have already checked the overall size is not + // greater than 16 bytes. For now, return a nullptr return value + // object. + return return_valobj_sp; + } + } + } + // Vector types up to 16 bytes are returned in GP return registers + if (type_flags & eTypeIsVector) { + if (*byte_size <= 8) + use_r2 = true; + else { + use_r2 = true; + use_r3 = true; + } + } + + if (use_r2) { + reg_ctx->ReadRegister(r2_info, r2_value); + + const size_t bytes_copied = r2_value.GetAsMemoryData( + *r2_info, data_sp->GetBytes(), r2_info->byte_size, target_byte_order, + error); + if (bytes_copied != r2_info->byte_size) + return return_valobj_sp; + sucess = true; + } + if (use_r3) { + reg_ctx->ReadRegister(r3_info, r3_value); + const size_t bytes_copied = r3_value.GetAsMemoryData( + *r3_info, data_sp->GetBytes() + r2_info->byte_size, + r3_info->byte_size, target_byte_order, error); + + if (bytes_copied != r3_info->byte_size) + return return_valobj_sp; + sucess = true; + } + if (sucess) { + // The result is in our data buffer. Create a variable object out of + // it + return_valobj_sp = ValueObjectConstResult::Create( + &thread, return_compiler_type, ConstString(""), return_ext); + } + return return_valobj_sp; + } + + // Any structure/vector greater than 16 bytes in size is returned in + // memory. The pointer to that memory is returned in r2. + uint64_t mem_address = reg_ctx->ReadRegisterAsUnsigned( + reg_ctx->GetRegisterInfoByName("r2", 0), 0); + + // We have got the address. Create a memory object out of it + return_valobj_sp = ValueObjectMemory::Create( + &thread, "", Address(mem_address, nullptr), return_compiler_type); + } + return return_valobj_sp; +} +#endif + +bool ABISysV_sw_64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { + unwind_plan.Clear(); + unwind_plan.SetRegisterKind(eRegisterKindDWARF); + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + // Our Call Frame Address is the stack pointer value + row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r30, 0); + + // The previous PC is in the RA + row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r26, true); + unwind_plan.AppendRow(row); + + // All other registers are the same. + + unwind_plan.SetSourceName("sw_64 at-func-entry default"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + unwind_plan.SetReturnAddressRegister(dwarf_r26); + return true; +} + +bool ABISysV_sw_64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { + unwind_plan.Clear(); + unwind_plan.SetRegisterKind(eRegisterKindDWARF); + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + row->SetUnspecifiedRegistersAreUndefined(true); + row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r30, 0); + + row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r26, true); + + unwind_plan.AppendRow(row); + unwind_plan.SetSourceName("sw_64 default unwind plan"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); + return true; +} + +bool ABISysV_sw_64::RegisterIsVolatile(const RegisterInfo *reg_info) { + return !RegisterIsCalleeSaved(reg_info); +} + +bool ABISysV_sw_64::IsSoftFloat(uint32_t fp_flag) const { + //return (fp_flag == lldb_private::ArchSpec::eMIPS_ABI_FP_SOFT); + return false; +} + +bool ABISysV_sw_64::RegisterIsCalleeSaved(const RegisterInfo *reg_info) { + if (reg_info) { + // Preserved registers are : + // r16-r23, r28, r29, r30, r31 +#if 0 + int reg = ((reg_info->byte_offset) / 8); + + bool save = (reg >= 16) && (reg <= 23); + save |= (reg >= 28) && (reg <= 31); +#endif + int reg = ((reg_info->byte_offset) / 8); + + bool save = (reg >= 9) && (reg <= 14); + save |= (reg == 15) || (reg == 26); + save |= (reg >= 29) && (reg <= 30); + + return save; + } + return false; +} + +void ABISysV_sw_64::Initialize() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), "System V ABI for sw_64 targets", CreateInstance); +} + +void ABISysV_sw_64::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +//lldb_private::ConstString ABISysV_sw_64::GetPluginNameStatic() { +// static ConstString g_name("sysv-sw_64"); +// return g_name; +//} +// +//// PluginInterface protocol +// +//lldb_private::ConstString ABISysV_sw_64::GetPluginName() { +// return GetPluginNameStatic(); +//} +// +//uint32_t ABISysV_sw_64::GetPluginVersion() { return 1; } diff --git a/lldb/source/Plugins/ABI/Sw64/ABISysV_sw_64.h b/lldb/source/Plugins/ABI/Sw64/ABISysV_sw_64.h new file mode 100755 index 000000000000..db353f8948a5 --- /dev/null +++ b/lldb/source/Plugins/ABI/Sw64/ABISysV_sw_64.h @@ -0,0 +1,104 @@ +//===-- ABISysV_sw_64.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_SOURCE_PLUGINS_ABI_SW64_ABISYSV_SW64_H +#define LLDB_SOURCE_PLUGINS_ABI_SW64_ABISYSV_SW64_H + +#include "lldb/Target/ABI.h" +#include "lldb/lldb-private.h" + +class ABISysV_sw_64 : public lldb_private::RegInfoBasedABI { +public: + ~ABISysV_sw_64() override = default; + + size_t GetRedZoneSize() const override; + + bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const override; + + bool GetArgumentValues(lldb_private::Thread &thread, + lldb_private::ValueList &values) const override; + + lldb_private::Status + SetReturnValueObject(lldb::StackFrameSP &frame_sp, + lldb::ValueObjectSP &new_value) override; + + lldb::ValueObjectSP + GetReturnValueObjectImpl(lldb_private::Thread &thread, + lldb_private::CompilerType &type) const override; + + bool + CreateFunctionEntryUnwindPlan(lldb_private::UnwindPlan &unwind_plan) override; + + bool CreateDefaultUnwindPlan(lldb_private::UnwindPlan &unwind_plan) override; + + bool RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override; + + bool IsSoftFloat(uint32_t fp_flag) const; + + // The SysV mips ABI requires that stack frames be 16 byte aligned. + // When there is a trap handler on the stack, e.g. _sigtramp in userland + // code, we've seen that the stack pointer is often not aligned properly + // before the handler is invoked. This means that lldb will stop the unwind + // early -- before the function which caused the trap. + // + // To work around this, we relax that alignment to be just word-size + // (8-bytes). + // Allowing the trap handlers for user space would be easy (_sigtramp) but + // in other environments there can be a large number of different functions + // involved in async traps. + bool CallFrameAddressIsValid(lldb::addr_t cfa) override { + // Make sure the stack call frame addresses are 8 byte aligned + if (cfa & (8ull - 1ull)) + return false; // Not 8 byte aligned + if (cfa == 0) + return false; // Zero is not a valid stack address + return true; + } + + bool CodeAddressIsValid(lldb::addr_t pc) override { + if (pc & (4ull - 1ull)) + return false; // Not 4 byte aligned + + // Anything else if fair game.. + return true; + } + + const lldb_private::RegisterInfo * + GetRegisterInfoArray(uint32_t &count) override; + + // Static Functions + + static void Initialize(); + + static void Terminate(); + + static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch); + + static llvm::StringRef GetPluginNameStatic() { return "sysv-sw_64"; } + + // PluginInterface protocol + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + +protected: + void CreateRegisterMapIfNeeded(); + + lldb::ValueObjectSP + GetReturnValueObjectSimple(lldb_private::Thread &thread, + lldb_private::CompilerType &ast_type) const; + + bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info); + +private: + using lldb_private::RegInfoBasedABI::RegInfoBasedABI; // Call CreateInstance instead. +}; + +#endif // LLDB_SOURCE_PLUGINS_ABI_SW64_ABISYSV_SW64_H diff --git a/lldb/source/Plugins/ABI/Sw64/CMakeLists.txt b/lldb/source/Plugins/ABI/Sw64/CMakeLists.txt new file mode 100755 index 000000000000..1f9bb25219b5 --- /dev/null +++ b/lldb/source/Plugins/ABI/Sw64/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginABISw64 PLUGIN + ABISw64.cpp + ABISysV_sw_64.cpp + ABISysV_sw_64.cpp + + LINK_LIBS + lldbCore + lldbSymbol + lldbTarget + LINK_COMPONENTS + Support + TargetParser + ) diff --git a/lldb/source/Plugins/Architecture/CMakeLists.txt b/lldb/source/Plugins/Architecture/CMakeLists.txt index 9ed8edf70af3..81473d7c6a86 100644 --- a/lldb/source/Plugins/Architecture/CMakeLists.txt +++ b/lldb/source/Plugins/Architecture/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(Arm) add_subdirectory(Mips) add_subdirectory(PPC64) add_subdirectory(AArch64) +add_subdirectory(Sw64) diff --git a/lldb/source/Plugins/Architecture/Sw64/ArchitectureSw64.cpp b/lldb/source/Plugins/Architecture/Sw64/ArchitectureSw64.cpp new file mode 100755 index 000000000000..89ba4b2549f1 --- /dev/null +++ b/lldb/source/Plugins/Architecture/Sw64/ArchitectureSw64.cpp @@ -0,0 +1,234 @@ +//===-- ArchitectureSw64.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 "Plugins/Architecture/Sw64/ArchitectureSw64.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Target/Target.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/Disassembler.h" +#include "lldb/Core/Module.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" + +using namespace lldb_private; +using namespace lldb; + +LLDB_PLUGIN_DEFINE(ArchitectureSw64) + +void ArchitectureSw64::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "Sw64-specific algorithms", + &ArchitectureSw64::Create); +} + +void ArchitectureSw64::Terminate() { + PluginManager::UnregisterPlugin(&ArchitectureSw64::Create); +} + +std::unique_ptr ArchitectureSw64::Create(const ArchSpec &arch) { + return arch.IsSw64() ? + std::unique_ptr(new ArchitectureSw64()) : nullptr; +} + +#if 0 +addr_t ArchitectureSw64::GetCallableLoadAddress(addr_t code_addr, + AddressClass addr_class) const { + bool is_alternate_isa = false; + + switch (addr_class) { + case AddressClass::eData: + case AddressClass::eDebug: + return LLDB_INVALID_ADDRESS; + case AddressClass::eCodeAlternateISA: + is_alternate_isa = true; + break; + default: break; + } + + if ((code_addr & 2ull) || is_alternate_isa) + return code_addr | 1u; + return code_addr; +} + +addr_t ArchitectureSw64::GetOpcodeLoadAddress(addr_t opcode_addr, + AddressClass addr_class) const { + switch (addr_class) { + case AddressClass::eData: + case AddressClass::eDebug: + return LLDB_INVALID_ADDRESS; + default: break; + } + return opcode_addr & ~(1ull); +} + +lldb::addr_t ArchitectureSw64::GetBreakableLoadAddress(lldb::addr_t addr, + Target &target) const { + + Log *log = GetLog(LLDBLog::Breakpoints); + + Address resolved_addr; + + SectionLoadList §ion_load_list = target.GetSectionLoadList(); + if (section_load_list.IsEmpty()) + // No sections are loaded, so we must assume we are not running yet and + // need to operate only on file address. + target.ResolveFileAddress(addr, resolved_addr); + else + target.ResolveLoadAddress(addr, resolved_addr); + + addr_t current_offset = 0; + + // Get the function boundaries to make sure we don't scan back before the + // beginning of the current function. + ModuleSP temp_addr_module_sp(resolved_addr.GetModule()); + if (temp_addr_module_sp) { + SymbolContext sc; + SymbolContextItem resolve_scope = + eSymbolContextFunction | eSymbolContextSymbol; + temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr, + resolve_scope, sc); + Address sym_addr; + if (sc.function) + sym_addr = sc.function->GetAddressRange().GetBaseAddress(); + else if (sc.symbol) + sym_addr = sc.symbol->GetAddress(); + + addr_t function_start = sym_addr.GetLoadAddress(&target); + if (function_start == LLDB_INVALID_ADDRESS) + function_start = sym_addr.GetFileAddress(); + + if (function_start) + current_offset = addr - function_start; + } + + // If breakpoint address is start of function then we dont have to do + // anything. + if (current_offset == 0) + return addr; + + auto insn = GetInstructionAtAddress(target, current_offset, addr); + + if (nullptr == insn || !insn->HasDelaySlot()) + return addr; + + // Adjust the breakable address + uint64_t breakable_addr = addr - insn->GetOpcode().GetByteSize(); + LLDB_LOGF(log, + "Target::%s Breakpoint at 0x%8.8" PRIx64 + " is adjusted to 0x%8.8" PRIx64 " due to delay slot\n", + __FUNCTION__, addr, breakable_addr); + + return breakable_addr; +} + +Instruction *ArchitectureSw64::GetInstructionAtAddress( + Target &target, const Address &resolved_addr, addr_t symbol_offset) const { + + auto loop_count = symbol_offset / 2; + +// uint32_t arch_flags = m_arch.GetFlags(); +// bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16; +// bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips; + + if (loop_count > 3) { + // Scan previous 6 bytes +// if (IsMips16 | IsMicromips) +// loop_count = 3; +// // For mips-only, instructions are always 4 bytes, so scan previous 4 +// // bytes only. +// else + loop_count = 2; + } + + // Create Disassembler Instance + lldb::DisassemblerSP disasm_sp( + Disassembler::FindPlugin(m_arch, nullptr, nullptr)); + + InstructionList instruction_list; + InstructionSP prev_insn; + uint32_t inst_to_choose = 0; + + Address addr = resolved_addr; + + for (uint32_t i = 1; i <= loop_count; i++) { + // Adjust the address to read from. + addr.Slide(-2); + uint32_t insn_size = 0; + + disasm_sp->ParseInstructions(target, addr, + {Disassembler::Limit::Bytes, i * 2}, nullptr); + + uint32_t num_insns = disasm_sp->GetInstructionList().GetSize(); + if (num_insns) { + prev_insn = disasm_sp->GetInstructionList().GetInstructionAtIndex(0); + insn_size = prev_insn->GetOpcode().GetByteSize(); + if (i == 1 && insn_size == 2) { + // This looks like a valid 2-byte instruction (but it could be a part + // of upper 4 byte instruction). + instruction_list.Append(prev_insn); + inst_to_choose = 1; + } + else if (i == 2) { + // Here we may get one 4-byte instruction or two 2-byte instructions. + if (num_insns == 2) { + // Looks like there are two 2-byte instructions above our + // breakpoint target address. Now the upper 2-byte instruction is + // either a valid 2-byte instruction or could be a part of it's + // upper 4-byte instruction. In both cases we don't care because in + // this case lower 2-byte instruction is definitely a valid + // instruction and whatever i=1 iteration has found out is true. + inst_to_choose = 1; + break; + } + else if (insn_size == 4) { + // This instruction claims its a valid 4-byte instruction. But it + // could be a part of it's upper 4-byte instruction. Lets try + // scanning upper 2 bytes to verify this. + instruction_list.Append(prev_insn); + inst_to_choose = 2; + } + } + else if (i == 3) { + if (insn_size == 4) + // FIXME: We reached here that means instruction at [target - 4] has + // already claimed to be a 4-byte instruction, and now instruction + // at [target - 6] is also claiming that it's a 4-byte instruction. + // This can not be true. In this case we can not decide the valid + // previous instruction so we let lldb set the breakpoint at the + // address given by user. + inst_to_choose = 0; + else + // This is straight-forward + inst_to_choose = 2; + break; + } + } + else { + // Decode failed, bytes do not form a valid instruction. So whatever + // previous iteration has found out is true. + if (i > 1) { + inst_to_choose = i - 1; + break; + } + } + } + + // Check if we are able to find any valid instruction. + if (inst_to_choose) { + if (inst_to_choose > instruction_list.GetSize()) + inst_to_choose--; + return instruction_list.GetInstructionAtIndex(inst_to_choose - 1).get(); + } + + return nullptr; +} +#endif diff --git a/lldb/source/Plugins/Architecture/Sw64/ArchitectureSw64.h b/lldb/source/Plugins/Architecture/Sw64/ArchitectureSw64.h new file mode 100755 index 000000000000..790a90d92ae8 --- /dev/null +++ b/lldb/source/Plugins/Architecture/Sw64/ArchitectureSw64.h @@ -0,0 +1,53 @@ +//===-- ArchitectureSw64.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_SOURCE_PLUGINS_ARCHITECTURE_SW64_ARCHITECTURESW64_H +#define LLDB_SOURCE_PLUGINS_ARCHITECTURE_SW64_ARCHITECTURESW64_H + +#include "lldb/Core/Architecture.h" +#include "lldb/Utility/ArchSpec.h" + +namespace lldb_private { + +class ArchitectureSw64 : public Architecture { +public: + static llvm::StringRef GetPluginNameStatic() { return "sw_64"; } + static void Initialize(); + static void Terminate(); + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + void OverrideStopInfo(Thread &thread) const override {} + +// lldb::addr_t GetBreakableLoadAddress(lldb::addr_t addr, +// Target &) const override; +// +// lldb::addr_t GetCallableLoadAddress(lldb::addr_t load_addr, +// AddressClass addr_class) const override; +// +// lldb::addr_t GetOpcodeLoadAddress(lldb::addr_t load_addr, +// AddressClass addr_class) const override; + +//private: +// Instruction *GetInstructionAtAddress(Target &target, +// const Address &resolved_addr, +// lldb::addr_t symbol_offset) const; +// +// static std::unique_ptr Create(const ArchSpec &arch); +// ArchitectureSw64(const ArchSpec &arch) : m_arch(arch) {} +// +// ArchSpec m_arch; + +private: + static std::unique_ptr Create(const ArchSpec &arch); + ArchitectureSw64() = default; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_ARCHITECTURE_SW64_ARCHITECTURESW64_H diff --git a/lldb/source/Plugins/Architecture/Sw64/CMakeLists.txt b/lldb/source/Plugins/Architecture/Sw64/CMakeLists.txt new file mode 100755 index 000000000000..79f83b0aae32 --- /dev/null +++ b/lldb/source/Plugins/Architecture/Sw64/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_library(lldbPluginArchitectureSw64 PLUGIN + ArchitectureSw64.cpp + + LINK_LIBS + lldbCore + lldbTarget + lldbUtility + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp index 09115cc670da..7690d36e786c 100644 --- a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp +++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp @@ -1496,6 +1496,11 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, case ArchSpec::eCore_mips64r6el: cpu = "mips64r6"; break; +#ifndef LHX20240725 + case ArchSpec::eCore_sw_64: + cpu = "sw_64"; + break; +#endif default: cpu = ""; break; diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp index b0afe0394622..bd895df42c83 100644 --- a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp +++ b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp @@ -70,6 +70,9 @@ llvm::Triple::ArchType stringTo(llvm::StringRef Str) { return llvm::StringSwitch(Str) .Case("arm", Triple::arm) .Cases("arm64", "arm64e", Triple::aarch64) +#ifndef LHX20240718 + .Case("sw_64", Triple::sw_64) +#endif .Case("mips", Triple::mips) .Case("msp430", Triple::msp430) .Case("ppc", Triple::ppc) diff --git a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp index a6e385f70709..de189f956267 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp @@ -202,6 +202,11 @@ unsigned ELFHeader::GetRelocationJumpSlotType() const { case EM_AARCH64: slot = R_AARCH64_JUMP_SLOT; break; +#ifndef LHX20240718 + case EM_SW64: + slot = R_SW_64_JMP_SLOT; + break; +#endif case EM_MIPS: slot = R_MIPS_JUMP_SLOT; break; diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 700af84a14c0..068eacdc73ad 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -338,6 +338,10 @@ static uint32_t subTypeFromElfHeader(const elf::ELFHeader &header) { return mipsVariantFromElfFlags(header); else if (header.e_machine == llvm::ELF::EM_PPC64) return ppc64VariantFromElfFlags(header); +#ifndef LHX20240718 + else if (header.e_machine == llvm::ELF::EM_SW64) + return ArchSpec::eSW64SubType_sw_64; +#endif else if (header.e_machine == llvm::ELF::EM_RISCV) return riscvVariantFromElfFlags(header); else if (header.e_machine == llvm::ELF::EM_LOONGARCH) @@ -1176,6 +1180,12 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, arch_spec.GetTriple().getOS() == llvm::Triple::OSType::UnknownOS) // The note.n_name == LLDB_NT_OWNER_GNU is valid for Linux platform arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); +#ifndef LHX20240725 + if (arch_spec.IsSw64() && + arch_spec.GetTriple().getOS() == llvm::Triple::OSType::UnknownOS) + // The note.n_name == LLDB_NT_OWNER_GNU is valid for Linux platform + arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); +#endif } // Process NetBSD ELF executables and shared libraries else if ((note.n_name == LLDB_NT_OWNER_NETBSD) && @@ -1273,6 +1283,11 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, // In case of MIPSR6, the LLDB_NT_OWNER_GNU note is missing for some // cases (e.g. compile with -nostdlib) Hence set OS to Linux arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); +#ifndef LHX20240725 + if (arch_spec.IsSw64() && + arch_spec.GetTriple().getOS() == llvm::Triple::OSType::UnknownOS) + arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); +#endif } } diff --git a/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp b/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp index 149f541a5d3d..3a9ea3677ec1 100644 --- a/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp +++ b/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp @@ -31,7 +31,11 @@ // Define these constants from Linux mman.h for use when targeting remote linux // systems even when host has different values. #define MAP_PRIVATE 2 +#ifdef __sw_64__ +#define MAP_ANON 0x10 +#else #define MAP_ANON 0x20 +#endif using namespace lldb; using namespace lldb_private; @@ -123,7 +127,7 @@ PlatformLinux::PlatformLinux(bool is_host) {llvm::Triple::x86_64, llvm::Triple::x86, llvm::Triple::arm, llvm::Triple::aarch64, llvm::Triple::mips64, llvm::Triple::mips64, llvm::Triple::hexagon, llvm::Triple::mips, llvm::Triple::mips64el, - llvm::Triple::mipsel, llvm::Triple::msp430, llvm::Triple::systemz}, + llvm::Triple::mipsel, llvm::Triple::msp430, llvm::Triple::sw_64, llvm::Triple::systemz}, llvm::Triple::Linux); } } diff --git a/lldb/source/Plugins/Process/Linux/CMakeLists.txt b/lldb/source/Plugins/Process/Linux/CMakeLists.txt index 708252f887bd..4a34d8ac8b86 100644 --- a/lldb/source/Plugins/Process/Linux/CMakeLists.txt +++ b/lldb/source/Plugins/Process/Linux/CMakeLists.txt @@ -8,6 +8,7 @@ add_lldb_library(lldbPluginProcessLinux NativeRegisterContextLinux.cpp NativeRegisterContextLinux_arm.cpp NativeRegisterContextLinux_arm64.cpp + NativeRegisterContextLinux_sw_64.cpp NativeRegisterContextLinux_loongarch64.cpp NativeRegisterContextLinux_ppc64le.cpp NativeRegisterContextLinux_riscv64.cpp diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_sw_64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_sw_64.cpp new file mode 100755 index 000000000000..56205c8f93da --- /dev/null +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_sw_64.cpp @@ -0,0 +1,815 @@ +//===-- NativeRegisterContextLinux_sw_64.cpp ---------------*- 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(__sw_64__) + +#include "NativeRegisterContextLinux_sw_64.h" + + +#include "Plugins/Process/Linux/NativeProcessLinux.h" +#include "Plugins/Process/Linux/Procfs.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "Plugins/Process/Utility/RegisterContextLinux_sw_64.h" +#include "lldb/Core/EmulateInstruction.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-private-enumerations.h" + +#define NUM_REGISTERS 32 + +#include +#include + +// refer to linux-stable-sw/arch/sw_64/include/uapi/asm/ptrace.h +#define DA_MATCH 163 +#define DA_MASK 164 +#define DV_MATCH 165 +#define DV_MASK 166 +#define DC_CTL 167 +#define MATCH_CTL 167 + +using namespace lldb_private; +using namespace lldb_private::process_linux; + +std::unique_ptr +NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( + //const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + const ArchSpec &target_arch, NativeThreadLinux &native_thread) { + switch (target_arch.GetMachine()) { + case llvm::Triple::sw_64: + return std::make_unique(target_arch, + native_thread); + default: + llvm_unreachable("have no register context for architecture"); + } +} + +llvm::Expected +NativeRegisterContextLinux::DetermineArchitecture(lldb::tid_t tid) { + return HostInfo::GetArchitecture(); +} + +#define REG_CONTEXT_SIZE \ + (GetRegisterInfoInterface().GetGPRSize() + sizeof(FPR_linux_sw_64) + \ + sizeof(SIMD_linux_sw_64)) + +// NativeRegisterContextLinux_sw_64 members. + +static RegisterInfoInterface * +CreateRegisterInfoInterface(const ArchSpec &target_arch) { + assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && + "Register setting path assumes this is a 64-bit host"); + return new RegisterContextLinux_sw_64(target_arch); +// target_arch, NativeRegisterContextLinux_sw_64::IsSIMDAvailable()); +// target_arch); +} + +NativeRegisterContextLinux_sw_64::NativeRegisterContextLinux_sw_64( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) +// : NativeRegisterContextLinux(native_thread, CreateRegisterInfoInterface(target_arch)) { + : NativeRegisterContextRegisterInfo( + native_thread, CreateRegisterInfoInterface(target_arch)), + NativeRegisterContextLinux(native_thread) { + switch (target_arch.GetMachine()) { + case llvm::Triple::sw_64: + m_reg_info.num_registers = k_num_registers_sw_64; + m_reg_info.num_gpr_registers = k_num_gpr_registers_sw_64; + m_reg_info.num_fpr_registers = k_num_fpr_registers_sw_64; + m_reg_info.last_gpr = k_last_gpr_sw_64; + m_reg_info.first_fpr = k_first_fpr_sw_64; + m_reg_info.last_fpr = k_last_fpr_sw_64; + m_reg_info.first_simd = k_first_simd_sw_64; + m_reg_info.last_simd = k_last_simd_sw_64; + break; + default: + assert(false && "Unhandled target architecture."); + break; + } + + // Initialize m_iovec to point to the buffer and buffer size using the + // conventions of Berkeley style UIO structures, as required by PTRACE + // extensions. + m_iovec.iov_base = &m_simd; + m_iovec.iov_len = sizeof(SIMD_linux_sw_64); + + // init h/w watchpoint addr map +// for (int index = 0; index <= MAX_NUM_WP; index++) +// hw_addr_map[index] = LLDB_INVALID_ADDRESS; + + ::memset(&m_gpr, 0, sizeof(GPR_linux_sw_64)); + ::memset(&m_fpr, 0, sizeof(FPR_linux_sw_64)); + ::memset(&m_simd, 0, sizeof(SIMD_linux_sw_64)); + ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); + + m_max_hwp_supported = MAX_NUM_WP; + //m_refresh_hwdebug_info = true; +} + +uint32_t NativeRegisterContextLinux_sw_64::GetRegisterSetCount() const { + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::sw_64: { + const auto context = static_cast + (GetRegisterInfoInterface()); + return context.GetRegisterSetCount(); + } + default: + llvm_unreachable("Unhandled target architecture."); + } +} + +const RegisterSet * +NativeRegisterContextLinux_sw_64::GetRegisterSet(uint32_t set_index) const { + if (set_index >= GetRegisterSetCount()) + return nullptr; + + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::sw_64: { + const auto context = static_cast + (GetRegisterInfoInterface()); + return context.GetRegisterSet(set_index); + } + default: + llvm_unreachable("Unhandled target architecture."); + } +} + +lldb_private::Status +NativeRegisterContextLinux_sw_64::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + uint8_t byte_size = reg_info->byte_size; + if (reg == LLDB_INVALID_REGNUM) { + // This is likely an internal register for lldb use only and should not be + // directly queried. + error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " + "register, cannot read directly", + reg_info->name); + return error; + } + +// if (IsSIMD(reg) /*&& !IsSIMDAvailable()*/) { +// error.SetErrorString("SIMD not available on this processor"); +// printf("SIMD not available on this processor\n"); +// return error; +// } +#ifndef LHX20210820 // refer to x86 and arm64 + if (IsSIMD(reg)) { + error = ReadFPR(); + if (error.Fail()) + return error; + } else { + uint32_t full_reg = reg; + bool is_subreg = reg_info->invalidate_regs && + (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); + + if (is_subreg) { + // Read the full aligned 64-bit register. + full_reg = reg_info->invalidate_regs[0]; + } + + error = ReadRegisterRaw(full_reg, reg_value); + + if (error.Success()) { + // If our read was not aligned (for ah,bh,ch,dh), shift our returned + // value one byte to the right. + if (is_subreg && (reg_info->byte_offset & 0x1)) + reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8); + + // If our return byte size was greater than the return value reg size, + // then use the type specified by reg_info rather than the uint64_t + // default + if (reg_value.GetByteSize() > reg_info->byte_size) + reg_value.SetType(*reg_info); + } + return error; + } + // Get pointer to m_fpr variable and set the data from it. + uint8_t *src = (uint8_t *)reg_info->byte_offset - + (sizeof(m_gpr) + sizeof(m_fpr)); +// reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, +// eByteOrderLittle, error); + error = ReadRegisterRaw(reg, reg_value); + return error; +} +#endif + +lldb_private::Status NativeRegisterContextLinux_sw_64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + + assert(reg_info && "reg_info is null"); + + const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg_index == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + if (IsSIMD(reg_index)/* && !IsSIMDAvailable()*/) { + error.SetErrorString("SIMD not available on this processor"); + //printf("SIMD not available on this processor\n"); + return error; + } + + if (IsFPR(reg_index) || IsSIMD(reg_index)) { + uint8_t *dst = nullptr; + uint64_t *src = nullptr; + uint8_t byte_size = reg_info->byte_size; + lldbassert(reg_info->byte_offset < sizeof(UserArea_sw_64)); + + // Initialise the FP and SIMD buffers by reading all co-processor 1 + // registers + ReadCP1(); + + if (IsFPR(reg_index)) { + if (/*IsFR0() &&*/ (byte_size != 4)) { + byte_size = 4; + uint8_t ptrace_index; + ptrace_index = reg_info->kinds[lldb::eRegisterKindProcessPlugin]; + dst = ReturnFPOffset(ptrace_index, reg_info->byte_offset); + } else + dst = (uint8_t *)&m_fpr + reg_info->byte_offset - sizeof(m_gpr); + } else + dst =(uint8_t *)&m_simd + reg_info->byte_offset - + (sizeof(m_gpr) + sizeof(m_fpr)); + switch (byte_size) { + case 4: + *(uint32_t *)dst = reg_value.GetAsUInt32(); + break; + case 8: + *(uint64_t *)dst = reg_value.GetAsUInt64(); + break; + case 16: + src = (uint64_t *)reg_value.GetBytes(); + *(uint64_t *)dst = *src; + *(uint64_t *)(dst + 8) = *(src + 1); + break; + default: + assert(false && "Unhandled data size."); + error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32, + reg_info->byte_size); + break; + } + error = WriteCP1(); + if (!error.Success()) { + error.SetErrorString("failed to write co-processor 1 register"); + return error; + } + } else { + error = WriteRegisterRaw(reg_index, reg_value); + } + + error = WriteRegisterRaw(reg_index, reg_value); + return error; +} + +Status NativeRegisterContextLinux_sw_64::ReadAllRegisterValues( + lldb::WritableDataBufferSP &data_sp) { + Status error; + + data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); + error = ReadGPR(); + if (!error.Success()) { + error.SetErrorString("ReadGPR() failed"); + return error; + } + + error = ReadCP1(); + if (!error.Success()) { + error.SetErrorString("ReadCP1() failed"); + return error; + } + + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, &m_gpr, GetRegisterInfoInterface().GetGPRSize()); + dst += GetRegisterInfoInterface().GetGPRSize(); + + ::memcpy(dst, &m_fpr, GetFPRSize()); + dst += GetFPRSize(); + + ::memcpy(dst, &m_simd, sizeof(SIMD_linux_sw_64)); + + return error; +} + +Status NativeRegisterContextLinux_sw_64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_sw_64::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_sw_64::%s data_sp contained mismatched " + "data size, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); + return error; + } + + const uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextLinux_sw_64::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + + ::memcpy(&m_gpr, src, GetRegisterInfoInterface().GetGPRSize()); + src += GetRegisterInfoInterface().GetGPRSize(); + + ::memcpy(&m_fpr, src, GetFPRSize()); + src += GetFPRSize(); + + ::memcpy(&m_simd, src, sizeof(SIMD_linux_sw_64)); + + error = WriteGPR(); + if (!error.Success()) { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_sw_64::%s WriteGPR() failed", + __FUNCTION__); + return error; + } + + error = WriteCP1(); + if (!error.Success()) { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_sw_64::%s WriteCP1() failed", + __FUNCTION__); + return error; + } + + return error; +} + +Status NativeRegisterContextLinux_sw_64::ReadCP1() { + Status error; + + uint8_t *src = nullptr; + uint8_t *dst = nullptr; + + lldb::ByteOrder byte_order = GetByteOrder(); + + bool IsBigEndian = (byte_order == lldb::eByteOrderBig); +/* + if (IsSIMDAvailable()) { + error = NativeRegisterContextLinux::ReadRegisterSet( + &m_iovec, sizeof(SIMD_linux_sw_64), NFPREG); + src = (uint8_t *)&m_simd + (IsBigEndian * 8); + dst = (uint8_t *)&m_fpr; + for (int i = 0; i < NUM_REGISTERS; i++) { + // Copy fp values from simd buffer fetched via ptrace + *(uint64_t *)dst = *(uint64_t *)src; + src = src + 16; + dst = dst + 8; + } +// m_fpr.fir = m_simd.fir; +// m_fpr.fcsr = m_simd.fcsr; +// m_fpr.config5 = m_simd.config5; + } else { + error = NativeRegisterContextLinux::ReadFPR(); + } +*/ + error = NativeRegisterContextLinux::ReadFPR(); + return error; +} + +uint8_t * +NativeRegisterContextLinux_sw_64::ReturnFPOffset(uint8_t reg_index, + uint32_t byte_offset) { + + uint8_t *fp_buffer_ptr = nullptr; + lldb::ByteOrder byte_order = GetByteOrder(); + bool IsBigEndian = (byte_order == lldb::eByteOrderBig); + if (reg_index % 2) { + uint8_t offset_diff = (IsBigEndian) ? 8 : 4; + fp_buffer_ptr = + (uint8_t *)&m_fpr + byte_offset - offset_diff - sizeof(m_gpr); + } else { + fp_buffer_ptr = + (uint8_t *)&m_fpr + byte_offset + 4 * (IsBigEndian) - sizeof(m_gpr); + } + return fp_buffer_ptr; +} + +Status NativeRegisterContextLinux_sw_64::WriteCP1() { + Status error; + + uint8_t *src = nullptr; + uint8_t *dst = nullptr; + + lldb::ByteOrder byte_order = GetByteOrder(); + + bool IsBigEndian = (byte_order == lldb::eByteOrderBig); +/* + if (IsSIMDAvailable()) { + dst = (uint8_t *)&m_simd + (IsBigEndian * 8); + src = (uint8_t *)&m_fpr; + for (int i = 0; i < NUM_REGISTERS; i++) { + // Copy fp values to simd buffer for ptrace + *(uint64_t *)dst = *(uint64_t *)src; + dst = dst + 16; + src = src + 8; + } +// m_simd.fir = m_fpr.fir; +// m_simd.fcsr = m_fpr.fcsr; +// m_simd.config5 = m_fpr.config5; + error = NativeRegisterContextLinux::WriteRegisterSet( + &m_iovec, sizeof(SIMD_linux_sw_64), NFPREG); + } else { + error = NativeRegisterContextLinux::WriteFPR(); + } +*/ + error = NativeRegisterContextLinux::WriteFPR(); + + return error; +} + +bool NativeRegisterContextLinux_sw_64::IsFPR(uint32_t reg_index) const { + return (m_reg_info.first_fpr <= reg_index && + reg_index <= m_reg_info.last_fpr); +} + +bool NativeRegisterContextLinux_sw_64::IsSIMD(uint32_t reg_index) const { + return (m_reg_info.first_simd <= reg_index && + reg_index <= m_reg_info.last_simd); +} + +Status NativeRegisterContextLinux_sw_64::GetWatchpointHitIndex( + uint32_t &wp_index, lldb::addr_t trap_addr) { + // refer to arm64 + Log *log = GetLog(POSIXLog::Watchpoints); + //Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); + + uint32_t watch_size; + lldb::addr_t watch_addr; + + for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { + watch_size = GetWatchpointSize(wp_index); + watch_addr = m_hwp_regs[wp_index].address; + + if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && + trap_addr < watch_addr + watch_size) { + m_hwp_regs[wp_index].hit_addr = trap_addr; + return Status(); + } + } + + wp_index = LLDB_INVALID_INDEX32; + return Status(); +} + +Status NativeRegisterContextLinux_sw_64::IsWatchpointVacant(uint32_t wp_index, + bool &is_vacant) { + is_vacant = false; + return Status("SW_64 TODO: " + "NativeRegisterContextLinux_sw_64::IsWatchpointVacant not " + "implemented"); +} + +bool NativeRegisterContextLinux_sw_64::ClearHardwareWatchpoint( + uint32_t wp_index) { + // refer to arm64 + Log *log = GetLog(POSIXLog::Watchpoints); + //Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + // Read hardware breakpoint and watchpoint information. + //Status error = ReadHardwareDebugInfo(); + +// if (error.Fail()) +// return false; + + if (wp_index >= m_max_hwp_supported) + return false; + + // Create a backup we can revert to in case of failure. + lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; + //lldb::addr_t tempAddr = m_hwp_regs[wp_index].address & ((1L<<53)-1); + uint32_t tempControl = m_hwp_regs[wp_index].control; + //uint32_t tempControl = (m_hwp_regs[wp_index].address >> 53) & 0x3L; + + // Update watchpoint in local cache + m_hwp_regs[wp_index].control &= ~1; + //m_hwp_regs[wp_index].control &= ~3; + //m_hwp_regs[wp_index].address &= ~(0x3L<<53); + m_hwp_regs[wp_index].address = 0; + + // Ptrace call to update hardware debug registers + Status error = WriteDebugRegisterValue(m_thread.GetID(), DA_MATCH, 0L); + Status error2 = WriteDebugRegisterValue(m_thread.GetID(), DA_MASK, 0L); + + if (error.Fail() & error2.Fail()) { + m_hwp_regs[wp_index].control = tempControl; + m_hwp_regs[wp_index].address = tempAddr; + + return false; + } + + return true; +} + +Status NativeRegisterContextLinux_sw_64::ClearAllHardwareWatchpoints() { + //printf("--> %s, %d\n", __FUNCTION__, __LINE__); + + lldb::addr_t tempAddr = 0; + uint32_t tempControl = 0; + + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if (m_hwp_regs[i].control & 0x01) { + //if (m_hwp_regs[i].control & 0x03) { + // Create a backup we can revert to in case of failure. + tempAddr = m_hwp_regs[i].address; + //tempAddr = m_hwp_regs[i].address & ((1L<<53)-1); + tempControl = m_hwp_regs[i].control; + //tempControl = (m_hwp_regs[i].address >> 53) & 0x3L; + + // Clear watchpoints in local cache + m_hwp_regs[i].control &= ~1; + //m_hwp_regs[i].control &= ~3; + m_hwp_regs[i].address = 0; + + // Ptrace call to update hardware debug registers + Status error = WriteDebugRegisterValue(m_thread.GetID(), DA_MATCH, 0L); + error = WriteDebugRegisterValue(m_thread.GetID(), DA_MASK, 0L); + + if (error.Fail()) { + m_hwp_regs[i].control = tempControl; + m_hwp_regs[i].address = tempAddr; + + return error; + } + } + } + + return Status(); +} + +Status NativeRegisterContextLinux_sw_64::SetHardwareWatchpointWithIndex( + lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { + //printf("--> %s, %d\n", __FUNCTION__, __LINE__); + Status error; + error.SetErrorString("SW_64 TODO: " + "NativeRegisterContextLinux_sw_64::" + "SetHardwareWatchpointWithIndex not implemented"); + return error; +} + +uint32_t NativeRegisterContextLinux_sw_64::SetHardwareWatchpoint( + lldb::addr_t addr, size_t size, uint32_t watch_flags) { + // refer to arm64 + Log *log = GetLog(POSIXLog::Watchpoints); + //Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, + watch_flags); + + // Read hardware breakpoint and watchpoint information. + // sw_64 not need, aarch64 only read value of m_max_hwp_supported + // First reading the current state of watch regs + //Status error = ReadHardwareDebugInfo(); + +// if (error.Fail()) +// return LLDB_INVALID_INDEX32; + + uint32_t control_value = 0, wp_index = 0; + lldb::addr_t real_addr = addr; + + // Check if we are setting watchpoint other than read/write/access Also + // update watchpoint flag to match AArch64 write-read bit configuration. + switch (watch_flags) { + case 1: + watch_flags = 2; + break; + case 2: + watch_flags = 1; + break; + case 3: + break; + default: + return LLDB_INVALID_INDEX32; + } + + // Check if size has a valid hardware watchpoint length. + if (size != 1 && size != 2 && size != 4 && size != 8) + return LLDB_INVALID_INDEX32; + + // Check 8-byte alignment for hardware watchpoint target address. Below is a + // hack to recalculate address and size in order to make sure we can watch + // non 8-byte alligned addresses as well. + if (addr & 0x07) { + uint8_t watch_mask = (addr & 0x07) + size; + + if (watch_mask > 0x08) + return LLDB_INVALID_INDEX32; + else if (watch_mask <= 0x02) + size = 2; + else if (watch_mask <= 0x04) + size = 4; + else + size = 8; + + //addr = addr & (~0x07); + //addr = addr & (~0x03); + } + + // Setup control value + control_value = watch_flags << 3; + //control_value = watch_flags; + control_value |= ((1 << size) - 1) << 5; + control_value |= (2 << 1) | 1; + + // Iterate over stored watchpoints and find a free wp_index + wp_index = LLDB_INVALID_INDEX32; + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if ((m_hwp_regs[i].control & 1) == 0) { + //if ((m_hwp_regs[i].control & 3) == 0) { + wp_index = i; // Mark last free slot + } else if (m_hwp_regs[i].address == addr) { + return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. + } + } + + if (wp_index == LLDB_INVALID_INDEX32) + return LLDB_INVALID_INDEX32; + + // Update watchpoint in local cache + m_hwp_regs[wp_index].real_addr = real_addr; + m_hwp_regs[wp_index].address = addr; + m_hwp_regs[wp_index].control = control_value; + + // PTRACE call to set corresponding watchpoint register. + //error = WriteHardwareDebugRegs(eDREGTypeWATCH); + + Status error = WriteDebugRegisterValue(m_thread.GetID(), DA_MATCH, (addr|(2UL<<53))); + //WriteDebugRegisterValue(m_thread.GetID(), DA_MATCH, (addr|(watch_flags<<53))); + Status error2 = WriteDebugRegisterValue(m_thread.GetID(), DA_MASK, ((1UL<<53)-1)); +#ifdef __sw_64_sw8a__ + Status error3 = WriteDebugRegisterValue(m_thread.GetID(), MATCH_CTL, 0x201); + + // TODO: modify control_value to support read, write, read/write watchpoint + //Status error = WriteDebugRegisterValue(m_thread.GetID(), MATCH_CTL, 0x101); // read, DA_MATCH + //Status error = WriteDebugRegisterValue(m_thread.GetID(), MATCH_CTL, 0x201); // write, DA_MATCH + //Status error = WriteDebugRegisterValue(m_thread.GetID(), MATCH_CTL, 0x301); // read & write, DA_MATCH + + if (error.Fail() & error2.Fail() & error3.Fail()) { +#else + if (error.Fail() & error2.Fail()) { +#endif + m_hwp_regs[wp_index].address = 0; + m_hwp_regs[wp_index].control &= ~1; + //m_hwp_regs[wp_index].control &= ~3; + + return LLDB_INVALID_INDEX32; + } + + return wp_index; +} + +// refer to arm64 +uint32_t +NativeRegisterContextLinux_sw_64::GetWatchpointSize(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + //Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) { + case 0x01: + return 1; + case 0x03: + return 2; + case 0x0f: + return 4; + case 0xff: + return 8; + default: + return 0; + } +} + +bool NativeRegisterContextLinux_sw_64::WatchpointIsEnabled(uint32_t wp_index) { + Log *log = GetLog(POSIXLog::Watchpoints); + //Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) + //if (((m_hwp_regs[wp_index].address >> 53) & 0x3L) != 0x0) + return true; + else + return false; +} + +lldb::addr_t +NativeRegisterContextLinux_sw_64::GetWatchpointAddress(uint32_t wp_index) { + // refer to arm64 + Log *log = GetLog(POSIXLog::Watchpoints); + //Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].real_addr; + else + return LLDB_INVALID_ADDRESS; +} + +lldb::addr_t +NativeRegisterContextLinux_sw_64::GetWatchpointHitAddress(uint32_t wp_index) { + // refer to arm64 + Log *log = GetLog(POSIXLog::Watchpoints); + //Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].hit_addr; + else + return LLDB_INVALID_ADDRESS; +} + +uint32_t NativeRegisterContextLinux_sw_64::NumSupportedHardwareWatchpoints() { + printf("--> %s, %d\n", __FUNCTION__, __LINE__); + return MAX_NUM_WP; +} + +Status +NativeRegisterContextLinux_sw_64::ReadRegisterRaw(uint32_t reg_index, + RegisterValue &value) { + const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); + + if (!reg_info) + return Status("register %" PRIu32 " not found", reg_index); + + uint32_t offset = reg_info->kinds[lldb::eRegisterKindProcessPlugin]; + return DoReadRegisterValue(offset, reg_info->name, reg_info->byte_size, + value); +} + +Status NativeRegisterContextLinux_sw_64::WriteRegisterRaw( + uint32_t reg_index, const RegisterValue &value) { + const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); + + if (!reg_info) + return Status("register %" PRIu32 " not found", reg_index); + + if (reg_info->invalidate_regs) + lldbassert(false && "reg_info->invalidate_regs is unhandled"); + + uint32_t offset = reg_info->kinds[lldb::eRegisterKindProcessPlugin]; + return DoWriteRegisterValue(offset, reg_info->name, value); +} + +Status NativeRegisterContextLinux_sw_64::ReadDebugRegisterValue( + lldb::tid_t tid, int regnum, uint64_t *value) { + Log *log = GetLog(POSIXLog::Watchpoints); + //Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + Status error; + error = NativeProcessLinux::PtraceWrapper(PTRACE_PEEKUSER, m_thread.GetID(), + reinterpret_cast(regnum), nullptr, 0, reinterpret_cast(value)); + if (log) + log->Printf("%s: pid = %d, regnum = %d *value = %d\n", __FUNCTION__, tid, regnum, *value); + return error; +} + +Status NativeRegisterContextLinux_sw_64::WriteDebugRegisterValue( + lldb::tid_t tid, int regnum, uint64_t value) { + Log *log = GetLog(POSIXLog::Watchpoints); + //Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + Status error; + error = NativeProcessLinux::PtraceWrapper(PTRACE_POKEUSER, m_thread.GetID(), + reinterpret_cast(regnum), reinterpret_cast(value)); + if (log) + log->Printf("%s: pid = %d, regnum = %d value = %d\n", __FUNCTION__, tid, regnum, value); + return error; +} + + +#endif // defined (__sw_64__) diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_sw_64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_sw_64.h new file mode 100755 index 000000000000..8578bcf156eb --- /dev/null +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_sw_64.h @@ -0,0 +1,149 @@ +//===-- NativeRegisterContextLinux_sw_64.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(__sw_64__) + +#ifndef lldb_NativeRegisterContextLinux_sw_64_h +#define lldb_NativeRegisterContextLinux_sw_64_h + +#include "Plugins/Process/Linux/NativeRegisterContextLinux.h" +#include "Plugins/Process/Utility/RegisterContext_sw_64.h" +#include "Plugins/Process/Utility/lldb-sw_64-linux-register-enums.h" +#include // For struct iovec + +// LHX: Here only used a pair of debug register: DA_MATCH and DA_MASK, +// MAX_NUM_WP set to 1 will cause watchpoint failed. +#define MAX_NUM_WP 2 + +namespace lldb_private { +namespace process_linux { + +class NativeProcessLinux; + +class NativeRegisterContextLinux_sw_64 : public NativeRegisterContextLinux { +public: + NativeRegisterContextLinux_sw_64(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + + uint32_t GetRegisterSetCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + Status ReadCP1(); + + Status WriteCP1(); + + uint8_t *ReturnFPOffset(uint8_t reg_index, uint32_t byte_offset); + +// Hardware breakpoints/watchpoint management functions + + uint32_t NumSupportedHardwareWatchpoints() override; + + uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags) override; + + bool ClearHardwareWatchpoint(uint32_t wp_index) override; + + Status ClearAllHardwareWatchpoints() override; + + Status GetWatchpointHitIndex(uint32_t &wp_index, + lldb::addr_t trap_addr) override; + + lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override; + + lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; + + uint32_t GetWatchpointSize(uint32_t wp_index); + + bool WatchpointIsEnabled(uint32_t wp_index); + + Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, + uint32_t watch_flags, + uint32_t wp_index); + + Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override; + +protected: + Status ReadRegisterRaw(uint32_t reg_index, RegisterValue &value) override; + + Status WriteRegisterRaw(uint32_t reg_index, + const RegisterValue &value) override; + + Status ReadDebugRegisterValue(lldb::tid_t tid, int regnum, uint64_t *value); + + Status WriteDebugRegisterValue(lldb::tid_t tid, int regnum, uint64_t value); + + bool IsFPR(uint32_t reg_index) const; + + bool IsSIMD(uint32_t reg_index) const; + + void *GetGPRBuffer() override { return &m_gpr; } + + void *GetFPRBuffer() override { return &m_fpr; } + + size_t GetFPRSize() override { return sizeof(m_fpr); } + +private: + // Info about register ranges. + struct RegInfo { + uint32_t num_registers; + uint32_t num_gpr_registers; + uint32_t num_fpr_registers; + + uint32_t last_gpr; + uint32_t first_fpr; + uint32_t last_fpr; + uint32_t first_simd; + uint32_t last_simd; + }; + + RegInfo m_reg_info; + + GPR_linux_sw_64 m_gpr; + + FPR_linux_sw_64 m_fpr; + + SIMD_linux_sw_64 m_simd; + + lldb::addr_t hw_addr_map[MAX_NUM_WP]; + + struct iovec m_iovec; + + // Debug register info for hardware watchpoints management. + struct DREG { + lldb::addr_t address; // Watchpoint address value. + lldb::addr_t hit_addr; // Address at which last watchpoint trigger exception + // occurred. + lldb::addr_t real_addr; // Address value that should cause target to stop. + uint32_t control; // Watchpoint control value. DA_MATCH[54:53] + //lldb::addr_t match; // DA_MATCH + //lldb::addr_t mask; // DA_MASK + //lldb::addr_t dc_ctl; // DC_CTL[20:19]: dv_match=[0:1], dav_match=[1:1] + }; + + struct DREG m_hwp_regs[MAX_NUM_WP]; // Native linux hardware watchpoints + uint32_t m_max_hwp_supported; + //bool m_refresh_hwdebug_info; +}; + +} // namespace process_linux +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextLinux_sw_64_h + +#endif // defined (__sw_64__) diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt index 1ebd0484f021..f3bb3f75ef5b 100644 --- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt +++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt @@ -25,6 +25,7 @@ add_lldb_library(lldbPluginProcessUtility RegisterContextFreeBSD_x86_64.cpp RegisterContextHistory.cpp RegisterContextLinux_i386.cpp + RegisterContextLinux_sw_64.cpp RegisterContextLinux_x86_64.cpp RegisterContextLinux_s390x.cpp RegisterContextMach_arm.cpp @@ -37,6 +38,7 @@ add_lldb_library(lldbPluginProcessUtility RegisterContextOpenBSD_x86_64.cpp RegisterContextPOSIX_arm.cpp RegisterContextPOSIX_arm64.cpp + RegisterContextPOSIX_sw_64.cpp RegisterContextPOSIX_loongarch64.cpp RegisterContextPOSIX_mips64.cpp RegisterContextPOSIX_powerpc.cpp diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 3f25dbc6abbb..a9067bd1700c 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -58,10 +58,17 @@ void LinuxSignals::Reset() { AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); +#ifndef __sw_64__ AddSignal(7, "SIGBUS", false, true, true, "bus error"); ADD_SIGCODE(SIGBUS, 7, BUS_ADRALN, 1, "illegal alignment"); ADD_SIGCODE(SIGBUS, 7, BUS_ADRERR, 2, "illegal address"); ADD_SIGCODE(SIGBUS, 7, BUS_OBJERR, 3, "hardware error"); +#else + AddSignal(10, "SIGBUS", false, true, true, "bus error"); + ADD_SIGCODE(SIGBUS, 10, BUS_ADRALN, 1, "illegal alignment"); + ADD_SIGCODE(SIGBUS, 10, BUS_ADRERR, 2, "illegal address"); + ADD_SIGCODE(SIGBUS, 10, BUS_OBJERR, 3, "hardware error"); +#endif AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); ADD_SIGCODE(SIGFPE, 8, FPE_INTDIV, 1, "integer divide by zero"); diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_sw_64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_sw_64.cpp new file mode 100755 index 000000000000..c681e4f9eddb --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_sw_64.cpp @@ -0,0 +1,180 @@ +//===-- RegisterContextLinux_sw_64.cpp ------------------------*- 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 +// +//===---------------------------------------------------------------------===// + + +#include +#include + +// For eh_frame and DWARF Register numbers +#include "RegisterContextLinux_sw_64.h" + +// For GP and FP buffers +#include "RegisterContext_sw_64.h" + +// Internal codes for all sw_64 registers +#include "lldb-sw_64-linux-register-enums.h" + +using namespace lldb; +using namespace lldb_private; + +// Include RegisterInfos_sw_64 to declare our g_register_infos_sw_64 +// structure. +#define DECLARE_REGISTER_INFOS_SW64_STRUCT +#define LINUX_SW64 +#include "RegisterInfos_sw_64.h" +#undef LINUX_SW64 +#undef DECLARE_REGISTER_INFOS_SW64_STRUCT + +// sw_64 general purpose registers. +const uint32_t g_gp_regnums_sw_64[] = { + gpr_r0_sw_64, gpr_r1_sw_64, gpr_r2_sw_64, + gpr_r3_sw_64, gpr_r4_sw_64, gpr_r5_sw_64, + gpr_r6_sw_64, gpr_r7_sw_64, gpr_r8_sw_64, + gpr_r9_sw_64, gpr_r10_sw_64, gpr_r11_sw_64, + gpr_r12_sw_64, gpr_r13_sw_64, gpr_r14_sw_64, + gpr_fp_sw_64, gpr_r16_sw_64, gpr_r17_sw_64, + gpr_r18_sw_64, gpr_r19_sw_64, gpr_r20_sw_64, + gpr_r21_sw_64, gpr_r22_sw_64, gpr_r23_sw_64, + gpr_r24_sw_64, gpr_r25_sw_64, gpr_ra_sw_64, + gpr_r27_sw_64, gpr_r28_sw_64, gpr_gp_sw_64, + gpr_sp_sw_64, gpr_zero_sw_64, gpr_pc_sw_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static_assert((sizeof(g_gp_regnums_sw_64) / sizeof(g_gp_regnums_sw_64[0])) - + 1 == + k_num_gpr_registers_sw_64, + "g_gp_regnums_sw_64 has wrong number of register infos"); + +// sw_64 floating point registers. +const uint32_t g_fp_regnums_sw_64[] = { + fpr_f0_sw_64, fpr_f1_sw_64, fpr_f2_sw_64, fpr_f3_sw_64, + fpr_f4_sw_64, fpr_f5_sw_64, fpr_f6_sw_64, fpr_f7_sw_64, + fpr_f8_sw_64, fpr_f9_sw_64, fpr_f10_sw_64, fpr_f11_sw_64, + fpr_f12_sw_64, fpr_f13_sw_64, fpr_f14_sw_64, fpr_f15_sw_64, + fpr_f16_sw_64, fpr_f17_sw_64, fpr_f18_sw_64, fpr_f19_sw_64, + fpr_f20_sw_64, fpr_f21_sw_64, fpr_f22_sw_64, fpr_f23_sw_64, + fpr_f24_sw_64, fpr_f25_sw_64, fpr_f26_sw_64, fpr_f27_sw_64, + fpr_f28_sw_64, fpr_f29_sw_64, fpr_f30_sw_64, fpr_f31_sw_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static_assert((sizeof(g_fp_regnums_sw_64) / sizeof(g_fp_regnums_sw_64[0])) - + 1 == + k_num_fpr_registers_sw_64, + "g_fp_regnums_sw_64 has wrong number of register infos"); + +// sw_64 SIMD registers. +const uint32_t g_simd_regnums_sw_64[] = { + simd_v0_sw_64, simd_v1_sw_64, simd_v2_sw_64, simd_v3_sw_64, + simd_v4_sw_64, simd_v5_sw_64, simd_v6_sw_64, simd_v7_sw_64, + simd_v8_sw_64, simd_v9_sw_64, simd_v10_sw_64, simd_v11_sw_64, + simd_v12_sw_64, simd_v13_sw_64, simd_v14_sw_64, simd_v15_sw_64, + simd_v16_sw_64, simd_v17_sw_64, simd_v18_sw_64, simd_v19_sw_64, + simd_v20_sw_64, simd_v21_sw_64, simd_v22_sw_64, simd_v23_sw_64, + simd_v24_sw_64, simd_v25_sw_64, simd_v26_sw_64, simd_v27_sw_64, + simd_v28_sw_64, simd_v29_sw_64, simd_v30_sw_64, simd_v31_sw_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; + +static_assert((sizeof(g_simd_regnums_sw_64) / sizeof(g_simd_regnums_sw_64[0])) - + 1 == + k_num_simd_registers_sw_64, + "g_simd_regnums_sw_64 has wrong number of register infos"); + +// Number of register sets provided by this context. +//constexpr size_t k_num_register_sets = 3; +enum { k_num_register_sets = 3 }; + +// Register sets for sw_64. +static const RegisterSet g_reg_sets_sw_64[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers_sw_64, + g_gp_regnums_sw_64}, + {"Floating Point Registers", "fpu", k_num_fpr_registers_sw_64, + g_fp_regnums_sw_64}, + {"SIMD Registers", "simd", k_num_simd_registers_sw_64, g_simd_regnums_sw_64}, +}; + +const RegisterSet * +RegisterContextLinux_sw_64::GetRegisterSet(size_t set) const { + if (set >= k_num_register_sets) + return nullptr; + + switch (GetTargetArchitecture().GetMachine()/*m_target_arch.GetMachine()*/) { + case llvm::Triple::sw_64: + return &g_reg_sets_sw_64[set]; + default: + assert(false && "Unhandled target architecture."); + return nullptr; + } + return nullptr; +} + +size_t +RegisterContextLinux_sw_64::GetRegisterSetCount() const { + return k_num_register_sets; +} + +static const RegisterInfo *GetRegisterInfoPtr(const ArchSpec &target_arch) { + switch (target_arch.GetMachine()) { + case llvm::Triple::sw_64: + return g_register_infos_sw_64; + default: + assert(false && "Unhandled target architecture."); + return nullptr; + } +} + +static uint32_t GetRegisterInfoCount(const ArchSpec &target_arch) { + switch (target_arch.GetMachine()) { + case llvm::Triple::sw_64: + return static_cast(sizeof(g_register_infos_sw_64) / + sizeof(g_register_infos_sw_64[0])); + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + +//uint32_t GetUserRegisterInfoCount_sw_64(const ArchSpec &target_arch, bool simd_present) { +uint32_t GetUserRegisterInfoCount_sw_64(const ArchSpec &target_arch) { + switch (target_arch.GetMachine()) { + case llvm::Triple::sw_64: + return static_cast(k_num_user_registers_sw_64); + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + +RegisterContextLinux_sw_64::RegisterContextLinux_sw_64( +// const ArchSpec &target_arch, bool simd_present) + const ArchSpec &target_arch) + : lldb_private::RegisterInfoInterface(target_arch), + m_register_info_p(GetRegisterInfoPtr(target_arch)), + m_register_info_count(GetRegisterInfoCount(target_arch)), + m_user_register_count( +// GetUserRegisterInfoCount_sw_64(target_arch, simd_present)) {} + GetUserRegisterInfoCount_sw_64(target_arch)) {} + +size_t RegisterContextLinux_sw_64::GetGPRSize() const { + return sizeof(GPR_linux_sw_64); +} + +const RegisterInfo *RegisterContextLinux_sw_64::GetRegisterInfo() const { + return m_register_info_p; +} + +uint32_t RegisterContextLinux_sw_64::GetRegisterCount() const { + return m_register_info_count; +} + +uint32_t RegisterContextLinux_sw_64::GetUserRegisterCount() const { + return m_user_register_count; +} + diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLinux_sw_64.h b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_sw_64.h new file mode 100755 index 000000000000..dc525ce19de4 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLinux_sw_64.h @@ -0,0 +1,39 @@ +//===-- RegisterContextLinux_sw_64.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 liblldb_RegisterContextLinux_sw_64_H_ +#define liblldb_RegisterContextLinux_sw_64_H_ + +#include "RegisterInfoInterface.h" +#include "lldb/lldb-private.h" + +class RegisterContextLinux_sw_64 : public lldb_private::RegisterInfoInterface { +public: +// RegisterContextLinux_sw_64(const lldb_private::ArchSpec &target_arch, bool simd_present = true); + + RegisterContextLinux_sw_64(const lldb_private::ArchSpec &target_arch); + size_t GetGPRSize() const override; + + const lldb_private::RegisterInfo *GetRegisterInfo() const override; + + const lldb_private::RegisterSet *GetRegisterSet(size_t set) const; + + size_t GetRegisterSetCount() const; + + uint32_t GetRegisterCount() const override; + + uint32_t GetUserRegisterCount() const override; + +private: + const lldb_private::RegisterInfo *m_register_info_p; + uint32_t m_register_info_count; + uint32_t m_user_register_count; +}; + +#endif + diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_sw_64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_sw_64.cpp new file mode 100755 index 000000000000..c6104a4db322 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_sw_64.cpp @@ -0,0 +1,186 @@ +//===-- RegisterContextPOSIX_sw_64.cpp -------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" +#include "llvm/Support/Compiler.h" + +#include "RegisterContextPOSIX_sw_64.h" +//#include "RegisterContextFreeBSD_mips64.h" +#include "RegisterContextLinux_sw_64.h" +//#include "RegisterContextLinux_mips.h" + +using namespace lldb_private; +using namespace lldb; + +bool RegisterContextPOSIX_sw_64::IsGPR(unsigned reg) { + return reg < m_registers_count[gpr_registers_count]; // GPR's come first. +} + +bool RegisterContextPOSIX_sw_64::IsFPR(unsigned reg) { + int set = GetRegisterSetCount(); + if (set > 1) + return reg < (m_registers_count[fpr_registers_count] + + m_registers_count[gpr_registers_count]); + return false; +} + +RegisterContextPOSIX_sw_64::RegisterContextPOSIX_sw_64( + Thread &thread, uint32_t concrete_frame_idx, + RegisterInfoInterface *register_info) + : RegisterContext(thread, concrete_frame_idx) { + m_register_info_up.reset(register_info); + m_num_registers = GetRegisterCount(); + int set = GetRegisterSetCount(); + + const RegisterSet *reg_set_ptr; + for(int i = 0; i < set; ++i) { + reg_set_ptr = GetRegisterSet(i); + m_registers_count[i] = reg_set_ptr->num_registers; + } + + assert(m_num_registers == + static_cast(m_registers_count[gpr_registers_count] + + m_registers_count[fpr_registers_count] + + m_registers_count[simd_registers_count])); +} + +RegisterContextPOSIX_sw_64::~RegisterContextPOSIX_sw_64() {} + +void RegisterContextPOSIX_sw_64::Invalidate() {} + +void RegisterContextPOSIX_sw_64::InvalidateAllRegisters() {} + +unsigned RegisterContextPOSIX_sw_64::GetRegisterOffset(unsigned reg) { + assert(reg < m_num_registers && "Invalid register number."); + return GetRegisterInfo()[reg].byte_offset; +} + +unsigned RegisterContextPOSIX_sw_64::GetRegisterSize(unsigned reg) { + assert(reg < m_num_registers && "Invalid register number."); + return GetRegisterInfo()[reg].byte_size; +} + +size_t RegisterContextPOSIX_sw_64::GetRegisterCount() { +#ifndef LHX20210708 +printf("-->RegisterContextPOSIX_sw_64::GetRegisterCount() return %d\n",m_register_info_up->GetRegisterCount()); +#endif + return m_register_info_up->GetRegisterCount(); +} + +size_t RegisterContextPOSIX_sw_64::GetGPRSize() { +#ifndef LHX20210708 +printf("-->RegisterContextPOSIX_sw_64::GetGPRSize() return %d\n",m_register_info_up->GetGPRSize()); +#endif + return m_register_info_up->GetGPRSize(); +} + +const RegisterInfo *RegisterContextPOSIX_sw_64::GetRegisterInfo() { + // Commonly, this method is overridden and g_register_infos is copied and + // specialized. So, use GetRegisterInfo() rather than g_register_infos in + // this scope. + return m_register_info_up->GetRegisterInfo(); +} + +const RegisterInfo * +RegisterContextPOSIX_sw_64::GetRegisterInfoAtIndex(size_t reg) { + if (reg < m_num_registers) + return &GetRegisterInfo()[reg]; + else + return nullptr; +} + +size_t RegisterContextPOSIX_sw_64::GetRegisterSetCount() { + ArchSpec target_arch = m_register_info_up->GetTargetArchitecture(); + switch (target_arch.GetTriple().getOS()) { + case llvm::Triple::Linux: { + const auto *context = static_cast( + m_register_info_up.get()); + return context->GetRegisterSetCount(); + } + default: { + printf("[default case]: here maybe wrong.\n"); + //const auto *context = static_cast( + // m_register_info_up.get()); + //return context->GetRegisterSetCount(); + } + + } +} + +const RegisterSet *RegisterContextPOSIX_sw_64::GetRegisterSet(size_t set) { + ArchSpec target_arch = m_register_info_up->GetTargetArchitecture(); + switch (target_arch.GetTriple().getOS()) { + case llvm::Triple::Linux: { + const auto *context = static_cast( + m_register_info_up.get()); + return context->GetRegisterSet(set); + } + default: { + printf("[default case]: here maybe wrong.\n"); + //const auto *context = static_cast( + // m_register_info_up.get()); + //return context->GetRegisterSet(set); + } + } +} + +const char *RegisterContextPOSIX_sw_64::GetRegisterName(unsigned reg) { + assert(reg < m_num_registers && "Invalid register offset."); +#ifndef LHX20210708 +printf("-->GetRegisterInfo()[reg].name=%s\n",GetRegisterInfo()[reg].name); +#endif + return GetRegisterInfo()[reg].name; +} + +lldb::ByteOrder RegisterContextPOSIX_sw_64::GetByteOrder() { + // Get the target process whose privileged thread was used for the register + // read. + lldb::ByteOrder byte_order = eByteOrderInvalid; + Process *process = CalculateProcess().get(); + + if (process) + byte_order = process->GetByteOrder(); +#ifndef LHX20210708 +printf("-->RegisterContextPOSIX_sw_64::GetByteOrder=%s\n",byte_order); +#endif + return byte_order; +} + +bool RegisterContextPOSIX_sw_64::IsRegisterSetAvailable(size_t set_index) { + size_t num_sets = GetRegisterSetCount(); + + return (set_index < num_sets); +} + +// Used when parsing DWARF and EH frame information and any other object file +// sections that contain register numbers in them. +uint32_t RegisterContextPOSIX_sw_64::ConvertRegisterKindToRegisterNumber( + lldb::RegisterKind kind, uint32_t num) { + const uint32_t num_regs = m_num_registers; + + assert(kind < kNumRegisterKinds); + for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx); + + if (reg_info->kinds[kind] == num) + return reg_idx; + } + + return LLDB_INVALID_REGNUM; +} diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_sw_64.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_sw_64.h new file mode 100755 index 000000000000..7261b285ed33 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_sw_64.h @@ -0,0 +1,84 @@ +//===-- RegisterContextPOSIX_sw_64.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 liblldb_RegisterContextPOSIX_sw_64_h_ +#define liblldb_RegisterContextPOSIX_sw_64_h_ + +#include "RegisterContext_sw_64.h" +#include "RegisterInfoInterface.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Utility/Log.h" + +using namespace lldb_private; + +class ProcessMonitor; + +class RegisterContextPOSIX_sw_64 : public lldb_private::RegisterContext { +public: + + enum Register_count{ + gpr_registers_count = 0, + fpr_registers_count, + simd_registers_count, + register_set_count + }; + + RegisterContextPOSIX_sw_64( + lldb_private::Thread &thread, uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + + ~RegisterContextPOSIX_sw_64() override; + + void Invalidate(); + + void InvalidateAllRegisters() override; + + size_t GetRegisterCount() override; + + virtual size_t GetGPRSize(); + + virtual unsigned GetRegisterSize(unsigned reg); + + virtual unsigned GetRegisterOffset(unsigned reg); + + const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override; + + size_t GetRegisterSetCount() override; + + const lldb_private::RegisterSet *GetRegisterSet(size_t set) override; + + const char *GetRegisterName(unsigned reg); + + uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, + uint32_t num) override; + +protected: + uint32_t m_num_registers; + uint8_t m_registers_count[register_set_count]; + std::unique_ptr + m_register_info_up; // Register Info Interface (FreeBSD or Linux) + + // Determines if an extended register set is supported on the processor + // running the inferior process. + virtual bool IsRegisterSetAvailable(size_t set_index); + + virtual const lldb_private::RegisterInfo *GetRegisterInfo(); + + bool IsGPR(unsigned reg); + + bool IsFPR(unsigned reg); + + lldb::ByteOrder GetByteOrder(); + + virtual bool ReadGPR() = 0; + virtual bool ReadFPR() = 0; + virtual bool WriteGPR() = 0; + virtual bool WriteFPR() = 0; +}; + +#endif // liblldb_RegisterContextPOSIX_sw_64_h_ diff --git a/lldb/source/Plugins/Process/Utility/RegisterContext_sw_64.h b/lldb/source/Plugins/Process/Utility/RegisterContext_sw_64.h new file mode 100755 index 000000000000..eb95b25b471e --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContext_sw_64.h @@ -0,0 +1,239 @@ +//===-- RegisterContext_sw_64.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 liblldb_RegisterContext_sw_64_H_ +#define liblldb_RegisterContext_sw_64_H_ + +#include +#include + +// eh_frame and DWARF Register numbers (eRegisterKindEHFrame & +// eRegisterKindDWARF) +enum { + dwarf_r0_sw_64 = 0, + dwarf_r1_sw_64, + dwarf_r2_sw_64, + dwarf_r3_sw_64, + dwarf_r4_sw_64, + dwarf_r5_sw_64, + dwarf_r6_sw_64, + dwarf_r7_sw_64, + dwarf_r8_sw_64, + dwarf_r9_sw_64, + dwarf_r10_sw_64, + dwarf_r11_sw_64, + dwarf_r12_sw_64, + dwarf_r13_sw_64, + dwarf_r14_sw_64, + dwarf_fp_sw_64, //15 + dwarf_r16_sw_64, + dwarf_r17_sw_64, + dwarf_r18_sw_64, + dwarf_r19_sw_64, + dwarf_r20_sw_64, + dwarf_r21_sw_64, + dwarf_r22_sw_64, + dwarf_r23_sw_64, + dwarf_r24_sw_64, + dwarf_r25_sw_64, + dwarf_ra_sw_64, + dwarf_r27_sw_64, + dwarf_r28_sw_64, + dwarf_gp_sw_64, //29 + dwarf_sp_sw_64, //30 + dwarf_zero_sw_64, //31 + dwarf_pc_sw_64, + dwarf_f0_sw_64, + dwarf_f1_sw_64, + dwarf_f2_sw_64, + dwarf_f3_sw_64, + dwarf_f4_sw_64, + dwarf_f5_sw_64, + dwarf_f6_sw_64, + dwarf_f7_sw_64, + dwarf_f8_sw_64, + dwarf_f9_sw_64, + dwarf_f10_sw_64, + dwarf_f11_sw_64, + dwarf_f12_sw_64, + dwarf_f13_sw_64, + dwarf_f14_sw_64, + dwarf_f15_sw_64, + dwarf_f16_sw_64, + dwarf_f17_sw_64, + dwarf_f18_sw_64, + dwarf_f19_sw_64, + dwarf_f20_sw_64, + dwarf_f21_sw_64, + dwarf_f22_sw_64, + dwarf_f23_sw_64, + dwarf_f24_sw_64, + dwarf_f25_sw_64, + dwarf_f26_sw_64, + dwarf_f27_sw_64, + dwarf_f28_sw_64, + dwarf_f29_sw_64, + dwarf_f30_sw_64, + dwarf_f31_sw_64, + + dwarf_v0_sw_64, + dwarf_v1_sw_64, + dwarf_v2_sw_64, + dwarf_v3_sw_64, + dwarf_v4_sw_64, + dwarf_v5_sw_64, + dwarf_v6_sw_64, + dwarf_v7_sw_64, + dwarf_v8_sw_64, + dwarf_v9_sw_64, + dwarf_v10_sw_64, + dwarf_v11_sw_64, + dwarf_v12_sw_64, + dwarf_v13_sw_64, + dwarf_v14_sw_64, + dwarf_v15_sw_64, + dwarf_v16_sw_64, + dwarf_v17_sw_64, + dwarf_v18_sw_64, + dwarf_v19_sw_64, + dwarf_v20_sw_64, + dwarf_v21_sw_64, + dwarf_v22_sw_64, + dwarf_v23_sw_64, + dwarf_v24_sw_64, + dwarf_v25_sw_64, + dwarf_v26_sw_64, + dwarf_v27_sw_64, + dwarf_v28_sw_64, + dwarf_v29_sw_64, + dwarf_v30_sw_64, + dwarf_v31_sw_64, + +}; + +// GP registers +struct GPR_linux_sw_64 { + uint64_t r0; + uint64_t r1; + uint64_t r2; + uint64_t r3; + uint64_t r4; + uint64_t r5; + uint64_t r6; + uint64_t r7; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t fp; + uint64_t r16; + uint64_t r17; + uint64_t r18; + uint64_t r19; + uint64_t r20; + uint64_t r21; + uint64_t r22; + uint64_t r23; + uint64_t r24; + uint64_t r25; + uint64_t ra; + uint64_t r27; + uint64_t r28; + uint64_t gp; + uint64_t sp; + uint64_t zero; + uint64_t pc; +}; + +// Floating Point Registers +struct FPR_linux_sw_64 { + uint64_t f0; + uint64_t f1; + uint64_t f2; + uint64_t f3; + uint64_t f4; + uint64_t f5; + uint64_t f6; + uint64_t f7; + uint64_t f8; + uint64_t f9; + uint64_t f10; + uint64_t f11; + uint64_t f12; + uint64_t f13; + uint64_t f14; + uint64_t f15; + uint64_t f16; + uint64_t f17; + uint64_t f18; + uint64_t f19; + uint64_t f20; + uint64_t f21; + uint64_t f22; + uint64_t f23; + uint64_t f24; + uint64_t f25; + uint64_t f26; + uint64_t f27; + uint64_t f28; + uint64_t f29; + uint64_t f30; + uint64_t f31; +}; + + +struct SIMDReg_sw_64 { + uint8_t byte[16]; // 128-bits for each SIMD register +}; + +struct SIMD_linux_sw_64 { + SIMDReg_sw_64 v0; + SIMDReg_sw_64 v1; + SIMDReg_sw_64 v2; + SIMDReg_sw_64 v3; + SIMDReg_sw_64 v4; + SIMDReg_sw_64 v5; + SIMDReg_sw_64 v6; + SIMDReg_sw_64 v7; + SIMDReg_sw_64 v8; + SIMDReg_sw_64 v9; + SIMDReg_sw_64 v10; + SIMDReg_sw_64 v11; + SIMDReg_sw_64 v12; + SIMDReg_sw_64 v13; + SIMDReg_sw_64 v14; + SIMDReg_sw_64 v15; + SIMDReg_sw_64 v16; + SIMDReg_sw_64 v17; + SIMDReg_sw_64 v18; + SIMDReg_sw_64 v19; + SIMDReg_sw_64 v20; + SIMDReg_sw_64 v21; + SIMDReg_sw_64 v22; + SIMDReg_sw_64 v23; + SIMDReg_sw_64 v24; + SIMDReg_sw_64 v25; + SIMDReg_sw_64 v26; + SIMDReg_sw_64 v27; + SIMDReg_sw_64 v28; + SIMDReg_sw_64 v29; + SIMDReg_sw_64 v30; + SIMDReg_sw_64 v31; +// uint32_t fcsr; /* FPU control status register */ +}; + +struct UserArea_sw_64 { + GPR_linux_sw_64 gpr; // General purpose registers. + FPR_linux_sw_64 fpr; // Floating point registers. + SIMD_linux_sw_64 simd; // SIMD registers. +}; + +#endif // liblldb_RegisterContext_sw_64_H_ diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_sw_64.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_sw_64.h new file mode 100755 index 000000000000..9549ebd47f47 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_sw_64.h @@ -0,0 +1,312 @@ +//===-- RegisterInfos_sw_64.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 +// +//===----------------------------------------------------------------------===// + +#include + +#include "lldb/Core/dwarf.h" +#include "llvm/Support/Compiler.h" + + +#ifdef DECLARE_REGISTER_INFOS_SW64_STRUCT + +// Computes the offset of the given GPR in the user data area. +#ifdef LINUX_SW64 +#define GPR_OFFSET(regname) \ + (LLVM_EXTENSION offsetof(UserArea_sw_64, gpr) + \ + LLVM_EXTENSION offsetof(GPR_linux_sw_64, regname)) +#endif + +// Computes the offset of the given FPR in the extended data area. +#define FPR_OFFSET(regname) \ + (LLVM_EXTENSION offsetof(UserArea_sw_64, fpr) + \ + LLVM_EXTENSION offsetof(FPR_linux_sw_64, regname)) + +// Computes the offset of the given SIMD in the extended data area. +#define SIMD_OFFSET(regname) \ + (LLVM_EXTENSION offsetof(UserArea_sw_64, simd) + \ + LLVM_EXTENSION offsetof(SIMD_linux_sw_64, regname)) + +// RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB + +// Note that the size and offset will be updated by platform-specific classes. +#ifdef LINUX_SW64 +#define DEFINE_GPR(reg, alt, kind1, kind2, kind3) \ + { \ + #reg, alt, sizeof(((GPR_linux_sw_64 *) 0)->reg), \ + GPR_OFFSET(reg), eEncodingUint, eFormatHex, \ + {kind1, kind2, kind3, ptrace_##reg##_sw_64, \ + gpr_##reg##_sw_64 }, \ + NULL, NULL, NULL, \ + } +#endif + +#define DEFINE_GPR_INFO(reg, alt, kind1, kind2, kind3) \ + { \ + #reg, alt, sizeof(((GPR_linux_sw_64 *) 0)->reg) / 2, \ + GPR_OFFSET(reg), eEncodingUint, eFormatHex, \ + {kind1, kind2, kind3, ptrace_##reg##_sw_64, \ + gpr_##reg##_sw_64 }, \ + NULL, NULL, NULL, \ + } +/* +const uint8_t dwarf_opcode_mips64[] = { + llvm::dwarf::DW_OP_regx, dwarf_sr_mips64, llvm::dwarf::DW_OP_lit1, + llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shl, llvm::dwarf::DW_OP_and, + llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shr}; +*/ +#define DEFINE_FPR(reg, alt, kind1, kind2, kind3) \ + { \ + #reg, alt, sizeof(((FPR_linux_sw_64 *) 0)->reg), \ + FPR_OFFSET(reg), eEncodingIEEE754, eFormatFloat, \ + {kind1, kind2, kind3, ptrace_##reg##_sw_64, \ + fpr_##reg##_sw_64 }, \ + NULL, NULL, NULL, \ + } + +#define DEFINE_FPR_INFO(reg, alt, kind1, kind2, kind3) \ + { \ + #reg, alt, sizeof(((FPR_linux_sw_64 *) 0)->reg), \ + FPR_OFFSET(reg), eEncodingUint, eFormatHex, \ + {kind1, kind2, kind3, ptrace_##reg##_sw_64, \ + fpr_##reg##_sw_64 }, \ + NULL, NULL, NULL, \ + } + + +#define DEFINE_SIMD(reg, alt, kind1, kind2, kind3, kind4) \ + { \ + #reg, alt, sizeof(((SIMD_linux_sw_64 *) 0)->reg), \ + SIMD_OFFSET(reg), eEncodingVector, eFormatVectorOfUInt8, \ + {kind1, kind2, kind3, kind4, \ + simd_##reg##_sw_64 }, \ + NULL, NULL, NULL, \ + } + +#define DEFINE_SIMD_INFO(reg, alt, kind1, kind2, kind3, kind4) \ + { \ + #reg, alt, sizeof(((SIMD_linux_sw_64 *) 0)->reg), \ + SIMD_OFFSET(reg), eEncodingUint, eFormatHex, \ + {kind1, kind2, kind3, kind4, \ + simd_##reg##_sw_64 }, \ + NULL, NULL, NULL, \ + } + +static RegisterInfo g_register_infos_sw_64[] = { +// General purpose registers. EH_Frame, DWARF, +// Generic, Process Plugin +#ifdef LINUX_SW64 + DEFINE_GPR(r0, "v0", dwarf_r0_sw_64, dwarf_r0_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r1, "t0", dwarf_r1_sw_64, dwarf_r1_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r2, "t1", dwarf_r2_sw_64, dwarf_r2_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r3, "t2", dwarf_r3_sw_64, dwarf_r3_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r4, "t3", dwarf_r4_sw_64, dwarf_r4_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r5, "t4", dwarf_r5_sw_64, dwarf_r5_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r6, "t5", dwarf_r6_sw_64, dwarf_r6_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r7, "t6", dwarf_r7_sw_64, dwarf_r7_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r8, "t7", dwarf_r8_sw_64, dwarf_r8_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r9, "s0", dwarf_r9_sw_64, dwarf_r9_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r10, "s1", dwarf_r10_sw_64, dwarf_r10_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r11, "s2", dwarf_r11_sw_64, dwarf_r11_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r12, "s3", dwarf_r12_sw_64, dwarf_r12_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r13, "s4", dwarf_r13_sw_64, dwarf_r13_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r14, "s5", dwarf_r14_sw_64, dwarf_r14_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(fp, "fp", dwarf_fp_sw_64, dwarf_fp_sw_64, + LLDB_REGNUM_GENERIC_FP), + DEFINE_GPR(r16, "a0", dwarf_r16_sw_64, dwarf_r16_sw_64, + LLDB_REGNUM_GENERIC_ARG1), + DEFINE_GPR(r17, "a1", dwarf_r17_sw_64, dwarf_r17_sw_64, + LLDB_REGNUM_GENERIC_ARG2), + DEFINE_GPR(r18, "a2", dwarf_r18_sw_64, dwarf_r18_sw_64, + LLDB_REGNUM_GENERIC_ARG3), + DEFINE_GPR(r19, "a3", dwarf_r19_sw_64, dwarf_r19_sw_64, + LLDB_REGNUM_GENERIC_ARG4), + DEFINE_GPR(r20, "a4", dwarf_r20_sw_64, dwarf_r20_sw_64, + LLDB_REGNUM_GENERIC_ARG5), + DEFINE_GPR(r21, "a5", dwarf_r21_sw_64, dwarf_r21_sw_64, + LLDB_REGNUM_GENERIC_ARG6), + DEFINE_GPR(r22, "t8", dwarf_r22_sw_64, dwarf_r22_sw_64, + LLDB_REGNUM_GENERIC_ARG7), + DEFINE_GPR(r23, "t9", dwarf_r23_sw_64, dwarf_r23_sw_64, + LLDB_REGNUM_GENERIC_ARG8), + DEFINE_GPR(r24, "t10", dwarf_r24_sw_64, dwarf_r24_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r25, "t11", dwarf_r25_sw_64, dwarf_r25_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(ra, "ra", dwarf_ra_sw_64, dwarf_ra_sw_64, + LLDB_REGNUM_GENERIC_RA), + DEFINE_GPR(r27, "pv", dwarf_r27_sw_64, dwarf_r27_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r28, "at", dwarf_r28_sw_64, dwarf_r28_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(gp, "gp", dwarf_gp_sw_64, dwarf_gp_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(sp, "sp", dwarf_sp_sw_64, dwarf_sp_sw_64, + LLDB_REGNUM_GENERIC_SP), + DEFINE_GPR(zero, "zero", dwarf_zero_sw_64, dwarf_zero_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(pc, "pc", dwarf_pc_sw_64, dwarf_pc_sw_64, + LLDB_REGNUM_GENERIC_PC), + DEFINE_FPR(f0, nullptr, dwarf_f0_sw_64, dwarf_f0_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f1, nullptr, dwarf_f1_sw_64, dwarf_f1_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f2, nullptr, dwarf_f2_sw_64, dwarf_f2_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f3, nullptr, dwarf_f3_sw_64, dwarf_f3_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f4, nullptr, dwarf_f4_sw_64, dwarf_f4_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f5, nullptr, dwarf_f5_sw_64, dwarf_f5_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f6, nullptr, dwarf_f6_sw_64, dwarf_f6_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f7, nullptr, dwarf_f7_sw_64, dwarf_f7_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f8, nullptr, dwarf_f8_sw_64, dwarf_f8_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f9, nullptr, dwarf_f9_sw_64, dwarf_f9_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f10, nullptr, dwarf_f10_sw_64, dwarf_f10_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f11, nullptr, dwarf_f11_sw_64, dwarf_f11_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f12, nullptr, dwarf_f12_sw_64, dwarf_f12_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f13, nullptr, dwarf_f13_sw_64, dwarf_f13_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f14, nullptr, dwarf_f14_sw_64, dwarf_f14_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f15, nullptr, dwarf_f15_sw_64, dwarf_f15_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f16, nullptr, dwarf_f16_sw_64, dwarf_f16_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f17, nullptr, dwarf_f17_sw_64, dwarf_f17_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f18, nullptr, dwarf_f18_sw_64, dwarf_f18_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f19, nullptr, dwarf_f19_sw_64, dwarf_f19_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f20, nullptr, dwarf_f20_sw_64, dwarf_f20_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f21, nullptr, dwarf_f21_sw_64, dwarf_f21_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f22, nullptr, dwarf_f22_sw_64, dwarf_f22_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f23, nullptr, dwarf_f23_sw_64, dwarf_f23_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f24, nullptr, dwarf_f24_sw_64, dwarf_f24_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f25, nullptr, dwarf_f25_sw_64, dwarf_f25_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f26, nullptr, dwarf_f26_sw_64, dwarf_f26_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f27, nullptr, dwarf_f27_sw_64, dwarf_f27_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f28, nullptr, dwarf_f28_sw_64, dwarf_f28_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f29, nullptr, dwarf_f29_sw_64, dwarf_f29_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f30, nullptr, dwarf_f30_sw_64, dwarf_f30_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f31, nullptr, dwarf_f31_sw_64, dwarf_f31_sw_64, + LLDB_INVALID_REGNUM), + DEFINE_SIMD(v0, nullptr, dwarf_v0_sw_64, dwarf_v0_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v1, nullptr, dwarf_v1_sw_64, dwarf_v1_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v2, nullptr, dwarf_v2_sw_64, dwarf_v2_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v3, nullptr, dwarf_v3_sw_64, dwarf_v3_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v4, nullptr, dwarf_v4_sw_64, dwarf_v4_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v5, nullptr, dwarf_v5_sw_64, dwarf_v5_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v6, nullptr, dwarf_v6_sw_64, dwarf_v6_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v7, nullptr, dwarf_v7_sw_64, dwarf_v7_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v8, nullptr, dwarf_v8_sw_64, dwarf_v8_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v9, nullptr, dwarf_v9_sw_64, dwarf_v9_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v10, nullptr, dwarf_v10_sw_64, dwarf_v10_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v11, nullptr, dwarf_v11_sw_64, dwarf_v11_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v12, nullptr, dwarf_v12_sw_64, dwarf_v12_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v13, nullptr, dwarf_v13_sw_64, dwarf_v13_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v14, nullptr, dwarf_v14_sw_64, dwarf_v14_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v15, nullptr, dwarf_v15_sw_64, dwarf_v15_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v16, nullptr, dwarf_v16_sw_64, dwarf_v16_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v17, nullptr, dwarf_v17_sw_64, dwarf_v17_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v18, nullptr, dwarf_v18_sw_64, dwarf_v18_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v19, nullptr, dwarf_v19_sw_64, dwarf_v19_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v20, nullptr, dwarf_v20_sw_64, dwarf_v20_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v21, nullptr, dwarf_v21_sw_64, dwarf_v21_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v22, nullptr, dwarf_v22_sw_64, dwarf_v22_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v23, nullptr, dwarf_v23_sw_64, dwarf_v23_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v24, nullptr, dwarf_v24_sw_64, dwarf_v24_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v25, nullptr, dwarf_v25_sw_64, dwarf_v25_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v26, nullptr, dwarf_v26_sw_64, dwarf_v26_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v27, nullptr, dwarf_v27_sw_64, dwarf_v27_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v28, nullptr, dwarf_v28_sw_64, dwarf_v28_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v29, nullptr, dwarf_v29_sw_64, dwarf_v29_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v30, nullptr, dwarf_v30_sw_64, dwarf_v30_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_SIMD(v31, nullptr, dwarf_v31_sw_64, dwarf_v31_sw_64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + +#endif +}; + +static_assert((sizeof(g_register_infos_sw_64) / + sizeof(g_register_infos_sw_64[0])) == k_num_registers_sw_64, + "g_register_infos_sw_64 has wrong number of register infos"); + +#undef DEFINE_GPR +#undef DEFINE_GPR_INFO +#undef DEFINE_FPR +#undef DEFINE_FPR_INFO +#undef GPR_OFFSET +#undef FPR_OFFSET + +#endif // DECLARE_REGISTER_INFOS_SW64_STRUCT diff --git a/lldb/source/Plugins/Process/Utility/lldb-sw_64-linux-register-enums.h b/lldb/source/Plugins/Process/Utility/lldb-sw_64-linux-register-enums.h new file mode 100755 index 000000000000..c8361d94bb76 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/lldb-sw_64-linux-register-enums.h @@ -0,0 +1,206 @@ +//===-- lldb-sw_64-linux-register-enums.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_sw_64_linux_register_enums_h +#define lldb_sw_64_linux_register_enums_h + +namespace lldb_private { +// LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) + +// Internal codes for all sw_64 registers. +enum { + k_first_gpr_sw_64, + gpr_r0_sw_64 = k_first_gpr_sw_64, + gpr_r1_sw_64, + gpr_r2_sw_64, + gpr_r3_sw_64, + gpr_r4_sw_64, + gpr_r5_sw_64, + gpr_r6_sw_64, + gpr_r7_sw_64, + gpr_r8_sw_64, + gpr_r9_sw_64, + gpr_r10_sw_64, + gpr_r11_sw_64, + gpr_r12_sw_64, + gpr_r13_sw_64, + gpr_r14_sw_64, + gpr_fp_sw_64, + gpr_r16_sw_64, + gpr_r17_sw_64, + gpr_r18_sw_64, + gpr_r19_sw_64, + gpr_r20_sw_64, + gpr_r21_sw_64, + gpr_r22_sw_64, + gpr_r23_sw_64, + gpr_r24_sw_64, + gpr_r25_sw_64, + gpr_ra_sw_64, + gpr_r27_sw_64, + gpr_r28_sw_64, + gpr_gp_sw_64, + gpr_sp_sw_64, + gpr_zero_sw_64, + gpr_pc_sw_64, + k_last_gpr_sw_64 = gpr_pc_sw_64, + + k_first_fpr_sw_64, + fpr_f0_sw_64 = k_first_fpr_sw_64, + fpr_f1_sw_64, + fpr_f2_sw_64, + fpr_f3_sw_64, + fpr_f4_sw_64, + fpr_f5_sw_64, + fpr_f6_sw_64, + fpr_f7_sw_64, + fpr_f8_sw_64, + fpr_f9_sw_64, + fpr_f10_sw_64, + fpr_f11_sw_64, + fpr_f12_sw_64, + fpr_f13_sw_64, + fpr_f14_sw_64, + fpr_f15_sw_64, + fpr_f16_sw_64, + fpr_f17_sw_64, + fpr_f18_sw_64, + fpr_f19_sw_64, + fpr_f20_sw_64, + fpr_f21_sw_64, + fpr_f22_sw_64, + fpr_f23_sw_64, + fpr_f24_sw_64, + fpr_f25_sw_64, + fpr_f26_sw_64, + fpr_f27_sw_64, + fpr_f28_sw_64, + fpr_f29_sw_64, + fpr_f30_sw_64, + fpr_f31_sw_64, + k_last_fpr_sw_64 = fpr_f31_sw_64, + + k_first_simd_sw_64, + simd_v0_sw_64 = k_first_simd_sw_64, + simd_v1_sw_64, + simd_v2_sw_64, + simd_v3_sw_64, + simd_v4_sw_64, + simd_v5_sw_64, + simd_v6_sw_64, + simd_v7_sw_64, + simd_v8_sw_64, + simd_v9_sw_64, + simd_v10_sw_64, + simd_v11_sw_64, + simd_v12_sw_64, + simd_v13_sw_64, + simd_v14_sw_64, + simd_v15_sw_64, + simd_v16_sw_64, + simd_v17_sw_64, + simd_v18_sw_64, + simd_v19_sw_64, + simd_v20_sw_64, + simd_v21_sw_64, + simd_v22_sw_64, + simd_v23_sw_64, + simd_v24_sw_64, + simd_v25_sw_64, + simd_v26_sw_64, + simd_v27_sw_64, + simd_v28_sw_64, + simd_v29_sw_64, + simd_v30_sw_64, + simd_v31_sw_64, + k_last_simd_sw_64 = simd_v31_sw_64, + + k_num_registers_sw_64, // total number of registers: gpr + fpr + simd + + k_num_gpr_registers_sw_64 = k_last_gpr_sw_64 - k_first_gpr_sw_64 + 1, + k_num_fpr_registers_sw_64 = k_last_fpr_sw_64 - k_first_fpr_sw_64 + 1, + k_num_simd_registers_sw_64 = k_last_simd_sw_64 - k_first_simd_sw_64 + 1, + k_num_user_registers_sw_64 = k_num_gpr_registers_sw_64 + + k_num_fpr_registers_sw_64 + + k_num_simd_registers_sw_64 +}; + +// Register no. for RegisterKind = eRegisterKindProcessPlugin +// The ptrace request PTRACE_PEEKUSER/PTRACE_POKEUSER used this number + +enum { + ptrace_r0_sw_64, + ptrace_r1_sw_64, + ptrace_r2_sw_64, + ptrace_r3_sw_64, + ptrace_r4_sw_64, + ptrace_r5_sw_64, + ptrace_r6_sw_64, + ptrace_r7_sw_64, + ptrace_r8_sw_64, + ptrace_r9_sw_64, + ptrace_r10_sw_64, + ptrace_r11_sw_64, + ptrace_r12_sw_64, + ptrace_r13_sw_64, + ptrace_r14_sw_64, + ptrace_fp_sw_64, + ptrace_r16_sw_64, + ptrace_r17_sw_64, + ptrace_r18_sw_64, + ptrace_r19_sw_64, + ptrace_r20_sw_64, + ptrace_r21_sw_64, + ptrace_r22_sw_64, + ptrace_r23_sw_64, + ptrace_r24_sw_64, + ptrace_r25_sw_64, + ptrace_ra_sw_64, + ptrace_r27_sw_64, + ptrace_r28_sw_64, + ptrace_gp_sw_64, + ptrace_sp_sw_64, + ptrace_zero_sw_64, + ptrace_f0_sw_64, + ptrace_f1_sw_64, + ptrace_f2_sw_64, + ptrace_f3_sw_64, + ptrace_f4_sw_64, + ptrace_f5_sw_64, + ptrace_f6_sw_64, + ptrace_f7_sw_64, + ptrace_f8_sw_64, + ptrace_f9_sw_64, + ptrace_f10_sw_64, + ptrace_f11_sw_64, + ptrace_f12_sw_64, + ptrace_f13_sw_64, + ptrace_f14_sw_64, + ptrace_f15_sw_64, + ptrace_f16_sw_64, + ptrace_f17_sw_64, + ptrace_f18_sw_64, + ptrace_f19_sw_64, + ptrace_f20_sw_64, + ptrace_f21_sw_64, + ptrace_f22_sw_64, + ptrace_f23_sw_64, + ptrace_f24_sw_64, + ptrace_f25_sw_64, + ptrace_f26_sw_64, + ptrace_f27_sw_64, + ptrace_f28_sw_64, + ptrace_f29_sw_64, + ptrace_f30_sw_64, + ptrace_f31_sw_64, + ptrace_pc_sw_64, +}; +} + +#endif // #ifndef lldb_sw_64_linux_register_enums_h diff --git a/lldb/source/Plugins/Process/elf-core/CMakeLists.txt b/lldb/source/Plugins/Process/elf-core/CMakeLists.txt index 8ddc671e3ae6..9aa125896026 100644 --- a/lldb/source/Plugins/Process/elf-core/CMakeLists.txt +++ b/lldb/source/Plugins/Process/elf-core/CMakeLists.txt @@ -4,6 +4,7 @@ add_lldb_library(lldbPluginProcessElfCore PLUGIN RegisterContextLinuxCore_x86_64.cpp RegisterContextPOSIXCore_arm.cpp RegisterContextPOSIXCore_arm64.cpp + RegisterContextPOSIXCore_sw_64.cpp RegisterContextPOSIXCore_mips64.cpp RegisterContextPOSIXCore_powerpc.cpp RegisterContextPOSIXCore_ppc64le.cpp diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index bfb59eceb2d0..50c4e2b37155 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -1002,6 +1002,12 @@ ArchSpec ProcessElfCore::GetArchitecture() { return target_arch; } +#ifndef LHX20240725 + if (target_arch.IsSw64()) { + return target_arch; + } +#endif + return arch; } diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_sw_64.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_sw_64.cpp new file mode 100755 index 000000000000..625d81e0c75a --- /dev/null +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_sw_64.cpp @@ -0,0 +1,107 @@ +//===-- RegisterContextPOSIXCore_sw_64.cpp ---------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "RegisterContextPOSIXCore_sw_64.h" + +#include "lldb/Target/Thread.h" +#include "lldb/Utility/RegisterValue.h" + +#include + +using namespace lldb_private; + +RegisterContextCorePOSIX_sw_64::RegisterContextCorePOSIX_sw_64( + Thread &thread, RegisterInfoInterface *register_info, + const DataExtractor &gpregset, llvm::ArrayRef notes) + : RegisterContextPOSIX_sw_64(thread, 0, register_info) { + m_gpr_buffer = std::make_shared(gpregset.GetDataStart(), + gpregset.GetByteSize()); + m_gpr.SetData(m_gpr_buffer); + m_gpr.SetByteOrder(gpregset.GetByteOrder()); + + DataExtractor fpregset = getRegset( + notes, register_info->GetTargetArchitecture().GetTriple(), FPR_Desc); + m_fpr_buffer = std::make_shared(fpregset.GetDataStart(), + fpregset.GetByteSize()); + m_fpr.SetData(m_fpr_buffer); + m_fpr.SetByteOrder(fpregset.GetByteOrder()); +} + +RegisterContextCorePOSIX_sw_64::~RegisterContextCorePOSIX_sw_64() {} + +bool RegisterContextCorePOSIX_sw_64::ReadGPR() { return true; } + +bool RegisterContextCorePOSIX_sw_64::ReadFPR() { return false; } + +bool RegisterContextCorePOSIX_sw_64::WriteGPR() { + assert(0); + return false; +} + +bool RegisterContextCorePOSIX_sw_64::WriteFPR() { + assert(0); + return false; +} + +// this refer to mips64 +bool RegisterContextCorePOSIX_sw_64::ReadRegister(const RegisterInfo *reg_info, + RegisterValue &value) { + + lldb::offset_t offset = reg_info->byte_offset; + lldb_private::ArchSpec arch = m_register_info_up->GetTargetArchitecture(); + uint64_t v; + if (IsGPR(reg_info->kinds[lldb::eRegisterKindLLDB])) { + if (reg_info->byte_size == 4 && !(arch.GetMachine() == llvm::Triple::sw_64)) + // In case of 32bit core file, the register data are placed at 4 byte + // offset. + offset = offset / 2; + v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + value = v; + return true; + } else if (IsFPR(reg_info->kinds[lldb::eRegisterKindLLDB])) { + offset = offset - sizeof(GPR_linux_sw_64); + v =m_fpr.GetMaxU64(&offset, reg_info->byte_size); + value = v; + return true; + } + return false; +} + +// this is copy from arm64, no effect +/* +bool RegisterContextCorePOSIX_sw_64::ReadRegister(const RegisterInfo *reg_info, + RegisterValue &value) { + lldb::offset_t offset = reg_info->byte_offset; + uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + if (offset == reg_info->byte_offset + reg_info->byte_size) { + value = v; + return true; + } + return false; +} +*/ + + +bool RegisterContextCorePOSIX_sw_64::ReadAllRegisterValues( + lldb::WritableDataBufferSP &data_sp) { + return false; +} + +bool RegisterContextCorePOSIX_sw_64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue &value) { + return false; +} + +bool RegisterContextCorePOSIX_sw_64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + return false; +} + +bool RegisterContextCorePOSIX_sw_64::HardwareSingleStep(bool enable) { + return false; +} diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_sw_64.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_sw_64.h new file mode 100755 index 000000000000..3c9e244e45f0 --- /dev/null +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_sw_64.h @@ -0,0 +1,55 @@ +//===-- RegisterContextPOSIXCore_sw_64.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 liblldb_RegisterContextCorePOSIX_sw_64_h_ +#define liblldb_RegisterContextCorePOSIX_sw_64_h_ + +#include "Plugins/Process/Utility/RegisterContextPOSIX_sw_64.h" +#include "Plugins/Process/elf-core/RegisterUtilities.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/DataExtractor.h" +//LHX: this file mostly same to aarch64, mips64, ppc64, x86_64 +class RegisterContextCorePOSIX_sw_64 : public RegisterContextPOSIX_sw_64 { +public: + RegisterContextCorePOSIX_sw_64( + lldb_private::Thread &thread, + lldb_private::RegisterInfoInterface *register_info, + const lldb_private::DataExtractor &gpregset, + llvm::ArrayRef notes); + + ~RegisterContextCorePOSIX_sw_64() override; + + bool ReadRegister(const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue &value) override; + + bool WriteRegister(const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue &value) override; + + bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override; + + bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + bool HardwareSingleStep(bool enable) override; + +protected: + bool ReadGPR() override; + + bool ReadFPR() override; + + bool WriteGPR() override; + + bool WriteFPR() override; + +private: + lldb::DataBufferSP m_gpr_buffer; + lldb::DataBufferSP m_fpr_buffer; + lldb_private::DataExtractor m_gpr; + lldb_private::DataExtractor m_fpr; +}; + +#endif // liblldb_RegisterContextCorePOSIX_sw_64_h_ diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 3ce2a4a5c3fa..ba5e536ba751 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -319,7 +319,11 @@ ELFLinuxPrPsInfo::ELFLinuxPrPsInfo() { size_t ELFLinuxPrPsInfo::GetSize(const lldb_private::ArchSpec &arch) { constexpr size_t mips_linux_pr_psinfo_size_o32_n32 = 128; +#ifndef LHX20240725 + if (arch.IsMIPS() || arch.IsSw64()) { +#else if (arch.IsMIPS()) { +#endif uint8_t address_byte_size = arch.GetAddressByteSize(); if (address_byte_size == 8) return sizeof(ELFLinuxPrPsInfo); @@ -362,7 +366,11 @@ Status ELFLinuxPrPsInfo::Parse(const DataExtractor &data, pr_flag = data.GetAddress(&offset); +#ifndef LHX20210811 + if (arch.IsMIPS() || arch.IsSw64()) { +#else if (arch.IsMIPS()) { +#endif // The pr_uid and pr_gid is always 32 bit irrespective of platforms pr_uid = data.GetU32(&offset); pr_gid = data.GetU32(&offset); @@ -394,6 +402,8 @@ ELFLinuxSigInfo::ELFLinuxSigInfo() { memset(this, 0, sizeof(ELFLinuxSigInfo)); } size_t ELFLinuxSigInfo::GetSize(const lldb_private::ArchSpec &arch) { if (arch.IsMIPS()) return sizeof(ELFLinuxSigInfo); + if (arch.IsSw64()) + return sizeof(ELFLinuxSigInfo); switch (arch.GetCore()) { case lldb_private::ArchSpec::eCore_x86_64_x86_64: return sizeof(ELFLinuxSigInfo); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index b4fb5b68dd41..5a7aa31e79ff 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -231,7 +231,7 @@ GDBRemoteCommunicationServerCommon::Handle_qHostInfo( host_arch.GetMachine() == llvm::Triple::aarch64_32 || host_arch.GetMachine() == llvm::Triple::aarch64_be || host_arch.GetMachine() == llvm::Triple::arm || - host_arch.GetMachine() == llvm::Triple::armeb || host_arch.IsMIPS()) + host_arch.GetMachine() == llvm::Triple::armeb || host_arch.IsMIPS() || host_arch.IsSw64()) response.Printf("watchpoint_exceptions_received:before;"); else response.Printf("watchpoint_exceptions_received:after;"); diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp index 11a123fb6d58..b396dfad2581 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -1899,6 +1899,14 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target, trap_opcode_size = sizeof(g_msp430_opcode); } break; +#ifndef LHX20240723 + case llvm::Triple::sw_64: { + static const uint8_t g_hex_opcode[] = {0x80, 0x00, 0x00, 0x00}; + trap_opcode = g_hex_opcode; + trap_opcode_size = sizeof(g_hex_opcode); + } break; +#endif + case llvm::Triple::systemz: { static const uint8_t g_hex_opcode[] = {0x00, 0x01}; trap_opcode = g_hex_opcode; diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index fb0e985a0d56..32e50a14c539 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -110,6 +110,13 @@ static const CoreDefinition g_core_definitions[] = { {eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64, ArchSpec::eCore_arm_aarch64, "aarch64"}, +#ifndef LHX20240726 + // The index order must be same with enum Core in include/lldb/Utility/ArchSpec.h + // i.e. the branch of sw_64 needs follow with aarch64 + {eByteOrderLittle, 8, 4, 4, llvm::Triple::sw_64, + ArchSpec::eCore_sw_64, "sw_64"}, +#endif + // mips32, mips32r2, mips32r3, mips32r5, mips32r6 {eByteOrderBig, 4, 2, 4, llvm::Triple::mips, ArchSpec::eCore_mips32, "mips"}, @@ -376,6 +383,11 @@ static const ArchDefinitionEntry g_elf_arch_entries[] = { 0xFFFFFFFFu, 0xFFFFFFFFu}, // ARM {ArchSpec::eCore_arm_aarch64, llvm::ELF::EM_AARCH64, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // ARM64 +#ifndef LHX20240718 + {ArchSpec::eCore_sw_64, llvm::ELF::EM_SW64, + ArchSpec::eSW64SubType_sw_64, 0xFFFFFFFFu, 0xFFFFFFFFu}, + //LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // SW64 +#endif {ArchSpec::eCore_s390x_generic, llvm::ELF::EM_S390, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // SystemZ {ArchSpec::eCore_sparc9_generic, llvm::ELF::EM_SPARCV9, @@ -558,6 +570,8 @@ const char *ArchSpec::GetArchitectureName() const { bool ArchSpec::IsMIPS() const { return GetTriple().isMIPS(); } +bool ArchSpec::IsSw64() const { return GetTriple().isSw64(); } + std::string ArchSpec::GetTargetABI() const { std::string abi; @@ -643,6 +657,21 @@ std::string ArchSpec::GetClangTargetCPU() const { } } + if (IsSw64()) { + switch (m_core) { + case ArchSpec::eCore_sw_64: +// This cpu name must same with clang/lib/Driver/ToolChains/Arch/Sw64.cpp +#ifdef __sw_64_sw8a__ + cpu = "sw8a"; +#else + cpu = "sw6b"; +#endif + break; + default: + break; + } + } + if (GetTriple().isARM()) cpu = llvm::ARM::getARMCPUForArch(GetTriple(), "").str(); return cpu; @@ -1268,6 +1297,15 @@ static bool cores_match(const ArchSpec::Core core1, const ArchSpec::Core core2, } break; + case ArchSpec::eCore_sw_64: + if (!enforce_exact_match) { + if (core2 >= ArchSpec::kCore_sw_64_first && + core2 <= ArchSpec::kCore_sw_64_last) + return true; + try_inverse = false; + } + break; + case ArchSpec::eCore_mips32: if (!enforce_exact_match) { if (core2 >= ArchSpec::kCore_mips32_first && -- Gitee