Index: cmake/LLDBDependencies.cmake =================================================================== --- cmake/LLDBDependencies.cmake +++ cmake/LLDBDependencies.cmake @@ -66,6 +66,7 @@ lldbPluginABISysV_ppc64 lldbPluginABISysV_mips lldbPluginABISysV_mips64 + lldbPluginABISysV_s390x lldbPluginInstructionARM lldbPluginInstructionARM64 lldbPluginInstructionMIPS Index: include/lldb/Core/ArchSpec.h =================================================================== --- include/lldb/Core/ArchSpec.h +++ include/lldb/Core/ArchSpec.h @@ -151,6 +151,8 @@ eCore_ppc64_generic, eCore_ppc64_ppc970_64, + eCore_s390x_generic, + eCore_sparc_generic, eCore_sparc9_generic, Index: packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py +++ packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py @@ -113,6 +113,8 @@ self.runCmd("breakpoint modify -c ($r0&&i)") elif re.match("mips",arch): self.runCmd("breakpoint modify -c ($r2&&i)") + elif arch in ['s390x']: + self.runCmd("breakpoint modify -c ($r2&&i)") self.runCmd("run") self.expect("process status", PROCESS_STOPPED, Index: packages/Python/lldbsuite/test/functionalities/disassembly/TestDisassembleBreakpoint.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/disassembly/TestDisassembleBreakpoint.py +++ packages/Python/lldbsuite/test/functionalities/disassembly/TestDisassembleBreakpoint.py @@ -43,6 +43,9 @@ elif re.match("mips" , arch): breakpoint_opcodes = ["break"] instructions = ['lw', 'sw'] + elif arch in ["s390x"]: + breakpoint_opcodes = [".long"] + instructions = [' l ', ' a ', ' st '] else: # TODO please add your arch here self.fail('unimplemented for arch = "{arch}"'.format(arch=self.getArchitecture())) Index: packages/Python/lldbsuite/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py +++ packages/Python/lldbsuite/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py @@ -33,6 +33,7 @@ @expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") @expectedFailureAll(triple = re.compile('^mips')) # Most of the MIPS boards provide only one H/W watchpoints, and S/W watchpoints are not supported yet + @expectedFailureAll(archs=['s390x']) # SystemZ also currently supports only one H/W watchpoint @skipIfDarwin def test_hello_watchlocation(self): """Test watching a location with '-s size' option.""" Index: packages/Python/lldbsuite/test/functionalities/watchpoint/step_over_watchpoint/TestStepOverWatchpoint.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/watchpoint/step_over_watchpoint/TestStepOverWatchpoint.py +++ packages/Python/lldbsuite/test/functionalities/watchpoint/step_over_watchpoint/TestStepOverWatchpoint.py @@ -20,6 +20,7 @@ @expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported @expectedFailureAll(oslist=["linux"], archs=['aarch64', 'arm'], bugnumber="llvm.org/pr26031") @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") + @expectedFailureAll(archs=['s390x']) # Read-write watchpoints not supported on SystemZ def test(self): """Test stepping over watchpoints.""" self.build() Index: packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py +++ packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py @@ -32,6 +32,7 @@ @expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") + @expectedFailureAll(archs=['s390x']) # Read-write watchpoints not supported on SystemZ def test_rw_watchpoint(self): """Test read_write watchpoint and expect to stop two times.""" self.build(dictionary=self.d) @@ -92,6 +93,7 @@ @expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") + @expectedFailureAll(archs=['s390x']) # Read-write watchpoints not supported on SystemZ def test_rw_watchpoint_delete(self): """Test delete watchpoint and expect not to stop for watchpoint.""" self.build(dictionary=self.d) @@ -137,6 +139,7 @@ @expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") + @expectedFailureAll(archs=['s390x']) # Read-write watchpoints not supported on SystemZ def test_rw_watchpoint_set_ignore_count(self): """Test watchpoint ignore count and expect to not to stop at all.""" self.build(dictionary=self.d) @@ -186,6 +189,7 @@ @expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") + @expectedFailureAll(archs=['s390x']) # Read-write watchpoints not supported on SystemZ def test_rw_disable_after_first_stop(self): """Test read_write watchpoint but disable it after the first stop.""" self.build(dictionary=self.d) @@ -245,6 +249,7 @@ @expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") + @expectedFailureAll(archs=['s390x']) # Read-write watchpoints not supported on SystemZ def test_rw_disable_then_enable(self): """Test read_write watchpoint, disable initially, then enable it.""" self.build(dictionary=self.d) Index: packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py +++ packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py @@ -59,7 +59,7 @@ self.listener.StartListeningForEvents (self.target_bcast, lldb.SBTarget.eBroadcastBitWatchpointChanged) error = lldb.SBError() - local_watch = local_var.Watch(True, True, True, error) + local_watch = local_var.Watch(True, False, True, error) if not error.Success(): self.fail ("Failed to make watchpoint for local_var: %s"%(error.GetCString())) Index: packages/Python/lldbsuite/test/lldbplatformutil.py =================================================================== --- packages/Python/lldbsuite/test/lldbplatformutil.py +++ packages/Python/lldbsuite/test/lldbplatformutil.py @@ -29,6 +29,8 @@ test_case.expect("register read x0", substrs = ['x0 = 0x']) elif re.match("mips",arch): test_case.expect("register read zero", substrs = ['zero = 0x']) + elif arch in ['s390x']: + test_case.expect("register read r0", substrs = ['r0 = 0x']) else: # TODO: Add check for other architectures test_case.fail("Unsupported architecture for test case (arch: %s)" % test_case.getArchitecture()) Index: packages/Python/lldbsuite/test/make/Makefile.rules =================================================================== --- packages/Python/lldbsuite/test/make/Makefile.rules +++ packages/Python/lldbsuite/test/make/Makefile.rules @@ -168,6 +168,10 @@ override ARCH := override ARCHFLAG := endif + ifeq "$(ARCH)" "s390x" + override ARCH := + override ARCHFLAG := + endif ifeq "$(findstring mips,$(ARCH))" "mips" override ARCHFLAG := - endif Index: packages/Python/lldbsuite/test/python_api/watchpoint/TestSetWatchpoint.py =================================================================== --- packages/Python/lldbsuite/test/python_api/watchpoint/TestSetWatchpoint.py +++ packages/Python/lldbsuite/test/python_api/watchpoint/TestSetWatchpoint.py @@ -28,6 +28,7 @@ @add_test_categories(['pyapi']) @expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") + @expectedFailureAll(archs=['s390x']) # Read-write watchpoints not supported on SystemZ def test_watch_val(self): """Exercise SBValue.Watch() API to set a watchpoint.""" self.build() Index: packages/Python/lldbsuite/test/python_api/watchpoint/TestWatchpointIgnoreCount.py =================================================================== --- packages/Python/lldbsuite/test/python_api/watchpoint/TestWatchpointIgnoreCount.py +++ packages/Python/lldbsuite/test/python_api/watchpoint/TestWatchpointIgnoreCount.py @@ -28,6 +28,7 @@ @add_test_categories(['pyapi']) @expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") + @expectedFailureAll(archs=['s390x']) # Read-write watchpoints not supported on SystemZ def test_set_watch_ignore_count(self): """Test SBWatchpoint.SetIgnoreCount() API.""" self.build() Index: packages/Python/lldbsuite/test/python_api/watchpoint/TestWatchpointIter.py =================================================================== --- packages/Python/lldbsuite/test/python_api/watchpoint/TestWatchpointIter.py +++ packages/Python/lldbsuite/test/python_api/watchpoint/TestWatchpointIter.py @@ -58,7 +58,7 @@ # Watch 'global' for read and write. value = frame0.FindValue('global', lldb.eValueTypeVariableGlobal) error = lldb.SBError(); - watchpoint = value.Watch(True, True, True, error) + watchpoint = value.Watch(True, False, True, error) self.assertTrue(value and watchpoint, "Successfully found the variable and set a watchpoint") self.DebugSBValue(value) Index: packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py =================================================================== --- packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py +++ packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py @@ -93,6 +93,7 @@ @add_test_categories(['pyapi']) @expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported @skipIf(archs=['mips', 'mipsel', 'mips64', 'mips64el']) # No size constraint on MIPS for watches + @skipIf(archs=['s390x']) # Likewise on SystemZ def test_watch_address_with_invalid_watch_size(self): """Exercise SBTarget.WatchAddress() API but pass an invalid watch_size.""" self.build() Index: packages/Python/lldbsuite/test/tools/lldb-mi/control/TestMiExec.py =================================================================== --- packages/Python/lldbsuite/test/tools/lldb-mi/control/TestMiExec.py +++ packages/Python/lldbsuite/test/tools/lldb-mi/control/TestMiExec.py @@ -234,18 +234,20 @@ # Test that --thread is optional self.runCmd("-exec-next-instruction --frame 0") self.expect("\^running") - self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"28\"") + # Depending on compiler, it can stop at different line + self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"(28|29)\"") # Test that --frame is optional self.runCmd("-exec-next-instruction --thread 1") self.expect("\^running") - self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"29\"") + # Depending on compiler, it can stop at different line + self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"(29|30)\"") # Test that both --thread and --frame are optional self.runCmd("-exec-next-instruction") self.expect("\^running") # Depending on compiler, it can stop at different line - self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"(29|30)\"") + self.expect("\*stopped,reason=\"end-stepping-range\".+?main\.cpp\",line=\"(29|30|31)\"") # Test that an invalid --thread is handled self.runCmd("-exec-next-instruction --thread 0") Index: packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py =================================================================== --- packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py +++ packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py @@ -1355,6 +1355,9 @@ #MIPS required "3" (ADDIU, SB, LD) machine instructions for updation of variable value if re.match("mips",arch): expected_step_count = 3 + #S390X requires "2" (LARL, MVI) machine instructions for updation of variable value + if re.match("s390x",arch): + expected_step_count = 2 self.assertEqual(step_count, expected_step_count) # Verify we hit the next state. Index: source/API/SystemInitializerFull.cpp =================================================================== --- source/API/SystemInitializerFull.cpp +++ source/API/SystemInitializerFull.cpp @@ -39,6 +39,7 @@ #include "Plugins/ABI/SysV-mips64/ABISysV_mips64.h" #include "Plugins/ABI/SysV-ppc/ABISysV_ppc.h" #include "Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h" +#include "Plugins/ABI/SysV-s390x/ABISysV_s390x.h" #include "Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h" #include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h" #include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" @@ -302,6 +303,7 @@ ABISysV_ppc64::Initialize(); ABISysV_mips::Initialize(); ABISysV_mips64::Initialize(); + ABISysV_s390x::Initialize(); DisassemblerLLVMC::Initialize(); JITLoaderGDB::Initialize(); @@ -430,6 +432,7 @@ ABISysV_ppc64::Terminate(); ABISysV_mips::Terminate(); ABISysV_mips64::Terminate(); + ABISysV_s390x::Terminate(); DisassemblerLLVMC::Terminate(); JITLoaderGDB::Terminate(); Index: source/Core/ArchSpec.cpp =================================================================== --- source/Core/ArchSpec.cpp +++ source/Core/ArchSpec.cpp @@ -130,6 +130,8 @@ { eByteOrderBig , 8, 4, 4, llvm::Triple::ppc64 , ArchSpec::eCore_ppc64_generic , "powerpc64" }, { eByteOrderBig , 8, 4, 4, llvm::Triple::ppc64 , ArchSpec::eCore_ppc64_ppc970_64 , "ppc970-64" }, + { eByteOrderBig , 8, 2, 6, llvm::Triple::systemz, ArchSpec::eCore_s390x_generic , "s390x" }, + { eByteOrderLittle, 4, 4, 4, llvm::Triple::sparc , ArchSpec::eCore_sparc_generic , "sparc" }, { eByteOrderLittle, 8, 4, 4, llvm::Triple::sparcv9, ArchSpec::eCore_sparc9_generic , "sparcv9" }, @@ -285,6 +287,7 @@ { ArchSpec::eCore_ppc64_generic , llvm::ELF::EM_PPC64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC64 { ArchSpec::eCore_arm_generic , llvm::ELF::EM_ARM , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM { ArchSpec::eCore_arm_aarch64 , llvm::ELF::EM_AARCH64, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM64 + { ArchSpec::eCore_s390x_generic , llvm::ELF::EM_S390 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // SystemZ { ArchSpec::eCore_sparc9_generic , llvm::ELF::EM_SPARCV9, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // SPARC V9 { ArchSpec::eCore_x86_64_x86_64 , llvm::ELF::EM_X86_64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // AMD64 { ArchSpec::eCore_mips32 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32 Index: source/Host/common/HostInfoBase.cpp =================================================================== --- source/Host/common/HostInfoBase.cpp +++ source/Host/common/HostInfoBase.cpp @@ -420,6 +420,7 @@ case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::sparcv9: + case llvm::Triple::systemz: arch_64.SetTriple(triple); break; } Index: source/Plugins/ABI/CMakeLists.txt =================================================================== --- source/Plugins/ABI/CMakeLists.txt +++ source/Plugins/ABI/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory(SysV-ppc64) add_subdirectory(SysV-mips) add_subdirectory(SysV-mips64) +add_subdirectory(SysV-s390x) add_subdirectory(SysV-i386) add_subdirectory(SysV-x86_64) add_subdirectory(MacOSX-i386) Index: source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h =================================================================== --- source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h +++ source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h @@ -0,0 +1,123 @@ +//===-- ABISysV_s390x.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ABISysV_s390x_h_ +#define liblldb_ABISysV_s390x_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Target/ABI.h" + +class ABISysV_s390x : public lldb_private::ABI +{ +public: + ~ABISysV_s390x() 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::Error + 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; + + int64_t + CFAOffset() const override + { + // On SystemZ, the CFA is at incoming SP + 160. + return 160; + } + + bool + RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override; + + 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 + { + // Code addressed must be 2 byte aligned + if (pc & 1ull) + return false; + return true; + } + + const lldb_private::RegisterInfo * + GetRegisterInfoArray(uint32_t &count) override; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + + static void + Initialize(); + + static void + Terminate(); + + static lldb::ABISP + CreateInstance(const lldb_private::ArchSpec &arch); + + static lldb_private::ConstString + GetPluginNameStatic(); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + + lldb_private::ConstString + GetPluginName() override; + + uint32_t + GetPluginVersion() override; + +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: + ABISysV_s390x() : lldb_private::ABI() + { + // Call CreateInstance instead. + } +}; + +#endif // liblldb_ABISysV_s390x_h_ Index: source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp =================================================================== --- source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp +++ source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp @@ -0,0 +1,793 @@ +//===-- ABISysV_s390x.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ABISysV_s390x.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" + +// Project includes +#include "lldb/Core/ConstString.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/RegisterValue.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" + +using namespace lldb; +using namespace lldb_private; + +enum dwarf_regnums +{ + // General Purpose Registers + dwarf_r0_s390x = 0, + dwarf_r1_s390x, + dwarf_r2_s390x, + dwarf_r3_s390x, + dwarf_r4_s390x, + dwarf_r5_s390x, + dwarf_r6_s390x, + dwarf_r7_s390x, + dwarf_r8_s390x, + dwarf_r9_s390x, + dwarf_r10_s390x, + dwarf_r11_s390x, + dwarf_r12_s390x, + dwarf_r13_s390x, + dwarf_r14_s390x, + dwarf_r15_s390x, + // Floating Point Registers / Vector Registers 0-15 + dwarf_f0_s390x = 16, + dwarf_f2_s390x, + dwarf_f4_s390x, + dwarf_f6_s390x, + dwarf_f1_s390x, + dwarf_f3_s390x, + dwarf_f5_s390x, + dwarf_f7_s390x, + dwarf_f8_s390x, + dwarf_f10_s390x, + dwarf_f12_s390x, + dwarf_f14_s390x, + dwarf_f9_s390x, + dwarf_f11_s390x, + dwarf_f13_s390x, + dwarf_f15_s390x, + // Access Registers + dwarf_acr0_s390x = 48, + dwarf_acr1_s390x, + dwarf_acr2_s390x, + dwarf_acr3_s390x, + dwarf_acr4_s390x, + dwarf_acr5_s390x, + dwarf_acr6_s390x, + dwarf_acr7_s390x, + dwarf_acr8_s390x, + dwarf_acr9_s390x, + dwarf_acr10_s390x, + dwarf_acr11_s390x, + dwarf_acr12_s390x, + dwarf_acr13_s390x, + dwarf_acr14_s390x, + dwarf_acr15_s390x, + // Program Status Word + dwarf_pswm_s390x = 64, + dwarf_pswa_s390x, + // Vector Registers 16-31 + dwarf_v16_s390x = 68, + dwarf_v18_s390x, + dwarf_v20_s390x, + dwarf_v22_s390x, + dwarf_v17_s390x, + dwarf_v19_s390x, + dwarf_v21_s390x, + dwarf_v23_s390x, + dwarf_v24_s390x, + dwarf_v26_s390x, + dwarf_v28_s390x, + dwarf_v30_s390x, + dwarf_v25_s390x, + dwarf_v27_s390x, + dwarf_v29_s390x, + dwarf_v31_s390x, +}; + +// RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB + +#define DEFINE_REG(name, size, alt, generic) \ + { \ + #name, alt, size, 0, eEncodingUint, eFormatHex, \ + { dwarf_##name##_s390x, dwarf_##name##_s390x, generic, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, \ + NULL, NULL, \ + } + +static RegisterInfo g_register_infos[] = +{ + DEFINE_REG(r0, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(r1, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(r2, 8, "arg1", LLDB_REGNUM_GENERIC_ARG1), + DEFINE_REG(r3, 8, "arg2", LLDB_REGNUM_GENERIC_ARG2), + DEFINE_REG(r4, 8, "arg3", LLDB_REGNUM_GENERIC_ARG3), + DEFINE_REG(r5, 8, "arg4", LLDB_REGNUM_GENERIC_ARG4), + DEFINE_REG(r6, 8, "arg5", LLDB_REGNUM_GENERIC_ARG5), + DEFINE_REG(r7, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(r8, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(r9, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(r10, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(r11, 8, "fp", LLDB_REGNUM_GENERIC_FP), + DEFINE_REG(r12, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(r13, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(r14, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(r15, 8, "sp", LLDB_REGNUM_GENERIC_SP), + DEFINE_REG(acr0, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(acr1, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(acr2, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(acr3, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(acr4, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(acr5, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(acr6, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(acr7, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(acr8, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(acr9, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(acr10, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(acr11, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(acr12, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(acr13, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(acr14, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(acr15, 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(pswm, 8, "flags", LLDB_REGNUM_GENERIC_FLAGS), + DEFINE_REG(pswa, 8, "pc", LLDB_REGNUM_GENERIC_PC), + DEFINE_REG(f0, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(f1, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(f2, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(f3, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(f4, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(f5, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(f6, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(f7, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(f8, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(f9, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(f10, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(f11, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(f12, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(f13, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(f14, 8, nullptr, LLDB_INVALID_REGNUM), + DEFINE_REG(f15, 8, nullptr, LLDB_INVALID_REGNUM), +}; + +static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos); +static bool g_register_info_names_constified = false; + +const lldb_private::RegisterInfo * +ABISysV_s390x::GetRegisterInfoArray(uint32_t &count) +{ + // Make the C-string names and alt_names for the register infos into const + // C-string values by having the ConstString unique the names in the global + // constant C-string pool. + if (!g_register_info_names_constified) + { + g_register_info_names_constified = true; + for (uint32_t i = 0; i < k_num_register_infos; ++i) + { + if (g_register_infos[i].name) + g_register_infos[i].name = ConstString(g_register_infos[i].name).GetCString(); + if (g_register_infos[i].alt_name) + g_register_infos[i].alt_name = ConstString(g_register_infos[i].alt_name).GetCString(); + } + } + count = k_num_register_infos; + return g_register_infos; +} + +size_t +ABISysV_s390x::GetRedZoneSize() const +{ + return 0; +} + +//------------------------------------------------------------------ +// Static Functions +//------------------------------------------------------------------ + +ABISP +ABISysV_s390x::CreateInstance(const ArchSpec &arch) +{ + static ABISP g_abi_sp; + if (arch.GetTriple().getArch() == llvm::Triple::systemz) + { + if (!g_abi_sp) + g_abi_sp.reset(new ABISysV_s390x); + return g_abi_sp; + } + return ABISP(); +} + +bool +ABISysV_s390x::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)); + + if (log) + { + StreamString s; + s.Printf("ABISysV_s390x::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%" PRIu64 " = 0x%" PRIx64, static_cast(i + 1), args[i]); + s.PutCString(")"); + log->PutCString(s.GetString().c_str()); + } + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + 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->GetRegisterInfoByName("r14", 0); + ProcessSP process_sp(thread.GetProcess()); + + // Allocate a new stack frame and space for stack arguments if necessary + + addr_t arg_pos = 0; + if (args.size() > 5) + { + sp -= 8 * (args.size() - 5); + arg_pos = sp; + } + + sp -= 160; + + // Process arguments + + for (size_t i = 0; i < args.size(); ++i) + { + if (i < 5) + { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); + if (log) + log->Printf("About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s", static_cast(i + 1), + args[i], reg_info->name); + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) + return false; + } + else + { + Error error; + if (log) + log->Printf("About to write arg%" PRIu64 " (0x%" PRIx64 ") onto stack", static_cast(i + 1), + args[i]); + if (!process_sp->WritePointerToMemory(arg_pos, args[i], error)) + return false; + arg_pos += 8; + } + } + + // %r14 is set to the return address + + if (log) + log->Printf("Writing RA: 0x%" PRIx64, (uint64_t)return_addr); + + if (!reg_ctx->WriteRegisterFromUnsigned(ra_reg_info, return_addr)) + return false; + + // %r15 is set to the actual stack value. + + if (log) + log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp); + + if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp)) + return false; + + // %pc is set to the address of the called function. + + if (log) + log->Printf("Writing PC: 0x%" PRIx64, (uint64_t)func_addr); + + if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr)) + return false; + + return true; +} + +static bool +ReadIntegerArgument(Scalar &scalar, unsigned int bit_width, bool is_signed, Thread &thread, + uint32_t *argument_register_ids, unsigned int ¤t_argument_register, + addr_t ¤t_stack_argument) +{ + if (bit_width > 64) + return false; // Scalar can't hold large integer arguments + + if (current_argument_register < 5) + { + scalar = + thread.GetRegisterContext()->ReadRegisterAsUnsigned(argument_register_ids[current_argument_register], 0); + current_argument_register++; + if (is_signed) + scalar.SignExtend(bit_width); + } + else + { + uint32_t byte_size = (bit_width + (8 - 1)) / 8; + Error error; + if (thread.GetProcess()->ReadScalarIntegerFromMemory(current_stack_argument + 8 - byte_size, byte_size, + is_signed, scalar, error)) + { + current_stack_argument += 8; + return true; + } + return false; + } + return true; +} + +bool +ABISysV_s390x::GetArgumentValues(Thread &thread, ValueList &values) const +{ + unsigned int num_values = values.GetSize(); + unsigned int value_index; + + // Extract the register context so we can read arguments from registers + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + + if (!reg_ctx) + return false; + + // Get the pointer to the first stack argument so we have a place to start + // when reading data + + addr_t sp = reg_ctx->GetSP(0); + + if (!sp) + return false; + + addr_t current_stack_argument = sp; + + uint32_t argument_register_ids[5]; + + argument_register_ids[0] = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1)->kinds[eRegisterKindLLDB]; + argument_register_ids[1] = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2)->kinds[eRegisterKindLLDB]; + argument_register_ids[2] = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG3)->kinds[eRegisterKindLLDB]; + argument_register_ids[3] = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG4)->kinds[eRegisterKindLLDB]; + argument_register_ids[4] = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG5)->kinds[eRegisterKindLLDB]; + + unsigned int current_argument_register = 0; + + return false; + for (value_index = 0; value_index < num_values; ++value_index) + { + Value *value = values.GetValueAtIndex(value_index); + + if (!value) + return false; + + // We currently only support extracting values with Clang QualTypes. + // Do we care about others? + CompilerType compiler_type = value->GetCompilerType(); + if (!compiler_type) + return false; + bool is_signed; + + if (compiler_type.IsIntegerType(is_signed)) + { + ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), is_signed, thread, + argument_register_ids, current_argument_register, current_stack_argument); + } + else if (compiler_type.IsPointerType()) + { + ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), false, thread, + argument_register_ids, current_argument_register, current_stack_argument); + } + } + + return true; +} + +Error +ABISysV_s390x::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp) +{ + Error 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(); + + bool is_signed; + uint32_t count; + bool is_complex; + + RegisterContext *reg_ctx = thread->GetRegisterContext().get(); + + bool set_it_simple = false; + if (compiler_type.IsIntegerType(is_signed) || compiler_type.IsPointerType()) + { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r2", 0); + + DataExtractor data; + Error 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 + { + size_t bit_width = compiler_type.GetBitSize(frame_sp.get()); + if (bit_width <= 64) + { + const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); + RegisterValue f0_value; + DataExtractor data; + Error 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[8]; + ByteOrder byte_order = data.GetByteOrder(); + + data.CopyByteOrderedData(0, num_bytes, buffer, 8, byte_order); + f0_value.SetBytes(buffer, 8, byte_order); + reg_ctx->WriteRegister(f0_info, f0_value); + set_it_simple = true; + } + else + { + // FIXME - don't know how to do 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."); + } + + return error; +} + +ValueObjectSP +ABISysV_s390x::GetReturnValueObjectSimple(Thread &thread, CompilerType &return_compiler_type) const +{ + ValueObjectSP return_valobj_sp; + Value value; + + if (!return_compiler_type) + return return_valobj_sp; + + // value.SetContext (Value::eContextTypeClangType, return_value_type); + value.SetCompilerType(return_compiler_type); + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return return_valobj_sp; + + const uint32_t type_flags = return_compiler_type.GetTypeInfo(); + if (type_flags & eTypeIsScalar) + { + value.SetValueType(Value::eValueTypeScalar); + + bool success = false; + if (type_flags & eTypeIsInteger) + { + // Extract the register context so we can read arguments from registers + + const size_t byte_size = return_compiler_type.GetByteSize(nullptr); + uint64_t raw_value = + thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg_ctx->GetRegisterInfoByName("r2", 0), 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 + { + const size_t byte_size = return_compiler_type.GetByteSize(nullptr); + if (byte_size <= sizeof(long double)) + { + const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); + RegisterValue f0_value; + if (reg_ctx->ReadRegister(f0_info, f0_value)) + { + DataExtractor data; + if (f0_value.GetData(data)) + { + lldb::offset_t offset = 0; + if (byte_size == sizeof(float)) + { + value.GetScalar() = (float)data.GetFloat(&offset); + success = true; + } + else if (byte_size == sizeof(double)) + { + value.GetScalar() = (double)data.GetDouble(&offset); + success = true; + } + else if (byte_size == sizeof(long double)) + { + // Don't handle long double yet. + } + } + } + } + } + } + + if (success) + return_valobj_sp = + ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); + } + else if (type_flags & eTypeIsPointer) + { + unsigned r2_id = reg_ctx->GetRegisterInfoByName("r2", 0)->kinds[eRegisterKindLLDB]; + value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r2_id, 0); + value.SetValueType(Value::eValueTypeScalar); + return_valobj_sp = ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); + } + + return return_valobj_sp; +} + +ValueObjectSP +ABISysV_s390x::GetReturnValueObjectImpl(Thread &thread, CompilerType &return_compiler_type) const +{ + ValueObjectSP return_valobj_sp; + + if (!return_compiler_type) + return return_valobj_sp; + + ExecutionContext exe_ctx(thread.shared_from_this()); + return_valobj_sp = GetReturnValueObjectSimple(thread, return_compiler_type); + if (return_valobj_sp) + return return_valobj_sp; + + RegisterContextSP reg_ctx_sp = thread.GetRegisterContext(); + if (!reg_ctx_sp) + return return_valobj_sp; + + if (return_compiler_type.IsAggregateType()) + { + // FIXME: This is just taking a guess, r2 may very well no longer hold the return storage location. + // If we are going to do this right, when we make a new frame we should check to see if it uses a memory + // return, and if we are at the first instruction and if so stash away the return location. Then we would + // only return the memory return value if we know it is valid. + + unsigned r2_id = reg_ctx_sp->GetRegisterInfoByName("r2", 0)->kinds[eRegisterKindLLDB]; + lldb::addr_t storage_addr = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r2_id, 0); + return_valobj_sp = ValueObjectMemory::Create(&thread, "", Address(storage_addr, nullptr), return_compiler_type); + } + + return return_valobj_sp; +} + +bool +ABISysV_s390x::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 + 160 + row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r15_s390x, 160); + + // The previous PC is in r14 + row->SetRegisterLocationToRegister(dwarf_pswa_s390x, dwarf_r14_s390x, true); + + // All other registers are the same. + unwind_plan.AppendRow(row); + unwind_plan.SetSourceName("s390x at-func-entry default"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + return true; +} + +bool +ABISysV_s390x::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) +{ + // There's really no default way to unwind on s390x. + // Trust the .eh_frame CFI, which should always be good. + return false; +} + +bool +ABISysV_s390x::RegisterIsVolatile(const RegisterInfo *reg_info) +{ + return !RegisterIsCalleeSaved(reg_info); +} + +bool +ABISysV_s390x::RegisterIsCalleeSaved(const RegisterInfo *reg_info) +{ + if (reg_info) + { + // Preserved registers are : + // r6-r13, r15 + // f8-f15 + + const char *name = reg_info->name; + if (name[0] == 'r') + { + switch (name[1]) + { + case '6': // r6 + case '7': // r7 + case '8': // r8 + case '9': // r9 + return name[2] == '\0'; + + case '1': // r10, r11, r12, r13, r15 + if ((name[2] >= '0' && name[2] <= '3') || name[2] == '5') + return name[3] == '\0'; + break; + + default: + break; + } + } + if (name[0] == 'f') + { + switch (name[1]) + { + case '8': // r8 + case '9': // r9 + return name[2] == '\0'; + + case '1': // r10, r11, r12, r13, r14, r15 + if (name[2] >= '0' && name[2] <= '5') + return name[3] == '\0'; + break; + + default: + break; + } + } + + // Accept shorter-variant versions + if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp + return true; + if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp + return true; + if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc + return true; + } + return false; +} + +void +ABISysV_s390x::Initialize() +{ + PluginManager::RegisterPlugin(GetPluginNameStatic(), "System V ABI for s390x targets", CreateInstance); +} + +void +ABISysV_s390x::Terminate() +{ + PluginManager::UnregisterPlugin(CreateInstance); +} + +lldb_private::ConstString +ABISysV_s390x::GetPluginNameStatic() +{ + static ConstString g_name("sysv-s390x"); + return g_name; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ + +lldb_private::ConstString +ABISysV_s390x::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +ABISysV_s390x::GetPluginVersion() +{ + return 1; +} Index: source/Plugins/ABI/SysV-s390x/CMakeLists.txt =================================================================== --- source/Plugins/ABI/SysV-s390x/CMakeLists.txt +++ source/Plugins/ABI/SysV-s390x/CMakeLists.txt @@ -0,0 +1,3 @@ +add_lldb_library(lldbPluginABISysV_s390x + ABISysV_s390x.cpp + ) Index: source/Plugins/ObjectFile/ELF/ELFHeader.cpp =================================================================== --- source/Plugins/ObjectFile/ELF/ELFHeader.cpp +++ source/Plugins/ObjectFile/ELF/ELFHeader.cpp @@ -198,6 +198,9 @@ case EM_MIPS: slot = R_MIPS_JUMP_SLOT; break; + case EM_S390: + slot = R_390_JMP_SLOT; + break; } return slot; Index: source/Plugins/Platform/Linux/PlatformLinux.cpp =================================================================== --- source/Plugins/Platform/Linux/PlatformLinux.cpp +++ source/Plugins/Platform/Linux/PlatformLinux.cpp @@ -485,6 +485,7 @@ case 6: triple.setArchName("mips"); break; case 7: triple.setArchName("mips64el"); break; case 8: triple.setArchName("mipsel"); break; + case 9: triple.setArchName("s390x"); break; default: return false; } // Leave the vendor as "llvm::Triple:UnknownVendor" and don't specify the vendor by Index: source/Plugins/Process/Linux/CMakeLists.txt =================================================================== --- source/Plugins/Process/Linux/CMakeLists.txt +++ source/Plugins/Process/Linux/CMakeLists.txt @@ -9,6 +9,7 @@ NativeRegisterContextLinux_arm64.cpp NativeRegisterContextLinux_x86_64.cpp NativeRegisterContextLinux_mips64.cpp + NativeRegisterContextLinux_s390x.cpp NativeThreadLinux.cpp ProcFileReader.cpp SingleStepCheck.cpp Index: source/Plugins/Process/Linux/NativeProcessLinux.cpp =================================================================== --- source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -2247,6 +2247,7 @@ // FIXME put this behind a breakpoint protocol class that can be // set per architecture. Need ARM, MIPS support here. static const uint8_t g_i386_opcode [] = { 0xCC }; + static const uint8_t g_s390x_opcode[] = { 0x00, 0x01 }; switch (m_arch.GetMachine ()) { @@ -2255,6 +2256,10 @@ actual_opcode_size = static_cast (sizeof(g_i386_opcode)); return Error (); + case llvm::Triple::systemz: + actual_opcode_size = static_cast (sizeof(g_s390x_opcode)); + return Error (); + case llvm::Triple::arm: case llvm::Triple::aarch64: case llvm::Triple::mips64: @@ -2294,6 +2299,7 @@ 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 }; + static const uint8_t g_s390x_opcode[] = { 0x00, 0x01 }; static const uint8_t g_thumb_breakpoint_opcode[] = { 0x01, 0xde }; switch (m_arch.GetMachine ()) @@ -2337,6 +2343,11 @@ actual_opcode_size = sizeof(g_mips64el_opcode); return Error (); + case llvm::Triple::systemz: + trap_opcode_bytes = g_s390x_opcode; + actual_opcode_size = sizeof(g_s390x_opcode); + return Error (); + default: assert(false && "CPU type not supported!"); return Error ("CPU type not supported"); Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.h =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.h +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.h @@ -0,0 +1,141 @@ +//===-- NativeRegisterContextLinux_s390x.h ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#if defined(__s390x__) && defined(__linux__) + +#ifndef lldb_NativeRegisterContextLinux_s390x_h +#define lldb_NativeRegisterContextLinux_s390x_h + +#include "Plugins/Process/Linux/NativeRegisterContextLinux.h" +#include "Plugins/Process/Utility/RegisterContext_s390x.h" +#include "Plugins/Process/Utility/lldb-s390x-register-enums.h" + +namespace lldb_private +{ +namespace process_linux +{ + +class NativeProcessLinux; + +class NativeRegisterContextLinux_s390x : public NativeRegisterContextLinux +{ +public: + NativeRegisterContextLinux_s390x(const ArchSpec &target_arch, NativeThreadProtocol &native_thread, + uint32_t concrete_frame_idx); + + uint32_t + GetRegisterSetCount() const override; + + const RegisterSet * + GetRegisterSet(uint32_t set_index) const override; + + uint32_t + GetUserRegisterCount() const override; + + Error + ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) override; + + Error + WriteRegister(const RegisterInfo *reg_info, const RegisterValue ®_value) override; + + Error + ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; + + Error + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + Error + IsWatchpointHit(uint32_t wp_index, bool &is_hit) override; + + Error + GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) override; + + Error + IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override; + + bool + ClearHardwareWatchpoint(uint32_t wp_index) override; + + Error + ClearAllHardwareWatchpoints() override; + + uint32_t + SetHardwareWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags) override; + + lldb::addr_t + GetWatchpointAddress(uint32_t wp_index) override; + + uint32_t + NumSupportedHardwareWatchpoints() override; + +protected: + Error + DoReadRegisterValue(uint32_t offset, const char *reg_name, uint32_t size, RegisterValue &value) override; + + Error + DoWriteRegisterValue(uint32_t offset, const char *reg_name, const RegisterValue &value) override; + + Error + DoReadGPR(void *buf, size_t buf_size) override; + + Error + DoWriteGPR(void *buf, size_t buf_size) override; + + Error + DoReadFPR(void *buf, size_t buf_size) override; + + Error + DoWriteFPR(void *buf, size_t buf_size) override; + +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; + }; + + // Private member variables. + RegInfo m_reg_info; + lldb::addr_t m_watchpoint_addr; + + // Private member methods. + bool + IsRegisterSetAvailable(uint32_t set_index) const; + + bool + IsGPR(uint32_t reg_index) const; + + bool + IsFPR(uint32_t reg_index) const; + + Error + PeekUserArea(uint32_t offset, void *buf, size_t buf_size); + + Error + PokeUserArea(uint32_t offset, const void *buf, size_t buf_size); + + Error + DoReadRegisterSet(uint32_t regset, void *buf, size_t buf_size); + + Error + DoWriteRegisterSet(uint32_t regset, const void *buf, size_t buf_size); +}; + +} // namespace process_linux +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextLinux_s390x_h + +#endif // defined(__s390x__) && defined(__linux__) Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp @@ -0,0 +1,716 @@ +//===-- NativeRegisterContextLinux_s390x.cpp --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#if defined(__s390x__) && defined(__linux__) + +#include "NativeRegisterContextLinux_s390x.h" + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Host/HostInfo.h" + +#include "Plugins/Process/Utility/RegisterContextLinux_s390x.h" + +#include +#include +#include + +using namespace lldb_private; +using namespace lldb_private::process_linux; + +// ---------------------------------------------------------------------------- +// Private namespace. +// ---------------------------------------------------------------------------- + +namespace +{ + // s390x 64-bit general purpose registers. + static const uint32_t g_gpr_regnums_s390x[] = + { + lldb_r0_s390x, + lldb_r1_s390x, + lldb_r2_s390x, + lldb_r3_s390x, + lldb_r4_s390x, + lldb_r5_s390x, + lldb_r6_s390x, + lldb_r7_s390x, + lldb_r8_s390x, + lldb_r9_s390x, + lldb_r10_s390x, + lldb_r11_s390x, + lldb_r12_s390x, + lldb_r13_s390x, + lldb_r14_s390x, + lldb_r15_s390x, + lldb_acr0_s390x, + lldb_acr1_s390x, + lldb_acr2_s390x, + lldb_acr3_s390x, + lldb_acr4_s390x, + lldb_acr5_s390x, + lldb_acr6_s390x, + lldb_acr7_s390x, + lldb_acr8_s390x, + lldb_acr9_s390x, + lldb_acr10_s390x, + lldb_acr11_s390x, + lldb_acr12_s390x, + lldb_acr13_s390x, + lldb_acr14_s390x, + lldb_acr15_s390x, + lldb_pswm_s390x, + lldb_pswa_s390x, + LLDB_INVALID_REGNUM // register sets need to end with this flag + }; + static_assert((sizeof(g_gpr_regnums_s390x) / sizeof(g_gpr_regnums_s390x[0])) - 1 == k_num_gpr_registers_s390x, + "g_gpr_regnums_s390x has wrong number of register infos"); + + // s390x 64-bit floating point registers. + static const uint32_t g_fpu_regnums_s390x[] = + { + lldb_f0_s390x, + lldb_f1_s390x, + lldb_f2_s390x, + lldb_f3_s390x, + lldb_f4_s390x, + lldb_f5_s390x, + lldb_f6_s390x, + lldb_f7_s390x, + lldb_f8_s390x, + lldb_f9_s390x, + lldb_f10_s390x, + lldb_f11_s390x, + lldb_f12_s390x, + lldb_f13_s390x, + lldb_f14_s390x, + lldb_f15_s390x, + lldb_fpc_s390x, + LLDB_INVALID_REGNUM // register sets need to end with this flag + }; + static_assert((sizeof(g_fpu_regnums_s390x) / sizeof(g_fpu_regnums_s390x[0])) - 1 == k_num_fpr_registers_s390x, + "g_fpu_regnums_s390x has wrong number of register infos"); + + // s390x Linux operating-system information. + static const uint32_t g_linux_regnums_s390x[] = + { + lldb_orig_r2_s390x, + lldb_last_break_s390x, + lldb_system_call_s390x, + LLDB_INVALID_REGNUM // register sets need to end with this flag + }; + static_assert((sizeof(g_linux_regnums_s390x) / sizeof(g_linux_regnums_s390x[0])) - 1 == k_num_linux_registers_s390x, + "g_linux_regnums_s390x has wrong number of register infos"); + + // Number of register sets provided by this context. + enum + { + k_num_register_sets = 3 + }; + + // Register sets for s390x 64-bit. + static const RegisterSet g_reg_sets_s390x[k_num_register_sets] = + { + { "General Purpose Registers", "gpr", k_num_gpr_registers_s390x, g_gpr_regnums_s390x }, + { "Floating Point Registers", "fpr", k_num_fpr_registers_s390x, g_fpu_regnums_s390x }, + { "Linux Operating System Data", "linux", k_num_linux_registers_s390x, g_linux_regnums_s390x }, + }; +} + +#define REG_CONTEXT_SIZE (sizeof(s390_regs) + sizeof(s390_fp_regs) + 4) + +// ---------------------------------------------------------------------------- +// Required ptrace defines. +// ---------------------------------------------------------------------------- + +#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ +#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ + +NativeRegisterContextLinux * +NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread, + uint32_t concrete_frame_idx) +{ + return new NativeRegisterContextLinux_s390x(target_arch, native_thread, concrete_frame_idx); +} + +// ---------------------------------------------------------------------------- +// NativeRegisterContextLinux_s390x 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_s390x(target_arch); +} + +NativeRegisterContextLinux_s390x::NativeRegisterContextLinux_s390x(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread, + uint32_t concrete_frame_idx) + : NativeRegisterContextLinux(native_thread, concrete_frame_idx, CreateRegisterInfoInterface(target_arch)) +{ + // Set up data about ranges of valid registers. + switch (target_arch.GetMachine()) + { + case llvm::Triple::systemz: + m_reg_info.num_registers = k_num_registers_s390x; + m_reg_info.num_gpr_registers = k_num_gpr_registers_s390x; + m_reg_info.num_fpr_registers = k_num_fpr_registers_s390x; + m_reg_info.last_gpr = k_last_gpr_s390x; + m_reg_info.first_fpr = k_first_fpr_s390x; + m_reg_info.last_fpr = k_last_fpr_s390x; + break; + default: + assert(false && "Unhandled target architecture."); + break; + } + + // Clear out the watchpoint state. + m_watchpoint_addr = LLDB_INVALID_ADDRESS; +} + +uint32_t +NativeRegisterContextLinux_s390x::GetRegisterSetCount() const +{ + uint32_t sets = 0; + for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) + { + if (IsRegisterSetAvailable(set_index)) + ++sets; + } + + return sets; +} + +uint32_t +NativeRegisterContextLinux_s390x::GetUserRegisterCount() const +{ + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) + { + const RegisterSet *set = GetRegisterSet(set_index); + if (set) + count += set->num_registers; + } + return count; +} + +const RegisterSet * +NativeRegisterContextLinux_s390x::GetRegisterSet(uint32_t set_index) const +{ + if (!IsRegisterSetAvailable(set_index)) + return nullptr; + + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) + { + case llvm::Triple::systemz: + return &g_reg_sets_s390x[set_index]; + default: + assert(false && "Unhandled target architecture."); + return nullptr; + } + + return nullptr; +} + +bool +NativeRegisterContextLinux_s390x::IsRegisterSetAvailable(uint32_t set_index) const +{ + return set_index < k_num_register_sets; +} + +bool +NativeRegisterContextLinux_s390x::IsGPR(uint32_t reg_index) const +{ + // GPRs come first. "orig_r2" counts as GPR since it is part of the GPR register area. + return reg_index <= m_reg_info.last_gpr || reg_index == lldb_orig_r2_s390x; +} + +bool +NativeRegisterContextLinux_s390x::IsFPR(uint32_t reg_index) const +{ + return (m_reg_info.first_fpr <= reg_index && reg_index <= m_reg_info.last_fpr); +} + +Error +NativeRegisterContextLinux_s390x::ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) +{ + if (!reg_info) + return Error("reg_info NULL"); + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + if (reg == LLDB_INVALID_REGNUM) + return Error("register \"%s\" is an internal-only lldb register, cannot read directly", reg_info->name); + + if (IsGPR(reg)) + { + s390_regs regs; + Error error = DoReadGPR(®s, sizeof(regs)); + if (error.Fail()) + return error; + + uint8_t *src = (uint8_t *)®s + reg_info->byte_offset; + assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs)); + switch (reg_info->byte_size) + { + case 4: + reg_value.SetUInt32(*(uint32_t *)src); + break; + case 8: + reg_value.SetUInt64(*(uint64_t *)src); + break; + default: + assert(false && "Unhandled data size."); + return Error("unhandled byte size: %" PRIu32, reg_info->byte_size); + } + return Error(); + } + + if (IsFPR(reg)) + { + s390_fp_regs fp_regs; + Error error = DoReadFPR(&fp_regs, sizeof(fp_regs)); + if (error.Fail()) + return error; + + // byte_offset is just the offset within FPR, not the whole user area. + uint8_t *src = (uint8_t *)&fp_regs + reg_info->byte_offset; + assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs)); + switch (reg_info->byte_size) + { + case 4: + reg_value.SetUInt32(*(uint32_t *)src); + break; + case 8: + reg_value.SetUInt64(*(uint64_t *)src); + break; + default: + assert(false && "Unhandled data size."); + return Error("unhandled byte size: %" PRIu32, reg_info->byte_size); + } + return Error(); + } + + if (reg == lldb_last_break_s390x) + { + uint64_t last_break; + Error error = DoReadRegisterSet(NT_S390_LAST_BREAK, &last_break, 8); + if (error.Fail()) + return error; + + reg_value.SetUInt64(last_break); + return Error(); + } + + if (reg == lldb_system_call_s390x) + { + uint32_t system_call; + Error error = DoReadRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); + if (error.Fail()) + return error; + + reg_value.SetUInt32(system_call); + return Error(); + } + + return Error("failed - register wasn't recognized"); +} + +Error +NativeRegisterContextLinux_s390x::WriteRegister(const RegisterInfo *reg_info, const RegisterValue ®_value) +{ + if (!reg_info) + return Error("reg_info NULL"); + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + if (reg == LLDB_INVALID_REGNUM) + return Error("register \"%s\" is an internal-only lldb register, cannot write directly", reg_info->name); + + if (IsGPR(reg)) + { + s390_regs regs; + Error error = DoReadGPR(®s, sizeof(regs)); + if (error.Fail()) + return error; + + uint8_t *dst = (uint8_t *)®s + reg_info->byte_offset; + assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs)); + switch (reg_info->byte_size) + { + case 4: + *(uint32_t *)dst = reg_value.GetAsUInt32(); + break; + case 8: + *(uint64_t *)dst = reg_value.GetAsUInt64(); + break; + default: + assert(false && "Unhandled data size."); + return Error("unhandled byte size: %" PRIu32, reg_info->byte_size); + } + return DoWriteGPR(®s, sizeof(regs)); + } + + if (IsFPR(reg)) + { + s390_fp_regs fp_regs; + Error error = DoReadFPR(&fp_regs, sizeof(fp_regs)); + if (error.Fail()) + return error; + + // byte_offset is just the offset within fp_regs, not the whole user area. + uint8_t *dst = (uint8_t *)&fp_regs + reg_info->byte_offset; + assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs)); + switch (reg_info->byte_size) + { + case 4: + *(uint32_t *)dst = reg_value.GetAsUInt32(); + break; + case 8: + *(uint64_t *)dst = reg_value.GetAsUInt64(); + break; + default: + assert(false && "Unhandled data size."); + return Error("unhandled byte size: %" PRIu32, reg_info->byte_size); + } + return DoWriteFPR(&fp_regs, sizeof(fp_regs)); + } + + if (reg == lldb_last_break_s390x) + { + return Error("The last break address is read-only"); + } + + if (reg == lldb_system_call_s390x) + { + uint32_t system_call = reg_value.GetAsUInt32(); + return DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); + } + + return Error("failed - register wasn't recognized"); +} + +Error +NativeRegisterContextLinux_s390x::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) +{ + Error error; + + data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); + if (!data_sp) + { + error.SetErrorStringWithFormat("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE); + return error; + } + + uint8_t *dst = data_sp->GetBytes(); + if (dst == nullptr) + { + error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", + REG_CONTEXT_SIZE); + return error; + } + + error = DoReadGPR(dst, sizeof(s390_regs)); + dst += sizeof(s390_regs); + if (error.Fail()) + return error; + + error = DoReadFPR(dst, sizeof(s390_fp_regs)); + dst += sizeof(s390_fp_regs); + if (error.Fail()) + return error; + + // Ignore errors if the regset is unsupported (happens on older kernels). + DoReadRegisterSet(NT_S390_SYSTEM_CALL, dst, 4); + dst += 4; + + // To enable inferior function calls while the process is stopped in + // an interrupted system call, we need to clear the system call flag. + // It will be restored to its original value by WriteAllRegisterValues. + // Again we ignore error if the regset is unsupported. + uint32_t system_call = 0; + DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); + + return error; +} + +Error +NativeRegisterContextLinux_s390x::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) +{ + Error error; + + if (!data_sp) + { + error.SetErrorStringWithFormat("NativeRegisterContextLinux_s390x::%s invalid data_sp provided", __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) + { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_s390x::%s data_sp contained mismatched data size, expected %" PRIu64 + ", actual %" PRIu64, + __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); + return error; + } + + uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) + { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_s390x::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__); + return error; + } + + error = DoWriteGPR(src, sizeof(s390_regs)); + src += sizeof(s390_regs); + if (error.Fail()) + return error; + + error = DoWriteFPR(src, sizeof(s390_fp_regs)); + src += sizeof(s390_fp_regs); + if (error.Fail()) + return error; + + // Ignore errors if the regset is unsupported (happens on older kernels). + DoWriteRegisterSet(NT_S390_SYSTEM_CALL, src, 4); + src += 4; + + return error; +} + +Error +NativeRegisterContextLinux_s390x::DoReadRegisterValue(uint32_t offset, const char *reg_name, uint32_t size, + RegisterValue &value) +{ + return Error("DoReadRegisterValue unsupported"); +} + +Error +NativeRegisterContextLinux_s390x::DoWriteRegisterValue(uint32_t offset, const char *reg_name, + const RegisterValue &value) +{ + return Error("DoWriteRegisterValue unsupported"); +} + +Error +NativeRegisterContextLinux_s390x::PeekUserArea(uint32_t offset, void *buf, size_t buf_size) +{ + ptrace_area parea; + parea.len = buf_size; + parea.process_addr = (addr_t)buf; + parea.kernel_addr = offset; + + return NativeProcessLinux::PtraceWrapper(PTRACE_PEEKUSR_AREA, m_thread.GetID(), &parea); +} + +Error +NativeRegisterContextLinux_s390x::PokeUserArea(uint32_t offset, const void *buf, size_t buf_size) +{ + ptrace_area parea; + parea.len = buf_size; + parea.process_addr = (addr_t)buf; + parea.kernel_addr = offset; + + return NativeProcessLinux::PtraceWrapper(PTRACE_POKEUSR_AREA, m_thread.GetID(), &parea); +} + +Error +NativeRegisterContextLinux_s390x::DoReadGPR(void *buf, size_t buf_size) +{ + assert(buf_size == sizeof(s390_regs)); + return PeekUserArea(offsetof(user_regs_struct, psw), buf, buf_size); +} + +Error +NativeRegisterContextLinux_s390x::DoWriteGPR(void *buf, size_t buf_size) +{ + assert(buf_size == sizeof(s390_regs)); + return PokeUserArea(offsetof(user_regs_struct, psw), buf, buf_size); +} + +Error +NativeRegisterContextLinux_s390x::DoReadFPR(void *buf, size_t buf_size) +{ + assert(buf_size == sizeof(s390_fp_regs)); + return PeekUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size); +} + +Error +NativeRegisterContextLinux_s390x::DoWriteFPR(void *buf, size_t buf_size) +{ + assert(buf_size == sizeof(s390_fp_regs)); + return PokeUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size); +} + +Error +NativeRegisterContextLinux_s390x::DoReadRegisterSet(uint32_t regset, void *buf, size_t buf_size) +{ + struct iovec iov; + iov.iov_base = buf; + iov.iov_len = buf_size; + + return ReadRegisterSet(&iov, buf_size, regset); +} + +Error +NativeRegisterContextLinux_s390x::DoWriteRegisterSet(uint32_t regset, const void *buf, size_t buf_size) +{ + struct iovec iov; + iov.iov_base = const_cast(buf); + iov.iov_len = buf_size; + + return WriteRegisterSet(&iov, buf_size, regset); +} + +Error +NativeRegisterContextLinux_s390x::IsWatchpointHit(uint32_t wp_index, bool &is_hit) +{ + per_lowcore_bits per_lowcore; + + if (wp_index >= NumSupportedHardwareWatchpoints()) + return Error("Watchpoint index out of range"); + + if (m_watchpoint_addr == LLDB_INVALID_ADDRESS) + { + is_hit = false; + return Error(); + } + + Error error = PeekUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore, sizeof(per_lowcore)); + if (error.Fail()) + { + is_hit = false; + return error; + } + + is_hit = (per_lowcore.perc_storage_alteration == 1 && per_lowcore.perc_store_real_address == 0); + + if (is_hit) + { + // Do not report this watchpoint again. + memset(&per_lowcore, 0, sizeof(per_lowcore)); + PokeUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore, sizeof(per_lowcore)); + } + + return Error(); +} + +Error +NativeRegisterContextLinux_s390x::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) +{ + uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); + for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) + { + bool is_hit; + Error error = IsWatchpointHit(wp_index, is_hit); + if (error.Fail()) + { + wp_index = LLDB_INVALID_INDEX32; + return error; + } + else if (is_hit) + { + return error; + } + } + wp_index = LLDB_INVALID_INDEX32; + return Error(); +} + +Error +NativeRegisterContextLinux_s390x::IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) +{ + if (wp_index >= NumSupportedHardwareWatchpoints()) + return Error("Watchpoint index out of range"); + + is_vacant = m_watchpoint_addr == LLDB_INVALID_ADDRESS; + + return Error(); +} + +bool +NativeRegisterContextLinux_s390x::ClearHardwareWatchpoint(uint32_t wp_index) +{ + per_struct per_info; + + if (wp_index >= NumSupportedHardwareWatchpoints()) + return false; + + Error error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, sizeof(per_info)); + if (error.Fail()) + return false; + + per_info.control_regs.bits.em_storage_alteration = 0; + per_info.control_regs.bits.storage_alt_space_ctl = 0; + per_info.starting_addr = 0; + per_info.ending_addr = 0; + + error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, sizeof(per_info)); + if (error.Fail()) + return false; + + m_watchpoint_addr = LLDB_INVALID_ADDRESS; + return true; +} + +Error +NativeRegisterContextLinux_s390x::ClearAllHardwareWatchpoints() +{ + if (ClearHardwareWatchpoint(0)) + return Error(); + return Error("Clearing all hardware watchpoints failed."); +} + +uint32_t +NativeRegisterContextLinux_s390x::SetHardwareWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags) +{ + per_struct per_info; + + if (watch_flags != 0x1) + return LLDB_INVALID_INDEX32; + + if (m_watchpoint_addr != LLDB_INVALID_ADDRESS) + return LLDB_INVALID_INDEX32; + + Error error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, sizeof(per_info)); + if (error.Fail()) + return LLDB_INVALID_INDEX32; + + per_info.control_regs.bits.em_storage_alteration = 1; + per_info.control_regs.bits.storage_alt_space_ctl = 1; + per_info.starting_addr = addr; + per_info.ending_addr = addr + size - 1; + + error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, sizeof(per_info)); + if (error.Fail()) + return LLDB_INVALID_INDEX32; + + m_watchpoint_addr = addr; + return 0; +} + +lldb::addr_t +NativeRegisterContextLinux_s390x::GetWatchpointAddress(uint32_t wp_index) +{ + if (wp_index >= NumSupportedHardwareWatchpoints()) + return LLDB_INVALID_ADDRESS; + return m_watchpoint_addr; +} + +uint32_t +NativeRegisterContextLinux_s390x::NumSupportedHardwareWatchpoints() +{ + return 1; +} + +#endif // defined(__s390x__) && defined(__linux__) Index: source/Plugins/Process/Utility/CMakeLists.txt =================================================================== --- source/Plugins/Process/Utility/CMakeLists.txt +++ source/Plugins/Process/Utility/CMakeLists.txt @@ -28,6 +28,7 @@ RegisterContextLinux_x86_64.cpp RegisterContextLinux_mips64.cpp RegisterContextLinux_mips.cpp + RegisterContextLinux_s390x.cpp RegisterContextLLDB.cpp RegisterContextMacOSXFrameBackchain.cpp RegisterContextMach_arm.cpp @@ -39,6 +40,7 @@ RegisterContextPOSIX_arm64.cpp RegisterContextPOSIX_mips64.cpp RegisterContextPOSIX_powerpc.cpp + RegisterContextPOSIX_s390x.cpp RegisterContextPOSIX_x86.cpp RegisterContextThreadMemory.cpp StopInfoMachException.cpp Index: source/Plugins/Process/Utility/RegisterContextLinux_s390x.h =================================================================== --- source/Plugins/Process/Utility/RegisterContextLinux_s390x.h +++ source/Plugins/Process/Utility/RegisterContextLinux_s390x.h @@ -0,0 +1,42 @@ +//===-- RegisterContextLinux_s390x.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextLinux_s390x_h_ +#define liblldb_RegisterContextLinux_s390x_h_ + +#include "RegisterInfoInterface.h" + +class RegisterContextLinux_s390x : public lldb_private::RegisterInfoInterface +{ +public: + RegisterContextLinux_s390x(const lldb_private::ArchSpec &target_arch); + + size_t + GetGPRSize() const override; + + const lldb_private::RegisterInfo * + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount() const override; + + uint32_t + GetUserRegisterCount() const override; + + const std::vector * + GetDynamicRegisterInfoP() const override; + +private: + const lldb_private::RegisterInfo *m_register_info_p; + uint32_t m_register_info_count; + uint32_t m_user_register_count; + std::vector d_register_infos; +}; + +#endif Index: source/Plugins/Process/Utility/RegisterContextLinux_s390x.cpp =================================================================== --- source/Plugins/Process/Utility/RegisterContextLinux_s390x.cpp +++ source/Plugins/Process/Utility/RegisterContextLinux_s390x.cpp @@ -0,0 +1,98 @@ +//===-- RegisterContextLinux_s390x.cpp --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "RegisterContextPOSIX_s390x.h" +#include "RegisterContextLinux_s390x.h" + +using namespace lldb_private; +using namespace lldb; + +//--------------------------------------------------------------------------- +// Include RegisterInfos_s390x to declare our g_register_infos_s390x structure. +//--------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_S390X_STRUCT +#include "RegisterInfos_s390x.h" +#undef DECLARE_REGISTER_INFOS_S390X_STRUCT + +static const RegisterInfo * +GetRegisterInfoPtr(const ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::systemz: + return g_register_infos_s390x; + default: + assert(false && "Unhandled target architecture."); + return nullptr; + } +} + +static uint32_t +GetRegisterInfoCount(const ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::systemz: + return k_num_registers_s390x; + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + +static uint32_t +GetUserRegisterInfoCount(const ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::systemz: + return k_num_user_registers_s390x + k_num_linux_registers_s390x; + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + +RegisterContextLinux_s390x::RegisterContextLinux_s390x(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(target_arch)) +{ +} + +const std::vector * +RegisterContextLinux_s390x::GetDynamicRegisterInfoP() const +{ + return &d_register_infos; +} + +const RegisterInfo * +RegisterContextLinux_s390x::GetRegisterInfo() const +{ + return m_register_info_p; +} + +uint32_t +RegisterContextLinux_s390x::GetRegisterCount() const +{ + return m_register_info_count; +} + +uint32_t +RegisterContextLinux_s390x::GetUserRegisterCount() const +{ + return m_user_register_count; +} + +size_t +RegisterContextLinux_s390x::GetGPRSize() const +{ + return 0; +} Index: source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h =================================================================== --- source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h +++ source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h @@ -0,0 +1,103 @@ +//===-- RegisterContextPOSIX_s390x.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIX_s390x_h_ +#define liblldb_RegisterContextPOSIX_s390x_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Log.h" +#include "lldb/Target/RegisterContext.h" +#include "RegisterInfoInterface.h" +#include "RegisterContext_s390x.h" +#include "lldb-s390x-register-enums.h" + +class ProcessMonitor; + +class RegisterContextPOSIX_s390x : public lldb_private::RegisterContext +{ +public: + RegisterContextPOSIX_s390x(lldb_private::Thread &thread, uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + + ~RegisterContextPOSIX_s390x() override; + + void + Invalidate(); + + void + InvalidateAllRegisters() override; + + size_t + GetRegisterCount() override; + + 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: + 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; + }; + + RegInfo m_reg_info; + std::unique_ptr m_register_info_ap; + + 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_s390x_h_ Index: source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp =================================================================== --- source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp +++ source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp @@ -0,0 +1,265 @@ +//===-- RegisterContextPOSIX_x86.cpp ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Host/Endian.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "llvm/Support/Compiler.h" + +#include "RegisterContext_s390x.h" +#include "RegisterContextPOSIX_s390x.h" + +using namespace lldb_private; +using namespace lldb; + +// s390x 64-bit general purpose registers. +static const uint32_t g_gpr_regnums_s390x[] = +{ + lldb_r0_s390x, + lldb_r1_s390x, + lldb_r2_s390x, + lldb_r3_s390x, + lldb_r4_s390x, + lldb_r5_s390x, + lldb_r6_s390x, + lldb_r7_s390x, + lldb_r8_s390x, + lldb_r9_s390x, + lldb_r10_s390x, + lldb_r11_s390x, + lldb_r12_s390x, + lldb_r13_s390x, + lldb_r14_s390x, + lldb_r15_s390x, + lldb_acr0_s390x, + lldb_acr1_s390x, + lldb_acr2_s390x, + lldb_acr3_s390x, + lldb_acr4_s390x, + lldb_acr5_s390x, + lldb_acr6_s390x, + lldb_acr7_s390x, + lldb_acr8_s390x, + lldb_acr9_s390x, + lldb_acr10_s390x, + lldb_acr11_s390x, + lldb_acr12_s390x, + lldb_acr13_s390x, + lldb_acr14_s390x, + lldb_acr15_s390x, + lldb_pswm_s390x, + lldb_pswa_s390x, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_gpr_regnums_s390x) / sizeof(g_gpr_regnums_s390x[0])) - 1 == k_num_gpr_registers_s390x, + "g_gpr_regnums_s390x has wrong number of register infos"); + +// s390x 64-bit floating point registers. +static const uint32_t g_fpu_regnums_s390x[] = +{ + lldb_f0_s390x, + lldb_f1_s390x, + lldb_f2_s390x, + lldb_f3_s390x, + lldb_f4_s390x, + lldb_f5_s390x, + lldb_f6_s390x, + lldb_f7_s390x, + lldb_f8_s390x, + lldb_f9_s390x, + lldb_f10_s390x, + lldb_f11_s390x, + lldb_f12_s390x, + lldb_f13_s390x, + lldb_f14_s390x, + lldb_f15_s390x, + lldb_fpc_s390x, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_fpu_regnums_s390x) / sizeof(g_fpu_regnums_s390x[0])) - 1 == k_num_fpr_registers_s390x, + "g_fpu_regnums_s390x has wrong number of register infos"); + +// Number of register sets provided by this context. +enum +{ + k_num_register_sets = 2 +}; + +// Register sets for s390x 64-bit. +static const RegisterSet g_reg_sets_s390x[k_num_register_sets] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers_s390x, g_gpr_regnums_s390x }, + { "Floating Point Registers", "fpr", k_num_fpr_registers_s390x, g_fpu_regnums_s390x }, +}; + +bool +RegisterContextPOSIX_s390x::IsGPR(unsigned reg) +{ + return reg <= m_reg_info.last_gpr; // GPRs come first. +} + +bool +RegisterContextPOSIX_s390x::IsFPR(unsigned reg) +{ + return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); +} + +RegisterContextPOSIX_s390x::RegisterContextPOSIX_s390x(Thread &thread, uint32_t concrete_frame_idx, + RegisterInfoInterface *register_info) + : RegisterContext(thread, concrete_frame_idx) +{ + m_register_info_ap.reset(register_info); + + switch (register_info->m_target_arch.GetMachine()) + { + case llvm::Triple::systemz: + m_reg_info.num_registers = k_num_registers_s390x; + m_reg_info.num_gpr_registers = k_num_gpr_registers_s390x; + m_reg_info.num_fpr_registers = k_num_fpr_registers_s390x; + m_reg_info.last_gpr = k_last_gpr_s390x; + m_reg_info.first_fpr = k_first_fpr_s390x; + m_reg_info.last_fpr = k_last_fpr_s390x; + break; + default: + assert(false && "Unhandled target architecture."); + break; + } +} + +RegisterContextPOSIX_s390x::~RegisterContextPOSIX_s390x() +{ +} + +void +RegisterContextPOSIX_s390x::Invalidate() +{ +} + +void +RegisterContextPOSIX_s390x::InvalidateAllRegisters() +{ +} + +const RegisterInfo * +RegisterContextPOSIX_s390x::GetRegisterInfo() +{ + return m_register_info_ap->GetRegisterInfo(); +} + +const RegisterInfo * +RegisterContextPOSIX_s390x::GetRegisterInfoAtIndex(size_t reg) +{ + if (reg < m_reg_info.num_registers) + return &GetRegisterInfo()[reg]; + else + return NULL; +} + +size_t +RegisterContextPOSIX_s390x::GetRegisterCount() +{ + return m_reg_info.num_registers; +} + +unsigned +RegisterContextPOSIX_s390x::GetRegisterOffset(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register number."); + return GetRegisterInfo()[reg].byte_offset; +} + +unsigned +RegisterContextPOSIX_s390x::GetRegisterSize(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register number."); + return GetRegisterInfo()[reg].byte_size; +} + +const char * +RegisterContextPOSIX_s390x::GetRegisterName(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register offset."); + return GetRegisterInfo()[reg].name; +} + +bool +RegisterContextPOSIX_s390x::IsRegisterSetAvailable(size_t set_index) +{ + return set_index < k_num_register_sets; +} + +size_t +RegisterContextPOSIX_s390x::GetRegisterSetCount() +{ + size_t sets = 0; + for (size_t set = 0; set < k_num_register_sets; ++set) + { + if (IsRegisterSetAvailable(set)) + ++sets; + } + + return sets; +} + +const RegisterSet * +RegisterContextPOSIX_s390x::GetRegisterSet(size_t set) +{ + if (IsRegisterSetAvailable(set)) + { + switch (m_register_info_ap->m_target_arch.GetMachine()) + { + case llvm::Triple::systemz: + return &g_reg_sets_s390x[set]; + default: + assert(false && "Unhandled target architecture."); + return NULL; + } + } + return NULL; +} + +lldb::ByteOrder +RegisterContextPOSIX_s390x::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(); + return byte_order; +} + +// Used when parsing DWARF and EH frame information and any other +// object file sections that contain register numbers in them. +uint32_t +RegisterContextPOSIX_s390x::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num) +{ + const uint32_t num_regs = GetRegisterCount(); + + 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; +} Index: source/Plugins/Process/Utility/RegisterContext_s390x.h =================================================================== --- source/Plugins/Process/Utility/RegisterContext_s390x.h +++ source/Plugins/Process/Utility/RegisterContext_s390x.h @@ -0,0 +1,93 @@ +//===-- RegisterContext_s390x.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContext_s390x_h_ +#define liblldb_RegisterContext_s390x_h_ + +//--------------------------------------------------------------------------- +// SystemZ ehframe, dwarf regnums +//--------------------------------------------------------------------------- + +// EHFrame and DWARF Register numbers (eRegisterKindEHFrame & eRegisterKindDWARF) +enum +{ + // General Purpose Registers + dwarf_r0_s390x = 0, + dwarf_r1_s390x, + dwarf_r2_s390x, + dwarf_r3_s390x, + dwarf_r4_s390x, + dwarf_r5_s390x, + dwarf_r6_s390x, + dwarf_r7_s390x, + dwarf_r8_s390x, + dwarf_r9_s390x, + dwarf_r10_s390x, + dwarf_r11_s390x, + dwarf_r12_s390x, + dwarf_r13_s390x, + dwarf_r14_s390x, + dwarf_r15_s390x, + // Floating Point Registers / Vector Registers 0-15 + dwarf_f0_s390x = 16, + dwarf_f2_s390x, + dwarf_f4_s390x, + dwarf_f6_s390x, + dwarf_f1_s390x, + dwarf_f3_s390x, + dwarf_f5_s390x, + dwarf_f7_s390x, + dwarf_f8_s390x, + dwarf_f10_s390x, + dwarf_f12_s390x, + dwarf_f14_s390x, + dwarf_f9_s390x, + dwarf_f11_s390x, + dwarf_f13_s390x, + dwarf_f15_s390x, + // Access Registers + dwarf_acr0_s390x = 48, + dwarf_acr1_s390x, + dwarf_acr2_s390x, + dwarf_acr3_s390x, + dwarf_acr4_s390x, + dwarf_acr5_s390x, + dwarf_acr6_s390x, + dwarf_acr7_s390x, + dwarf_acr8_s390x, + dwarf_acr9_s390x, + dwarf_acr10_s390x, + dwarf_acr11_s390x, + dwarf_acr12_s390x, + dwarf_acr13_s390x, + dwarf_acr14_s390x, + dwarf_acr15_s390x, + // Program Status Word + dwarf_pswm_s390x = 64, + dwarf_pswa_s390x, + // Vector Registers 16-31 + dwarf_v16_s390x = 68, + dwarf_v18_s390x, + dwarf_v20_s390x, + dwarf_v22_s390x, + dwarf_v17_s390x, + dwarf_v19_s390x, + dwarf_v21_s390x, + dwarf_v23_s390x, + dwarf_v24_s390x, + dwarf_v26_s390x, + dwarf_v28_s390x, + dwarf_v30_s390x, + dwarf_v25_s390x, + dwarf_v27_s390x, + dwarf_v29_s390x, + dwarf_v31_s390x, +}; + +#endif Index: source/Plugins/Process/Utility/RegisterInfos_s390x.h =================================================================== --- source/Plugins/Process/Utility/RegisterInfos_s390x.h +++ source/Plugins/Process/Utility/RegisterInfos_s390x.h @@ -0,0 +1,132 @@ +//===-- RegisterInfos_s390x.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +#include + +// C++ Includes +// Other libraries and framework includes +#include "llvm/Support/Compiler.h" + +// Project includes + +#ifdef DECLARE_REGISTER_INFOS_S390X_STRUCT + +// Computes the offset of the given GPR in the user data area. +#define GPR_OFFSET(num) (16 + 8 * num) +// Computes the offset of the given ACR in the user data area. +#define ACR_OFFSET(num) (16 + 8 * 16 + 4 * num) +// Computes the offset of the given FPR in the extended data area. +#define FPR_OFFSET(num) (8 + 8 * num) + +// RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB + +#define DEFINE_GPR(name, size, offset, alt, generic) \ + { \ + #name, alt, size, offset, eEncodingUint, eFormatHex, \ + { dwarf_##name##_s390x, dwarf_##name##_s390x, generic, LLDB_INVALID_REGNUM, lldb_##name##_s390x }, \ + NULL, NULL, \ + } + +#define DEFINE_GPR_NODWARF(name, size, offset, alt, generic) \ + { \ + #name, alt, size, offset, eEncodingUint, eFormatHex, \ + { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, generic, LLDB_INVALID_REGNUM, lldb_##name##_s390x }, \ + NULL, NULL, \ + } + +#define DEFINE_FPR(name, size, offset) \ + { \ + #name, NULL, size, offset, eEncodingUint, eFormatHex, \ + { dwarf_##name##_s390x, dwarf_##name##_s390x, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##name##_s390x }, \ + NULL, NULL, \ + } + +#define DEFINE_FPR_NODWARF(name, size, offset) \ + { \ + #name, NULL, size, offset, eEncodingUint, eFormatHex, \ + { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##name##_s390x }, \ + NULL, NULL, \ + } + +static RegisterInfo g_register_infos_s390x[] = +{ + // General purpose registers. + DEFINE_GPR(r0, 8, GPR_OFFSET(0), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(r1, 8, GPR_OFFSET(1), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(r2, 8, GPR_OFFSET(2), "arg1", LLDB_REGNUM_GENERIC_ARG1), + DEFINE_GPR(r3, 8, GPR_OFFSET(3), "arg2", LLDB_REGNUM_GENERIC_ARG2), + DEFINE_GPR(r4, 8, GPR_OFFSET(4), "arg3", LLDB_REGNUM_GENERIC_ARG3), + DEFINE_GPR(r5, 8, GPR_OFFSET(5), "arg4", LLDB_REGNUM_GENERIC_ARG4), + DEFINE_GPR(r6, 8, GPR_OFFSET(6), "arg5", LLDB_REGNUM_GENERIC_ARG5), + DEFINE_GPR(r7, 8, GPR_OFFSET(7), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(r8, 8, GPR_OFFSET(8), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(r9, 8, GPR_OFFSET(9), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(r10, 8, GPR_OFFSET(10), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(r11, 8, GPR_OFFSET(11), "fp", LLDB_REGNUM_GENERIC_FP), + DEFINE_GPR(r12, 8, GPR_OFFSET(12), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(r13, 8, GPR_OFFSET(13), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(r14, 8, GPR_OFFSET(14), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(r15, 8, GPR_OFFSET(15), "sp", LLDB_REGNUM_GENERIC_SP), + DEFINE_GPR(acr0, 4, ACR_OFFSET(0), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(acr1, 4, ACR_OFFSET(1), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(acr2, 4, ACR_OFFSET(2), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(acr3, 4, ACR_OFFSET(3), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(acr4, 4, ACR_OFFSET(4), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(acr5, 4, ACR_OFFSET(5), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(acr6, 4, ACR_OFFSET(6), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(acr7, 4, ACR_OFFSET(7), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(acr8, 4, ACR_OFFSET(8), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(acr9, 4, ACR_OFFSET(9), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(acr10, 4, ACR_OFFSET(10), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(acr11, 4, ACR_OFFSET(11), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(acr12, 4, ACR_OFFSET(12), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(acr13, 4, ACR_OFFSET(13), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(acr14, 4, ACR_OFFSET(14), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(acr15, 4, ACR_OFFSET(15), nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR(pswm, 8, 0, "flags", LLDB_REGNUM_GENERIC_FLAGS), + DEFINE_GPR(pswa, 8, 8, "pc", LLDB_REGNUM_GENERIC_PC), + + // Floating point registers. + DEFINE_FPR(f0, 8, FPR_OFFSET(0)), + DEFINE_FPR(f1, 8, FPR_OFFSET(1)), + DEFINE_FPR(f2, 8, FPR_OFFSET(2)), + DEFINE_FPR(f3, 8, FPR_OFFSET(3)), + DEFINE_FPR(f4, 8, FPR_OFFSET(4)), + DEFINE_FPR(f5, 8, FPR_OFFSET(5)), + DEFINE_FPR(f6, 8, FPR_OFFSET(6)), + DEFINE_FPR(f7, 8, FPR_OFFSET(7)), + DEFINE_FPR(f8, 8, FPR_OFFSET(8)), + DEFINE_FPR(f9, 8, FPR_OFFSET(9)), + DEFINE_FPR(f10, 8, FPR_OFFSET(10)), + DEFINE_FPR(f11, 8, FPR_OFFSET(11)), + DEFINE_FPR(f12, 8, FPR_OFFSET(12)), + DEFINE_FPR(f13, 8, FPR_OFFSET(13)), + DEFINE_FPR(f14, 8, FPR_OFFSET(14)), + DEFINE_FPR(f15, 8, FPR_OFFSET(15)), + DEFINE_FPR_NODWARF(fpc, 4, 0), + + // Linux operating-specific info. + DEFINE_GPR_NODWARF(orig_r2, 8, 16 + 16 * 8 + 16 * 4, nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR_NODWARF(last_break, 8, 0, nullptr, LLDB_INVALID_REGNUM), + DEFINE_GPR_NODWARF(system_call, 4, 0, nullptr, LLDB_INVALID_REGNUM), +}; + +static_assert((sizeof(g_register_infos_s390x) / sizeof(g_register_infos_s390x[0])) == k_num_registers_s390x, + "g_register_infos_s390x has wrong number of register infos"); + +#undef GPR_OFFSET +#undef ACR_OFFSET +#undef FPR_OFFSET +#undef DEFINE_GPR +#undef DEFINE_GPR_NODWARF +#undef DEFINE_FPR +#undef DEFINE_FPR_NODWARF + +#endif // DECLARE_REGISTER_INFOS_S390X_STRUCT Index: source/Plugins/Process/Utility/lldb-s390x-register-enums.h =================================================================== --- source/Plugins/Process/Utility/lldb-s390x-register-enums.h +++ source/Plugins/Process/Utility/lldb-s390x-register-enums.h @@ -0,0 +1,94 @@ +//===-- lldb-s390x-register-enums.h -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_s390x_register_enums_h +#define lldb_s390x_register_enums_h + +namespace lldb_private +{ +// LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) + +//--------------------------------------------------------------------------- +// Internal codes for all s390x registers. +//--------------------------------------------------------------------------- +enum +{ + k_first_gpr_s390x, + lldb_r0_s390x = k_first_gpr_s390x, + lldb_r1_s390x, + lldb_r2_s390x, + lldb_r3_s390x, + lldb_r4_s390x, + lldb_r5_s390x, + lldb_r6_s390x, + lldb_r7_s390x, + lldb_r8_s390x, + lldb_r9_s390x, + lldb_r10_s390x, + lldb_r11_s390x, + lldb_r12_s390x, + lldb_r13_s390x, + lldb_r14_s390x, + lldb_r15_s390x, + lldb_acr0_s390x, + lldb_acr1_s390x, + lldb_acr2_s390x, + lldb_acr3_s390x, + lldb_acr4_s390x, + lldb_acr5_s390x, + lldb_acr6_s390x, + lldb_acr7_s390x, + lldb_acr8_s390x, + lldb_acr9_s390x, + lldb_acr10_s390x, + lldb_acr11_s390x, + lldb_acr12_s390x, + lldb_acr13_s390x, + lldb_acr14_s390x, + lldb_acr15_s390x, + lldb_pswm_s390x, + lldb_pswa_s390x, + k_last_gpr_s390x = lldb_pswa_s390x, + + k_first_fpr_s390x, + lldb_f0_s390x = k_first_fpr_s390x, + lldb_f1_s390x, + lldb_f2_s390x, + lldb_f3_s390x, + lldb_f4_s390x, + lldb_f5_s390x, + lldb_f6_s390x, + lldb_f7_s390x, + lldb_f8_s390x, + lldb_f9_s390x, + lldb_f10_s390x, + lldb_f11_s390x, + lldb_f12_s390x, + lldb_f13_s390x, + lldb_f14_s390x, + lldb_f15_s390x, + lldb_fpc_s390x, + k_last_fpr_s390x = lldb_fpc_s390x, + + // These are only available on Linux. + k_first_linux_s390x, + lldb_orig_r2_s390x = k_first_linux_s390x, + lldb_last_break_s390x, + lldb_system_call_s390x, + k_last_linux_s390x = lldb_system_call_s390x, + + k_num_registers_s390x, + k_num_gpr_registers_s390x = k_last_gpr_s390x - k_first_gpr_s390x + 1, + k_num_fpr_registers_s390x = k_last_fpr_s390x - k_first_fpr_s390x + 1, + k_num_linux_registers_s390x = k_last_linux_s390x - k_first_linux_s390x + 1, + k_num_user_registers_s390x = k_num_gpr_registers_s390x + k_num_fpr_registers_s390x, +}; +} + +#endif // #ifndef lldb_s390x_register_enums_h Index: source/Plugins/Process/elf-core/CMakeLists.txt =================================================================== --- source/Plugins/Process/elf-core/CMakeLists.txt +++ source/Plugins/Process/elf-core/CMakeLists.txt @@ -7,5 +7,6 @@ RegisterContextPOSIXCore_arm64.cpp RegisterContextPOSIXCore_mips64.cpp RegisterContextPOSIXCore_powerpc.cpp + RegisterContextPOSIXCore_s390x.cpp RegisterContextPOSIXCore_x86_64.cpp ) Index: source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h =================================================================== --- source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h +++ source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h @@ -0,0 +1,65 @@ +//===-- RegisterContextCorePOSIX_s390x.h ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextCorePOSIX_s390x_h_ +#define liblldb_RegisterContextCorePOSIX_s390x_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/DataBufferHeap.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_s390x.h" + +class RegisterContextCorePOSIX_s390x : public RegisterContextPOSIX_s390x +{ +public: + RegisterContextCorePOSIX_s390x(lldb_private::Thread &thread, lldb_private::RegisterInfoInterface *register_info, + const lldb_private::DataExtractor &gpregset, + const lldb_private::DataExtractor &fpregset); + + ~RegisterContextCorePOSIX_s390x() 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::DataBufferSP &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_private::DataExtractor m_gpr; + + lldb::DataBufferSP m_fpr_buffer; + lldb_private::DataExtractor m_fpr; +}; + +#endif // liblldb_RegisterContextCorePOSIX_s390x_h_ Index: source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp =================================================================== --- source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp +++ source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp @@ -0,0 +1,115 @@ +//===-- RegisterContextCorePOSIX_s390x.cpp ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" +#include "RegisterContextPOSIXCore_s390x.h" + +using namespace lldb_private; + +RegisterContextCorePOSIX_s390x::RegisterContextCorePOSIX_s390x(Thread &thread, RegisterInfoInterface *register_info, + const DataExtractor &gpregset, + const DataExtractor &fpregset) + : RegisterContextPOSIX_s390x(thread, 0, register_info) +{ + m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize())); + m_gpr.SetData(m_gpr_buffer); + m_gpr.SetByteOrder(gpregset.GetByteOrder()); + + m_fpr_buffer.reset(new DataBufferHeap(fpregset.GetDataStart(), fpregset.GetByteSize())); + m_fpr.SetData(m_fpr_buffer); + m_fpr.SetByteOrder(fpregset.GetByteOrder()); +} + +RegisterContextCorePOSIX_s390x::~RegisterContextCorePOSIX_s390x() +{ +} + +bool +RegisterContextCorePOSIX_s390x::ReadGPR() +{ + return true; +} + +bool +RegisterContextCorePOSIX_s390x::ReadFPR() +{ + return true; +} + +bool +RegisterContextCorePOSIX_s390x::WriteGPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_s390x::WriteFPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_s390x::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + if (reg == LLDB_INVALID_REGNUM) + return false; + + if (IsGPR(reg)) + { + 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.SetUInt(v, reg_info->byte_size); + return true; + } + } + + if (IsFPR(reg)) + { + lldb::offset_t offset = reg_info->byte_offset; + uint64_t v = m_fpr.GetMaxU64(&offset, reg_info->byte_size); + if (offset == reg_info->byte_offset + reg_info->byte_size) + { + value.SetUInt(v, reg_info->byte_size); + return true; + } + } + + return false; +} + +bool +RegisterContextCorePOSIX_s390x::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_s390x::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + return false; +} + +bool +RegisterContextCorePOSIX_s390x::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_s390x::HardwareSingleStep(bool enable) +{ + return false; +} Index: source/Plugins/Process/elf-core/ThreadElfCore.h =================================================================== --- source/Plugins/Process/elf-core/ThreadElfCore.h +++ source/Plugins/Process/elf-core/ThreadElfCore.h @@ -68,6 +68,7 @@ { switch(arch.GetCore()) { + case lldb_private::ArchSpec::eCore_s390x_generic: case lldb_private::ArchSpec::eCore_x86_64_x86_64: return ELFLINUXPRSTATUS64_SIZE; default: @@ -102,6 +103,7 @@ { switch(arch.GetCore()) { + case lldb_private::ArchSpec::eCore_s390x_generic: case lldb_private::ArchSpec::eCore_x86_64_x86_64: return ELFLINUXPRPSINFO64_SIZE; default: Index: source/Plugins/Process/elf-core/ThreadElfCore.cpp =================================================================== --- source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -18,6 +18,7 @@ #include "ProcessElfCore.h" #include "Plugins/Process/Utility/RegisterContextLinux_arm.h" #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" +#include "Plugins/Process/Utility/RegisterContextLinux_s390x.h" #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_arm.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h" @@ -29,6 +30,7 @@ #include "RegisterContextPOSIXCore_arm64.h" #include "RegisterContextPOSIXCore_mips64.h" #include "RegisterContextPOSIXCore_powerpc.h" +#include "RegisterContextPOSIXCore_s390x.h" #include "RegisterContextPOSIXCore_x86_64.h" using namespace lldb; @@ -139,6 +141,9 @@ case llvm::Triple::aarch64: reg_interface = new RegisterContextLinux_arm64(arch); break; + case llvm::Triple::systemz: + reg_interface = new RegisterContextLinux_s390x(arch); + break; case llvm::Triple::x86_64: reg_interface = new RegisterContextLinux_x86_64(arch); break; @@ -174,6 +179,9 @@ case llvm::Triple::ppc64: m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_powerpc (*this, reg_interface, m_gpregset_data, m_fpregset_data, m_vregset_data)); break; + case llvm::Triple::systemz: + m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_s390x (*this, reg_interface, m_gpregset_data, m_fpregset_data)); + break; case llvm::Triple::x86: case llvm::Triple::x86_64: m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); @@ -218,6 +226,7 @@ size_t len; switch(arch.GetCore()) { + case ArchSpec::eCore_s390x_generic: case ArchSpec::eCore_x86_64_x86_64: len = data.ExtractBytes(0, ELFLINUXPRSTATUS64_SIZE, byteorder, this); return len == ELFLINUXPRSTATUS64_SIZE; @@ -241,6 +250,7 @@ size_t len; switch(arch.GetCore()) { + case ArchSpec::eCore_s390x_generic: case ArchSpec::eCore_x86_64_x86_64: len = data.ExtractBytes(0, ELFLINUXPRPSINFO64_SIZE, byteorder, this); return len == ELFLINUXPRPSINFO64_SIZE; Index: source/Target/Platform.cpp =================================================================== --- source/Target/Platform.cpp +++ source/Target/Platform.cpp @@ -2118,6 +2118,14 @@ } break; + case llvm::Triple::systemz: + { + static const uint8_t g_hex_opcode[] = {0x00, 0x01}; + trap_opcode = g_hex_opcode; + trap_opcode_size = sizeof(g_hex_opcode); + } + break; + case llvm::Triple::hexagon: { static const uint8_t g_hex_opcode[] = {0x0c, 0xdb, 0x00, 0x54}; Index: source/Target/Thread.cpp =================================================================== --- source/Target/Thread.cpp +++ source/Target/Thread.cpp @@ -2340,6 +2340,7 @@ case llvm::Triple::mips64el: case llvm::Triple::ppc: case llvm::Triple::ppc64: + case llvm::Triple::systemz: case llvm::Triple::hexagon: m_unwinder_ap.reset (new UnwindLLDB (*this)); break;