lldbPluginABISysV_ppc64
lldbPluginABISysV_mips
lldbPluginABISysV_mips64
+ lldbPluginABISysV_s390x
lldbPluginInstructionARM
lldbPluginInstructionARM64
lldbPluginInstructionMIPS
eCore_ppc64_generic,
eCore_ppc64_ppc970_64,
+ eCore_s390x_generic,
+
eCore_sparc_generic,
eCore_sparc9_generic,
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,
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()))
_i386_pid = 32306
_x86_64_pid = 32259
+ _s390x_pid = 1045
@skipIf(bugnumber="llvm.org/pr26947")
def test_i386(self):
"""Test that lldb can read the process information from an x86_64 linux core file."""
self.do_test("x86_64", self._x86_64_pid)
+ def test_s390x(self):
+ """Test that lldb can read the process information from an s390x linux core file."""
+ self.do_test("s390x", self._s390x_pid)
+
def test_same_pid_running(self):
"""Test that we read the information from the core correctly even if we have a running
process with the same PID around"""
@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."""
@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()
@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)
@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)
@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)
@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)
@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)
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()))
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())
override ARCH :=
override ARCHFLAG :=
endif
+ ifeq "$(ARCH)" "s390x"
+ override ARCH :=
+ override ARCHFLAG :=
+ endif
ifeq "$(findstring mips,$(ARCH))" "mips"
override ARCHFLAG := -
endif
@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()
@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()
# 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)
@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()
# 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")
#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.
#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"
ABISysV_ppc64::Initialize();
ABISysV_mips::Initialize();
ABISysV_mips64::Initialize();
+ ABISysV_s390x::Initialize();
DisassemblerLLVMC::Initialize();
JITLoaderGDB::Initialize();
ABISysV_ppc64::Terminate();
ABISysV_mips::Terminate();
ABISysV_mips64::Terminate();
+ ABISysV_s390x::Terminate();
DisassemblerLLVMC::Terminate();
JITLoaderGDB::Terminate();
{ 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" },
{ 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
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
case llvm::Triple::sparcv9:
+ case llvm::Triple::systemz:
arch_64.SetTriple(triple);
break;
}
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)
--- /dev/null
+//===-- 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<addr_t> 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<uint64_t>(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<uint64_t>(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<uint64_t>(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::GetFallbackRegisterLocation (const RegisterInfo *reg_info,
+ UnwindPlan::Row::RegisterLocation &unwind_regloc)
+{
+ // If a volatile register is being requested, we don't want to forward the next frame's register contents
+ // up the stack -- the register is not retrievable at this frame.
+ if (RegisterIsVolatile(reg_info))
+ {
+ unwind_regloc.SetUndefined();
+ return true;
+ }
+
+ 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;
+}
--- /dev/null
+//===-- 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<lldb::addr_t> 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;
+
+ bool
+ RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override;
+
+ bool
+ GetFallbackRegisterLocation (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::UnwindPlan::Row::RegisterLocation &unwind_regloc) 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_
--- /dev/null
+add_lldb_library(lldbPluginABISysV_s390x
+ ABISysV_s390x.cpp
+ )
case EM_MIPS:
slot = R_MIPS_JUMP_SLOT;
break;
+ case EM_S390:
+ slot = R_390_JMP_SLOT;
+ break;
}
return slot;
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
NativeRegisterContextLinux_arm64.cpp
NativeRegisterContextLinux_x86_64.cpp
NativeRegisterContextLinux_mips64.cpp
+ NativeRegisterContextLinux_s390x.cpp
NativeThreadLinux.cpp
ProcFileReader.cpp
SingleStepCheck.cpp
// 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 ())
{
actual_opcode_size = static_cast<uint32_t> (sizeof(g_i386_opcode));
return Error ();
+ case llvm::Triple::systemz:
+ actual_opcode_size = static_cast<uint32_t> (sizeof(g_s390x_opcode));
+ return Error ();
+
case llvm::Triple::arm:
case llvm::Triple::aarch64:
case llvm::Triple::mips64:
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 ())
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");
--- /dev/null
+//===-- 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 <asm/ptrace.h>
+#include <linux/uio.h>
+#include <sys/ptrace.h>
+
+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<void *>(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__)
--- /dev/null
+//===-- 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__)
RegisterContextLinux_x86_64.cpp
RegisterContextLinux_mips64.cpp
RegisterContextLinux_mips.cpp
+ RegisterContextLinux_s390x.cpp
RegisterContextLLDB.cpp
RegisterContextMacOSXFrameBackchain.cpp
RegisterContextMach_arm.cpp
RegisterContextPOSIX_arm64.cpp
RegisterContextPOSIX_mips64.cpp
RegisterContextPOSIX_powerpc.cpp
+ RegisterContextPOSIX_s390x.cpp
RegisterContextPOSIX_x86.cpp
RegisterContextThreadMemory.cpp
StopInfoMachException.cpp
--- /dev/null
+//===-- 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<lldb_private::RegisterInfo> *
+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;
+}
--- /dev/null
+//===-- 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<lldb_private::RegisterInfo> *
+ 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<lldb_private::RegisterInfo> d_register_infos;
+};
+
+#endif
--- /dev/null
+//===-- 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 <cstring>
+#include <errno.h>
+#include <stdint.h>
+
+#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;
+}
--- /dev/null
+//===-- 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<lldb_private::RegisterInfoInterface> 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_
--- /dev/null
+//===-- 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
--- /dev/null
+//===-- 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 <stddef.h>
+
+// 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
--- /dev/null
+//===-- 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
RegisterContextPOSIXCore_arm64.cpp
RegisterContextPOSIXCore_mips64.cpp
RegisterContextPOSIXCore_powerpc.cpp
+ RegisterContextPOSIXCore_s390x.cpp
RegisterContextPOSIXCore_x86_64.cpp
)
--- /dev/null
+//===-- 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;
+}
--- /dev/null
+//===-- 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_
#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"
#include "RegisterContextPOSIXCore_arm64.h"
#include "RegisterContextPOSIXCore_mips64.h"
#include "RegisterContextPOSIXCore_powerpc.h"
+#include "RegisterContextPOSIXCore_s390x.h"
#include "RegisterContextPOSIXCore_x86_64.h"
using namespace lldb;
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;
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));
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;
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;
{
switch(arch.GetCore())
{
+ case lldb_private::ArchSpec::eCore_s390x_generic:
case lldb_private::ArchSpec::eCore_x86_64_x86_64:
return ELFLINUXPRSTATUS64_SIZE;
default:
{
switch(arch.GetCore())
{
+ case lldb_private::ArchSpec::eCore_s390x_generic:
case lldb_private::ArchSpec::eCore_x86_64_x86_64:
return ELFLINUXPRPSINFO64_SIZE;
default:
}
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};
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;