diff --git a/Add-support-for-sw64.patch b/Add-support-for-sw64.patch new file mode 100644 index 0000000000000000000000000000000000000000..31c625f42097d59ca18d7a14e96509b5df11f96a --- /dev/null +++ b/Add-support-for-sw64.patch @@ -0,0 +1,5087 @@ +From cee68ee49c3339d77d49c0cf816c424c430f9ce9 Mon Sep 17 00:00:00 2001 +From: Liu Hanxu +Date: Thu, 20 Feb 2025 05:57:30 +0000 +Subject: [PATCH] Add support for sw64 + +--- + 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 100644 lldb/source/Plugins/ABI/Sw64/ABISw64.cpp + create mode 100644 lldb/source/Plugins/ABI/Sw64/ABISw64.h + create mode 100644 lldb/source/Plugins/ABI/Sw64/ABISysV_sw_64.cpp + create mode 100644 lldb/source/Plugins/ABI/Sw64/ABISysV_sw_64.h + create mode 100644 lldb/source/Plugins/ABI/Sw64/CMakeLists.txt + create mode 100644 lldb/source/Plugins/Architecture/Sw64/ArchitectureSw64.cpp + create mode 100644 lldb/source/Plugins/Architecture/Sw64/ArchitectureSw64.h + create mode 100644 lldb/source/Plugins/Architecture/Sw64/CMakeLists.txt + create mode 100644 lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_sw_64.cpp + create mode 100644 lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_sw_64.h + create mode 100644 lldb/source/Plugins/Process/Utility/RegisterContextLinux_sw_64.cpp + create mode 100644 lldb/source/Plugins/Process/Utility/RegisterContextLinux_sw_64.h + create mode 100644 lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_sw_64.cpp + create mode 100644 lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_sw_64.h + create mode 100644 lldb/source/Plugins/Process/Utility/RegisterContext_sw_64.h + create mode 100644 lldb/source/Plugins/Process/Utility/RegisterInfos_sw_64.h + create mode 100644 lldb/source/Plugins/Process/Utility/lldb-sw_64-linux-register-enums.h + create mode 100644 lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_sw_64.cpp + create mode 100644 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 a226a3a5a..723b326a7 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 5c44c2f38..094ae1254 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 b3ef8f027..d111b5ede 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 828aea674..8986d9cc5 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 100644 +index 000000000..d7de4869f +--- /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 100644 +index 000000000..08a0f8cec +--- /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 100644 +index 000000000..b13f9ed60 +--- /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 100644 +index 000000000..db353f894 +--- /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 100644 +index 000000000..1f9bb2521 +--- /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 9ed8edf70..81473d7c6 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 100644 +index 000000000..89ba4b254 +--- /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 100644 +index 000000000..790a90d92 +--- /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 100644 +index 000000000..79f83b0aa +--- /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 09115cc67..7690d36e7 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 b0afe0394..bd895df42 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 a6e385f70..de189f956 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 700af84a1..068eacdc7 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 149f541a5..3a9ea3677 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 708252f88..4a34d8ac8 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 100644 +index 000000000..56205c8f9 +--- /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 100644 +index 000000000..8578bcf15 +--- /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 1ebd0484f..f3bb3f75e 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 3f25dbc6a..a9067bd17 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 100644 +index 000000000..c681e4f9e +--- /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 100644 +index 000000000..dc525ce19 +--- /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 100644 +index 000000000..c6104a4db +--- /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 100644 +index 000000000..7261b285e +--- /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 100644 +index 000000000..eb95b25b4 +--- /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 100644 +index 000000000..9549ebd47 +--- /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 100644 +index 000000000..c8361d94b +--- /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 8ddc671e3..9aa125896 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 bfb59eceb..50c4e2b37 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 100644 +index 000000000..625d81e0c +--- /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 100644 +index 000000000..3c9e244e4 +--- /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 3ce2a4a5c..ba5e536ba 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 b4fb5b68d..5a7aa31e7 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 11a123fb6..b396dfad2 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 fb0e985a0..32e50a14c 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 && +-- +2.33.0 + diff --git a/lldb.spec b/lldb.spec index f758d653bc166bdd2d33f52ed239339722083d04..43060b4a0167db627916e72733fa90fcaeab9c74 100644 --- a/lldb.spec +++ b/lldb.spec @@ -2,12 +2,13 @@ Name: lldb Version: 17.0.6 -Release: 2 +Release: 3 Summary: Next generation high-performance debugger License: NCSA URL: http://lldb.llvm.org/ Source0: https://github.com/llvm/llvm-project/releases/download/llvmorg-%{version}/%{name}-%{version}.src.tar.xz +Patch0: Add-support-for-sw64.patch BuildRequires: gcc BuildRequires: gcc-c++ @@ -131,6 +132,9 @@ rm -f %{buildroot}%{python3_sitearch}/six.* %{python3_sitearch}/lldb %changelog +* Thu Feb 20 2025 Liu Hanxu - 17.0.6-3 +- Add support for sw64 + * Tue Aug 20 2024 liyunfei - 17.0.6-2 - Add BiSheng Autotuner support.