diff options
author | Jason Molenda <jmolenda@apple.com> | 2014-03-29 18:54:20 +0000 |
---|---|---|
committer | Jason Molenda <jmolenda@apple.com> | 2014-03-29 18:54:20 +0000 |
commit | a332978b2ab53306acdef10858c7e954e605ab37 (patch) | |
tree | db0802288ce9a50156d440b82ae606eae60cf129 /lldb/source/Plugins/Process | |
parent | 61e595be4dcd9e63bc3a2b6787ffb647457969cd (diff) | |
download | bcm5719-llvm-a332978b2ab53306acdef10858c7e954e605ab37.tar.gz bcm5719-llvm-a332978b2ab53306acdef10858c7e954e605ab37.zip |
lldb arm64 import.
These changes were written by Greg Clayton, Jim Ingham, Jason Molenda.
It builds cleanly against TOT llvm with xcodebuild. I updated the
cmake files by visual inspection but did not try a build. I haven't
built these sources on any non-Mac platforms - I don't think this
patch adds any code that requires darwin, but please let me know if
I missed something.
In debugserver, MachProcess.cpp and MachTask.cpp were renamed to
MachProcess.mm and MachTask.mm as they picked up some new Objective-C
code needed to launch processes when running on iOS.
llvm-svn: 205113
Diffstat (limited to 'lldb/source/Plugins/Process')
15 files changed, 2251 insertions, 74 deletions
diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt b/lldb/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt index 4203a87cfd8..b0172037b04 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt @@ -5,6 +5,7 @@ add_lldb_library(lldbPluginProcessMacOSXKernel ProcessKDP.cpp ProcessKDPLog.cpp RegisterContextKDP_arm.cpp + RegisterContextKDP_arm64.cpp RegisterContextKDP_i386.cpp RegisterContextKDP_x86_64.cpp ThreadKDP.cpp diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp new file mode 100644 index 00000000000..ed62f1982d3 --- /dev/null +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp @@ -0,0 +1,161 @@ +//===-- RegisterContextKDP_arm64.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "RegisterContextKDP_arm64.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "ProcessKDP.h" +#include "ThreadKDP.h" + +using namespace lldb; +using namespace lldb_private; + + +RegisterContextKDP_arm64::RegisterContextKDP_arm64 (ThreadKDP &thread, uint32_t concrete_frame_idx) : + RegisterContextDarwin_arm64 (thread, concrete_frame_idx), + m_kdp_thread (thread) +{ +} + +RegisterContextKDP_arm64::~RegisterContextKDP_arm64() +{ +} + +int +RegisterContextKDP_arm64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + +int +RegisterContextKDP_arm64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + +int +RegisterContextKDP_arm64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, EXCRegSet, &exc, sizeof(exc), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + +int +RegisterContextKDP_arm64::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + +int +RegisterContextKDP_arm64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + +int +RegisterContextKDP_arm64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + +int +RegisterContextKDP_arm64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, EXCRegSet, &exc, sizeof(exc), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + +int +RegisterContextKDP_arm64::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + + diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h new file mode 100644 index 00000000000..8780b7be4a9 --- /dev/null +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h @@ -0,0 +1,61 @@ +//===-- RegisterContextKDP_arm64.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_RegisterContextKDP_arm64_h_ +#define liblldb_RegisterContextKDP_arm64_h_ + +// C Includes + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h" + +class ThreadKDP; + +class RegisterContextKDP_arm64 : public RegisterContextDarwin_arm64 +{ +public: + + RegisterContextKDP_arm64 (ThreadKDP &thread, + uint32_t concrete_frame_idx); + + virtual + ~RegisterContextKDP_arm64(); + +protected: + + virtual int + DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr); + + int + DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu); + + int + DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc); + + int + DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg); + + int + DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr); + + int + DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu); + + int + DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc); + + int + DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg); + + ThreadKDP &m_kdp_thread; +}; + +#endif // liblldb_RegisterContextKDP_arm64_h_ diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp index bb7e8a317a0..562ba8b0a16 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp @@ -26,6 +26,7 @@ #include "ProcessKDP.h" #include "ProcessKDPLog.h" #include "RegisterContextKDP_arm.h" +#include "RegisterContextKDP_arm64.h" #include "RegisterContextKDP_i386.h" #include "RegisterContextKDP_x86_64.h" #include "Plugins/Process/Utility/StopInfoMachException.h" @@ -127,6 +128,9 @@ ThreadKDP::CreateRegisterContextForFrame (StackFrame *frame) case llvm::MachO::CPU_TYPE_ARM: reg_ctx_sp.reset (new RegisterContextKDP_arm (*this, concrete_frame_idx)); break; + case llvm::MachO::CPU_TYPE_ARM64: + reg_ctx_sp.reset (new RegisterContextKDP_arm64 (*this, concrete_frame_idx)); + break; case llvm::MachO::CPU_TYPE_I386: reg_ctx_sp.reset (new RegisterContextKDP_i386 (*this, concrete_frame_idx)); break; diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt index 6cd8e645900..e1a64ecfdc8 100644 --- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt +++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt @@ -8,6 +8,7 @@ add_lldb_library(lldbPluginProcessUtility HistoryUnwind.cpp InferiorCallPOSIX.cpp RegisterContextDarwin_arm.cpp + RegisterContextDarwin_arm64.cpp RegisterContextDarwin_i386.cpp RegisterContextDarwin_x86_64.cpp RegisterContextDummy.cpp diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp new file mode 100644 index 00000000000..b42f35b927b --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp @@ -0,0 +1,1235 @@ +//===-- RegisterContextDarwin_arm64.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(__APPLE__) + +#include "RegisterContextDarwin_arm64.h" + +// C Includes +#include <mach/mach_types.h> +#include <mach/thread_act.h> +#include <sys/sysctl.h> + +// C++ Includes +// Other libraries and framework includes +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Host/Endian.h" +#include "llvm/Support/Compiler.h" + +#include "Plugins/Process/Utility/InstructionUtils.h" + +// Support building against older versions of LLVM, this macro was added +// recently. +#ifndef LLVM_EXTENSION +#define LLVM_EXTENSION +#endif + +// Project includes +#include "ARM64_GCC_Registers.h" +#include "ARM64_DWARF_Registers.h" + +using namespace lldb; +using namespace lldb_private; + +enum +{ + gpr_x0 = 0, + gpr_x1, + gpr_x2, + gpr_x3, + gpr_x4, + gpr_x5, + gpr_x6, + gpr_x7, + gpr_x8, + gpr_x9, + gpr_x10, + gpr_x11, + gpr_x12, + gpr_x13, + gpr_x14, + gpr_x15, + gpr_x16, + gpr_x17, + gpr_x18, + gpr_x19, + gpr_x20, + gpr_x21, + gpr_x22, + gpr_x23, + gpr_x24, + gpr_x25, + gpr_x26, + gpr_x27, + gpr_x28, + gpr_x29 = 29, gpr_fp = gpr_x29, + gpr_x30 = 30, gpr_lr = gpr_x30, gpr_ra = gpr_x30, + gpr_x31 = 31, gpr_sp = gpr_x31, + gpr_pc = 32, + gpr_cpsr, + + fpu_v0, + fpu_v1, + fpu_v2, + fpu_v3, + fpu_v4, + fpu_v5, + fpu_v6, + fpu_v7, + fpu_v8, + fpu_v9, + fpu_v10, + fpu_v11, + fpu_v12, + fpu_v13, + fpu_v14, + fpu_v15, + fpu_v16, + fpu_v17, + fpu_v18, + fpu_v19, + fpu_v20, + fpu_v21, + fpu_v22, + fpu_v23, + fpu_v24, + fpu_v25, + fpu_v26, + fpu_v27, + fpu_v28, + fpu_v29, + fpu_v30, + fpu_v31, + + fpu_fpsr, + fpu_fpcr, + + exc_far, + exc_esr, + exc_exception, + + dbg_bvr0, + dbg_bvr1, + dbg_bvr2, + dbg_bvr3, + dbg_bvr4, + dbg_bvr5, + dbg_bvr6, + dbg_bvr7, + dbg_bvr8, + dbg_bvr9, + dbg_bvr10, + dbg_bvr11, + dbg_bvr12, + dbg_bvr13, + dbg_bvr14, + dbg_bvr15, + + dbg_bcr0, + dbg_bcr1, + dbg_bcr2, + dbg_bcr3, + dbg_bcr4, + dbg_bcr5, + dbg_bcr6, + dbg_bcr7, + dbg_bcr8, + dbg_bcr9, + dbg_bcr10, + dbg_bcr11, + dbg_bcr12, + dbg_bcr13, + dbg_bcr14, + dbg_bcr15, + + dbg_wvr0, + dbg_wvr1, + dbg_wvr2, + dbg_wvr3, + dbg_wvr4, + dbg_wvr5, + dbg_wvr6, + dbg_wvr7, + dbg_wvr8, + dbg_wvr9, + dbg_wvr10, + dbg_wvr11, + dbg_wvr12, + dbg_wvr13, + dbg_wvr14, + dbg_wvr15, + + dbg_wcr0, + dbg_wcr1, + dbg_wcr2, + dbg_wcr3, + dbg_wcr4, + dbg_wcr5, + dbg_wcr6, + dbg_wcr7, + dbg_wcr8, + dbg_wcr9, + dbg_wcr10, + dbg_wcr11, + dbg_wcr12, + dbg_wcr13, + dbg_wcr14, + dbg_wcr15, + + k_num_registers +}; + + +RegisterContextDarwin_arm64::RegisterContextDarwin_arm64(Thread &thread, uint32_t concrete_frame_idx) : + RegisterContext(thread, concrete_frame_idx), + gpr(), + fpu(), + exc() +{ + uint32_t i; + for (i=0; i<kNumErrors; i++) + { + gpr_errs[i] = -1; + fpu_errs[i] = -1; + exc_errs[i] = -1; + } +} + +RegisterContextDarwin_arm64::~RegisterContextDarwin_arm64() +{ +} + + +#define GPR_OFFSET(idx) ((idx) * 8) +#define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::GPR, reg)) + +#define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextDarwin_arm64::GPR)) +#define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::FPU, reg)) + +#define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::EXC, reg) + sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU)) +#define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::DBG, reg) + sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU) + sizeof (RegisterContextDarwin_arm64::EXC)) + +#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextDarwin_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL +#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU) + sizeof (RegisterContextDarwin_arm64::EXC)) + +static RegisterInfo g_register_infos[] = { +// General purpose registers +// NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS +// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== =============== +{ "x0", NULL, 8, GPR_OFFSET(0), eEncodingUint, eFormatHex, { arm64_gcc::x0, arm64_dwarf::x0, LLDB_INVALID_REGNUM, arm64_gcc::x0, gpr_x0 }, NULL, NULL}, +{ "x1", NULL, 8, GPR_OFFSET(1), eEncodingUint, eFormatHex, { arm64_gcc::x1, arm64_dwarf::x1, LLDB_INVALID_REGNUM, arm64_gcc::x1, gpr_x1 }, NULL, NULL}, +{ "x2", NULL, 8, GPR_OFFSET(2), eEncodingUint, eFormatHex, { arm64_gcc::x2, arm64_dwarf::x2, LLDB_INVALID_REGNUM, arm64_gcc::x2, gpr_x2 }, NULL, NULL}, +{ "x3", NULL, 8, GPR_OFFSET(3), eEncodingUint, eFormatHex, { arm64_gcc::x3, arm64_dwarf::x3, LLDB_INVALID_REGNUM, arm64_gcc::x3, gpr_x3 }, NULL, NULL}, +{ "x4", NULL, 8, GPR_OFFSET(4), eEncodingUint, eFormatHex, { arm64_gcc::x4, arm64_dwarf::x4, LLDB_INVALID_REGNUM, arm64_gcc::x4, gpr_x4 }, NULL, NULL}, +{ "x5", NULL, 8, GPR_OFFSET(5), eEncodingUint, eFormatHex, { arm64_gcc::x5, arm64_dwarf::x5, LLDB_INVALID_REGNUM, arm64_gcc::x5, gpr_x5 }, NULL, NULL}, +{ "x6", NULL, 8, GPR_OFFSET(6), eEncodingUint, eFormatHex, { arm64_gcc::x6, arm64_dwarf::x6, LLDB_INVALID_REGNUM, arm64_gcc::x6, gpr_x6 }, NULL, NULL}, +{ "x7", NULL, 8, GPR_OFFSET(7), eEncodingUint, eFormatHex, { arm64_gcc::x7, arm64_dwarf::x7, LLDB_INVALID_REGNUM, arm64_gcc::x7, gpr_x7 }, NULL, NULL}, +{ "x8", NULL, 8, GPR_OFFSET(8), eEncodingUint, eFormatHex, { arm64_gcc::x8, arm64_dwarf::x8, LLDB_INVALID_REGNUM, arm64_gcc::x8, gpr_x8 }, NULL, NULL}, +{ "x9", NULL, 8, GPR_OFFSET(9), eEncodingUint, eFormatHex, { arm64_gcc::x9, arm64_dwarf::x9, LLDB_INVALID_REGNUM, arm64_gcc::x9, gpr_x9 }, NULL, NULL}, +{ "x10", NULL, 8, GPR_OFFSET(10), eEncodingUint, eFormatHex, { arm64_gcc::x10, arm64_dwarf::x10, LLDB_INVALID_REGNUM, arm64_gcc::x10, gpr_x10 }, NULL, NULL}, +{ "x11", NULL, 8, GPR_OFFSET(11), eEncodingUint, eFormatHex, { arm64_gcc::x11, arm64_dwarf::x11, LLDB_INVALID_REGNUM, arm64_gcc::x11, gpr_x11 }, NULL, NULL}, +{ "x12", NULL, 8, GPR_OFFSET(12), eEncodingUint, eFormatHex, { arm64_gcc::x12, arm64_dwarf::x12, LLDB_INVALID_REGNUM, arm64_gcc::x12, gpr_x12 }, NULL, NULL}, +{ "x13", NULL, 8, GPR_OFFSET(13), eEncodingUint, eFormatHex, { arm64_gcc::x13, arm64_dwarf::x13, LLDB_INVALID_REGNUM, arm64_gcc::x13, gpr_x13 }, NULL, NULL}, +{ "x14", NULL, 8, GPR_OFFSET(14), eEncodingUint, eFormatHex, { arm64_gcc::x14, arm64_dwarf::x14, LLDB_INVALID_REGNUM, arm64_gcc::x14, gpr_x14 }, NULL, NULL}, +{ "x15", NULL, 8, GPR_OFFSET(15), eEncodingUint, eFormatHex, { arm64_gcc::x15, arm64_dwarf::x15, LLDB_INVALID_REGNUM, arm64_gcc::x15, gpr_x15 }, NULL, NULL}, +{ "x16", NULL, 8, GPR_OFFSET(16), eEncodingUint, eFormatHex, { arm64_gcc::x16, arm64_dwarf::x16, LLDB_INVALID_REGNUM, arm64_gcc::x16, gpr_x16 }, NULL, NULL}, +{ "x17", NULL, 8, GPR_OFFSET(17), eEncodingUint, eFormatHex, { arm64_gcc::x17, arm64_dwarf::x17, LLDB_INVALID_REGNUM, arm64_gcc::x17, gpr_x17 }, NULL, NULL}, +{ "x18", NULL, 8, GPR_OFFSET(18), eEncodingUint, eFormatHex, { arm64_gcc::x18, arm64_dwarf::x18, LLDB_INVALID_REGNUM, arm64_gcc::x18, gpr_x18 }, NULL, NULL}, +{ "x19", NULL, 8, GPR_OFFSET(19), eEncodingUint, eFormatHex, { arm64_gcc::x19, arm64_dwarf::x19, LLDB_INVALID_REGNUM, arm64_gcc::x19, gpr_x19 }, NULL, NULL}, +{ "x20", NULL, 8, GPR_OFFSET(20), eEncodingUint, eFormatHex, { arm64_gcc::x20, arm64_dwarf::x20, LLDB_INVALID_REGNUM, arm64_gcc::x20, gpr_x20 }, NULL, NULL}, +{ "x21", NULL, 8, GPR_OFFSET(21), eEncodingUint, eFormatHex, { arm64_gcc::x21, arm64_dwarf::x21, LLDB_INVALID_REGNUM, arm64_gcc::x21, gpr_x21 }, NULL, NULL}, +{ "x22", NULL, 8, GPR_OFFSET(22), eEncodingUint, eFormatHex, { arm64_gcc::x22, arm64_dwarf::x22, LLDB_INVALID_REGNUM, arm64_gcc::x22, gpr_x22 }, NULL, NULL}, +{ "x23", NULL, 8, GPR_OFFSET(23), eEncodingUint, eFormatHex, { arm64_gcc::x23, arm64_dwarf::x23, LLDB_INVALID_REGNUM, arm64_gcc::x23, gpr_x23 }, NULL, NULL}, +{ "x24", NULL, 8, GPR_OFFSET(24), eEncodingUint, eFormatHex, { arm64_gcc::x24, arm64_dwarf::x24, LLDB_INVALID_REGNUM, arm64_gcc::x24, gpr_x24 }, NULL, NULL}, +{ "x25", NULL, 8, GPR_OFFSET(25), eEncodingUint, eFormatHex, { arm64_gcc::x25, arm64_dwarf::x25, LLDB_INVALID_REGNUM, arm64_gcc::x25, gpr_x25 }, NULL, NULL}, +{ "x26", NULL, 8, GPR_OFFSET(26), eEncodingUint, eFormatHex, { arm64_gcc::x26, arm64_dwarf::x26, LLDB_INVALID_REGNUM, arm64_gcc::x26, gpr_x26 }, NULL, NULL}, +{ "x27", NULL, 8, GPR_OFFSET(27), eEncodingUint, eFormatHex, { arm64_gcc::x27, arm64_dwarf::x27, LLDB_INVALID_REGNUM, arm64_gcc::x27, gpr_x27 }, NULL, NULL}, +{ "x28", NULL, 8, GPR_OFFSET(28), eEncodingUint, eFormatHex, { arm64_gcc::x28, arm64_dwarf::x28, LLDB_INVALID_REGNUM, arm64_gcc::x28, gpr_x28 }, NULL, NULL}, + +{ "fp", "x29", 8, GPR_OFFSET(29), eEncodingUint, eFormatHex, { arm64_gcc::fp, arm64_dwarf::fp, LLDB_REGNUM_GENERIC_FP, arm64_gcc::fp, gpr_fp }, NULL, NULL}, +{ "lr", "x30", 8, GPR_OFFSET(30), eEncodingUint, eFormatHex, { arm64_gcc::lr, arm64_dwarf::lr, LLDB_REGNUM_GENERIC_RA, arm64_gcc::lr, gpr_lr }, NULL, NULL}, +{ "sp", "x31", 8, GPR_OFFSET(31), eEncodingUint, eFormatHex, { arm64_gcc::sp, arm64_dwarf::sp, LLDB_REGNUM_GENERIC_SP, arm64_gcc::sp, gpr_sp }, NULL, NULL}, +{ "pc", NULL, 8, GPR_OFFSET(32), eEncodingUint, eFormatHex, { arm64_gcc::pc, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, arm64_gcc::pc, gpr_pc }, NULL, NULL}, + +{ "cpsr", NULL, 4, GPR_OFFSET_NAME(cpsr), eEncodingUint, eFormatHex, { arm64_gcc::cpsr, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, arm64_gcc::cpsr, gpr_cpsr }, NULL, NULL}, + +{ "v0", NULL, 16, FPU_OFFSET(0), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v0, LLDB_INVALID_REGNUM, arm64_gcc::v0, fpu_v0 }, NULL, NULL}, +{ "v1", NULL, 16, FPU_OFFSET(1), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v1, LLDB_INVALID_REGNUM, arm64_gcc::v1, fpu_v1 }, NULL, NULL}, +{ "v2", NULL, 16, FPU_OFFSET(2), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v2, LLDB_INVALID_REGNUM, arm64_gcc::v2, fpu_v2 }, NULL, NULL}, +{ "v3", NULL, 16, FPU_OFFSET(3), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v3, LLDB_INVALID_REGNUM, arm64_gcc::v3, fpu_v3 }, NULL, NULL}, +{ "v4", NULL, 16, FPU_OFFSET(4), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v4, LLDB_INVALID_REGNUM, arm64_gcc::v4, fpu_v4 }, NULL, NULL}, +{ "v5", NULL, 16, FPU_OFFSET(5), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v5, LLDB_INVALID_REGNUM, arm64_gcc::v5, fpu_v5 }, NULL, NULL}, +{ "v6", NULL, 16, FPU_OFFSET(6), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v6, LLDB_INVALID_REGNUM, arm64_gcc::v6, fpu_v6 }, NULL, NULL}, +{ "v7", NULL, 16, FPU_OFFSET(7), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v7, LLDB_INVALID_REGNUM, arm64_gcc::v7, fpu_v7 }, NULL, NULL}, +{ "v8", NULL, 16, FPU_OFFSET(8), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v8, LLDB_INVALID_REGNUM, arm64_gcc::v8, fpu_v8 }, NULL, NULL}, +{ "v9", NULL, 16, FPU_OFFSET(9), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v9, LLDB_INVALID_REGNUM, arm64_gcc::v9, fpu_v9 }, NULL, NULL}, +{ "v10", NULL, 16, FPU_OFFSET(10), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v10, LLDB_INVALID_REGNUM, arm64_gcc::v10, fpu_v10 }, NULL, NULL}, +{ "v11", NULL, 16, FPU_OFFSET(11), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v11, LLDB_INVALID_REGNUM, arm64_gcc::v11, fpu_v11 }, NULL, NULL}, +{ "v12", NULL, 16, FPU_OFFSET(12), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v12, LLDB_INVALID_REGNUM, arm64_gcc::v12, fpu_v12 }, NULL, NULL}, +{ "v13", NULL, 16, FPU_OFFSET(13), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v13, LLDB_INVALID_REGNUM, arm64_gcc::v13, fpu_v13 }, NULL, NULL}, +{ "v14", NULL, 16, FPU_OFFSET(14), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v14, LLDB_INVALID_REGNUM, arm64_gcc::v14, fpu_v14 }, NULL, NULL}, +{ "v15", NULL, 16, FPU_OFFSET(15), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v15, LLDB_INVALID_REGNUM, arm64_gcc::v15, fpu_v15 }, NULL, NULL}, +{ "v16", NULL, 16, FPU_OFFSET(16), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v16, LLDB_INVALID_REGNUM, arm64_gcc::v16, fpu_v16 }, NULL, NULL}, +{ "v17", NULL, 16, FPU_OFFSET(17), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v17, LLDB_INVALID_REGNUM, arm64_gcc::v17, fpu_v17 }, NULL, NULL}, +{ "v18", NULL, 16, FPU_OFFSET(18), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v18, LLDB_INVALID_REGNUM, arm64_gcc::v18, fpu_v18 }, NULL, NULL}, +{ "v19", NULL, 16, FPU_OFFSET(19), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v19, LLDB_INVALID_REGNUM, arm64_gcc::v19, fpu_v19 }, NULL, NULL}, +{ "v20", NULL, 16, FPU_OFFSET(20), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v20, LLDB_INVALID_REGNUM, arm64_gcc::v20, fpu_v20 }, NULL, NULL}, +{ "v21", NULL, 16, FPU_OFFSET(21), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v21, LLDB_INVALID_REGNUM, arm64_gcc::v21, fpu_v21 }, NULL, NULL}, +{ "v22", NULL, 16, FPU_OFFSET(22), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v22, LLDB_INVALID_REGNUM, arm64_gcc::v22, fpu_v22 }, NULL, NULL}, +{ "v23", NULL, 16, FPU_OFFSET(23), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v23, LLDB_INVALID_REGNUM, arm64_gcc::v23, fpu_v23 }, NULL, NULL}, +{ "v24", NULL, 16, FPU_OFFSET(24), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v24, LLDB_INVALID_REGNUM, arm64_gcc::v24, fpu_v24 }, NULL, NULL}, +{ "v25", NULL, 16, FPU_OFFSET(25), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v25, LLDB_INVALID_REGNUM, arm64_gcc::v25, fpu_v25 }, NULL, NULL}, +{ "v26", NULL, 16, FPU_OFFSET(26), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v26, LLDB_INVALID_REGNUM, arm64_gcc::v26, fpu_v26 }, NULL, NULL}, +{ "v27", NULL, 16, FPU_OFFSET(27), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v27, LLDB_INVALID_REGNUM, arm64_gcc::v27, fpu_v27 }, NULL, NULL}, +{ "v28", NULL, 16, FPU_OFFSET(28), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v28, LLDB_INVALID_REGNUM, arm64_gcc::v28, fpu_v28 }, NULL, NULL}, +{ "v29", NULL, 16, FPU_OFFSET(29), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v29, LLDB_INVALID_REGNUM, arm64_gcc::v29, fpu_v29 }, NULL, NULL}, +{ "v30", NULL, 16, FPU_OFFSET(30), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v30, LLDB_INVALID_REGNUM, arm64_gcc::v30, fpu_v30 }, NULL, NULL}, +{ "v31", NULL, 16, FPU_OFFSET(31), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v31, LLDB_INVALID_REGNUM, arm64_gcc::v31, fpu_v31 }, NULL, NULL}, + +{ "fpsr", NULL, 4, FPU_OFFSET_NAME(fpsr), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpsr }, NULL, NULL}, +{ "fpcr", NULL, 4, FPU_OFFSET_NAME(fpcr), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpcr }, NULL, NULL}, + +{ "far", NULL, 8, EXC_OFFSET_NAME(far), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, NULL, NULL}, +{ "esr", NULL, 4, EXC_OFFSET_NAME(esr), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_esr }, NULL, NULL}, +{ "exception",NULL, 4, EXC_OFFSET_NAME(exception), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL}, + +{ DEFINE_DBG (bvr, 0) }, +{ DEFINE_DBG (bvr, 1) }, +{ DEFINE_DBG (bvr, 2) }, +{ DEFINE_DBG (bvr, 3) }, +{ DEFINE_DBG (bvr, 4) }, +{ DEFINE_DBG (bvr, 5) }, +{ DEFINE_DBG (bvr, 6) }, +{ DEFINE_DBG (bvr, 7) }, +{ DEFINE_DBG (bvr, 8) }, +{ DEFINE_DBG (bvr, 9) }, +{ DEFINE_DBG (bvr, 10) }, +{ DEFINE_DBG (bvr, 11) }, +{ DEFINE_DBG (bvr, 12) }, +{ DEFINE_DBG (bvr, 13) }, +{ DEFINE_DBG (bvr, 14) }, +{ DEFINE_DBG (bvr, 15) }, + +{ DEFINE_DBG (bcr, 0) }, +{ DEFINE_DBG (bcr, 1) }, +{ DEFINE_DBG (bcr, 2) }, +{ DEFINE_DBG (bcr, 3) }, +{ DEFINE_DBG (bcr, 4) }, +{ DEFINE_DBG (bcr, 5) }, +{ DEFINE_DBG (bcr, 6) }, +{ DEFINE_DBG (bcr, 7) }, +{ DEFINE_DBG (bcr, 8) }, +{ DEFINE_DBG (bcr, 9) }, +{ DEFINE_DBG (bcr, 10) }, +{ DEFINE_DBG (bcr, 11) }, +{ DEFINE_DBG (bcr, 12) }, +{ DEFINE_DBG (bcr, 13) }, +{ DEFINE_DBG (bcr, 14) }, +{ DEFINE_DBG (bcr, 15) }, + +{ DEFINE_DBG (wvr, 0) }, +{ DEFINE_DBG (wvr, 1) }, +{ DEFINE_DBG (wvr, 2) }, +{ DEFINE_DBG (wvr, 3) }, +{ DEFINE_DBG (wvr, 4) }, +{ DEFINE_DBG (wvr, 5) }, +{ DEFINE_DBG (wvr, 6) }, +{ DEFINE_DBG (wvr, 7) }, +{ DEFINE_DBG (wvr, 8) }, +{ DEFINE_DBG (wvr, 9) }, +{ DEFINE_DBG (wvr, 10) }, +{ DEFINE_DBG (wvr, 11) }, +{ DEFINE_DBG (wvr, 12) }, +{ DEFINE_DBG (wvr, 13) }, +{ DEFINE_DBG (wvr, 14) }, +{ DEFINE_DBG (wvr, 15) }, + +{ DEFINE_DBG (wcr, 0) }, +{ DEFINE_DBG (wcr, 1) }, +{ DEFINE_DBG (wcr, 2) }, +{ DEFINE_DBG (wcr, 3) }, +{ DEFINE_DBG (wcr, 4) }, +{ DEFINE_DBG (wcr, 5) }, +{ DEFINE_DBG (wcr, 6) }, +{ DEFINE_DBG (wcr, 7) }, +{ DEFINE_DBG (wcr, 8) }, +{ DEFINE_DBG (wcr, 9) }, +{ DEFINE_DBG (wcr, 10) }, +{ DEFINE_DBG (wcr, 11) }, +{ DEFINE_DBG (wcr, 12) }, +{ DEFINE_DBG (wcr, 13) }, +{ DEFINE_DBG (wcr, 14) }, +{ DEFINE_DBG (wcr, 15) } +}; + +// General purpose registers +static uint32_t +g_gpr_regnums[] = +{ + gpr_x0, + gpr_x1, + gpr_x2, + gpr_x3, + gpr_x4, + gpr_x5, + gpr_x6, + gpr_x7, + gpr_x8, + gpr_x9, + gpr_x10, + gpr_x11, + gpr_x12, + gpr_x13, + gpr_x14, + gpr_x15, + gpr_x16, + gpr_x17, + gpr_x18, + gpr_x19, + gpr_x20, + gpr_x21, + gpr_x22, + gpr_x23, + gpr_x24, + gpr_x25, + gpr_x26, + gpr_x27, + gpr_x28, + gpr_fp, + gpr_lr, + gpr_sp, + gpr_pc, + gpr_cpsr +}; + +// Floating point registers +static uint32_t +g_fpu_regnums[] = +{ + fpu_v0, + fpu_v1, + fpu_v2, + fpu_v3, + fpu_v4, + fpu_v5, + fpu_v6, + fpu_v7, + fpu_v8, + fpu_v9, + fpu_v10, + fpu_v11, + fpu_v12, + fpu_v13, + fpu_v14, + fpu_v15, + fpu_v16, + fpu_v17, + fpu_v18, + fpu_v19, + fpu_v20, + fpu_v21, + fpu_v22, + fpu_v23, + fpu_v24, + fpu_v25, + fpu_v26, + fpu_v27, + fpu_v28, + fpu_v29, + fpu_v30, + fpu_v31, + fpu_fpsr, + fpu_fpcr +}; + +// Exception registers + +static uint32_t +g_exc_regnums[] = +{ + exc_far, + exc_esr, + exc_exception +}; + +static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo)); + +void +RegisterContextDarwin_arm64::InvalidateAllRegisters () +{ + InvalidateAllRegisterStates(); +} + + +size_t +RegisterContextDarwin_arm64::GetRegisterCount () +{ + assert(k_num_register_infos == k_num_registers); + return k_num_registers; +} + +const RegisterInfo * +RegisterContextDarwin_arm64::GetRegisterInfoAtIndex (size_t reg) +{ + assert(k_num_register_infos == k_num_registers); + if (reg < k_num_registers) + return &g_register_infos[reg]; + return NULL; +} + +size_t +RegisterContextDarwin_arm64::GetRegisterInfosCount () +{ + return k_num_register_infos; +} + +const RegisterInfo * +RegisterContextDarwin_arm64::GetRegisterInfos () +{ + return g_register_infos; +} + + +// Number of registers in each register set +const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t); +const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t); +const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t); + +//---------------------------------------------------------------------- +// Register set definitions. The first definitions at register set index +// of zero is for all registers, followed by other registers sets. The +// register information for the all register set need not be filled in. +//---------------------------------------------------------------------- +static const RegisterSet g_reg_sets[] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, }, + { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums }, + { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums } +}; + +const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet); + + +size_t +RegisterContextDarwin_arm64::GetRegisterSetCount () +{ + return k_num_regsets; +} + +const RegisterSet * +RegisterContextDarwin_arm64::GetRegisterSet (size_t reg_set) +{ + if (reg_set < k_num_regsets) + return &g_reg_sets[reg_set]; + return NULL; +} + + +//---------------------------------------------------------------------- +// Register information defintions for arm64 +//---------------------------------------------------------------------- +int +RegisterContextDarwin_arm64::GetSetForNativeRegNum (int reg) +{ + if (reg < fpu_v0) + return GPRRegSet; + else if (reg < exc_far) + return FPURegSet; + else if (reg < k_num_registers) + return EXCRegSet; + return -1; +} + +int +RegisterContextDarwin_arm64::ReadGPR (bool force) +{ + int set = GPRRegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr)); + } + return GetError(GPRRegSet, Read); +} + +int +RegisterContextDarwin_arm64::ReadFPU (bool force) +{ + int set = FPURegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu)); + } + return GetError(FPURegSet, Read); +} + +int +RegisterContextDarwin_arm64::ReadEXC (bool force) +{ + int set = EXCRegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadEXC(GetThreadID(), set, exc)); + } + return GetError(EXCRegSet, Read); +} + +int +RegisterContextDarwin_arm64::ReadDBG (bool force) +{ + int set = DBGRegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadDBG(GetThreadID(), set, dbg)); + } + return GetError(DBGRegSet, Read); +} + +int +RegisterContextDarwin_arm64::WriteGPR () +{ + int set = GPRRegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr)); + SetError (set, Read, -1); + return GetError(GPRRegSet, Write); +} + +int +RegisterContextDarwin_arm64::WriteFPU () +{ + int set = FPURegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu)); + SetError (set, Read, -1); + return GetError(FPURegSet, Write); +} + +int +RegisterContextDarwin_arm64::WriteEXC () +{ + int set = EXCRegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc)); + SetError (set, Read, -1); + return GetError(EXCRegSet, Write); +} + +int +RegisterContextDarwin_arm64::WriteDBG () +{ + int set = DBGRegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteDBG(GetThreadID(), set, dbg)); + SetError (set, Read, -1); + return GetError(DBGRegSet, Write); +} + + +int +RegisterContextDarwin_arm64::ReadRegisterSet (uint32_t set, bool force) +{ + switch (set) + { + case GPRRegSet: return ReadGPR(force); + case FPURegSet: return ReadFPU(force); + case EXCRegSet: return ReadEXC(force); + case DBGRegSet: return ReadDBG(force); + default: break; + } + return KERN_INVALID_ARGUMENT; +} + +int +RegisterContextDarwin_arm64::WriteRegisterSet (uint32_t set) +{ + // Make sure we have a valid context to set. + if (RegisterSetIsCached(set)) + { + switch (set) + { + case GPRRegSet: return WriteGPR(); + case FPURegSet: return WriteFPU(); + case EXCRegSet: return WriteEXC(); + case DBGRegSet: return WriteDBG(); + default: break; + } + } + return KERN_INVALID_ARGUMENT; +} + +void +RegisterContextDarwin_arm64::LogDBGRegisters (Log *log, const DBG& dbg) +{ + if (log) + { + for (uint32_t i=0; i<16; i++) + log->Printf("BVR%-2u/BCR%-2u = { 0x%8.8llx, 0x%8.8llx } WVR%-2u/WCR%-2u = { 0x%8.8llx, 0x%8.8llx }", + i, i, dbg.bvr[i], dbg.bcr[i], + i, i, dbg.wvr[i], dbg.wcr[i]); + } +} + + +bool +RegisterContextDarwin_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + int set = RegisterContextDarwin_arm64::GetSetForNativeRegNum (reg); + + if (set == -1) + return false; + + if (ReadRegisterSet(set, false) != KERN_SUCCESS) + return false; + + switch (reg) + { + case gpr_x0: + case gpr_x1: + case gpr_x2: + case gpr_x3: + case gpr_x4: + case gpr_x5: + case gpr_x6: + case gpr_x7: + case gpr_x8: + case gpr_x9: + case gpr_x10: + case gpr_x11: + case gpr_x12: + case gpr_x13: + case gpr_x14: + case gpr_x15: + case gpr_x16: + case gpr_x17: + case gpr_x18: + case gpr_x19: + case gpr_x20: + case gpr_x21: + case gpr_x22: + case gpr_x23: + case gpr_x24: + case gpr_x25: + case gpr_x26: + case gpr_x27: + case gpr_x28: + case gpr_fp: + case gpr_sp: + case gpr_lr: + case gpr_pc: + case gpr_cpsr: + value.SetUInt64 (gpr.x[reg - gpr_x0]); + break; + + case fpu_v0: + case fpu_v1: + case fpu_v2: + case fpu_v3: + case fpu_v4: + case fpu_v5: + case fpu_v6: + case fpu_v7: + case fpu_v8: + case fpu_v9: + case fpu_v10: + case fpu_v11: + case fpu_v12: + case fpu_v13: + case fpu_v14: + case fpu_v15: + case fpu_v16: + case fpu_v17: + case fpu_v18: + case fpu_v19: + case fpu_v20: + case fpu_v21: + case fpu_v22: + case fpu_v23: + case fpu_v24: + case fpu_v25: + case fpu_v26: + case fpu_v27: + case fpu_v28: + case fpu_v29: + case fpu_v30: + case fpu_v31: + value.SetBytes(fpu.v[reg].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder()); + break; + + case fpu_fpsr: + value.SetUInt32 (fpu.fpsr); + break; + + case fpu_fpcr: + value.SetUInt32 (fpu.fpcr); + break; + + case exc_exception: + value.SetUInt32 (exc.exception); + break; + case exc_esr: + value.SetUInt32 (exc.esr); + break; + case exc_far: + value.SetUInt64 (exc.far); + break; + + default: + value.SetValueToInvalid(); + return false; + + } + return true; +} + + +bool +RegisterContextDarwin_arm64::WriteRegister (const RegisterInfo *reg_info, + const RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + int set = GetSetForNativeRegNum (reg); + + if (set == -1) + return false; + + if (ReadRegisterSet(set, false) != KERN_SUCCESS) + return false; + + switch (reg) + { + case gpr_x0: + case gpr_x1: + case gpr_x2: + case gpr_x3: + case gpr_x4: + case gpr_x5: + case gpr_x6: + case gpr_x7: + case gpr_x8: + case gpr_x9: + case gpr_x10: + case gpr_x11: + case gpr_x12: + case gpr_x13: + case gpr_x14: + case gpr_x15: + case gpr_x16: + case gpr_x17: + case gpr_x18: + case gpr_x19: + case gpr_x20: + case gpr_x21: + case gpr_x22: + case gpr_x23: + case gpr_x24: + case gpr_x25: + case gpr_x26: + case gpr_x27: + case gpr_x28: + case gpr_fp: + case gpr_sp: + case gpr_lr: + case gpr_pc: + case gpr_cpsr: + gpr.x[reg - gpr_x0] = value.GetAsUInt64(); + break; + + case fpu_v0: + case fpu_v1: + case fpu_v2: + case fpu_v3: + case fpu_v4: + case fpu_v5: + case fpu_v6: + case fpu_v7: + case fpu_v8: + case fpu_v9: + case fpu_v10: + case fpu_v11: + case fpu_v12: + case fpu_v13: + case fpu_v14: + case fpu_v15: + case fpu_v16: + case fpu_v17: + case fpu_v18: + case fpu_v19: + case fpu_v20: + case fpu_v21: + case fpu_v22: + case fpu_v23: + case fpu_v24: + case fpu_v25: + case fpu_v26: + case fpu_v27: + case fpu_v28: + case fpu_v29: + case fpu_v30: + case fpu_v31: + ::memcpy (fpu.v[reg].bytes, value.GetBytes(), value.GetByteSize()); + break; + + case fpu_fpsr: + fpu.fpsr = value.GetAsUInt32(); + break; + + case fpu_fpcr: + fpu.fpcr = value.GetAsUInt32(); + break; + + case exc_exception: + exc.exception = value.GetAsUInt32(); + break; + case exc_esr: + exc.esr = value.GetAsUInt32(); + break; + case exc_far: + exc.far = value.GetAsUInt64(); + break; + + default: + return false; + + } + return WriteRegisterSet(set) == KERN_SUCCESS; +} + +bool +RegisterContextDarwin_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) +{ + data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (data_sp && + ReadGPR (false) == KERN_SUCCESS && + ReadFPU (false) == KERN_SUCCESS && + ReadEXC (false) == KERN_SUCCESS) + { + uint8_t *dst = data_sp->GetBytes(); + ::memcpy (dst, &gpr, sizeof(gpr)); + dst += sizeof(gpr); + + ::memcpy (dst, &fpu, sizeof(fpu)); + dst += sizeof(gpr); + + ::memcpy (dst, &exc, sizeof(exc)); + return true; + } + return false; +} + +bool +RegisterContextDarwin_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) +{ + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) + { + const uint8_t *src = data_sp->GetBytes(); + ::memcpy (&gpr, src, sizeof(gpr)); + src += sizeof(gpr); + + ::memcpy (&fpu, src, sizeof(fpu)); + src += sizeof(gpr); + + ::memcpy (&exc, src, sizeof(exc)); + uint32_t success_count = 0; + if (WriteGPR() == KERN_SUCCESS) + ++success_count; + if (WriteFPU() == KERN_SUCCESS) + ++success_count; + if (WriteEXC() == KERN_SUCCESS) + ++success_count; + return success_count == 3; + } + return false; +} + +uint32_t +RegisterContextDarwin_arm64::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg) +{ + if (kind == eRegisterKindGeneric) + { + switch (reg) + { + case LLDB_REGNUM_GENERIC_PC: return gpr_pc; + case LLDB_REGNUM_GENERIC_SP: return gpr_sp; + case LLDB_REGNUM_GENERIC_FP: return gpr_fp; + case LLDB_REGNUM_GENERIC_RA: return gpr_lr; + case LLDB_REGNUM_GENERIC_FLAGS: return gpr_cpsr; + default: + break; + } + } + else if (kind == eRegisterKindDWARF) + { + switch (reg) + { + case arm64_dwarf::x0: return gpr_x0; + case arm64_dwarf::x1: return gpr_x1; + case arm64_dwarf::x2: return gpr_x2; + case arm64_dwarf::x3: return gpr_x3; + case arm64_dwarf::x4: return gpr_x4; + case arm64_dwarf::x5: return gpr_x5; + case arm64_dwarf::x6: return gpr_x6; + case arm64_dwarf::x7: return gpr_x7; + case arm64_dwarf::x8: return gpr_x8; + case arm64_dwarf::x9: return gpr_x9; + case arm64_dwarf::x10: return gpr_x10; + case arm64_dwarf::x11: return gpr_x11; + case arm64_dwarf::x12: return gpr_x12; + case arm64_dwarf::x13: return gpr_x13; + case arm64_dwarf::x14: return gpr_x14; + case arm64_dwarf::x15: return gpr_x15; + case arm64_dwarf::x16: return gpr_x16; + case arm64_dwarf::x17: return gpr_x17; + case arm64_dwarf::x18: return gpr_x18; + case arm64_dwarf::x19: return gpr_x19; + case arm64_dwarf::x20: return gpr_x20; + case arm64_dwarf::x21: return gpr_x21; + case arm64_dwarf::x22: return gpr_x22; + case arm64_dwarf::x23: return gpr_x23; + case arm64_dwarf::x24: return gpr_x24; + case arm64_dwarf::x25: return gpr_x25; + case arm64_dwarf::x26: return gpr_x26; + case arm64_dwarf::x27: return gpr_x27; + case arm64_dwarf::x28: return gpr_x28; + + case arm64_dwarf::fp: return gpr_fp; + case arm64_dwarf::sp: return gpr_sp; + case arm64_dwarf::lr: return gpr_lr; + case arm64_dwarf::pc: return gpr_pc; + case arm64_dwarf::cpsr: return gpr_cpsr; + + case arm64_dwarf::v0: return fpu_v0; + case arm64_dwarf::v1: return fpu_v1; + case arm64_dwarf::v2: return fpu_v2; + case arm64_dwarf::v3: return fpu_v3; + case arm64_dwarf::v4: return fpu_v4; + case arm64_dwarf::v5: return fpu_v5; + case arm64_dwarf::v6: return fpu_v6; + case arm64_dwarf::v7: return fpu_v7; + case arm64_dwarf::v8: return fpu_v8; + case arm64_dwarf::v9: return fpu_v9; + case arm64_dwarf::v10: return fpu_v10; + case arm64_dwarf::v11: return fpu_v11; + case arm64_dwarf::v12: return fpu_v12; + case arm64_dwarf::v13: return fpu_v13; + case arm64_dwarf::v14: return fpu_v14; + case arm64_dwarf::v15: return fpu_v15; + case arm64_dwarf::v16: return fpu_v16; + case arm64_dwarf::v17: return fpu_v17; + case arm64_dwarf::v18: return fpu_v18; + case arm64_dwarf::v19: return fpu_v19; + case arm64_dwarf::v20: return fpu_v20; + case arm64_dwarf::v21: return fpu_v21; + case arm64_dwarf::v22: return fpu_v22; + case arm64_dwarf::v23: return fpu_v23; + case arm64_dwarf::v24: return fpu_v24; + case arm64_dwarf::v25: return fpu_v25; + case arm64_dwarf::v26: return fpu_v26; + case arm64_dwarf::v27: return fpu_v27; + case arm64_dwarf::v28: return fpu_v28; + case arm64_dwarf::v29: return fpu_v29; + case arm64_dwarf::v30: return fpu_v30; + case arm64_dwarf::v31: return fpu_v31; + + default: + break; + } + } + else if (kind == eRegisterKindGCC) + { + switch (reg) + { + case arm64_gcc::x0: return gpr_x0; + case arm64_gcc::x1: return gpr_x1; + case arm64_gcc::x2: return gpr_x2; + case arm64_gcc::x3: return gpr_x3; + case arm64_gcc::x4: return gpr_x4; + case arm64_gcc::x5: return gpr_x5; + case arm64_gcc::x6: return gpr_x6; + case arm64_gcc::x7: return gpr_x7; + case arm64_gcc::x8: return gpr_x8; + case arm64_gcc::x9: return gpr_x9; + case arm64_gcc::x10: return gpr_x10; + case arm64_gcc::x11: return gpr_x11; + case arm64_gcc::x12: return gpr_x12; + case arm64_gcc::x13: return gpr_x13; + case arm64_gcc::x14: return gpr_x14; + case arm64_gcc::x15: return gpr_x15; + case arm64_gcc::x16: return gpr_x16; + case arm64_gcc::x17: return gpr_x17; + case arm64_gcc::x18: return gpr_x18; + case arm64_gcc::x19: return gpr_x19; + case arm64_gcc::x20: return gpr_x20; + case arm64_gcc::x21: return gpr_x21; + case arm64_gcc::x22: return gpr_x22; + case arm64_gcc::x23: return gpr_x23; + case arm64_gcc::x24: return gpr_x24; + case arm64_gcc::x25: return gpr_x25; + case arm64_gcc::x26: return gpr_x26; + case arm64_gcc::x27: return gpr_x27; + case arm64_gcc::x28: return gpr_x28; + case arm64_gcc::fp: return gpr_fp; + case arm64_gcc::sp: return gpr_sp; + case arm64_gcc::lr: return gpr_lr; + case arm64_gcc::pc: return gpr_pc; + case arm64_gcc::cpsr: return gpr_cpsr; + } + } + else if (kind == eRegisterKindLLDB) + { + return reg; + } + return LLDB_INVALID_REGNUM; +} + + +uint32_t +RegisterContextDarwin_arm64::NumSupportedHardwareWatchpoints () +{ +#if defined (__arm64__) + // autodetect how many watchpoints are supported dynamically... + static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX; + if (g_num_supported_hw_watchpoints == UINT32_MAX) + { + size_t len; + uint32_t n = 0; + len = sizeof (n); + if (::sysctlbyname("hw.optional.watchpoint", &n, &len, NULL, 0) == 0) + { + g_num_supported_hw_watchpoints = n; + } + } + return g_num_supported_hw_watchpoints; +#else + // TODO: figure out remote case here! + return 2; +#endif +} + + +uint32_t +RegisterContextDarwin_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write) +{ +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(addr = %8.8p, size = %u, read = %u, write = %u)", addr, size, read, write); + + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + + // Can't watch zero bytes + if (size == 0) + return LLDB_INVALID_INDEX32; + + // We must watch for either read or write + if (read == false && write == false) + return LLDB_INVALID_INDEX32; + + // Can't watch more than 4 bytes per WVR/WCR pair + if (size > 4) + return LLDB_INVALID_INDEX32; + + // We can only watch up to four bytes that follow a 4 byte aligned address + // per watchpoint register pair. Since we have at most so we can only watch + // until the next 4 byte boundary and we need to make sure we can properly + // encode this. + uint32_t addr_word_offset = addr % 4; +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset); + + uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset; +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask); + if (byte_mask > 0xfu) + return LLDB_INVALID_INDEX32; + + // Read the debug state + int kret = ReadDBG (false); + + if (kret == KERN_SUCCESS) + { + // Check to make sure we have the needed hardware support + uint32_t i = 0; + + for (i=0; i<num_hw_watchpoints; ++i) + { + if ((dbg.wcr[i] & WCR_ENABLE) == 0) + break; // We found an available hw breakpoint slot (in i) + } + + // See if we found an available hw breakpoint slot above + if (i < num_hw_watchpoints) + { + // Make the byte_mask into a valid Byte Address Select mask + uint32_t byte_address_select = byte_mask << 5; + // Make sure bits 1:0 are clear in our address + dbg.wvr[i] = addr & ~((lldb::addr_t)3); + dbg.wcr[i] = byte_address_select | // Which bytes that follow the IMVA that we will watch + S_USER | // Stop only in user mode + (read ? WCR_LOAD : 0) | // Stop on read access? + (write ? WCR_STORE : 0) | // Stop on write access? + WCR_ENABLE; // Enable this watchpoint; + + kret = WriteDBG(); +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret); + + if (kret == KERN_SUCCESS) + return i; + } + else + { +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints); + } + } + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContextDarwin_arm64::ClearHardwareWatchpoint (uint32_t hw_index) +{ + int kret = ReadDBG (false); + + const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); + if (kret == KERN_SUCCESS) + { + if (hw_index < num_hw_points) + { + dbg.wcr[hw_index] = 0; +// if (log) log->Printf ("RegisterContextDarwin_arm64::ClearHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x", +// hw_index, +// hw_index, +// dbg.wvr[hw_index], +// hw_index, +// dbg.wcr[hw_index]); + + kret = WriteDBG(); + + if (kret == KERN_SUCCESS) + return true; + } + } + return false; +} + +#endif diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h new file mode 100644 index 00000000000..44479c81058 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h @@ -0,0 +1,296 @@ +//===-- RegisterContextDarwin_arm64.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_RegisterContextDarwin_arm64_h_ +#define liblldb_RegisterContextDarwin_arm64_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Target/RegisterContext.h" + +// Break only in privileged or user mode +#define S_RSVD ((uint32_t)(0u << 1)) +#define S_PRIV ((uint32_t)(1u << 1)) +#define S_USER ((uint32_t)(2u << 1)) +#define S_PRIV_USER ((S_PRIV) | (S_USER)) + +#define WCR_ENABLE ((uint32_t)(1u)) + +// Watchpoint load/store +#define WCR_LOAD ((uint32_t)(1u << 3)) +#define WCR_STORE ((uint32_t)(1u << 4)) + +class RegisterContextDarwin_arm64 : public lldb_private::RegisterContext +{ +public: + + RegisterContextDarwin_arm64(lldb_private::Thread &thread, uint32_t concrete_frame_idx); + + virtual + ~RegisterContextDarwin_arm64(); + + virtual void + InvalidateAllRegisters (); + + virtual size_t + GetRegisterCount (); + + virtual const lldb_private::RegisterInfo * + GetRegisterInfoAtIndex (size_t reg); + + virtual size_t + GetRegisterSetCount (); + + virtual const lldb_private::RegisterSet * + GetRegisterSet (size_t set); + + virtual bool + ReadRegister (const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue ®_value); + + virtual bool + WriteRegister (const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue ®_value); + + virtual bool + ReadAllRegisterValues (lldb::DataBufferSP &data_sp); + + virtual bool + WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); + + virtual uint32_t + ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + + virtual uint32_t + NumSupportedHardwareWatchpoints (); + + virtual uint32_t + SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write); + + virtual bool + ClearHardwareWatchpoint (uint32_t hw_index); + + // mirrors <mach/arm/thread_status.h> arm_thread_state64_t + struct GPR + { + uint64_t x[29]; // x0-x28 + uint64_t fp; // x29 + uint64_t lr; // x30 + uint64_t sp; // x31 + uint64_t pc; // pc + uint32_t cpsr; // cpsr + }; + + + struct VReg + { + uint8_t bytes[16]; + }; + + // mirrors <mach/arm/thread_status.h> arm_neon_state64_t + struct FPU + { + VReg v[32]; + uint32_t fpsr; + uint32_t fpcr; + }; + + // mirrors <mach/arm/thread_status.h> arm_exception_state64_t + struct EXC + { + uint64_t far; // Virtual Fault Address + uint32_t esr; // Exception syndrome + uint32_t exception; // number of arm exception token + }; + + // mirrors <mach/arm/thread_status.h> arm_debug_state64_t + struct DBG + { + uint64_t bvr[16]; + uint64_t bcr[16]; + uint64_t wvr[16]; + uint64_t wcr[16]; + uint64_t mdscr_el1; + }; + + static void + LogDBGRegisters (lldb_private::Log *log, const DBG& dbg); + +protected: + + enum + { + GPRRegSet = 6, // ARM_THREAD_STATE64 + FPURegSet = 17, // ARM_NEON_STATE64 + EXCRegSet = 7, // ARM_EXCEPTION_STATE64 + DBGRegSet = 15 // ARM_DEBUG_STATE64 + }; + + enum + { + GPRWordCount = sizeof(GPR)/sizeof(uint32_t), // ARM_THREAD_STATE64_COUNT + FPUWordCount = sizeof(FPU)/sizeof(uint32_t), // ARM_NEON_STATE64_COUNT + EXCWordCount = sizeof(EXC)/sizeof(uint32_t), // ARM_EXCEPTION_STATE64_COUNT + DBGWordCount = sizeof(DBG)/sizeof(uint32_t) // ARM_DEBUG_STATE64_COUNT + }; + + enum + { + Read = 0, + Write = 1, + kNumErrors = 2 + }; + + GPR gpr; + FPU fpu; + EXC exc; + DBG dbg; + int gpr_errs[2]; // Read/Write errors + int fpu_errs[2]; // Read/Write errors + int exc_errs[2]; // Read/Write errors + int dbg_errs[2]; // Read/Write errors + + void + InvalidateAllRegisterStates() + { + SetError (GPRRegSet, Read, -1); + SetError (FPURegSet, Read, -1); + SetError (EXCRegSet, Read, -1); + } + + int + GetError (int flavor, uint32_t err_idx) const + { + if (err_idx < kNumErrors) + { + switch (flavor) + { + // When getting all errors, just OR all values together to see if + // we got any kind of error. + case GPRRegSet: return gpr_errs[err_idx]; + case FPURegSet: return fpu_errs[err_idx]; + case EXCRegSet: return exc_errs[err_idx]; + case DBGRegSet: return dbg_errs[err_idx]; + default: break; + } + } + return -1; + } + + bool + SetError (int flavor, uint32_t err_idx, int err) + { + if (err_idx < kNumErrors) + { + switch (flavor) + { + case GPRRegSet: + gpr_errs[err_idx] = err; + return true; + + case FPURegSet: + fpu_errs[err_idx] = err; + return true; + + case EXCRegSet: + exc_errs[err_idx] = err; + return true; + + case DBGRegSet: + exc_errs[err_idx] = err; + return true; + + default: break; + } + } + return false; + } + + bool + RegisterSetIsCached (int set) const + { + return GetError(set, Read) == 0; + } + + int + ReadGPR (bool force); + + int + ReadFPU (bool force); + + int + ReadEXC (bool force); + + int + ReadDBG (bool force); + + int + WriteGPR (); + + int + WriteFPU (); + + int + WriteEXC (); + + int + WriteDBG (); + + + // Subclasses override these to do the actual reading. + virtual int + DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) + { + return -1; + } + + virtual int + DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0; + + virtual int + DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0; + + virtual int + DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) = 0; + + virtual int + DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0; + + virtual int + DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0; + + virtual int + DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0; + + virtual int + DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) = 0; + + int + ReadRegisterSet (uint32_t set, bool force); + + int + WriteRegisterSet (uint32_t set); + + static uint32_t + GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num); + + static int + GetSetForNativeRegNum (int reg_num); + + static size_t + GetRegisterInfosCount (); + + static const lldb_private::RegisterInfo * + GetRegisterInfos (); +}; + +#endif // liblldb_RegisterContextDarwin_arm64_h_ diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp index 5b6d9fe9f3b..131aa452e3e 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp @@ -149,7 +149,7 @@ RegisterContextMacOSXFrameBackchain::ReadRegister (const RegisterInfo *reg_info, // TOOD: need a better way to detect when "long double" types are // the same bytes size as "double" -#if !defined(__arm__) && !defined(_MSC_VER) && !defined(__mips__) +#if !defined(__arm__) && !defined(__arm64__) && !defined(_MSC_VER) && !defined(__mips__) case sizeof (long double): if (sizeof (long double) == sizeof(uint32_t)) { diff --git a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp index 8aa21c61856..d1862398086 100644 --- a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp +++ b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp @@ -439,6 +439,37 @@ StopInfoMachException::CreateStopReasonWithMachException } break; + case llvm::Triple::arm64: + { + if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT + { + // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0 is set + return StopInfo::CreateStopReasonToTrace(thread); + } + if (exc_code == 0x102) // EXC_ARM_DA_DEBUG + { + // It's a watchpoint, then, if the exc_sub_code indicates a known/enabled + // data break address from our watchpoint list. + lldb::WatchpointSP wp_sp; + if (target) + wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); + if (wp_sp && wp_sp->IsEnabled()) + { + // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data. + // Set the hardware index if that's the case. + if (exc_data_count >= 3) + wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); + return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); + } + // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as EXC_BAD_ACCESS + if (thread.GetTemporaryResumeState() == eStateStepping) + return StopInfo::CreateStopReasonToTrace(thread); + } + // It looks like exc_sub_code has the 4 bytes of the instruction that triggered the + // exception, i.e. our breakpoint opcode + is_actual_breakpoint = exc_code == 1; + } + default: break; } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index e27186ff86c..f436799a86a 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -27,6 +27,7 @@ #include "lldb/Host/Endian.h" #include "lldb/Host/Host.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Target/Target.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -57,6 +58,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_supports_vCont_S (eLazyBoolCalculate), m_qHostInfo_is_valid (eLazyBoolCalculate), m_qProcessInfo_is_valid (eLazyBoolCalculate), + m_qGDBServerVersion_is_valid (eLazyBoolCalculate), m_supports_alloc_dealloc_memory (eLazyBoolCalculate), m_supports_memory_region_info (eLazyBoolCalculate), m_supports_watchpoint_support_info (eLazyBoolCalculate), @@ -65,6 +67,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_attach_or_wait_reply(eLazyBoolCalculate), m_prepare_for_reg_writing_reply (eLazyBoolCalculate), m_supports_p (eLazyBoolCalculate), + m_avoid_g_packets (eLazyBoolCalculate), m_supports_QSaveRegisterState (eLazyBoolCalculate), m_supports_qXfer_auxv_read (eLazyBoolCalculate), m_supports_qXfer_libraries_read (eLazyBoolCalculate), @@ -100,6 +103,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_os_build (), m_os_kernel (), m_hostname (), + m_gdb_server_name(), + m_gdb_server_version(UINT32_MAX), m_default_packet_timeout (0), m_max_packet_size (0) { @@ -301,10 +306,12 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_QSaveRegisterState = eLazyBoolCalculate; m_qHostInfo_is_valid = eLazyBoolCalculate; m_qProcessInfo_is_valid = eLazyBoolCalculate; + m_qGDBServerVersion_is_valid = eLazyBoolCalculate; m_supports_alloc_dealloc_memory = eLazyBoolCalculate; m_supports_memory_region_info = eLazyBoolCalculate; m_prepare_for_reg_writing_reply = eLazyBoolCalculate; m_attach_or_wait_reply = eLazyBoolCalculate; + m_avoid_g_packets = eLazyBoolCalculate; m_supports_qXfer_auxv_read = eLazyBoolCalculate; m_supports_qXfer_libraries_read = eLazyBoolCalculate; m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; @@ -322,8 +329,18 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_z4 = true; m_supports_QEnvironment = true; m_supports_QEnvironmentHexEncoded = true; + m_host_arch.Clear(); m_process_arch.Clear(); + m_os_version_major = UINT32_MAX; + m_os_version_minor = UINT32_MAX; + m_os_version_update = UINT32_MAX; + m_os_build.clear(); + m_os_kernel.clear(); + m_hostname.clear(); + m_gdb_server_name.clear(); + m_gdb_server_version = UINT32_MAX; + m_default_packet_timeout = 0; m_max_packet_size = 0; } @@ -1314,6 +1331,41 @@ GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch) return -1; } +int +GDBRemoteCommunicationClient::SendLaunchEventDataPacket (char const *data, bool *was_supported) +{ + if (data && *data != '\0') + { + StreamString packet; + packet.Printf("QSetProcessEvent:%s", data); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) + { + if (response.IsOKResponse()) + { + if (was_supported) + *was_supported = true; + return 0; + } + else if (response.IsUnsupportedResponse()) + { + if (was_supported) + *was_supported = false; + return -1; + } + else + { + uint8_t error = response.GetError(); + if (was_supported) + *was_supported = true; + if (error) + return error; + } + } + } + return -1; +} + bool GDBRemoteCommunicationClient::GetOSVersion (uint32_t &major, uint32_t &minor, @@ -1394,6 +1446,69 @@ GDBRemoteCommunicationClient::GetProcessArchitecture () return m_process_arch; } +bool +GDBRemoteCommunicationClient::GetGDBServerVersion() +{ + if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate) + { + m_gdb_server_name.clear(); + m_gdb_server_version = 0; + m_qGDBServerVersion_is_valid = eLazyBoolNo; + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse ("qGDBServerVersion", response, false) == PacketResult::Success) + { + if (response.IsNormalResponse()) + { + std::string name; + std::string value; + bool success = false; + while (response.GetNameColonValue(name, value)) + { + if (name.compare("name") == 0) + { + success = true; + m_gdb_server_name.swap(value); + } + else if (name.compare("version") == 0) + { + size_t dot_pos = value.find('.'); + if (dot_pos != std::string::npos) + value[dot_pos] = '\0'; + const uint32_t version = Args::StringToUInt32(value.c_str(), UINT32_MAX, 0); + if (version != UINT32_MAX) + { + success = true; + m_gdb_server_version = version; + } + } + } + if (success) + m_qGDBServerVersion_is_valid = eLazyBoolYes; + } + } + } + return m_qGDBServerVersion_is_valid == eLazyBoolYes; +} + +const char * +GDBRemoteCommunicationClient::GetGDBServerProgramName() +{ + if (GetGDBServerVersion()) + { + if (!m_gdb_server_name.empty()) + return m_gdb_server_name.c_str(); + } + return NULL; +} + +uint32_t +GDBRemoteCommunicationClient::GetGDBServerProgramVersion() +{ + if (GetGDBServerVersion()) + return m_gdb_server_version; + return 0; +} bool GDBRemoteCommunicationClient::GetHostInfo (bool force) @@ -1558,6 +1673,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) { switch (m_host_arch.GetMachine()) { + case llvm::Triple::arm64: case llvm::Triple::arm: case llvm::Triple::thumb: os_name = "ios"; @@ -1598,6 +1714,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) { switch (m_host_arch.GetMachine()) { + case llvm::Triple::arm64: case llvm::Triple::arm: case llvm::Triple::thumb: host_triple.setOS(llvm::Triple::IOS); @@ -3229,6 +3346,38 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s } bool +GDBRemoteCommunicationClient::AvoidGPackets (ProcessGDBRemote *process) +{ + // Some targets have issues with g/G packets and we need to avoid using them + if (m_avoid_g_packets == eLazyBoolCalculate) + { + if (process) + { + m_avoid_g_packets = eLazyBoolNo; + const ArchSpec &arch = process->GetTarget().GetArchitecture(); + if (arch.IsValid() + && arch.GetTriple().getVendor() == llvm::Triple::Apple + && arch.GetTriple().getOS() == llvm::Triple::IOS + && arch.GetTriple().getArch() == llvm::Triple::arm64) + { + m_avoid_g_packets = eLazyBoolYes; + uint32_t gdb_server_version = GetGDBServerProgramVersion(); + if (gdb_server_version != 0) + { + const char *gdb_server_name = GetGDBServerProgramName(); + if (gdb_server_name && strcmp(gdb_server_name, "debugserver") == 0) + { + if (gdb_server_version >= 310) + m_avoid_g_packets = eLazyBoolNo; + } + } + } + } + } + return m_avoid_g_packets == eLazyBoolYes; +} + +bool GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response) { Mutex::Locker locker; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 4e404b6ab44..8de845fa5fe 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -159,6 +159,10 @@ public: int SendLaunchArchPacket (const char *arch); + + int + SendLaunchEventDataPacket (const char *data, bool *was_supported = NULL); + //------------------------------------------------------------------ /// Sends a "vAttach:PID" where PID is in hex. /// @@ -494,7 +498,16 @@ public: bool RestoreRegisterState (lldb::tid_t tid, uint32_t save_id); + + const char * + GetGDBServerProgramName(); + uint32_t + GetGDBServerProgramVersion(); + + bool + AvoidGPackets(ProcessGDBRemote *process); + protected: PacketResult @@ -505,6 +518,9 @@ protected: bool GetCurrentProcessInfo (); + bool + GetGDBServerVersion(); + //------------------------------------------------------------------ // Classes that inherit from GDBRemoteCommunicationClient can see and modify these //------------------------------------------------------------------ @@ -519,6 +535,7 @@ protected: lldb_private::LazyBool m_supports_vCont_S; lldb_private::LazyBool m_qHostInfo_is_valid; lldb_private::LazyBool m_qProcessInfo_is_valid; + lldb_private::LazyBool m_qGDBServerVersion_is_valid; lldb_private::LazyBool m_supports_alloc_dealloc_memory; lldb_private::LazyBool m_supports_memory_region_info; lldb_private::LazyBool m_supports_watchpoint_support_info; @@ -527,6 +544,7 @@ protected: lldb_private::LazyBool m_attach_or_wait_reply; lldb_private::LazyBool m_prepare_for_reg_writing_reply; lldb_private::LazyBool m_supports_p; + lldb_private::LazyBool m_avoid_g_packets; lldb_private::LazyBool m_supports_QSaveRegisterState; lldb_private::LazyBool m_supports_qXfer_auxv_read; lldb_private::LazyBool m_supports_qXfer_libraries_read; @@ -574,6 +592,8 @@ protected: std::string m_os_build; std::string m_os_kernel; std::string m_hostname; + std::string m_gdb_server_name; // from reply to qGDBServerVersion, empty if qGDBServerVersion is not supported + uint32_t m_gdb_server_version; // from reply to qGDBServerVersion, zero if qGDBServerVersion is not supported uint32_t m_default_packet_timeout; uint64_t m_max_packet_size; // as returned by qSupported diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 5542f7915a1..2fadf3359f5 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -447,22 +447,21 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet } #if defined(__APPLE__) -#if defined(__arm__) +#if defined(__arm__) || defined(__arm64__) // For iOS devices, we are connected through a USB Mux so we never pretend // to actually have a hostname as far as the remote lldb that is connecting // to this lldb-platform is concerned response.PutCString ("hostname:"); response.PutCStringAsRawHex8("127.0.0.1"); response.PutChar(';'); -#else // #if defined(__arm__) +#else // #if defined(__arm__) || defined(__arm64__) if (Host::GetHostname (s)) { response.PutCString ("hostname:"); response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } - -#endif // #if defined(__arm__) +#endif // #if defined(__arm__) || defined(__arm64__) #else // #if defined(__APPLE__) if (Host::GetHostname (s)) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index 73b9b3e8267..9e5b0d79e10 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -21,6 +21,7 @@ #include "lldb/Interpreter/PythonDataObjects.h" #endif #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Target.h" #include "lldb/Utility/Utils.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -502,6 +503,8 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) StringExtractorGDBRemote response; + const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false; + Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers.")) { @@ -519,29 +522,62 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) packet_len = ::snprintf (packet, sizeof(packet), "g"); assert (packet_len < ((int)sizeof(packet) - 1)); - if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) + if (use_g_packet && gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { - if (response.IsErrorResponse()) - return false; - - std::string &response_str = response.GetStringRef(); - if (isxdigit(response_str[0])) + int packet_len = 0; + if (thread_suffix_supported) + packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID()); + else + packet_len = ::snprintf (packet, sizeof(packet), "g"); + assert (packet_len < ((int)sizeof(packet) - 1)); + + if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { - response_str.insert(0, 1, 'G'); - if (thread_suffix_supported) + if (response.IsErrorResponse()) + return false; + + std::string &response_str = response.GetStringRef(); + if (isxdigit(response_str[0])) { - char thread_id_cstr[64]; - ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - response_str.append (thread_id_cstr); + response_str.insert(0, 1, 'G'); + if (thread_suffix_supported) + { + char thread_id_cstr[64]; + ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); + response_str.append (thread_id_cstr); + } + data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size())); + return true; } - data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size())); - return true; } } + else + { + // For the use_g_packet == false case, we're going to read each register + // individually and store them as binary data in a buffer instead of as ascii + // characters. + const RegisterInfo *reg_info; + + // data_sp will take ownership of this DataBufferHeap pointer soon. + DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0)); + + for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++) + { + if (reg_info->value_regs) // skip registers that are slices of real registers + continue; + ReadRegisterBytes (reg_info, m_reg_data); + // ReadRegisterBytes saves the contents of the register in to the m_reg_data buffer + } + memcpy (reg_ctx->GetBytes(), m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize()); + + data_sp = reg_ctx; + return true; + } } } else { + Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); if (log) { @@ -575,6 +611,8 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false; + StringExtractorGDBRemote response; Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write all registers.")) @@ -588,63 +626,126 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data // as well. const char *G_packet = (const char *)data_sp->GetBytes(); size_t G_packet_len = data_sp->GetByteSize(); - if (gdb_comm.SendPacketAndWaitForResponse (G_packet, - G_packet_len, - response, - false) == GDBRemoteCommunication::PacketResult::Success) + if (use_g_packet + && gdb_comm.SendPacketAndWaitForResponse (G_packet, + G_packet_len, + response, + false) == GDBRemoteCommunication::PacketResult::Success) { - if (response.IsOKResponse()) - return true; - else if (response.IsErrorResponse()) + // The data_sp contains the entire G response packet including the + // G, and if the thread suffix is supported, it has the thread suffix + // as well. + const char *G_packet = (const char *)data_sp->GetBytes(); + size_t G_packet_len = data_sp->GetByteSize(); + if (gdb_comm.SendPacketAndWaitForResponse (G_packet, + G_packet_len, + response, + false) == GDBRemoteCommunication::PacketResult::Success) { - uint32_t num_restored = 0; - // We need to manually go through all of the registers and - // restore them manually - - response.GetStringRef().assign (G_packet, G_packet_len); - response.SetFilePos(1); // Skip the leading 'G' - DataBufferHeap buffer (m_reg_data.GetByteSize(), 0); - DataExtractor restore_data (buffer.GetBytes(), - buffer.GetByteSize(), - m_reg_data.GetByteOrder(), - m_reg_data.GetAddressByteSize()); - - const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(), - restore_data.GetByteSize(), - '\xcc'); - - if (bytes_extracted < restore_data.GetByteSize()) - restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder()); - - //ReadRegisterBytes (const RegisterInfo *reg_info, RegisterValue &value, DataExtractor &data) - const RegisterInfo *reg_info; - // We have to march the offset of each register along in the - // buffer to make sure we get the right offset. - uint32_t reg_byte_offset = 0; - for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, reg_byte_offset += reg_info->byte_size) + if (response.IsOKResponse()) + return true; + else if (response.IsErrorResponse()) { - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - // Skip composite registers. - if (reg_info->value_regs) - continue; + uint32_t num_restored = 0; + // We need to manually go through all of the registers and + // restore them manually + + response.GetStringRef().assign (G_packet, G_packet_len); + response.SetFilePos(1); // Skip the leading 'G' + + // G_packet_len is hex-ascii characters plus prefix 'G' plus suffix therad specifier. + // This means buffer will be a little more than 2x larger than necessary but we resize + // it down once we've extracted all hex ascii chars from the packet. + DataBufferHeap buffer (G_packet_len, 0); + DataExtractor restore_data (buffer.GetBytes(), + buffer.GetByteSize(), + m_reg_data.GetByteOrder(), + m_reg_data.GetAddressByteSize()); + + const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(), + restore_data.GetByteSize(), + '\xcc'); + + if (bytes_extracted < restore_data.GetByteSize()) + restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder()); + + const RegisterInfo *reg_info; + + // The g packet contents may either include the slice registers (registers defined in + // terms of other registers, e.g. eax is a subset of rax) or not. The slice registers + // should NOT be in the g packet, but some implementations may incorrectly include them. + // + // If the slice registers are included in the packet, we must step over the slice registers + // when parsing the packet -- relying on the RegisterInfo byte_offset field would be incorrect. + // If the slice registers are not included, then using the byte_offset values into the + // data buffer is the best way to find individual register values. + + int size_including_slice_registers = 0; + int size_not_including_slice_registers = 0; + int size_by_highest_offset = 0; + + for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx) + { + size_including_slice_registers += reg_info->byte_size; + if (reg_info->value_regs == NULL) + size_not_including_slice_registers += reg_info->byte_size; + if (reg_info->byte_offset >= size_by_highest_offset) + size_by_highest_offset = reg_info->byte_offset + reg_info->byte_size; + } - // Only write down the registers that need to be written - // if we are going to be doing registers individually. - bool write_reg = true; - const uint32_t reg_byte_size = reg_info->byte_size; + bool use_byte_offset_into_buffer; + if (size_by_highest_offset == restore_data.GetByteSize()) + { + // The size of the packet agrees with the highest offset: + size in the register file + use_byte_offset_into_buffer = true; + } + else if (size_not_including_slice_registers == restore_data.GetByteSize()) + { + // The size of the packet is the same as concenating all of the registers sequentially, + // skipping the slice registers + use_byte_offset_into_buffer = true; + } + else if (size_including_slice_registers == restore_data.GetByteSize()) + { + // The slice registers are present in the packet (when they shouldn't be). + // Don't try to use the RegisterInfo byte_offset into the restore_data, it will + // point to the wrong place. + use_byte_offset_into_buffer = false; + } + else { + // None of our expected sizes match the actual g packet data we're looking at. + // The most conservative approach here is to use the running total byte offset. + use_byte_offset_into_buffer = false; + } - const char *restore_src = (const char *)restore_data.PeekData(reg_byte_offset, reg_byte_size); - if (restore_src) + // In case our register definitions don't include the correct offsets, + // keep track of the size of each reg & compute offset based on that. + uint32_t running_byte_offset = 0; + for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, running_byte_offset += reg_info->byte_size) { - if (GetRegisterIsValid(reg)) + // Skip composite aka slice registers (e.g. eax is a slice of rax). + if (reg_info->value_regs) + continue; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + uint32_t register_offset; + if (use_byte_offset_into_buffer) + { + register_offset = reg_info->byte_offset; + } + else { - const char *current_src = (const char *)m_reg_data.PeekData(reg_byte_offset, reg_byte_size); - if (current_src) - write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0; + register_offset = running_byte_offset; } - if (write_reg) + // Only write down the registers that need to be written + // if we are going to be doing registers individually. + bool write_reg = true; + const uint32_t reg_byte_size = reg_info->byte_size; + + const char *restore_src = (const char *)restore_data.PeekData(register_offset, reg_byte_size); + if (restore_src) { StreamString packet; packet.Printf ("P%x=", reg); @@ -662,14 +763,88 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data response, false) == GDBRemoteCommunication::PacketResult::Success) { - if (response.IsOKResponse()) - ++num_restored; + const char *current_src = (const char *)m_reg_data.PeekData(register_offset, reg_byte_size); + if (current_src) + write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0; + } + + if (write_reg) + { + StreamString packet; + packet.Printf ("P%x=", reg); + packet.PutBytesAsRawHex8 (restore_src, + reg_byte_size, + lldb::endian::InlHostByteOrder(), + lldb::endian::InlHostByteOrder()); + + if (thread_suffix_supported) + packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); + + SetRegisterIsValid(reg, false); + if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), + packet.GetString().size(), + response, + false) == GDBRemoteCommunication::PacketResult::Success) + { + if (response.IsOKResponse()) + ++num_restored; + } } } } + return num_restored > 0; + } + } + } + else + { + // For the use_g_packet == false case, we're going to write each register + // individually. The data buffer is binary data in this case, instead of + // ascii characters. + + bool arm64_debugserver = false; + if (m_thread.GetProcess().get()) + { + const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture(); + if (arch.IsValid() + && arch.GetMachine() == llvm::Triple::arm64 + && arch.GetTriple().getVendor() == llvm::Triple::Apple + && arch.GetTriple().getOS() == llvm::Triple::IOS) + { + arm64_debugserver = true; + } + } + uint32_t num_restored = 0; + const RegisterInfo *reg_info; + for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++) + { + if (reg_info->value_regs) // skip registers that are slices of real registers + continue; + // Skip the fpsr and fpcr floating point status/control register writing to + // work around a bug in an older version of debugserver that would lead to + // register context corruption when writing fpsr/fpcr. + if (arm64_debugserver && + (strcmp (reg_info->name, "fpsr") == 0 || strcmp (reg_info->name, "fpcr") == 0)) + { + continue; + } + StreamString packet; + packet.Printf ("P%x=", reg_info->kinds[eRegisterKindLLDB]); + packet.PutBytesAsRawHex8 (data_sp->GetBytes() + reg_info->byte_offset, reg_info->byte_size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder()); + if (thread_suffix_supported) + packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); + + SetRegisterIsValid(reg_info, false); + if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), + packet.GetString().size(), + response, + false) == GDBRemoteCommunication::PacketResult::Success) + { + if (response.IsOKResponse()) + ++num_restored; } - return num_restored > 0; } + return num_restored > 0; } } } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 1bee5806e5f..48db3b0ffae 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -800,6 +800,10 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) m_gdb_comm.SendLaunchArchPacket (m_target.GetArchitecture().GetArchitectureName()); + const char * launch_event_data = launch_info.GetLaunchEventData(); + if (launch_event_data != NULL && *launch_event_data != '\0') + m_gdb_comm.SendLaunchEventDataPacket (launch_event_data); + if (working_dir && working_dir[0]) { m_gdb_comm.SetWorkingDir (working_dir); @@ -2608,7 +2612,7 @@ ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false); debugserver_launch_info.SetUserID(process_info.GetUserID()); -#if defined (__APPLE__) && defined (__arm__) +#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__)) // On iOS, still do a local connection using a random port const char *hostname = "127.0.0.1"; uint16_t port = get_random_port (); @@ -2924,13 +2928,33 @@ ProcessGDBRemote::AsyncThread (void *arg) break; case eStateExited: + { process->SetLastStopPacket (response); process->ClearThreadIDList(); response.SetFilePos(1); - process->SetExitStatus(response.GetHexU8(), NULL); + + int exit_status = response.GetHexU8(); + const char *desc_cstr = NULL; + StringExtractor extractor; + std::string desc_string; + if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';') + { + std::string desc_token; + while (response.GetNameColonValue (desc_token, desc_string)) + { + if (desc_token == "description") + { + extractor.GetStringRef().swap(desc_string); + extractor.SetFilePos(0); + extractor.GetHexByteString (desc_string); + desc_cstr = desc_string.c_str(); + } + } + } + process->SetExitStatus(exit_status, desc_cstr); done = true; break; - + } case eStateInvalid: process->SetExitStatus(-1, "lost connection"); break; @@ -3066,6 +3090,25 @@ ProcessGDBRemote::GetDynamicLoader () return m_dyld_ap.get(); } +Error +ProcessGDBRemote::SendEventData(const char *data) +{ + int return_value; + bool was_supported; + + Error error; + + return_value = m_gdb_comm.SendLaunchEventDataPacket (data, &was_supported); + if (return_value != 0) + { + if (!was_supported) + error.SetErrorString("Sending events is not supported for this process."); + else + error.SetErrorStringWithFormat("Error sending event data: %d.", return_value); + } + return error; +} + const DataBufferSP ProcessGDBRemote::GetAuxvData() { @@ -3079,7 +3122,6 @@ ProcessGDBRemote::GetAuxvData() return buf; } - class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed { private: diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 1d4a23509e6..4f5cca57659 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -221,13 +221,15 @@ public: return m_gdb_comm; } + virtual lldb_private::Error + SendEventData(const char *data); + //---------------------------------------------------------------------- // Override SetExitStatus so we can disconnect from the remote GDB server //---------------------------------------------------------------------- virtual bool SetExitStatus (int exit_status, const char *cstr); - protected: friend class ThreadGDBRemote; friend class GDBRemoteCommunicationClient; |