aboutsummaryrefslogtreecommitdiffstats
path: root/source/Plugins/Process/Utility
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
committerEd Maste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
commitf034231a6a1fd5d6395206c1651de8cd9402cca3 (patch)
treef561dabc721ad515599172c16da3a4400b7f4aec /source/Plugins/Process/Utility
downloadsrc-f034231a6a1fd5d6395206c1651de8cd9402cca3.tar.gz
src-f034231a6a1fd5d6395206c1651de8cd9402cca3.zip
Import lldb as of SVN r188801
(A number of files not required for the FreeBSD build have been removed.) Sponsored by: DARPA, AFRL
Notes
Notes: svn path=/vendor/lldb/dist/; revision=254721
Diffstat (limited to 'source/Plugins/Process/Utility')
-rw-r--r--source/Plugins/Process/Utility/ARMDefines.h110
-rw-r--r--source/Plugins/Process/Utility/ARMUtils.h394
-rw-r--r--source/Plugins/Process/Utility/DynamicRegisterInfo.cpp279
-rw-r--r--source/Plugins/Process/Utility/DynamicRegisterInfo.h85
-rw-r--r--source/Plugins/Process/Utility/InferiorCallPOSIX.cpp274
-rw-r--r--source/Plugins/Process/Utility/InferiorCallPOSIX.h43
-rw-r--r--source/Plugins/Process/Utility/InstructionUtils.h136
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp1226
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_arm.h333
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp980
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_i386.h269
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp1066
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h274
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDummy.cpp137
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDummy.h77
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.cpp1541
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.h212
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp206
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h77
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_arm.cpp87
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_arm.h56
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_i386.cpp72
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_i386.h49
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp72
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_x86_64.h49
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMemory.cpp174
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMemory.h102
-rw-r--r--source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp261
-rw-r--r--source/Plugins/Process/Utility/RegisterContextThreadMemory.h114
-rw-r--r--source/Plugins/Process/Utility/StopInfoMachException.cpp482
-rw-r--r--source/Plugins/Process/Utility/StopInfoMachException.h77
-rw-r--r--source/Plugins/Process/Utility/ThreadMemory.cpp140
-rw-r--r--source/Plugins/Process/Utility/ThreadMemory.h152
-rw-r--r--source/Plugins/Process/Utility/UnwindLLDB.cpp322
-rw-r--r--source/Plugins/Process/Utility/UnwindLLDB.h125
-rw-r--r--source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp275
-rw-r--r--source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h74
37 files changed, 10402 insertions, 0 deletions
diff --git a/source/Plugins/Process/Utility/ARMDefines.h b/source/Plugins/Process/Utility/ARMDefines.h
new file mode 100644
index 000000000000..4b1f06a2f9cd
--- /dev/null
+++ b/source/Plugins/Process/Utility/ARMDefines.h
@@ -0,0 +1,110 @@
+//===-- lldb_ARMDefines.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_ARMDefines_h_
+#define lldb_ARMDefines_h_
+
+// Common defintions for the ARM/Thumb Instruction Set Architecture.
+
+namespace lldb_private {
+
+// ARM shifter types
+typedef enum
+{
+ SRType_LSL,
+ SRType_LSR,
+ SRType_ASR,
+ SRType_ROR,
+ SRType_RRX,
+ SRType_Invalid
+} ARM_ShifterType;
+
+// ARM conditions // Meaning (integer) Meaning (floating-point) Condition flags
+#define COND_EQ 0x0 // Equal Equal Z == 1
+#define COND_NE 0x1 // Not equal Not equal, or unordered Z == 0
+#define COND_CS 0x2 // Carry set >, ==, or unordered C == 1
+#define COND_HS 0x2
+#define COND_CC 0x3 // Carry clear Less than C == 0
+#define COND_LO 0x3
+#define COND_MI 0x4 // Minus, negative Less than N == 1
+#define COND_PL 0x5 // Plus, positive or zero >, ==, or unordered N == 0
+#define COND_VS 0x6 // Overflow Unordered V == 1
+#define COND_VC 0x7 // No overflow Not unordered V == 0
+#define COND_HI 0x8 // Unsigned higher Greater than, or unordered C == 1 and Z == 0
+#define COND_LS 0x9 // Unsigned lower or same Less than or equal C == 0 or Z == 1
+#define COND_GE 0xA // Greater than or equal Greater than or equal N == V
+#define COND_LT 0xB // Less than Less than, or unordered N != V
+#define COND_GT 0xC // Greater than Greater than Z == 0 and N == V
+#define COND_LE 0xD // Less than or equal <, ==, or unordered Z == 1 or N != V
+#define COND_AL 0xE // Always (unconditional) Always (unconditional) Any
+#define COND_UNCOND 0xF
+
+static inline const char *ARMCondCodeToString(uint32_t CC)
+{
+ switch (CC) {
+ default: assert(0 && "Unknown condition code");
+ case COND_EQ: return "eq";
+ case COND_NE: return "ne";
+ case COND_HS: return "hs";
+ case COND_LO: return "lo";
+ case COND_MI: return "mi";
+ case COND_PL: return "pl";
+ case COND_VS: return "vs";
+ case COND_VC: return "vc";
+ case COND_HI: return "hi";
+ case COND_LS: return "ls";
+ case COND_GE: return "ge";
+ case COND_LT: return "lt";
+ case COND_GT: return "gt";
+ case COND_LE: return "le";
+ case COND_AL: return "al";
+ }
+}
+
+// Bit positions for CPSR
+#define CPSR_T_POS 5
+#define CPSR_F_POS 6
+#define CPSR_I_POS 7
+#define CPSR_A_POS 8
+#define CPSR_E_POS 9
+#define CPSR_J_POS 24
+#define CPSR_Q_POS 27
+#define CPSR_V_POS 28
+#define CPSR_C_POS 29
+#define CPSR_Z_POS 30
+#define CPSR_N_POS 31
+
+// CPSR mode definitions
+#define CPSR_MODE_USR 0x10u
+#define CPSR_MODE_FIQ 0x11u
+#define CPSR_MODE_IRQ 0x12u
+#define CPSR_MODE_SVC 0x13u
+#define CPSR_MODE_ABT 0x17u
+#define CPSR_MODE_UND 0x1bu
+#define CPSR_MODE_SYS 0x1fu
+
+// Masks for CPSR
+#define MASK_CPSR_MODE_MASK (0x0000001fu)
+#define MASK_CPSR_IT_MASK (0x0600fc00u)
+#define MASK_CPSR_T (1u << CPSR_T_POS)
+#define MASK_CPSR_F (1u << CPSR_F_POS)
+#define MASK_CPSR_I (1u << CPSR_I_POS)
+#define MASK_CPSR_A (1u << CPSR_A_POS)
+#define MASK_CPSR_E (1u << CPSR_E_POS)
+#define MASK_CPSR_GE_MASK (0x000f0000u)
+#define MASK_CPSR_J (1u << CPSR_J_POS)
+#define MASK_CPSR_Q (1u << CPSR_Q_POS)
+#define MASK_CPSR_V (1u << CPSR_V_POS)
+#define MASK_CPSR_C (1u << CPSR_C_POS)
+#define MASK_CPSR_Z (1u << CPSR_Z_POS)
+#define MASK_CPSR_N (1u << CPSR_N_POS)
+
+} // namespace lldb_private
+
+#endif // lldb_ARMDefines_h_
diff --git a/source/Plugins/Process/Utility/ARMUtils.h b/source/Plugins/Process/Utility/ARMUtils.h
new file mode 100644
index 000000000000..76d64e15a53e
--- /dev/null
+++ b/source/Plugins/Process/Utility/ARMUtils.h
@@ -0,0 +1,394 @@
+//===-- ARMUtils.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_ARMUtils_h_
+#define lldb_ARMUtils_h_
+
+#include "ARMDefines.h"
+#include "InstructionUtils.h"
+#include "llvm/Support/MathExtras.h" // for SignExtend64 template function
+
+// Common utilities for the ARM/Thumb Instruction Set Architecture.
+
+namespace lldb_private {
+
+static inline uint32_t Align(uint32_t val, uint32_t alignment)
+{
+ return alignment * (val / alignment);
+}
+
+static inline uint32_t DecodeImmShift(const uint32_t type, const uint32_t imm5, ARM_ShifterType &shift_t)
+{
+ switch (type)
+ {
+ default:
+ //assert(0 && "Invalid shift type");
+ case 0:
+ shift_t = SRType_LSL;
+ return imm5;
+ case 1:
+ shift_t = SRType_LSR;
+ return (imm5 == 0 ? 32 : imm5);
+ case 2:
+ shift_t = SRType_ASR;
+ return (imm5 == 0 ? 32 : imm5);
+ case 3:
+ if (imm5 == 0)
+ {
+ shift_t = SRType_RRX;
+ return 1;
+ }
+ else
+ {
+ shift_t = SRType_ROR;
+ return imm5;
+ }
+ }
+ shift_t = SRType_Invalid;
+ return UINT32_MAX;
+
+}
+
+// A8.6.35 CMP (register) -- Encoding T3
+// Convenience function.
+static inline uint32_t DecodeImmShiftThumb(const uint32_t opcode, ARM_ShifterType &shift_t)
+{
+ return DecodeImmShift(Bits32(opcode, 5, 4), Bits32(opcode, 14, 12)<<2 | Bits32(opcode, 7, 6), shift_t);
+}
+
+// A8.6.35 CMP (register) -- Encoding A1
+// Convenience function.
+static inline uint32_t DecodeImmShiftARM(const uint32_t opcode, ARM_ShifterType &shift_t)
+{
+ return DecodeImmShift(Bits32(opcode, 6, 5), Bits32(opcode, 11, 7), shift_t);
+}
+
+static inline uint32_t DecodeImmShift(const ARM_ShifterType shift_t, const uint32_t imm5)
+{
+ ARM_ShifterType dont_care;
+ return DecodeImmShift(shift_t, imm5, dont_care);
+}
+
+static inline ARM_ShifterType DecodeRegShift(const uint32_t type)
+{
+ switch (type) {
+ default:
+ //assert(0 && "Invalid shift type");
+ return SRType_Invalid;
+ case 0:
+ return SRType_LSL;
+ case 1:
+ return SRType_LSR;
+ case 2:
+ return SRType_ASR;
+ case 3:
+ return SRType_ROR;
+ }
+}
+
+static inline uint32_t LSL_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ carry_out = amount <= 32 ? Bit32(value, 32 - amount) : 0;
+ return value << amount;
+}
+
+static inline uint32_t LSL(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = LSL_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t LSR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ carry_out = amount <= 32 ? Bit32(value, amount - 1) : 0;
+ return value >> amount;
+}
+
+static inline uint32_t LSR(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = LSR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t ASR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0 || amount > 32) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ bool negative = BitIsSet(value, 31);
+ if (amount <= 32)
+ {
+ carry_out = Bit32(value, amount - 1);
+ int64_t extended = llvm::SignExtend64<32>(value);
+ return UnsignedBits(extended, amount + 31, amount);
+ }
+ else
+ {
+ carry_out = (negative ? 1 : 0);
+ return (negative ? 0xffffffff : 0);
+ }
+}
+
+static inline uint32_t ASR(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = ASR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t ROR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ uint32_t amt = amount % 32;
+ uint32_t result = Rotr32(value, amt);
+ carry_out = Bit32(value, 31);
+ return result;
+}
+
+static inline uint32_t ROR(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = ROR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t RRX_C(const uint32_t value, const uint32_t carry_in, uint32_t &carry_out, bool *success)
+{
+ *success = true;
+ carry_out = Bit32(value, 0);
+ return Bit32(carry_in, 0) << 31 | Bits32(value, 31, 1);
+}
+
+static inline uint32_t RRX(const uint32_t value, const uint32_t carry_in, bool *success)
+{
+ *success = true;
+ uint32_t dont_care;
+ uint32_t result = RRX_C(value, carry_in, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t Shift_C(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
+ const uint32_t carry_in, uint32_t &carry_out, bool *success)
+{
+ if (type == SRType_RRX && amount != 1) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+
+ if (amount == 0) {
+ carry_out = carry_in;
+ return value;
+ }
+ uint32_t result;
+ switch (type) {
+ case SRType_LSL:
+ result = LSL_C(value, amount, carry_out, success);
+ break;
+ case SRType_LSR:
+ result = LSR_C(value, amount, carry_out, success);
+ break;
+ case SRType_ASR:
+ result = ASR_C(value, amount, carry_out, success);
+ break;
+ case SRType_ROR:
+ result = ROR_C(value, amount, carry_out, success);
+ break;
+ case SRType_RRX:
+ result = RRX_C(value, carry_in, carry_out, success);
+ break;
+ default:
+ *success = false;
+ break;
+ }
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t Shift(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
+ const uint32_t carry_in, bool *success)
+{
+ // Don't care about carry out in this case.
+ uint32_t dont_care;
+ uint32_t result = Shift_C(value, type, amount, carry_in, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t bits(const uint32_t val, const uint32_t msbit, const uint32_t lsbit)
+{
+ return Bits32(val, msbit, lsbit);
+}
+
+static inline uint32_t bit(const uint32_t val, const uint32_t msbit)
+{
+ return bits(val, msbit, msbit);
+}
+
+static uint32_t ror(uint32_t val, uint32_t N, uint32_t shift)
+{
+ uint32_t m = shift % N;
+ return (val >> m) | (val << (N - m));
+}
+
+// (imm32, carry_out) = ARMExpandImm_C(imm12, carry_in)
+static inline uint32_t ARMExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
+{
+ uint32_t imm32; // the expanded result
+ uint32_t imm = bits(opcode, 7, 0); // immediate value
+ uint32_t amt = 2 * bits(opcode, 11, 8); // rotate amount
+ if (amt == 0)
+ {
+ imm32 = imm;
+ carry_out = carry_in;
+ }
+ else
+ {
+ imm32 = ror(imm, 32, amt);
+ carry_out = Bit32(imm32, 31);
+ }
+ return imm32;
+}
+
+static inline uint32_t ARMExpandImm(uint32_t opcode)
+{
+ // 'carry_in' argument to following function call does not affect the imm32 result.
+ uint32_t carry_in = 0;
+ uint32_t carry_out;
+ return ARMExpandImm_C(opcode, carry_in, carry_out);
+}
+
+// (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)
+static inline uint32_t ThumbExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
+{
+ uint32_t imm32; // the expaned result
+ const uint32_t i = bit(opcode, 26);
+ const uint32_t imm3 = bits(opcode, 14, 12);
+ const uint32_t abcdefgh = bits(opcode, 7, 0);
+ const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;
+
+ if (bits(imm12, 11, 10) == 0)
+ {
+ switch (bits(imm12, 9, 8)) {
+ default: // Keep static analyzer happy with a default case
+ case 0:
+ imm32 = abcdefgh;
+ break;
+
+ case 1:
+ imm32 = abcdefgh << 16 | abcdefgh;
+ break;
+
+ case 2:
+ imm32 = abcdefgh << 24 | abcdefgh << 8;
+ break;
+
+ case 3:
+ imm32 = abcdefgh << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;
+ break;
+ }
+ carry_out = carry_in;
+ }
+ else
+ {
+ const uint32_t unrotated_value = 0x80 | bits(imm12, 6, 0);
+ imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7));
+ carry_out = Bit32(imm32, 31);
+ }
+ return imm32;
+}
+
+static inline uint32_t ThumbExpandImm(uint32_t opcode)
+{
+ // 'carry_in' argument to following function call does not affect the imm32 result.
+ uint32_t carry_in = 0;
+ uint32_t carry_out;
+ return ThumbExpandImm_C(opcode, carry_in, carry_out);
+}
+
+// imm32 = ZeroExtend(i:imm3:imm8, 32)
+static inline uint32_t ThumbImm12(uint32_t opcode)
+{
+ const uint32_t i = bit(opcode, 26);
+ const uint32_t imm3 = bits(opcode, 14, 12);
+ const uint32_t imm8 = bits(opcode, 7, 0);
+ const uint32_t imm12 = i << 11 | imm3 << 8 | imm8;
+ return imm12;
+}
+
+// imm32 = ZeroExtend(imm7:'00', 32)
+static inline uint32_t ThumbImm7Scaled(uint32_t opcode)
+{
+ const uint32_t imm7 = bits(opcode, 6, 0);
+ return imm7 * 4;
+}
+
+// imm32 = ZeroExtend(imm8:'00', 32)
+static inline uint32_t ThumbImm8Scaled(uint32_t opcode)
+{
+ const uint32_t imm8 = bits(opcode, 7, 0);
+ return imm8 * 4;
+}
+
+// This function performs the check for the register numbers 13 and 15 that are
+// not permitted for many Thumb register specifiers.
+static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }
+
+} // namespace lldb_private
+
+#endif // lldb_ARMUtils_h_
diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
new file mode 100644
index 000000000000..0c95d66cef94
--- /dev/null
+++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
@@ -0,0 +1,279 @@
+//===-- DynamicRegisterInfo.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/lldb-python.h"
+
+#include "DynamicRegisterInfo.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+
+#ifndef LLDB_DISABLE_PYTHON
+#include "lldb/Interpreter/PythonDataObjects.h"
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+DynamicRegisterInfo::DynamicRegisterInfo () :
+ m_regs (),
+ m_sets (),
+ m_set_reg_nums (),
+ m_set_names (),
+ m_reg_data_byte_size (0)
+{
+}
+
+DynamicRegisterInfo::DynamicRegisterInfo (const lldb_private::PythonDictionary &dict) :
+ m_regs (),
+ m_sets (),
+ m_set_reg_nums (),
+ m_set_names (),
+ m_reg_data_byte_size (0)
+{
+ SetRegisterInfo (dict);
+}
+
+DynamicRegisterInfo::~DynamicRegisterInfo ()
+{
+}
+
+
+size_t
+DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict)
+{
+#ifndef LLDB_DISABLE_PYTHON
+ PythonList sets (dict.GetItemForKey("sets"));
+ if (sets)
+ {
+ const uint32_t num_sets = sets.GetSize();
+ for (uint32_t i=0; i<num_sets; ++i)
+ {
+ PythonString py_set_name(sets.GetItemAtIndex(i));
+ ConstString set_name;
+ if (py_set_name)
+ set_name.SetCString(py_set_name.GetString());
+ if (set_name)
+ {
+ RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
+ m_sets.push_back (new_set);
+ }
+ else
+ {
+ Clear();
+ return 0;
+ }
+ }
+ m_set_reg_nums.resize(m_sets.size());
+ }
+ PythonList regs (dict.GetItemForKey("registers"));
+ if (regs)
+ {
+ const uint32_t num_regs = regs.GetSize();
+ PythonString name_pystr("name");
+ PythonString altname_pystr("alt-name");
+ PythonString bitsize_pystr("bitsize");
+ PythonString offset_pystr("offset");
+ PythonString encoding_pystr("encoding");
+ PythonString format_pystr("format");
+ PythonString set_pystr("set");
+ PythonString gcc_pystr("gcc");
+ PythonString dwarf_pystr("dwarf");
+ PythonString generic_pystr("generic");
+ for (uint32_t i=0; i<num_regs; ++i)
+ {
+ PythonDictionary reg_info_dict(regs.GetItemAtIndex(i));
+ if (reg_info_dict)
+ {
+ // { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 2, 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', },
+ RegisterInfo reg_info;
+ bzero (&reg_info, sizeof(reg_info));
+
+ reg_info.name = ConstString (reg_info_dict.GetItemForKeyAsString(name_pystr)).GetCString();
+ if (reg_info.name == NULL)
+ {
+ Clear();
+ return 0;
+ }
+
+ reg_info.alt_name = ConstString (reg_info_dict.GetItemForKeyAsString(altname_pystr)).GetCString();
+
+ reg_info.byte_offset = reg_info_dict.GetItemForKeyAsInteger(offset_pystr, UINT32_MAX);
+
+ if (reg_info.byte_offset == UINT32_MAX)
+ {
+ Clear();
+ return 0;
+ }
+ reg_info.byte_size = reg_info_dict.GetItemForKeyAsInteger(bitsize_pystr, 0) / 8;
+
+ if (reg_info.byte_size == 0)
+ {
+ Clear();
+ return 0;
+ }
+
+ const char *format_cstr = reg_info_dict.GetItemForKeyAsString(format_pystr);
+ if (format_cstr)
+ {
+ if (Args::StringToFormat(format_cstr, reg_info.format, NULL).Fail())
+ {
+ Clear();
+ return 0;
+ }
+ }
+ else
+ reg_info.format = eFormatHex;
+
+ const char *encoding_cstr = reg_info_dict.GetItemForKeyAsString(encoding_pystr);
+ if (encoding_cstr)
+ reg_info.encoding = Args::StringToEncoding (encoding_cstr, eEncodingUint);
+ else
+ reg_info.encoding = eEncodingUint;
+
+ const int64_t set = reg_info_dict.GetItemForKeyAsInteger(set_pystr, -1);
+ if (set >= m_sets.size())
+ {
+ Clear();
+ return 0;
+ }
+
+ reg_info.kinds[lldb::eRegisterKindLLDB] = i;
+ reg_info.kinds[lldb::eRegisterKindGDB] = i;
+ reg_info.kinds[lldb::eRegisterKindGCC] = reg_info_dict.GetItemForKeyAsInteger(gcc_pystr, LLDB_INVALID_REGNUM);
+ reg_info.kinds[lldb::eRegisterKindDWARF] = reg_info_dict.GetItemForKeyAsInteger(dwarf_pystr, LLDB_INVALID_REGNUM);
+ reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister (reg_info_dict.GetItemForKeyAsString(generic_pystr));
+ const size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
+ if (m_reg_data_byte_size < end_reg_offset)
+ m_reg_data_byte_size = end_reg_offset;
+
+ m_regs.push_back (reg_info);
+ m_set_reg_nums[set].push_back(i);
+
+ }
+ else
+ {
+ Clear();
+ return 0;
+ }
+ }
+ Finalize ();
+ }
+#endif
+ return 0;
+}
+
+
+void
+DynamicRegisterInfo::AddRegister (RegisterInfo &reg_info,
+ ConstString &reg_name,
+ ConstString &reg_alt_name,
+ ConstString &set_name)
+{
+ const uint32_t reg_num = m_regs.size();
+ reg_info.name = reg_name.AsCString();
+ assert (reg_info.name);
+ reg_info.alt_name = reg_alt_name.AsCString(NULL);
+ m_regs.push_back (reg_info);
+ uint32_t set = GetRegisterSetIndexByName (set_name, true);
+ assert (set < m_sets.size());
+ assert (set < m_set_reg_nums.size());
+ assert (set < m_set_names.size());
+ m_set_reg_nums[set].push_back(reg_num);
+ size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
+ if (m_reg_data_byte_size < end_reg_offset)
+ m_reg_data_byte_size = end_reg_offset;
+}
+
+void
+DynamicRegisterInfo::Finalize ()
+{
+ for (uint32_t set = 0; set < m_sets.size(); ++set)
+ {
+ assert (m_sets.size() == m_set_reg_nums.size());
+ m_sets[set].num_registers = m_set_reg_nums[set].size();
+ m_sets[set].registers = &m_set_reg_nums[set][0];
+ }
+}
+
+size_t
+DynamicRegisterInfo::GetNumRegisters() const
+{
+ return m_regs.size();
+}
+
+size_t
+DynamicRegisterInfo::GetNumRegisterSets() const
+{
+ return m_sets.size();
+}
+
+size_t
+DynamicRegisterInfo::GetRegisterDataByteSize() const
+{
+ return m_reg_data_byte_size;
+}
+
+const RegisterInfo *
+DynamicRegisterInfo::GetRegisterInfoAtIndex (uint32_t i) const
+{
+ if (i < m_regs.size())
+ return &m_regs[i];
+ return NULL;
+}
+
+const RegisterSet *
+DynamicRegisterInfo::GetRegisterSet (uint32_t i) const
+{
+ if (i < m_sets.size())
+ return &m_sets[i];
+ return NULL;
+}
+
+uint32_t
+DynamicRegisterInfo::GetRegisterSetIndexByName (ConstString &set_name, bool can_create)
+{
+ name_collection::iterator pos, end = m_set_names.end();
+ for (pos = m_set_names.begin(); pos != end; ++pos)
+ {
+ if (*pos == set_name)
+ return std::distance (m_set_names.begin(), pos);
+ }
+
+ m_set_names.push_back(set_name);
+ m_set_reg_nums.resize(m_set_reg_nums.size()+1);
+ RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
+ m_sets.push_back (new_set);
+ return m_sets.size() - 1;
+}
+
+uint32_t
+DynamicRegisterInfo::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const
+{
+ reg_collection::const_iterator pos, end = m_regs.end();
+ for (pos = m_regs.begin(); pos != end; ++pos)
+ {
+ if (pos->kinds[kind] == num)
+ return std::distance (m_regs.begin(), pos);
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+void
+DynamicRegisterInfo::Clear()
+{
+ m_regs.clear();
+ m_sets.clear();
+ m_set_reg_nums.clear();
+ m_set_names.clear();
+}
diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/source/Plugins/Process/Utility/DynamicRegisterInfo.h
new file mode 100644
index 000000000000..a11cd333545f
--- /dev/null
+++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.h
@@ -0,0 +1,85 @@
+//===-- DynamicRegisterInfo.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_DynamicRegisterInfo_h_
+#define lldb_DynamicRegisterInfo_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+
+class DynamicRegisterInfo
+{
+public:
+ DynamicRegisterInfo ();
+
+ DynamicRegisterInfo (const lldb_private::PythonDictionary &dict);
+
+ virtual
+ ~DynamicRegisterInfo ();
+
+ size_t
+ SetRegisterInfo (const lldb_private::PythonDictionary &dict);
+
+ void
+ AddRegister (lldb_private::RegisterInfo &reg_info,
+ lldb_private::ConstString &reg_name,
+ lldb_private::ConstString &reg_alt_name,
+ lldb_private::ConstString &set_name);
+
+ void
+ Finalize ();
+
+ size_t
+ GetNumRegisters() const;
+
+ size_t
+ GetNumRegisterSets() const;
+
+ size_t
+ GetRegisterDataByteSize() const;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t i) const;
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet (uint32_t i) const;
+
+ uint32_t
+ GetRegisterSetIndexByName (lldb_private::ConstString &set_name, bool can_create);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const;
+
+ void
+ Clear();
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from DynamicRegisterInfo can see and modify these
+ //------------------------------------------------------------------
+ typedef std::vector <lldb_private::RegisterInfo> reg_collection;
+ typedef std::vector <lldb_private::RegisterSet> set_collection;
+ typedef std::vector <uint32_t> reg_num_collection;
+ typedef std::vector <reg_num_collection> set_reg_num_collection;
+ typedef std::vector <lldb_private::ConstString> name_collection;
+
+ reg_collection m_regs;
+ set_collection m_sets;
+ set_reg_num_collection m_set_reg_nums;
+ name_collection m_set_names;
+ size_t m_reg_data_byte_size; // The number of bytes required to store all registers
+};
+
+#endif // lldb_DynamicRegisterInfo_h_
diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
new file mode 100644
index 000000000000..499d6d766150
--- /dev/null
+++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -0,0 +1,274 @@
+//===-- InferiorCallPOSIX.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InferiorCallPOSIX.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+
+#include <sys/mman.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
+ addr_t addr, addr_t length, unsigned prot,
+ unsigned flags, addr_t fd, addr_t offset) {
+ Thread *thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL)
+ return false;
+
+ const bool append = true;
+ const bool include_symbols = true;
+ const bool include_inlines = false;
+ SymbolContextList sc_list;
+ const uint32_t count
+ = process->GetTarget().GetImages().FindFunctions (ConstString ("mmap"),
+ eFunctionNameTypeFull,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ if (count > 0)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc))
+ {
+ const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = false;
+ const bool stop_other_threads = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ const bool try_all_threads = true;
+ const uint32_t timeout_usec = 500000;
+
+ addr_t prot_arg, flags_arg = 0;
+ if (prot == eMmapProtNone)
+ prot_arg = PROT_NONE;
+ else {
+ prot_arg = 0;
+ if (prot & eMmapProtExec)
+ prot_arg |= PROT_EXEC;
+ if (prot & eMmapProtRead)
+ prot_arg |= PROT_READ;
+ if (prot & eMmapProtWrite)
+ prot_arg |= PROT_WRITE;
+ }
+
+ if (flags & eMmapFlagsPrivate)
+ flags_arg |= MAP_PRIVATE;
+ if (flags & eMmapFlagsAnon)
+ flags_arg |= MAP_ANON;
+
+ AddressRange mmap_range;
+ if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, mmap_range))
+ {
+ ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
+ ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ ThreadPlanCallFunction *call_function_thread_plan
+ = new ThreadPlanCallFunction (*thread,
+ mmap_range.GetBaseAddress(),
+ clang_void_ptr_type,
+ stop_other_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ &addr,
+ &length,
+ &prot_arg,
+ &flags_arg,
+ &fd,
+ &offset);
+ lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
+ if (call_plan_sp)
+ {
+ StreamFile error_strm;
+ // This plan is a utility plan, so set it to discard itself when done.
+ call_plan_sp->SetIsMasterPlan (true);
+ call_plan_sp->SetOkayToDiscard(true);
+
+ StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+ if (frame)
+ {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext (exe_ctx);
+ ExecutionResults result = process->RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ stop_other_threads,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ error_strm);
+ if (result == eExecutionCompleted)
+ {
+
+ allocated_addr = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ if (process->GetAddressByteSize() == 4)
+ {
+ if (allocated_addr == UINT32_MAX)
+ return false;
+ }
+ else if (process->GetAddressByteSize() == 8)
+ {
+ if (allocated_addr == UINT64_MAX)
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
+ addr_t length) {
+ Thread *thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL)
+ return false;
+
+ const bool append = true;
+ const bool include_symbols = true;
+ const bool include_inlines = false;
+ SymbolContextList sc_list;
+ const uint32_t count
+ = process->GetTarget().GetImages().FindFunctions (ConstString ("munmap"),
+ eFunctionNameTypeFull,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ if (count > 0)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc))
+ {
+ const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = false;
+ const bool stop_other_threads = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ const bool try_all_threads = true;
+ const uint32_t timeout_usec = 500000;
+
+ AddressRange munmap_range;
+ if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range))
+ {
+ lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread,
+ munmap_range.GetBaseAddress(),
+ ClangASTType(),
+ stop_other_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ &addr,
+ &length));
+ if (call_plan_sp)
+ {
+ StreamFile error_strm;
+ // This plan is a utility plan, so set it to discard itself when done.
+ call_plan_sp->SetIsMasterPlan (true);
+ call_plan_sp->SetOkayToDiscard(true);
+
+ StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+ if (frame)
+ {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext (exe_ctx);
+ ExecutionResults result = process->RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ stop_other_threads,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ error_strm);
+ if (result == eExecutionCompleted)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t &returned_func) {
+ Thread *thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL || address == NULL)
+ return false;
+
+ const bool stop_other_threads = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ const bool try_all_threads = true;
+ const uint32_t timeout_usec = 500000;
+
+ ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
+ ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ ThreadPlanCallFunction *call_function_thread_plan
+ = new ThreadPlanCallFunction (*thread,
+ *address,
+ clang_void_ptr_type,
+ stop_other_threads,
+ unwind_on_error,
+ ignore_breakpoints);
+ lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
+ if (call_plan_sp)
+ {
+ StreamFile error_strm;
+ // This plan is a utility plan, so set it to discard itself when done.
+ call_plan_sp->SetIsMasterPlan (true);
+ call_plan_sp->SetOkayToDiscard(true);
+
+ StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+ if (frame)
+ {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext (exe_ctx);
+ ExecutionResults result = process->RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ stop_other_threads,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ error_strm);
+ if (result == eExecutionCompleted)
+ {
+ returned_func = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+
+ if (process->GetAddressByteSize() == 4)
+ {
+ if (returned_func == UINT32_MAX)
+ return false;
+ }
+ else if (process->GetAddressByteSize() == 8)
+ {
+ if (returned_func == UINT64_MAX)
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.h b/source/Plugins/Process/Utility/InferiorCallPOSIX.h
new file mode 100644
index 000000000000..d8b6d0ed57fd
--- /dev/null
+++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.h
@@ -0,0 +1,43 @@
+//===-- InferiorCallPOSIX.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_InferiorCallPOSIX_h_
+#define lldb_InferiorCallPOSIX_h_
+
+// Inferior execution of POSIX functions.
+
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+
+class Process;
+
+enum MmapProt {
+ eMmapProtNone = 0,
+ eMmapProtExec = 1,
+ eMmapProtRead = 2,
+ eMmapProtWrite = 4
+};
+
+enum MmapFlags {
+ eMmapFlagsPrivate = 1,
+ eMmapFlagsAnon = 2
+};
+
+bool InferiorCallMmap(Process *proc, lldb::addr_t &allocated_addr,
+ lldb::addr_t addr, lldb::addr_t length, unsigned prot,
+ unsigned flags, lldb::addr_t fd, lldb::addr_t offset);
+
+bool InferiorCallMunmap(Process *proc, lldb::addr_t addr, lldb::addr_t length);
+
+bool InferiorCall(Process *proc, const Address *address, lldb::addr_t &returned_func);
+
+} // namespace lldb_private
+
+#endif // lldb_InferiorCallPOSIX_h_
diff --git a/source/Plugins/Process/Utility/InstructionUtils.h b/source/Plugins/Process/Utility/InstructionUtils.h
new file mode 100644
index 000000000000..4bb644e6efe6
--- /dev/null
+++ b/source/Plugins/Process/Utility/InstructionUtils.h
@@ -0,0 +1,136 @@
+//===-- InstructionUtils.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_InstructionUtils_h_
+#define lldb_InstructionUtils_h_
+
+// Common utilities for manipulating instruction bit fields.
+
+namespace lldb_private {
+
+// Return the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 64-bit unsigned value.
+static inline uint64_t
+Bits64 (const uint64_t bits, const uint32_t msbit, const uint32_t lsbit)
+{
+ assert(msbit < 64 && lsbit <= msbit);
+ return (bits >> lsbit) & ((1u << (msbit - lsbit + 1)) - 1);
+}
+
+// Return the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 32-bit unsigned value.
+static inline uint32_t
+Bits32 (const uint32_t bits, const uint32_t msbit, const uint32_t lsbit)
+{
+ assert(msbit < 32 && lsbit <= msbit);
+ return (bits >> lsbit) & ((1u << (msbit - lsbit + 1)) - 1);
+}
+
+// Return the bit value from the 'bit' position of a 32-bit unsigned value.
+static inline uint32_t
+Bit32 (const uint32_t bits, const uint32_t bit)
+{
+ return (bits >> bit) & 1u;
+}
+
+static inline uint64_t
+Bit64 (const uint64_t bits, const uint32_t bit)
+{
+ return (bits >> bit) & 1ull;
+}
+
+// Set the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 32-bit unsigned value to 'val'.
+static inline void
+SetBits32(uint32_t &bits, const uint32_t msbit, const uint32_t lsbit, const uint32_t val)
+{
+ assert(msbit < 32 && lsbit < 32 && msbit >= lsbit);
+ uint32_t mask = ((1u << (msbit - lsbit + 1)) - 1);
+ bits &= ~(mask << lsbit);
+ bits |= (val & mask) << lsbit;
+}
+
+// Set the 'bit' position of a 32-bit unsigned value to 'val'.
+static inline void
+SetBit32(uint32_t &bits, const uint32_t bit, const uint32_t val)
+{
+ SetBits32(bits, bit, bit, val);
+}
+
+// Rotate a 32-bit unsigned value right by the specified amount.
+static inline uint32_t
+Rotr32 (uint32_t bits, uint32_t amt)
+{
+ assert(amt < 32 && "Invalid rotate amount");
+ return (bits >> amt) | (bits << ((32-amt)&31));
+}
+
+// Rotate a 32-bit unsigned value left by the specified amount.
+static inline uint32_t
+Rotl32 (uint32_t bits, uint32_t amt)
+{
+ assert(amt < 32 && "Invalid rotate amount");
+ return (bits << amt) | (bits >> ((32-amt)&31));
+}
+
+// Create a mask that starts at bit zero and includes "bit"
+static inline uint64_t
+MaskUpToBit (const uint64_t bit)
+{
+ return (1ull << (bit + 1ull)) - 1ull;
+}
+
+// Return an integer result equal to the number of bits of x that are ones.
+static inline uint32_t
+BitCount (uint64_t x)
+{
+ // c accumulates the total bits set in x
+ uint32_t c;
+ for (c = 0; x; ++c)
+ {
+ x &= x - 1; // clear the least significant bit set
+ }
+ return c;
+}
+
+static inline bool
+BitIsSet (const uint64_t value, const uint64_t bit)
+{
+ return (value & (1ull << bit)) != 0;
+}
+
+static inline bool
+BitIsClear (const uint64_t value, const uint64_t bit)
+{
+ return (value & (1ull << bit)) == 0;
+}
+
+static inline uint64_t
+UnsignedBits (const uint64_t value, const uint64_t msbit, const uint64_t lsbit)
+{
+ uint64_t result = value >> lsbit;
+ result &= MaskUpToBit (msbit - lsbit);
+ return result;
+}
+
+static inline int64_t
+SignedBits (const uint64_t value, const uint64_t msbit, const uint64_t lsbit)
+{
+ uint64_t result = UnsignedBits (value, msbit, lsbit);
+ if (BitIsSet(value, msbit))
+ {
+ // Sign extend
+ result |= ~MaskUpToBit (msbit - lsbit);
+ }
+ return result;
+}
+
+} // namespace lldb_private
+
+#endif // lldb_InstructionUtils_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
new file mode 100644
index 000000000000..4d77b6f20fdc
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
@@ -0,0 +1,1226 @@
+//===-- RegisterContextDarwin_arm.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_arm.h"
+
+// C Includes
+#include <mach/mach_types.h>
+#include <mach/thread_act.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 "ARM_GCC_Registers.h"
+#include "ARM_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gpr_r0 = 0,
+ gpr_r1,
+ gpr_r2,
+ gpr_r3,
+ gpr_r4,
+ gpr_r5,
+ gpr_r6,
+ gpr_r7,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13, gpr_sp = gpr_r13,
+ gpr_r14, gpr_lr = gpr_r14,
+ gpr_r15, gpr_pc = gpr_r15,
+ gpr_cpsr,
+
+ fpu_s0,
+ fpu_s1,
+ fpu_s2,
+ fpu_s3,
+ fpu_s4,
+ fpu_s5,
+ fpu_s6,
+ fpu_s7,
+ fpu_s8,
+ fpu_s9,
+ fpu_s10,
+ fpu_s11,
+ fpu_s12,
+ fpu_s13,
+ fpu_s14,
+ fpu_s15,
+ fpu_s16,
+ fpu_s17,
+ fpu_s18,
+ fpu_s19,
+ fpu_s20,
+ fpu_s21,
+ fpu_s22,
+ fpu_s23,
+ fpu_s24,
+ fpu_s25,
+ fpu_s26,
+ fpu_s27,
+ fpu_s28,
+ fpu_s29,
+ fpu_s30,
+ fpu_s31,
+ fpu_fpscr,
+
+ exc_exception,
+ exc_fsr,
+ exc_far,
+
+ 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_arm::RegisterContextDarwin_arm(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_arm::~RegisterContextDarwin_arm()
+{
+}
+
+
+#define GPR_OFFSET(idx) ((idx) * 4)
+#define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextDarwin_arm::GPR))
+#define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU))
+#define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextDarwin_arm::DBG, reg) + sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU) + sizeof (RegisterContextDarwin_arm::EXC)))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextDarwin_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(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_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU) + sizeof (RegisterContextDarwin_arm::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
+// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== ===============
+{ "r0", NULL, 4, GPR_OFFSET(0), eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_INVALID_REGNUM, gdb_arm_r0, gpr_r0 }, NULL, NULL},
+{ "r1", NULL, 4, GPR_OFFSET(1), eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_INVALID_REGNUM, gdb_arm_r1, gpr_r1 }, NULL, NULL},
+{ "r2", NULL, 4, GPR_OFFSET(2), eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_INVALID_REGNUM, gdb_arm_r2, gpr_r2 }, NULL, NULL},
+{ "r3", NULL, 4, GPR_OFFSET(3), eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_INVALID_REGNUM, gdb_arm_r3, gpr_r3 }, NULL, NULL},
+{ "r4", NULL, 4, GPR_OFFSET(4), eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, gdb_arm_r4, gpr_r4 }, NULL, NULL},
+{ "r5", NULL, 4, GPR_OFFSET(5), eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, gdb_arm_r5, gpr_r5 }, NULL, NULL},
+{ "r6", NULL, 4, GPR_OFFSET(6), eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, gdb_arm_r6, gpr_r6 }, NULL, NULL},
+{ "r7", NULL, 4, GPR_OFFSET(7), eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, gdb_arm_r7, gpr_r7 }, NULL, NULL},
+{ "r8", NULL, 4, GPR_OFFSET(8), eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, gdb_arm_r8, gpr_r8 }, NULL, NULL},
+{ "r9", NULL, 4, GPR_OFFSET(9), eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, gdb_arm_r9, gpr_r9 }, NULL, NULL},
+{ "r10", NULL, 4, GPR_OFFSET(10), eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, gdb_arm_r10, gpr_r10 }, NULL, NULL},
+{ "r11", NULL, 4, GPR_OFFSET(11), eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM, gdb_arm_r11, gpr_r11 }, NULL, NULL},
+{ "r12", NULL, 4, GPR_OFFSET(12), eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, gdb_arm_r12, gpr_r12 }, NULL, NULL},
+{ "sp", "r13", 4, GPR_OFFSET(13), eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, gdb_arm_sp, gpr_sp }, NULL, NULL},
+{ "lr", "r14", 4, GPR_OFFSET(14), eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_arm_lr, gpr_lr }, NULL, NULL},
+{ "pc", "r15", 4, GPR_OFFSET(15), eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, gdb_arm_pc, gpr_pc }, NULL, NULL},
+{ "cpsr", "psr", 4, GPR_OFFSET(16), eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, gdb_arm_cpsr, gpr_cpsr }, NULL, NULL},
+
+{ "s0", NULL, 4, FPU_OFFSET(0), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, gdb_arm_s0, fpu_s0 }, NULL, NULL},
+{ "s1", NULL, 4, FPU_OFFSET(1), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, gdb_arm_s1, fpu_s1 }, NULL, NULL},
+{ "s2", NULL, 4, FPU_OFFSET(2), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, gdb_arm_s2, fpu_s2 }, NULL, NULL},
+{ "s3", NULL, 4, FPU_OFFSET(3), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, gdb_arm_s3, fpu_s3 }, NULL, NULL},
+{ "s4", NULL, 4, FPU_OFFSET(4), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, gdb_arm_s4, fpu_s4 }, NULL, NULL},
+{ "s5", NULL, 4, FPU_OFFSET(5), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, gdb_arm_s5, fpu_s5 }, NULL, NULL},
+{ "s6", NULL, 4, FPU_OFFSET(6), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, gdb_arm_s6, fpu_s6 }, NULL, NULL},
+{ "s7", NULL, 4, FPU_OFFSET(7), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, gdb_arm_s7, fpu_s7 }, NULL, NULL},
+{ "s8", NULL, 4, FPU_OFFSET(8), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, gdb_arm_s8, fpu_s8 }, NULL, NULL},
+{ "s9", NULL, 4, FPU_OFFSET(9), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, gdb_arm_s9, fpu_s9 }, NULL, NULL},
+{ "s10", NULL, 4, FPU_OFFSET(10), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, gdb_arm_s10, fpu_s10 }, NULL, NULL},
+{ "s11", NULL, 4, FPU_OFFSET(11), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, gdb_arm_s11, fpu_s11 }, NULL, NULL},
+{ "s12", NULL, 4, FPU_OFFSET(12), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, gdb_arm_s12, fpu_s12 }, NULL, NULL},
+{ "s13", NULL, 4, FPU_OFFSET(13), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, gdb_arm_s13, fpu_s13 }, NULL, NULL},
+{ "s14", NULL, 4, FPU_OFFSET(14), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, gdb_arm_s14, fpu_s14 }, NULL, NULL},
+{ "s15", NULL, 4, FPU_OFFSET(15), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, gdb_arm_s15, fpu_s15 }, NULL, NULL},
+{ "s16", NULL, 4, FPU_OFFSET(16), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, gdb_arm_s16, fpu_s16 }, NULL, NULL},
+{ "s17", NULL, 4, FPU_OFFSET(17), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, gdb_arm_s17, fpu_s17 }, NULL, NULL},
+{ "s18", NULL, 4, FPU_OFFSET(18), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, gdb_arm_s18, fpu_s18 }, NULL, NULL},
+{ "s19", NULL, 4, FPU_OFFSET(19), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, gdb_arm_s19, fpu_s19 }, NULL, NULL},
+{ "s20", NULL, 4, FPU_OFFSET(20), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, gdb_arm_s20, fpu_s20 }, NULL, NULL},
+{ "s21", NULL, 4, FPU_OFFSET(21), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, gdb_arm_s21, fpu_s21 }, NULL, NULL},
+{ "s22", NULL, 4, FPU_OFFSET(22), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, gdb_arm_s22, fpu_s22 }, NULL, NULL},
+{ "s23", NULL, 4, FPU_OFFSET(23), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, gdb_arm_s23, fpu_s23 }, NULL, NULL},
+{ "s24", NULL, 4, FPU_OFFSET(24), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, gdb_arm_s24, fpu_s24 }, NULL, NULL},
+{ "s25", NULL, 4, FPU_OFFSET(25), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, gdb_arm_s25, fpu_s25 }, NULL, NULL},
+{ "s26", NULL, 4, FPU_OFFSET(26), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, gdb_arm_s26, fpu_s26 }, NULL, NULL},
+{ "s27", NULL, 4, FPU_OFFSET(27), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, gdb_arm_s27, fpu_s27 }, NULL, NULL},
+{ "s28", NULL, 4, FPU_OFFSET(28), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, gdb_arm_s28, fpu_s28 }, NULL, NULL},
+{ "s29", NULL, 4, FPU_OFFSET(29), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, gdb_arm_s29, fpu_s29 }, NULL, NULL},
+{ "s30", NULL, 4, FPU_OFFSET(30), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, gdb_arm_s30, fpu_s30 }, NULL, NULL},
+{ "s31", NULL, 4, FPU_OFFSET(31), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, gdb_arm_s31, fpu_s31 }, NULL, NULL},
+{ "fpscr", NULL, 4, FPU_OFFSET(32), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, gdb_arm_fpscr, fpu_fpscr }, NULL, NULL},
+
+{ "exception",NULL, 4, EXC_OFFSET(0), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL},
+{ "fsr", NULL, 4, EXC_OFFSET(1), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_fsr }, NULL, NULL},
+{ "far", NULL, 4, EXC_OFFSET(2), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, 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_r0,
+ gpr_r1,
+ gpr_r2,
+ gpr_r3,
+ gpr_r4,
+ gpr_r5,
+ gpr_r6,
+ gpr_r7,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_sp,
+ gpr_lr,
+ gpr_pc,
+ gpr_cpsr
+};
+
+// Floating point registers
+static uint32_t
+g_fpu_regnums[] =
+{
+ fpu_s0,
+ fpu_s1,
+ fpu_s2,
+ fpu_s3,
+ fpu_s4,
+ fpu_s5,
+ fpu_s6,
+ fpu_s7,
+ fpu_s8,
+ fpu_s9,
+ fpu_s10,
+ fpu_s11,
+ fpu_s12,
+ fpu_s13,
+ fpu_s14,
+ fpu_s15,
+ fpu_s16,
+ fpu_s17,
+ fpu_s18,
+ fpu_s19,
+ fpu_s20,
+ fpu_s21,
+ fpu_s22,
+ fpu_s23,
+ fpu_s24,
+ fpu_s25,
+ fpu_s26,
+ fpu_s27,
+ fpu_s28,
+ fpu_s29,
+ fpu_s30,
+ fpu_s31,
+ fpu_fpscr,
+};
+
+// Exception registers
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_exception,
+ exc_fsr,
+ exc_far,
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+void
+RegisterContextDarwin_arm::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_arm::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_arm::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_arm::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_arm::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_arm::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_arm::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Register information defintions for 32 bit i386.
+//----------------------------------------------------------------------
+int
+RegisterContextDarwin_arm::GetSetForNativeRegNum (int reg)
+{
+ if (reg < fpu_s0)
+ return GPRRegSet;
+ else if (reg < exc_exception)
+ return FPURegSet;
+ else if (reg < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+int
+RegisterContextDarwin_arm::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::ReadDBG (bool force)
+{
+ int set = DBGRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadDBG(GetThreadID(), set, dbg));
+ }
+ return GetError(DBGRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::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_arm::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_arm::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_arm::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_arm::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_arm::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_arm::LogDBGRegisters (Log *log, const DBG& dbg)
+{
+ if (log)
+ {
+ for (uint32_t i=0; i<16; i++)
+ log->Printf("BVR%-2u/BCR%-2u = { 0x%8.8x, 0x%8.8x } WVR%-2u/WCR%-2u = { 0x%8.8x, 0x%8.8x }",
+ i, i, dbg.bvr[i], dbg.bcr[i],
+ i, i, dbg.wvr[i], dbg.wcr[i]);
+ }
+}
+
+
+bool
+RegisterContextDarwin_arm::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_arm::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_r0:
+ case gpr_r1:
+ case gpr_r2:
+ case gpr_r3:
+ case gpr_r4:
+ case gpr_r5:
+ case gpr_r6:
+ case gpr_r7:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ value.SetUInt32 (gpr.r[reg - gpr_r0]);
+ break;
+
+ case fpu_s0:
+ case fpu_s1:
+ case fpu_s2:
+ case fpu_s3:
+ case fpu_s4:
+ case fpu_s5:
+ case fpu_s6:
+ case fpu_s7:
+ case fpu_s8:
+ case fpu_s9:
+ case fpu_s10:
+ case fpu_s11:
+ case fpu_s12:
+ case fpu_s13:
+ case fpu_s14:
+ case fpu_s15:
+ case fpu_s16:
+ case fpu_s17:
+ case fpu_s18:
+ case fpu_s19:
+ case fpu_s20:
+ case fpu_s21:
+ case fpu_s22:
+ case fpu_s23:
+ case fpu_s24:
+ case fpu_s25:
+ case fpu_s26:
+ case fpu_s27:
+ case fpu_s28:
+ case fpu_s29:
+ case fpu_s30:
+ case fpu_s31:
+ value.SetUInt32 (fpu.floats.s[reg], RegisterValue::eTypeFloat);
+ break;
+
+ case fpu_fpscr:
+ value.SetUInt32 (fpu.fpscr);
+ break;
+
+ case exc_exception:
+ value.SetUInt32 (exc.exception);
+ break;
+ case exc_fsr:
+ value.SetUInt32 (exc.fsr);
+ break;
+ case exc_far:
+ value.SetUInt32 (exc.far);
+ break;
+
+ default:
+ value.SetValueToInvalid();
+ return false;
+
+ }
+ return true;
+}
+
+
+bool
+RegisterContextDarwin_arm::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_r0:
+ case gpr_r1:
+ case gpr_r2:
+ case gpr_r3:
+ case gpr_r4:
+ case gpr_r5:
+ case gpr_r6:
+ case gpr_r7:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ gpr.r[reg - gpr_r0] = value.GetAsUInt32();
+ break;
+
+ case fpu_s0:
+ case fpu_s1:
+ case fpu_s2:
+ case fpu_s3:
+ case fpu_s4:
+ case fpu_s5:
+ case fpu_s6:
+ case fpu_s7:
+ case fpu_s8:
+ case fpu_s9:
+ case fpu_s10:
+ case fpu_s11:
+ case fpu_s12:
+ case fpu_s13:
+ case fpu_s14:
+ case fpu_s15:
+ case fpu_s16:
+ case fpu_s17:
+ case fpu_s18:
+ case fpu_s19:
+ case fpu_s20:
+ case fpu_s21:
+ case fpu_s22:
+ case fpu_s23:
+ case fpu_s24:
+ case fpu_s25:
+ case fpu_s26:
+ case fpu_s27:
+ case fpu_s28:
+ case fpu_s29:
+ case fpu_s30:
+ case fpu_s31:
+ fpu.floats.s[reg] = value.GetAsUInt32();
+ break;
+
+ case fpu_fpscr:
+ fpu.fpscr = value.GetAsUInt32();
+ break;
+
+ case exc_exception:
+ exc.exception = value.GetAsUInt32();
+ break;
+ case exc_fsr:
+ exc.fsr = value.GetAsUInt32();
+ break;
+ case exc_far:
+ exc.far = value.GetAsUInt32();
+ break;
+
+ default:
+ return false;
+
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextDarwin_arm::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_arm::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_arm::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_r7;
+ 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 dwarf_r0: return gpr_r0;
+ case dwarf_r1: return gpr_r1;
+ case dwarf_r2: return gpr_r2;
+ case dwarf_r3: return gpr_r3;
+ case dwarf_r4: return gpr_r4;
+ case dwarf_r5: return gpr_r5;
+ case dwarf_r6: return gpr_r6;
+ case dwarf_r7: return gpr_r7;
+ case dwarf_r8: return gpr_r8;
+ case dwarf_r9: return gpr_r9;
+ case dwarf_r10: return gpr_r10;
+ case dwarf_r11: return gpr_r11;
+ case dwarf_r12: return gpr_r12;
+ case dwarf_sp: return gpr_sp;
+ case dwarf_lr: return gpr_lr;
+ case dwarf_pc: return gpr_pc;
+ case dwarf_spsr: return gpr_cpsr;
+
+ case dwarf_s0: return fpu_s0;
+ case dwarf_s1: return fpu_s1;
+ case dwarf_s2: return fpu_s2;
+ case dwarf_s3: return fpu_s3;
+ case dwarf_s4: return fpu_s4;
+ case dwarf_s5: return fpu_s5;
+ case dwarf_s6: return fpu_s6;
+ case dwarf_s7: return fpu_s7;
+ case dwarf_s8: return fpu_s8;
+ case dwarf_s9: return fpu_s9;
+ case dwarf_s10: return fpu_s10;
+ case dwarf_s11: return fpu_s11;
+ case dwarf_s12: return fpu_s12;
+ case dwarf_s13: return fpu_s13;
+ case dwarf_s14: return fpu_s14;
+ case dwarf_s15: return fpu_s15;
+ case dwarf_s16: return fpu_s16;
+ case dwarf_s17: return fpu_s17;
+ case dwarf_s18: return fpu_s18;
+ case dwarf_s19: return fpu_s19;
+ case dwarf_s20: return fpu_s20;
+ case dwarf_s21: return fpu_s21;
+ case dwarf_s22: return fpu_s22;
+ case dwarf_s23: return fpu_s23;
+ case dwarf_s24: return fpu_s24;
+ case dwarf_s25: return fpu_s25;
+ case dwarf_s26: return fpu_s26;
+ case dwarf_s27: return fpu_s27;
+ case dwarf_s28: return fpu_s28;
+ case dwarf_s29: return fpu_s29;
+ case dwarf_s30: return fpu_s30;
+ case dwarf_s31: return fpu_s31;
+
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC)
+ {
+ switch (reg)
+ {
+ case gcc_r0: return gpr_r0;
+ case gcc_r1: return gpr_r1;
+ case gcc_r2: return gpr_r2;
+ case gcc_r3: return gpr_r3;
+ case gcc_r4: return gpr_r4;
+ case gcc_r5: return gpr_r5;
+ case gcc_r6: return gpr_r6;
+ case gcc_r7: return gpr_r7;
+ case gcc_r8: return gpr_r8;
+ case gcc_r9: return gpr_r9;
+ case gcc_r10: return gpr_r10;
+ case gcc_r11: return gpr_r11;
+ case gcc_r12: return gpr_r12;
+ case gcc_sp: return gpr_sp;
+ case gcc_lr: return gpr_lr;
+ case gcc_pc: return gpr_pc;
+ case gcc_cpsr: return gpr_cpsr;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+uint32_t
+RegisterContextDarwin_arm::NumSupportedHardwareBreakpoints ()
+{
+#if defined (__arm__)
+ // Set the init value to something that will let us know that we need to
+ // autodetect how many breakpoints are supported dynamically...
+ static uint32_t g_num_supported_hw_breakpoints = UINT32_MAX;
+ if (g_num_supported_hw_breakpoints == UINT32_MAX)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_breakpoints = 0;
+
+ uint32_t register_DBGDIDR;
+
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ g_num_supported_hw_breakpoints = Bits32 (register_DBGDIDR, 27, 24);
+ // Zero is reserved for the BRP count, so don't increment it if it is zero
+ if (g_num_supported_hw_breakpoints > 0)
+ g_num_supported_hw_breakpoints++;
+// if (log) log->Printf ("DBGDIDR=0x%8.8x (number BRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_breakpoints);
+
+ }
+ return g_num_supported_hw_breakpoints;
+#else
+ // TODO: figure out remote case here!
+ return 6;
+#endif
+}
+
+uint32_t
+RegisterContextDarwin_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ // Make sure our address isn't bogus
+ if (addr & 1)
+ return LLDB_INVALID_INDEX32;
+
+ int kret = ReadDBG (false);
+
+ if (kret == KERN_SUCCESS)
+ {
+ const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints();
+ uint32_t i;
+ for (i=0; i<num_hw_breakpoints; ++i)
+ {
+ if ((dbg.bcr[i] & BCR_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_breakpoints)
+ {
+ // Make sure bits 1:0 are clear in our address
+ dbg.bvr[i] = addr & ~((lldb::addr_t)3);
+
+ if (size == 2 || addr & 2)
+ {
+ uint32_t byte_addr_select = (addr & 2) ? BAS_IMVA_2_3 : BAS_IMVA_0_1;
+
+ // We have a thumb breakpoint
+ // We have an ARM breakpoint
+ dbg.bcr[i] = BCR_M_IMVA_MATCH | // Stop on address mismatch
+ byte_addr_select | // Set the correct byte address select so we only trigger on the correct opcode
+ S_USER | // Which modes should this breakpoint stop in?
+ BCR_ENABLE; // Enable this hardware breakpoint
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (Thumb)",
+// addr,
+// size,
+// i,
+// i,
+// dbg.bvr[i],
+// dbg.bcr[i]);
+ }
+ else if (size == 4)
+ {
+ // We have an ARM breakpoint
+ dbg.bcr[i] = BCR_M_IMVA_MATCH | // Stop on address mismatch
+ BAS_IMVA_ALL | // Stop on any of the four bytes following the IMVA
+ S_USER | // Which modes should this breakpoint stop in?
+ BCR_ENABLE; // Enable this hardware breakpoint
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (ARM)",
+// addr,
+// size,
+// i,
+// i,
+// dbg.bvr[i],
+// dbg.bcr[i]);
+ }
+
+ kret = WriteDBG();
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+// else
+// {
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint(addr = %8.8p, size = %u) => all hardware breakpoint resources are being used.", addr, size);
+// }
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextDarwin_arm::ClearHardwareBreakpoint (uint32_t hw_index)
+{
+ int kret = ReadDBG (false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareBreakpoints();
+ if (kret == KERN_SUCCESS)
+ {
+ if (hw_index < num_hw_points)
+ {
+ dbg.bcr[hw_index] = 0;
+// if (log) log->Printf ("RegisterContextDarwin_arm::SetHardwareBreakpoint( %u ) - BVR%u = 0x%8.8x BCR%u = 0x%8.8x",
+// hw_index,
+// hw_index,
+// dbg.bvr[hw_index],
+// hw_index,
+// dbg.bcr[hw_index]);
+
+ kret = WriteDBG();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
+
+uint32_t
+RegisterContextDarwin_arm::NumSupportedHardwareWatchpoints ()
+{
+#if defined (__arm__)
+ // Set the init value to something that will let us know that we need to
+ // 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)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_watchpoints = 0;
+
+ uint32_t register_DBGDIDR;
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ g_num_supported_hw_watchpoints = Bits32 (register_DBGDIDR, 31, 28) + 1;
+// if (log) log->Printf ("DBGDIDR=0x%8.8x (number WRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_watchpoints);
+ }
+ return g_num_supported_hw_watchpoints;
+#else
+ // TODO: figure out remote case here!
+ return 2;
+#endif
+}
+
+
+uint32_t
+RegisterContextDarwin_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+// if (log) log->Printf ("RegisterContextDarwin_arm::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_arm::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_arm::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_arm::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+ else
+ {
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints);
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextDarwin_arm::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_arm::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/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h
new file mode 100644
index 000000000000..0bf204f57c80
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h
@@ -0,0 +1,333 @@
+//===-- RegisterContextDarwin_arm.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_arm_h_
+#define liblldb_RegisterContextDarwin_arm_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+// BCR address match type
+#define BCR_M_IMVA_MATCH ((uint32_t)(0u << 21))
+#define BCR_M_CONTEXT_ID_MATCH ((uint32_t)(1u << 21))
+#define BCR_M_IMVA_MISMATCH ((uint32_t)(2u << 21))
+#define BCR_M_RESERVED ((uint32_t)(3u << 21))
+
+// Link a BVR/BCR or WVR/WCR pair to another
+#define E_ENABLE_LINKING ((uint32_t)(1u << 20))
+
+// Byte Address Select
+#define BAS_IMVA_PLUS_0 ((uint32_t)(1u << 5))
+#define BAS_IMVA_PLUS_1 ((uint32_t)(1u << 6))
+#define BAS_IMVA_PLUS_2 ((uint32_t)(1u << 7))
+#define BAS_IMVA_PLUS_3 ((uint32_t)(1u << 8))
+#define BAS_IMVA_0_1 ((uint32_t)(3u << 5))
+#define BAS_IMVA_2_3 ((uint32_t)(3u << 7))
+#define BAS_IMVA_ALL ((uint32_t)(0xfu << 5))
+
+// 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 BCR_ENABLE ((uint32_t)(1u))
+#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_arm : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextDarwin_arm(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_arm();
+
+ 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 &reg_value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_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
+ NumSupportedHardwareBreakpoints ();
+
+ virtual uint32_t
+ SetHardwareBreakpoint (lldb::addr_t addr, size_t size);
+
+ virtual bool
+ ClearHardwareBreakpoint (uint32_t hw_idx);
+
+ 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);
+
+ struct GPR
+ {
+ uint32_t r[16]; // R0-R15
+ uint32_t cpsr; // CPSR
+ };
+
+
+ struct QReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ union {
+ uint32_t s[32];
+ uint64_t d[32];
+ QReg q[16]; // the 128-bit NEON registers
+ } floats;
+ uint32_t fpscr;
+ };
+
+// struct NeonReg
+// {
+// uint8_t bytes[16];
+// };
+//
+// struct VFPv3
+// {
+// union {
+// uint32_t s[32];
+// uint64_t d[32];
+// NeonReg q[16];
+// } v3;
+// uint32_t fpscr;
+// };
+
+ struct EXC
+ {
+ uint32_t exception;
+ uint32_t fsr; /* Fault status */
+ uint32_t far; /* Virtual Fault Address */
+ };
+
+ struct DBG
+ {
+ uint32_t bvr[16];
+ uint32_t bcr[16];
+ uint32_t wvr[16];
+ uint32_t wcr[16];
+ };
+
+ static void
+ LogDBGRegisters (lldb_private::Log *log, const DBG& dbg);
+
+protected:
+
+ enum
+ {
+ GPRRegSet = 1, // ARM_THREAD_STATE
+ FPURegSet = 2, // ARM_VFP_STATE
+ EXCRegSet = 3, // ARM_EXCEPTION_STATE
+ DBGRegSet = 4 // ARM_DEBUG_STATE
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t),
+ DBGWordCount = sizeof(DBG)/sizeof(uint32_t)
+ };
+
+ 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_arm_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
new file mode 100644
index 000000000000..a94d1f538a28
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
@@ -0,0 +1,980 @@
+//===-- RegisterContextDarwin_i386.cpp --------------------------*- 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> // offsetof
+
+// 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"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "RegisterContextDarwin_i386.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gpr_eax = 0,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs,
+
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr,
+
+ k_num_registers,
+
+ // Aliases
+ fpu_fctrl = fpu_fcw,
+ fpu_fstat = fpu_fsw,
+ fpu_ftag = fpu_ftw,
+ fpu_fiseg = fpu_cs,
+ fpu_fioff = fpu_ip,
+ fpu_foseg = fpu_ds,
+ fpu_fooff = fpu_dp
+};
+
+enum
+{
+ gcc_eax = 0,
+ gcc_ecx,
+ gcc_edx,
+ gcc_ebx,
+ gcc_ebp,
+ gcc_esp,
+ gcc_esi,
+ gcc_edi,
+ gcc_eip,
+ gcc_eflags
+};
+
+enum
+{
+ dwarf_eax = 0,
+ dwarf_ecx,
+ dwarf_edx,
+ dwarf_ebx,
+ dwarf_esp,
+ dwarf_ebp,
+ dwarf_esi,
+ dwarf_edi,
+ dwarf_eip,
+ dwarf_eflags,
+ dwarf_stmm0 = 11,
+ dwarf_stmm1,
+ dwarf_stmm2,
+ dwarf_stmm3,
+ dwarf_stmm4,
+ dwarf_stmm5,
+ dwarf_stmm6,
+ dwarf_stmm7,
+ dwarf_xmm0 = 21,
+ dwarf_xmm1,
+ dwarf_xmm2,
+ dwarf_xmm3,
+ dwarf_xmm4,
+ dwarf_xmm5,
+ dwarf_xmm6,
+ dwarf_xmm7
+};
+
+enum
+{
+ gdb_eax = 0,
+ gdb_ecx = 1,
+ gdb_edx = 2,
+ gdb_ebx = 3,
+ gdb_esp = 4,
+ gdb_ebp = 5,
+ gdb_esi = 6,
+ gdb_edi = 7,
+ gdb_eip = 8,
+ gdb_eflags = 9,
+ gdb_cs = 10,
+ gdb_ss = 11,
+ gdb_ds = 12,
+ gdb_es = 13,
+ gdb_fs = 14,
+ gdb_gs = 15,
+ gdb_stmm0 = 16,
+ gdb_stmm1 = 17,
+ gdb_stmm2 = 18,
+ gdb_stmm3 = 19,
+ gdb_stmm4 = 20,
+ gdb_stmm5 = 21,
+ gdb_stmm6 = 22,
+ gdb_stmm7 = 23,
+ gdb_fctrl = 24, gdb_fcw = gdb_fctrl,
+ gdb_fstat = 25, gdb_fsw = gdb_fstat,
+ gdb_ftag = 26, gdb_ftw = gdb_ftag,
+ gdb_fiseg = 27, gdb_fpu_cs = gdb_fiseg,
+ gdb_fioff = 28, gdb_ip = gdb_fioff,
+ gdb_foseg = 29, gdb_fpu_ds = gdb_foseg,
+ gdb_fooff = 30, gdb_dp = gdb_fooff,
+ gdb_fop = 31,
+ gdb_xmm0 = 32,
+ gdb_xmm1 = 33,
+ gdb_xmm2 = 34,
+ gdb_xmm3 = 35,
+ gdb_xmm4 = 36,
+ gdb_xmm5 = 37,
+ gdb_xmm6 = 38,
+ gdb_xmm7 = 39,
+ gdb_mxcsr = 40,
+ gdb_mm0 = 41,
+ gdb_mm1 = 42,
+ gdb_mm2 = 43,
+ gdb_mm3 = 44,
+ gdb_mm4 = 45,
+ gdb_mm5 = 46,
+ gdb_mm6 = 47,
+ gdb_mm7 = 48
+};
+
+RegisterContextDarwin_i386::RegisterContextDarwin_i386 (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_i386::~RegisterContextDarwin_i386()
+{
+}
+
+
+
+#define GPR_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_i386::GPR, reg))
+#define FPU_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_i386::FPU, reg) + sizeof (RegisterContextDarwin_i386::GPR))
+#define EXC_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_i386::EXC, reg) + sizeof (RegisterContextDarwin_i386::GPR) + sizeof (RegisterContextDarwin_i386::FPU))
+
+// These macros will auto define the register name, alt name, register size,
+// register offset, encoding, format and native register. This ensures that
+// the register state structures are defined correctly and have the correct
+// sizes and offsets.
+#define DEFINE_GPR(reg, alt) #reg, alt, sizeof(((RegisterContextDarwin_i386::GPR *)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_UINT(reg) #reg, NULL, sizeof(((RegisterContextDarwin_i386::FPU *)NULL)->reg), FPU_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_VECT(reg, i) #reg#i, NULL, sizeof(((RegisterContextDarwin_i386::FPU *)NULL)->reg[i].bytes), FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_##reg##i, LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i }, NULL, NULL
+
+#define DEFINE_EXC(reg) #reg, NULL, sizeof(((RegisterContextDarwin_i386::EXC *)NULL)->reg), EXC_OFFSET(reg), eEncodingUint, eFormatHex
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_i386::GPR) + sizeof (RegisterContextDarwin_i386::FPU) + sizeof (RegisterContextDarwin_i386::EXC))
+
+static RegisterInfo g_register_infos[] =
+{
+// Macro auto defines most stuff GCC DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS
+// =============================== ======================= =================== ========================= ================== ================= ========== ===============
+ { DEFINE_GPR(eax , NULL) , { gcc_eax , dwarf_eax , LLDB_INVALID_REGNUM , gdb_eax , gpr_eax }, NULL, NULL},
+ { DEFINE_GPR(ebx , NULL) , { gcc_ebx , dwarf_ebx , LLDB_INVALID_REGNUM , gdb_ebx , gpr_ebx }, NULL, NULL},
+ { DEFINE_GPR(ecx , NULL) , { gcc_ecx , dwarf_ecx , LLDB_INVALID_REGNUM , gdb_ecx , gpr_ecx }, NULL, NULL},
+ { DEFINE_GPR(edx , NULL) , { gcc_edx , dwarf_edx , LLDB_INVALID_REGNUM , gdb_edx , gpr_edx }, NULL, NULL},
+ { DEFINE_GPR(edi , NULL) , { gcc_edi , dwarf_edi , LLDB_INVALID_REGNUM , gdb_edi , gpr_edi }, NULL, NULL},
+ { DEFINE_GPR(esi , NULL) , { gcc_esi , dwarf_esi , LLDB_INVALID_REGNUM , gdb_esi , gpr_esi }, NULL, NULL},
+ { DEFINE_GPR(ebp , "fp") , { gcc_ebp , dwarf_ebp , LLDB_REGNUM_GENERIC_FP , gdb_ebp , gpr_ebp }, NULL, NULL},
+ { DEFINE_GPR(esp , "sp") , { gcc_esp , dwarf_esp , LLDB_REGNUM_GENERIC_SP , gdb_esp , gpr_esp }, NULL, NULL},
+ { DEFINE_GPR(ss , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ss , gpr_ss }, NULL, NULL},
+ { DEFINE_GPR(eflags , "flags") , { gcc_eflags , dwarf_eflags , LLDB_REGNUM_GENERIC_FLAGS , gdb_eflags , gpr_eflags }, NULL, NULL},
+ { DEFINE_GPR(eip , "pc") , { gcc_eip , dwarf_eip , LLDB_REGNUM_GENERIC_PC , gdb_eip , gpr_eip }, NULL, NULL},
+ { DEFINE_GPR(cs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_cs , gpr_cs }, NULL, NULL},
+ { DEFINE_GPR(ds , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ds , gpr_ds }, NULL, NULL},
+ { DEFINE_GPR(es , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_es , gpr_es }, NULL, NULL},
+ { DEFINE_GPR(fs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fs , gpr_fs }, NULL, NULL},
+ { DEFINE_GPR(gs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gs , gpr_gs }, NULL, NULL},
+
+ { DEFINE_FPU_UINT(fcw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fcw , fpu_fcw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fsw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fsw , fpu_fsw }, NULL, NULL},
+ { DEFINE_FPU_UINT(ftw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ftw , fpu_ftw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fop) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fop , fpu_fop }, NULL, NULL},
+ { DEFINE_FPU_UINT(ip) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ip , fpu_ip }, NULL, NULL},
+ { DEFINE_FPU_UINT(cs) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_cs , fpu_cs }, NULL, NULL},
+ { DEFINE_FPU_UINT(dp) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_dp , fpu_dp }, NULL, NULL},
+ { DEFINE_FPU_UINT(ds) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ds , fpu_ds }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_mxcsr , fpu_mxcsr }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsrmask) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, fpu_mxcsrmask}, NULL, NULL},
+ { DEFINE_FPU_VECT(stmm,0) },
+ { DEFINE_FPU_VECT(stmm,1) },
+ { DEFINE_FPU_VECT(stmm,2) },
+ { DEFINE_FPU_VECT(stmm,3) },
+ { DEFINE_FPU_VECT(stmm,4) },
+ { DEFINE_FPU_VECT(stmm,5) },
+ { DEFINE_FPU_VECT(stmm,6) },
+ { DEFINE_FPU_VECT(stmm,7) },
+ { DEFINE_FPU_VECT(xmm,0) },
+ { DEFINE_FPU_VECT(xmm,1) },
+ { DEFINE_FPU_VECT(xmm,2) },
+ { DEFINE_FPU_VECT(xmm,3) },
+ { DEFINE_FPU_VECT(xmm,4) },
+ { DEFINE_FPU_VECT(xmm,5) },
+ { DEFINE_FPU_VECT(xmm,6) },
+ { DEFINE_FPU_VECT(xmm,7) },
+
+ { DEFINE_EXC(trapno) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_trapno }, NULL, NULL},
+ { DEFINE_EXC(err) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_err }, NULL, NULL},
+ { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL}
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+void
+RegisterContextDarwin_i386::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_i386::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_i386::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_i386::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_i386::GetRegisterInfos ()
+{
+ return g_register_infos;
+}
+
+
+// General purpose registers
+static uint32_t
+g_gpr_regnums[] =
+{
+ gpr_eax,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs
+};
+
+// Floating point registers
+static uint32_t
+g_fpu_regnums[] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7
+};
+
+// Exception registers
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr
+};
+
+// 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_i386::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_i386::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Register information definitions for 32 bit i386.
+//----------------------------------------------------------------------
+int
+RegisterContextDarwin_i386::GetSetForNativeRegNum (int reg_num)
+{
+ if (reg_num < fpu_fcw)
+ return GPRRegSet;
+ else if (reg_num < exc_trapno)
+ return FPURegSet;
+ else if (reg_num < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+
+void
+RegisterContextDarwin_i386::LogGPR(Log *log, const char *title)
+{
+ if (log)
+ {
+ if (title)
+ log->Printf ("%s", title);
+ for (uint32_t i=0; i<k_num_gpr_registers; i++)
+ {
+ uint32_t reg = gpr_eax + i;
+ log->Printf("%12s = 0x%8.8x", g_register_infos[reg].name, (&gpr.eax)[reg]);
+ }
+ }
+}
+
+
+
+int
+RegisterContextDarwin_i386::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(set, Read);
+}
+
+int
+RegisterContextDarwin_i386::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(set, Read);
+}
+
+int
+RegisterContextDarwin_i386::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(set, Read);
+}
+
+int
+RegisterContextDarwin_i386::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+int
+RegisterContextDarwin_i386::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+int
+RegisterContextDarwin_i386::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+int
+RegisterContextDarwin_i386::ReadRegisterSet (uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR(force);
+ case FPURegSet: return ReadFPU(force);
+ case EXCRegSet: return ReadEXC(force);
+ default: break;
+ }
+ return -1;
+}
+
+int
+RegisterContextDarwin_i386::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();
+ default: break;
+ }
+ }
+ return -1;
+}
+
+bool
+RegisterContextDarwin_i386::ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_i386::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_eax:
+ case gpr_ebx:
+ case gpr_ecx:
+ case gpr_edx:
+ case gpr_edi:
+ case gpr_esi:
+ case gpr_ebp:
+ case gpr_esp:
+ case gpr_ss:
+ case gpr_eflags:
+ case gpr_eip:
+ case gpr_cs:
+ case gpr_ds:
+ case gpr_es:
+ case gpr_fs:
+ case gpr_gs:
+ value = (&gpr.eax)[reg - gpr_eax];
+ break;
+
+ case fpu_fcw:
+ value = fpu.fcw;
+ break;
+
+ case fpu_fsw:
+ value = fpu.fsw;
+ break;
+
+ case fpu_ftw:
+ value = fpu.ftw;
+ break;
+
+ case fpu_fop:
+ value = fpu.fop;
+ break;
+
+ case fpu_ip:
+ value = fpu.ip;
+ break;
+
+ case fpu_cs:
+ value = fpu.cs;
+ break;
+
+ case fpu_dp:
+ value = fpu.dp;
+ break;
+
+ case fpu_ds:
+ value = fpu.ds;
+ break;
+
+ case fpu_mxcsr:
+ value = fpu.mxcsr;
+ break;
+
+ case fpu_mxcsrmask:
+ value = fpu.mxcsrmask;
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ // These values don't fit into scalar types,
+ // RegisterContext::ReadRegisterBytes() must be used for these
+ // registers
+ //::memcpy (reg_value.value.vector.uint8, fpu.stmm[reg - fpu_stmm0].bytes, 10);
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ //::memcpy (reg_value.value.vector.uint8, fpu.xmm[reg - fpu_xmm0].bytes, 16);
+ return false;
+
+ case exc_trapno:
+ value = exc.trapno;
+ break;
+
+ case exc_err:
+ value = exc.err;
+ break;
+
+ case exc_faultvaddr:
+ value = exc.faultvaddr;
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+
+bool
+RegisterContextDarwin_i386::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) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_eax:
+ case gpr_ebx:
+ case gpr_ecx:
+ case gpr_edx:
+ case gpr_edi:
+ case gpr_esi:
+ case gpr_ebp:
+ case gpr_esp:
+ case gpr_ss:
+ case gpr_eflags:
+ case gpr_eip:
+ case gpr_cs:
+ case gpr_ds:
+ case gpr_es:
+ case gpr_fs:
+ case gpr_gs:
+ (&gpr.eax)[reg - gpr_eax] = value.GetAsUInt32();
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.GetAsUInt16();
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.GetAsUInt16();
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.GetAsUInt8();
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.GetAsUInt16();
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.GetAsUInt32();
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.GetAsUInt16();
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.GetAsUInt32();
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.GetAsUInt16();
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.GetAsUInt32();
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.GetAsUInt32();
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ ::memcpy (fpu.stmm[reg - fpu_stmm0].bytes, value.GetBytes(), value.GetByteSize());
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ ::memcpy (fpu.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize());
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.GetAsUInt32();
+ break;
+
+ case exc_err:
+ exc.err = value.GetAsUInt32();
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.GetAsUInt32();
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == 0;
+}
+
+bool
+RegisterContextDarwin_i386::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == 0 &&
+ ReadFPU (false) == 0 &&
+ ReadEXC (false) == 0)
+ {
+ 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_i386::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() == 0)
+ ++success_count;
+ if (WriteFPU() == 0)
+ ++success_count;
+ if (WriteEXC() == 0)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+
+uint32_t
+RegisterContextDarwin_i386::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_eip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_esp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_ebp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_eflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case dwarf_eax: return gpr_eax;
+ case dwarf_ecx: return gpr_ecx;
+ case dwarf_edx: return gpr_edx;
+ case dwarf_ebx: return gpr_ebx;
+ case dwarf_esp: return gpr_esp;
+ case dwarf_ebp: return gpr_ebp;
+ case dwarf_esi: return gpr_esi;
+ case dwarf_edi: return gpr_edi;
+ case dwarf_eip: return gpr_eip;
+ case dwarf_eflags: return gpr_eflags;
+ case dwarf_stmm0: return fpu_stmm0;
+ case dwarf_stmm1: return fpu_stmm1;
+ case dwarf_stmm2: return fpu_stmm2;
+ case dwarf_stmm3: return fpu_stmm3;
+ case dwarf_stmm4: return fpu_stmm4;
+ case dwarf_stmm5: return fpu_stmm5;
+ case dwarf_stmm6: return fpu_stmm6;
+ case dwarf_stmm7: return fpu_stmm7;
+ case dwarf_xmm0: return fpu_xmm0;
+ case dwarf_xmm1: return fpu_xmm1;
+ case dwarf_xmm2: return fpu_xmm2;
+ case dwarf_xmm3: return fpu_xmm3;
+ case dwarf_xmm4: return fpu_xmm4;
+ case dwarf_xmm5: return fpu_xmm5;
+ case dwarf_xmm6: return fpu_xmm6;
+ case dwarf_xmm7: return fpu_xmm7;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGDB)
+ {
+ switch (reg)
+ {
+ case gdb_eax : return gpr_eax;
+ case gdb_ebx : return gpr_ebx;
+ case gdb_ecx : return gpr_ecx;
+ case gdb_edx : return gpr_edx;
+ case gdb_esi : return gpr_esi;
+ case gdb_edi : return gpr_edi;
+ case gdb_ebp : return gpr_ebp;
+ case gdb_esp : return gpr_esp;
+ case gdb_eip : return gpr_eip;
+ case gdb_eflags : return gpr_eflags;
+ case gdb_cs : return gpr_cs;
+ case gdb_ss : return gpr_ss;
+ case gdb_ds : return gpr_ds;
+ case gdb_es : return gpr_es;
+ case gdb_fs : return gpr_fs;
+ case gdb_gs : return gpr_gs;
+ case gdb_stmm0 : return fpu_stmm0;
+ case gdb_stmm1 : return fpu_stmm1;
+ case gdb_stmm2 : return fpu_stmm2;
+ case gdb_stmm3 : return fpu_stmm3;
+ case gdb_stmm4 : return fpu_stmm4;
+ case gdb_stmm5 : return fpu_stmm5;
+ case gdb_stmm6 : return fpu_stmm6;
+ case gdb_stmm7 : return fpu_stmm7;
+ case gdb_fctrl : return fpu_fctrl;
+ case gdb_fstat : return fpu_fstat;
+ case gdb_ftag : return fpu_ftag;
+ case gdb_fiseg : return fpu_fiseg;
+ case gdb_fioff : return fpu_fioff;
+ case gdb_foseg : return fpu_foseg;
+ case gdb_fooff : return fpu_fooff;
+ case gdb_fop : return fpu_fop;
+ case gdb_xmm0 : return fpu_xmm0;
+ case gdb_xmm1 : return fpu_xmm1;
+ case gdb_xmm2 : return fpu_xmm2;
+ case gdb_xmm3 : return fpu_xmm3;
+ case gdb_xmm4 : return fpu_xmm4;
+ case gdb_xmm5 : return fpu_xmm5;
+ case gdb_xmm6 : return fpu_xmm6;
+ case gdb_xmm7 : return fpu_xmm7;
+ case gdb_mxcsr : return fpu_mxcsr;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+bool
+RegisterContextDarwin_i386::HardwareSingleStep (bool enable)
+{
+ if (ReadGPR(false) != 0)
+ return false;
+
+ const uint32_t trace_bit = 0x100u;
+ if (enable)
+ {
+ // If the trace bit is already set, there is nothing to do
+ if (gpr.eflags & trace_bit)
+ return true;
+ else
+ gpr.eflags |= trace_bit;
+ }
+ else
+ {
+ // If the trace bit is already cleared, there is nothing to do
+ if (gpr.eflags & trace_bit)
+ gpr.eflags &= ~trace_bit;
+ else
+ return true;
+ }
+
+ return WriteGPR() == 0;
+}
+
+
+
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h
new file mode 100644
index 000000000000..a588494f9dcf
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h
@@ -0,0 +1,269 @@
+//===-- RegisterContextDarwin_i386.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_i386_h_
+#define liblldb_RegisterContextDarwin_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+class RegisterContextDarwin_i386 : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextDarwin_i386(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_i386();
+
+ 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 bool
+ HardwareSingleStep (bool enable);
+
+ struct GPR
+ {
+ uint32_t eax;
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebp;
+ uint32_t esp;
+ uint32_t ss;
+ uint32_t eflags;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+ };
+
+ struct MMSReg
+ {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ uint32_t pad[2];
+ uint16_t fcw;
+ uint16_t fsw;
+ uint8_t ftw;
+ uint8_t pad1;
+ uint16_t fop;
+ uint32_t ip;
+ uint16_t cs;
+ uint16_t pad2;
+ uint32_t dp;
+ uint16_t ds;
+ uint16_t pad3;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[8];
+ uint8_t pad4[14*16];
+ int pad5;
+ };
+
+ struct EXC
+ {
+ uint32_t trapno;
+ uint32_t err;
+ uint32_t faultvaddr;
+ };
+
+protected:
+
+ enum
+ {
+ GPRRegSet = 1,
+ FPURegSet = 2,
+ EXCRegSet = 3
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t)
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_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];
+ 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;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == 0;
+ }
+
+ void
+ LogGPR (lldb_private::Log *log, const char *title);
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) = 0;
+
+ 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
+ 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;
+
+ 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_i386_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
new file mode 100644
index 000000000000..433782fe20c0
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
@@ -0,0 +1,1066 @@
+//===-- RegisterContextDarwin_x86_64.cpp ------------------------*- 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 <stdarg.h>
+#include <stddef.h> // offsetof
+
+// 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"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "RegisterContextDarwin_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gpr_rax = 0,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs,
+
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15,
+
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr,
+
+ k_num_registers,
+
+ // Aliases
+ fpu_fctrl = fpu_fcw,
+ fpu_fstat = fpu_fsw,
+ fpu_ftag = fpu_ftw,
+ fpu_fiseg = fpu_cs,
+ fpu_fioff = fpu_ip,
+ fpu_foseg = fpu_ds,
+ fpu_fooff = fpu_dp
+};
+
+enum gcc_dwarf_regnums
+{
+ gcc_dwarf_gpr_rax = 0,
+ gcc_dwarf_gpr_rdx,
+ gcc_dwarf_gpr_rcx,
+ gcc_dwarf_gpr_rbx,
+ gcc_dwarf_gpr_rsi,
+ gcc_dwarf_gpr_rdi,
+ gcc_dwarf_gpr_rbp,
+ gcc_dwarf_gpr_rsp,
+ gcc_dwarf_gpr_r8,
+ gcc_dwarf_gpr_r9,
+ gcc_dwarf_gpr_r10,
+ gcc_dwarf_gpr_r11,
+ gcc_dwarf_gpr_r12,
+ gcc_dwarf_gpr_r13,
+ gcc_dwarf_gpr_r14,
+ gcc_dwarf_gpr_r15,
+ gcc_dwarf_gpr_rip,
+ gcc_dwarf_fpu_xmm0,
+ gcc_dwarf_fpu_xmm1,
+ gcc_dwarf_fpu_xmm2,
+ gcc_dwarf_fpu_xmm3,
+ gcc_dwarf_fpu_xmm4,
+ gcc_dwarf_fpu_xmm5,
+ gcc_dwarf_fpu_xmm6,
+ gcc_dwarf_fpu_xmm7,
+ gcc_dwarf_fpu_xmm8,
+ gcc_dwarf_fpu_xmm9,
+ gcc_dwarf_fpu_xmm10,
+ gcc_dwarf_fpu_xmm11,
+ gcc_dwarf_fpu_xmm12,
+ gcc_dwarf_fpu_xmm13,
+ gcc_dwarf_fpu_xmm14,
+ gcc_dwarf_fpu_xmm15,
+ gcc_dwarf_fpu_stmm0,
+ gcc_dwarf_fpu_stmm1,
+ gcc_dwarf_fpu_stmm2,
+ gcc_dwarf_fpu_stmm3,
+ gcc_dwarf_fpu_stmm4,
+ gcc_dwarf_fpu_stmm5,
+ gcc_dwarf_fpu_stmm6,
+ gcc_dwarf_fpu_stmm7
+
+};
+
+enum gdb_regnums
+{
+ gdb_gpr_rax = 0,
+ gdb_gpr_rbx = 1,
+ gdb_gpr_rcx = 2,
+ gdb_gpr_rdx = 3,
+ gdb_gpr_rsi = 4,
+ gdb_gpr_rdi = 5,
+ gdb_gpr_rbp = 6,
+ gdb_gpr_rsp = 7,
+ gdb_gpr_r8 = 8,
+ gdb_gpr_r9 = 9,
+ gdb_gpr_r10 = 10,
+ gdb_gpr_r11 = 11,
+ gdb_gpr_r12 = 12,
+ gdb_gpr_r13 = 13,
+ gdb_gpr_r14 = 14,
+ gdb_gpr_r15 = 15,
+ gdb_gpr_rip = 16,
+ gdb_gpr_rflags = 17,
+ gdb_gpr_cs = 18,
+ gdb_gpr_ss = 19,
+ gdb_gpr_ds = 20,
+ gdb_gpr_es = 21,
+ gdb_gpr_fs = 22,
+ gdb_gpr_gs = 23,
+ gdb_fpu_stmm0 = 24,
+ gdb_fpu_stmm1 = 25,
+ gdb_fpu_stmm2 = 26,
+ gdb_fpu_stmm3 = 27,
+ gdb_fpu_stmm4 = 28,
+ gdb_fpu_stmm5 = 29,
+ gdb_fpu_stmm6 = 30,
+ gdb_fpu_stmm7 = 31,
+ gdb_fpu_fctrl = 32, gdb_fpu_fcw = gdb_fpu_fctrl,
+ gdb_fpu_fstat = 33, gdb_fpu_fsw = gdb_fpu_fstat,
+ gdb_fpu_ftag = 34, gdb_fpu_ftw = gdb_fpu_ftag,
+ gdb_fpu_fiseg = 35, gdb_fpu_cs = gdb_fpu_fiseg,
+ gdb_fpu_fioff = 36, gdb_fpu_ip = gdb_fpu_fioff,
+ gdb_fpu_foseg = 37, gdb_fpu_ds = gdb_fpu_foseg,
+ gdb_fpu_fooff = 38, gdb_fpu_dp = gdb_fpu_fooff,
+ gdb_fpu_fop = 39,
+ gdb_fpu_xmm0 = 40,
+ gdb_fpu_xmm1 = 41,
+ gdb_fpu_xmm2 = 42,
+ gdb_fpu_xmm3 = 43,
+ gdb_fpu_xmm4 = 44,
+ gdb_fpu_xmm5 = 45,
+ gdb_fpu_xmm6 = 46,
+ gdb_fpu_xmm7 = 47,
+ gdb_fpu_xmm8 = 48,
+ gdb_fpu_xmm9 = 49,
+ gdb_fpu_xmm10 = 50,
+ gdb_fpu_xmm11 = 51,
+ gdb_fpu_xmm12 = 52,
+ gdb_fpu_xmm13 = 53,
+ gdb_fpu_xmm14 = 54,
+ gdb_fpu_xmm15 = 55,
+ gdb_fpu_mxcsr = 56
+};
+
+RegisterContextDarwin_x86_64::RegisterContextDarwin_x86_64 (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_x86_64::~RegisterContextDarwin_x86_64()
+{
+}
+
+#define GPR_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_x86_64::GPR, reg))
+#define FPU_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_x86_64::FPU, reg) + sizeof (RegisterContextDarwin_x86_64::GPR))
+#define EXC_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_x86_64::EXC, reg) + sizeof (RegisterContextDarwin_x86_64::GPR) + sizeof (RegisterContextDarwin_x86_64::FPU))
+
+// These macros will auto define the register name, alt name, register size,
+// register offset, encoding, format and native register. This ensures that
+// the register state structures are defined correctly and have the correct
+// sizes and offsets.
+#define DEFINE_GPR(reg, alt) #reg, alt, sizeof(((RegisterContextDarwin_x86_64::GPR *)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_UINT(reg) #reg, NULL, sizeof(((RegisterContextDarwin_x86_64::FPU *)NULL)->reg), FPU_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_VECT(reg, i) #reg#i, NULL, sizeof(((RegisterContextDarwin_x86_64::FPU *)NULL)->reg[i].bytes), FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL
+#define DEFINE_EXC(reg) #reg, NULL, sizeof(((RegisterContextDarwin_x86_64::EXC *)NULL)->reg), EXC_OFFSET(reg), eEncodingUint, eFormatHex
+
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_x86_64::GPR) + sizeof (RegisterContextDarwin_x86_64::FPU) + sizeof (RegisterContextDarwin_x86_64::EXC))
+
+// General purpose registers for 64 bit
+static RegisterInfo g_register_infos[] =
+{
+// Macro auto defines most stuff GCC DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS
+// =============================== ====================== =================== ========================== ==================== =================== ========== ===============
+ { DEFINE_GPR (rax , NULL) , { gcc_dwarf_gpr_rax , gcc_dwarf_gpr_rax , LLDB_INVALID_REGNUM , gdb_gpr_rax , gpr_rax }, NULL, NULL},
+ { DEFINE_GPR (rbx , NULL) , { gcc_dwarf_gpr_rbx , gcc_dwarf_gpr_rbx , LLDB_INVALID_REGNUM , gdb_gpr_rbx , gpr_rbx }, NULL, NULL},
+ { DEFINE_GPR (rcx , NULL) , { gcc_dwarf_gpr_rcx , gcc_dwarf_gpr_rcx , LLDB_INVALID_REGNUM , gdb_gpr_rcx , gpr_rcx }, NULL, NULL},
+ { DEFINE_GPR (rdx , NULL) , { gcc_dwarf_gpr_rdx , gcc_dwarf_gpr_rdx , LLDB_INVALID_REGNUM , gdb_gpr_rdx , gpr_rdx }, NULL, NULL},
+ { DEFINE_GPR (rdi , NULL) , { gcc_dwarf_gpr_rdi , gcc_dwarf_gpr_rdi , LLDB_INVALID_REGNUM , gdb_gpr_rdi , gpr_rdi }, NULL, NULL},
+ { DEFINE_GPR (rsi , NULL) , { gcc_dwarf_gpr_rsi , gcc_dwarf_gpr_rsi , LLDB_INVALID_REGNUM , gdb_gpr_rsi , gpr_rsi }, NULL, NULL},
+ { DEFINE_GPR (rbp , "fp") , { gcc_dwarf_gpr_rbp , gcc_dwarf_gpr_rbp , LLDB_REGNUM_GENERIC_FP , gdb_gpr_rbp , gpr_rbp }, NULL, NULL},
+ { DEFINE_GPR (rsp , "sp") , { gcc_dwarf_gpr_rsp , gcc_dwarf_gpr_rsp , LLDB_REGNUM_GENERIC_SP , gdb_gpr_rsp , gpr_rsp }, NULL, NULL},
+ { DEFINE_GPR (r8 , NULL) , { gcc_dwarf_gpr_r8 , gcc_dwarf_gpr_r8 , LLDB_INVALID_REGNUM , gdb_gpr_r8 , gpr_r8 }, NULL, NULL},
+ { DEFINE_GPR (r9 , NULL) , { gcc_dwarf_gpr_r9 , gcc_dwarf_gpr_r9 , LLDB_INVALID_REGNUM , gdb_gpr_r9 , gpr_r9 }, NULL, NULL},
+ { DEFINE_GPR (r10 , NULL) , { gcc_dwarf_gpr_r10 , gcc_dwarf_gpr_r10 , LLDB_INVALID_REGNUM , gdb_gpr_r10 , gpr_r10 }, NULL, NULL},
+ { DEFINE_GPR (r11 , NULL) , { gcc_dwarf_gpr_r11 , gcc_dwarf_gpr_r11 , LLDB_INVALID_REGNUM , gdb_gpr_r11 , gpr_r11 }, NULL, NULL},
+ { DEFINE_GPR (r12 , NULL) , { gcc_dwarf_gpr_r12 , gcc_dwarf_gpr_r12 , LLDB_INVALID_REGNUM , gdb_gpr_r12 , gpr_r12 }, NULL, NULL},
+ { DEFINE_GPR (r13 , NULL) , { gcc_dwarf_gpr_r13 , gcc_dwarf_gpr_r13 , LLDB_INVALID_REGNUM , gdb_gpr_r13 , gpr_r13 }, NULL, NULL},
+ { DEFINE_GPR (r14 , NULL) , { gcc_dwarf_gpr_r14 , gcc_dwarf_gpr_r14 , LLDB_INVALID_REGNUM , gdb_gpr_r14 , gpr_r14 }, NULL, NULL},
+ { DEFINE_GPR (r15 , NULL) , { gcc_dwarf_gpr_r15 , gcc_dwarf_gpr_r15 , LLDB_INVALID_REGNUM , gdb_gpr_r15 , gpr_r15 }, NULL, NULL},
+ { DEFINE_GPR (rip , "pc") , { gcc_dwarf_gpr_rip , gcc_dwarf_gpr_rip , LLDB_REGNUM_GENERIC_PC , gdb_gpr_rip , gpr_rip }, NULL, NULL},
+ { DEFINE_GPR (rflags, "flags") , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, gdb_gpr_rflags , gpr_rflags }, NULL, NULL},
+ { DEFINE_GPR (cs , NULL) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gpr_cs , gpr_cs }, NULL, NULL},
+ { DEFINE_GPR (fs , NULL) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gpr_fs , gpr_fs }, NULL, NULL},
+ { DEFINE_GPR (gs , NULL) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gpr_gs , gpr_gs }, NULL, NULL},
+
+ { DEFINE_FPU_UINT(fcw) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_fcw , fpu_fcw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fsw) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_fsw , fpu_fsw }, NULL, NULL},
+ { DEFINE_FPU_UINT(ftw) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_ftw , fpu_ftw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fop) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_fop , fpu_fop }, NULL, NULL},
+ { DEFINE_FPU_UINT(ip) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_ip , fpu_ip }, NULL, NULL},
+ { DEFINE_FPU_UINT(cs) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_cs , fpu_cs }, NULL, NULL},
+ { DEFINE_FPU_UINT(dp) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_dp , fpu_dp }, NULL, NULL},
+ { DEFINE_FPU_UINT(ds) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_ds , fpu_ds }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsr) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_mxcsr , fpu_mxcsr }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsrmask) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, fpu_mxcsrmask }, NULL, NULL},
+ { DEFINE_FPU_VECT(stmm,0) },
+ { DEFINE_FPU_VECT(stmm,1) },
+ { DEFINE_FPU_VECT(stmm,2) },
+ { DEFINE_FPU_VECT(stmm,3) },
+ { DEFINE_FPU_VECT(stmm,4) },
+ { DEFINE_FPU_VECT(stmm,5) },
+ { DEFINE_FPU_VECT(stmm,6) },
+ { DEFINE_FPU_VECT(stmm,7) },
+ { DEFINE_FPU_VECT(xmm,0) },
+ { DEFINE_FPU_VECT(xmm,1) },
+ { DEFINE_FPU_VECT(xmm,2) },
+ { DEFINE_FPU_VECT(xmm,3) },
+ { DEFINE_FPU_VECT(xmm,4) },
+ { DEFINE_FPU_VECT(xmm,5) },
+ { DEFINE_FPU_VECT(xmm,6) },
+ { DEFINE_FPU_VECT(xmm,7) },
+ { DEFINE_FPU_VECT(xmm,8) },
+ { DEFINE_FPU_VECT(xmm,9) },
+ { DEFINE_FPU_VECT(xmm,10) },
+ { DEFINE_FPU_VECT(xmm,11) },
+ { DEFINE_FPU_VECT(xmm,12) },
+ { DEFINE_FPU_VECT(xmm,13) },
+ { DEFINE_FPU_VECT(xmm,14) },
+ { DEFINE_FPU_VECT(xmm,15) },
+
+ { DEFINE_EXC(trapno) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_trapno }, NULL, NULL},
+ { DEFINE_EXC(err) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_err }, NULL, NULL},
+ { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL}
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+
+void
+RegisterContextDarwin_x86_64::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_x86_64::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+
+const RegisterInfo *
+RegisterContextDarwin_x86_64::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_x86_64::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextDarwin_x86_64::GetRegisterInfos ()
+{
+ return g_register_infos;
+}
+
+
+
+static uint32_t g_gpr_regnums[] =
+{
+ gpr_rax,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs
+};
+
+static uint32_t g_fpu_regnums[] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15
+};
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr
+};
+
+// 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_x86_64::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_x86_64::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+int
+RegisterContextDarwin_x86_64::GetSetForNativeRegNum (int reg_num)
+{
+ if (reg_num < fpu_fcw)
+ return GPRRegSet;
+ else if (reg_num < exc_trapno)
+ return FPURegSet;
+ else if (reg_num < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+void
+RegisterContextDarwin_x86_64::LogGPR(Log *log, const char *format, ...)
+{
+ if (log)
+ {
+ if (format)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+ for (uint32_t i=0; i<k_num_gpr_registers; i++)
+ {
+ uint32_t reg = gpr_rax + i;
+ log->Printf("%12s = 0x%16.16" PRIx64, g_register_infos[reg].name, (&gpr.rax)[reg]);
+ }
+ }
+}
+
+int
+RegisterContextDarwin_x86_64::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+int
+RegisterContextDarwin_x86_64::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+int
+RegisterContextDarwin_x86_64::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+int
+RegisterContextDarwin_x86_64::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+int
+RegisterContextDarwin_x86_64::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+int
+RegisterContextDarwin_x86_64::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+int
+RegisterContextDarwin_x86_64::ReadRegisterSet(uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR (force);
+ case FPURegSet: return ReadFPU (force);
+ case EXCRegSet: return ReadEXC (force);
+ default: break;
+ }
+ return -1;
+}
+
+int
+RegisterContextDarwin_x86_64::WriteRegisterSet(uint32_t set)
+{
+ // Make sure we have a valid context to set.
+ switch (set)
+ {
+ case GPRRegSet: return WriteGPR ();
+ case FPURegSet: return WriteFPU ();
+ case EXCRegSet: return WriteEXC ();
+ default: break;
+ }
+ return -1;
+}
+
+
+bool
+RegisterContextDarwin_x86_64::ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_x86_64::GetSetForNativeRegNum (reg);
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_rax:
+ case gpr_rbx:
+ case gpr_rcx:
+ case gpr_rdx:
+ case gpr_rdi:
+ case gpr_rsi:
+ case gpr_rbp:
+ case gpr_rsp:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_r13:
+ case gpr_r14:
+ case gpr_r15:
+ case gpr_rip:
+ case gpr_rflags:
+ case gpr_cs:
+ case gpr_fs:
+ case gpr_gs:
+ value = (&gpr.rax)[reg - gpr_rax];
+ break;
+
+ case fpu_fcw:
+ value = fpu.fcw;
+ break;
+
+ case fpu_fsw:
+ value = fpu.fsw;
+ break;
+
+ case fpu_ftw:
+ value = fpu.ftw;
+ break;
+
+ case fpu_fop:
+ value = fpu.fop;
+ break;
+
+ case fpu_ip:
+ value = fpu.ip;
+ break;
+
+ case fpu_cs:
+ value = fpu.cs;
+ break;
+
+ case fpu_dp:
+ value = fpu.dp;
+ break;
+
+ case fpu_ds:
+ value = fpu.ds;
+ break;
+
+ case fpu_mxcsr:
+ value = fpu.mxcsr;
+ break;
+
+ case fpu_mxcsrmask:
+ value = fpu.mxcsrmask;
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ value.SetBytes(fpu.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder());
+ break;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ value.SetBytes(fpu.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder());
+ break;
+
+ case exc_trapno:
+ value = exc.trapno;
+ break;
+
+ case exc_err:
+ value = exc.err;
+ break;
+
+ case exc_faultvaddr:
+ value = exc.faultvaddr;
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+
+bool
+RegisterContextDarwin_x86_64::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_x86_64::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_rax:
+ case gpr_rbx:
+ case gpr_rcx:
+ case gpr_rdx:
+ case gpr_rdi:
+ case gpr_rsi:
+ case gpr_rbp:
+ case gpr_rsp:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_r13:
+ case gpr_r14:
+ case gpr_r15:
+ case gpr_rip:
+ case gpr_rflags:
+ case gpr_cs:
+ case gpr_fs:
+ case gpr_gs:
+ (&gpr.rax)[reg - gpr_rax] = value.GetAsUInt64();
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.GetAsUInt16();
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.GetAsUInt16();
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.GetAsUInt8();
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.GetAsUInt16();
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.GetAsUInt32();
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.GetAsUInt16();
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.GetAsUInt32();
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.GetAsUInt16();
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.GetAsUInt32();
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.GetAsUInt32();
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ ::memcpy (fpu.stmm[reg - fpu_stmm0].bytes, value.GetBytes(), value.GetByteSize());
+ break;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ ::memcpy (fpu.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize());
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.GetAsUInt32();
+ break;
+
+ case exc_err:
+ exc.err = value.GetAsUInt32();
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.GetAsUInt64();
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == 0;
+}
+
+bool
+RegisterContextDarwin_x86_64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == 0 &&
+ ReadFPU (false) == 0 &&
+ ReadEXC (false) == 0)
+ {
+ 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_x86_64::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() == 0)
+ ++success_count;
+ if (WriteFPU() == 0)
+ ++success_count;
+ if (WriteEXC() == 0)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+
+uint32_t
+RegisterContextDarwin_x86_64::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_rip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_rsp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_rbp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_rflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case gcc_dwarf_gpr_rax: return gpr_rax;
+ case gcc_dwarf_gpr_rdx: return gpr_rdx;
+ case gcc_dwarf_gpr_rcx: return gpr_rcx;
+ case gcc_dwarf_gpr_rbx: return gpr_rbx;
+ case gcc_dwarf_gpr_rsi: return gpr_rsi;
+ case gcc_dwarf_gpr_rdi: return gpr_rdi;
+ case gcc_dwarf_gpr_rbp: return gpr_rbp;
+ case gcc_dwarf_gpr_rsp: return gpr_rsp;
+ case gcc_dwarf_gpr_r8: return gpr_r8;
+ case gcc_dwarf_gpr_r9: return gpr_r9;
+ case gcc_dwarf_gpr_r10: return gpr_r10;
+ case gcc_dwarf_gpr_r11: return gpr_r11;
+ case gcc_dwarf_gpr_r12: return gpr_r12;
+ case gcc_dwarf_gpr_r13: return gpr_r13;
+ case gcc_dwarf_gpr_r14: return gpr_r14;
+ case gcc_dwarf_gpr_r15: return gpr_r15;
+ case gcc_dwarf_gpr_rip: return gpr_rip;
+ case gcc_dwarf_fpu_xmm0: return fpu_xmm0;
+ case gcc_dwarf_fpu_xmm1: return fpu_xmm1;
+ case gcc_dwarf_fpu_xmm2: return fpu_xmm2;
+ case gcc_dwarf_fpu_xmm3: return fpu_xmm3;
+ case gcc_dwarf_fpu_xmm4: return fpu_xmm4;
+ case gcc_dwarf_fpu_xmm5: return fpu_xmm5;
+ case gcc_dwarf_fpu_xmm6: return fpu_xmm6;
+ case gcc_dwarf_fpu_xmm7: return fpu_xmm7;
+ case gcc_dwarf_fpu_xmm8: return fpu_xmm8;
+ case gcc_dwarf_fpu_xmm9: return fpu_xmm9;
+ case gcc_dwarf_fpu_xmm10: return fpu_xmm10;
+ case gcc_dwarf_fpu_xmm11: return fpu_xmm11;
+ case gcc_dwarf_fpu_xmm12: return fpu_xmm12;
+ case gcc_dwarf_fpu_xmm13: return fpu_xmm13;
+ case gcc_dwarf_fpu_xmm14: return fpu_xmm14;
+ case gcc_dwarf_fpu_xmm15: return fpu_xmm15;
+ case gcc_dwarf_fpu_stmm0: return fpu_stmm0;
+ case gcc_dwarf_fpu_stmm1: return fpu_stmm1;
+ case gcc_dwarf_fpu_stmm2: return fpu_stmm2;
+ case gcc_dwarf_fpu_stmm3: return fpu_stmm3;
+ case gcc_dwarf_fpu_stmm4: return fpu_stmm4;
+ case gcc_dwarf_fpu_stmm5: return fpu_stmm5;
+ case gcc_dwarf_fpu_stmm6: return fpu_stmm6;
+ case gcc_dwarf_fpu_stmm7: return fpu_stmm7;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGDB)
+ {
+ switch (reg)
+ {
+ case gdb_gpr_rax : return gpr_rax;
+ case gdb_gpr_rbx : return gpr_rbx;
+ case gdb_gpr_rcx : return gpr_rcx;
+ case gdb_gpr_rdx : return gpr_rdx;
+ case gdb_gpr_rsi : return gpr_rsi;
+ case gdb_gpr_rdi : return gpr_rdi;
+ case gdb_gpr_rbp : return gpr_rbp;
+ case gdb_gpr_rsp : return gpr_rsp;
+ case gdb_gpr_r8 : return gpr_r8;
+ case gdb_gpr_r9 : return gpr_r9;
+ case gdb_gpr_r10 : return gpr_r10;
+ case gdb_gpr_r11 : return gpr_r11;
+ case gdb_gpr_r12 : return gpr_r12;
+ case gdb_gpr_r13 : return gpr_r13;
+ case gdb_gpr_r14 : return gpr_r14;
+ case gdb_gpr_r15 : return gpr_r15;
+ case gdb_gpr_rip : return gpr_rip;
+ case gdb_gpr_rflags : return gpr_rflags;
+ case gdb_gpr_cs : return gpr_cs;
+ case gdb_gpr_ss : return gpr_gs; // HACK: For now for "ss", just copy what is in "gs"
+ case gdb_gpr_ds : return gpr_gs; // HACK: For now for "ds", just copy what is in "gs"
+ case gdb_gpr_es : return gpr_gs; // HACK: For now for "es", just copy what is in "gs"
+ case gdb_gpr_fs : return gpr_fs;
+ case gdb_gpr_gs : return gpr_gs;
+ case gdb_fpu_stmm0 : return fpu_stmm0;
+ case gdb_fpu_stmm1 : return fpu_stmm1;
+ case gdb_fpu_stmm2 : return fpu_stmm2;
+ case gdb_fpu_stmm3 : return fpu_stmm3;
+ case gdb_fpu_stmm4 : return fpu_stmm4;
+ case gdb_fpu_stmm5 : return fpu_stmm5;
+ case gdb_fpu_stmm6 : return fpu_stmm6;
+ case gdb_fpu_stmm7 : return fpu_stmm7;
+ case gdb_fpu_fctrl : return fpu_fctrl;
+ case gdb_fpu_fstat : return fpu_fstat;
+ case gdb_fpu_ftag : return fpu_ftag;
+ case gdb_fpu_fiseg : return fpu_fiseg;
+ case gdb_fpu_fioff : return fpu_fioff;
+ case gdb_fpu_foseg : return fpu_foseg;
+ case gdb_fpu_fooff : return fpu_fooff;
+ case gdb_fpu_fop : return fpu_fop;
+ case gdb_fpu_xmm0 : return fpu_xmm0;
+ case gdb_fpu_xmm1 : return fpu_xmm1;
+ case gdb_fpu_xmm2 : return fpu_xmm2;
+ case gdb_fpu_xmm3 : return fpu_xmm3;
+ case gdb_fpu_xmm4 : return fpu_xmm4;
+ case gdb_fpu_xmm5 : return fpu_xmm5;
+ case gdb_fpu_xmm6 : return fpu_xmm6;
+ case gdb_fpu_xmm7 : return fpu_xmm7;
+ case gdb_fpu_xmm8 : return fpu_xmm8;
+ case gdb_fpu_xmm9 : return fpu_xmm9;
+ case gdb_fpu_xmm10 : return fpu_xmm10;
+ case gdb_fpu_xmm11 : return fpu_xmm11;
+ case gdb_fpu_xmm12 : return fpu_xmm12;
+ case gdb_fpu_xmm13 : return fpu_xmm13;
+ case gdb_fpu_xmm14 : return fpu_xmm14;
+ case gdb_fpu_xmm15 : return fpu_xmm15;
+ case gdb_fpu_mxcsr : return fpu_mxcsr;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+bool
+RegisterContextDarwin_x86_64::HardwareSingleStep (bool enable)
+{
+ if (ReadGPR(true) != 0)
+ return false;
+
+ const uint64_t trace_bit = 0x100ull;
+ if (enable)
+ {
+
+ if (gpr.rflags & trace_bit)
+ return true; // trace bit is already set, there is nothing to do
+ else
+ gpr.rflags |= trace_bit;
+ }
+ else
+ {
+ if (gpr.rflags & trace_bit)
+ gpr.rflags &= ~trace_bit;
+ else
+ return true; // trace bit is clear, there is nothing to do
+ }
+
+ return WriteGPR() == 0;
+}
+
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h
new file mode 100644
index 000000000000..4b8127af997c
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h
@@ -0,0 +1,274 @@
+//===-- RegisterContextDarwin_x86_64.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_x86_64_h_
+#define liblldb_RegisterContextDarwin_x86_64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+class RegisterContextDarwin_x86_64 : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextDarwin_x86_64 (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_x86_64();
+
+ 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 bool
+ HardwareSingleStep (bool enable);
+
+ struct GPR
+ {
+ uint64_t rax;
+ uint64_t rbx;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rsp;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t rip;
+ uint64_t rflags;
+ uint64_t cs;
+ uint64_t fs;
+ uint64_t gs;
+ };
+
+ struct MMSReg
+ {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ uint32_t pad[2];
+ uint16_t fcw; // "fctrl"
+ uint16_t fsw; // "fstat"
+ uint8_t ftw; // "ftag"
+ uint8_t pad1;
+ uint16_t fop; // "fop"
+ uint32_t ip; // "fioff"
+ uint16_t cs; // "fiseg"
+ uint16_t pad2;
+ uint32_t dp; // "fooff"
+ uint16_t ds; // "foseg"
+ uint16_t pad3;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[16];
+ uint8_t pad4[6*16];
+ int pad5;
+ };
+
+ struct EXC
+ {
+ uint32_t trapno;
+ uint32_t err;
+ uint64_t faultvaddr;
+ };
+
+protected:
+
+ enum
+ {
+ GPRRegSet = 4,
+ FPURegSet = 5,
+ EXCRegSet = 6
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t)
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_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];
+ 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;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == 0;
+ }
+
+ void
+ LogGPR (lldb_private::Log *log, const char *format, ...);
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) = 0;
+
+ 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
+ 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;
+
+ 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_x86_64_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDummy.cpp b/source/Plugins/Process/Utility/RegisterContextDummy.cpp
new file mode 100644
index 000000000000..1e282ce74f2e
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDummy.cpp
@@ -0,0 +1,137 @@
+//===-- RegisterContextDummy.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/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "RegisterContextDummy.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextDummy::RegisterContextDummy (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size) :
+RegisterContext (thread, concrete_frame_idx)
+{
+ m_reg_set0.name = "General Purpose Registers";
+ m_reg_set0.short_name = "GPR";
+ m_reg_set0.num_registers = 1;
+ m_reg_set0.registers = new uint32_t(0);
+
+ m_pc_reg_info.name = "pc";
+ m_pc_reg_info.alt_name = "pc";
+ m_pc_reg_info.byte_offset = 0;
+ m_pc_reg_info.byte_size = address_byte_size;
+ m_pc_reg_info.encoding = eEncodingUint;
+ m_pc_reg_info.format = eFormatPointer;
+ m_pc_reg_info.invalidate_regs = NULL;
+ m_pc_reg_info.value_regs = NULL;
+ m_pc_reg_info.kinds[eRegisterKindGCC] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindDWARF] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ m_pc_reg_info.kinds[eRegisterKindGDB] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindLLDB] = LLDB_INVALID_REGNUM;
+}
+
+RegisterContextDummy::~RegisterContextDummy ()
+{
+ delete m_reg_set0.registers;
+ delete m_pc_reg_info.invalidate_regs;
+ delete m_pc_reg_info.value_regs;
+}
+
+void
+RegisterContextDummy::InvalidateAllRegisters () {}
+
+size_t
+RegisterContextDummy::GetRegisterCount ()
+{
+ return 1;
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextDummy::GetRegisterInfoAtIndex (size_t reg)
+{
+ if (reg)
+ return NULL;
+ return &m_pc_reg_info;
+}
+
+size_t
+RegisterContextDummy::GetRegisterSetCount ()
+{
+ return 1;
+}
+
+const lldb_private::RegisterSet *
+RegisterContextDummy::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set)
+ return NULL;
+ return &m_reg_set0;
+}
+
+bool
+RegisterContextDummy::ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+ uint32_t reg_number = reg_info->kinds[eRegisterKindGeneric];
+ if (reg_number == LLDB_REGNUM_GENERIC_PC)
+ {
+ value.SetUInt(LLDB_INVALID_ADDRESS, reg_info->byte_size);
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDummy::WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextDummy::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextDummy::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+uint32_t
+RegisterContextDummy::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC)
+ return 0;
+ return LLDB_INVALID_REGNUM;
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextDummy.h b/source/Plugins/Process/Utility/RegisterContextDummy.h
new file mode 100644
index 000000000000..ee8d5a134bbc
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDummy.h
@@ -0,0 +1,77 @@
+//===-- RegisterContextDummy.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_RegisterContextDummy_h_
+#define lldb_RegisterContextDummy_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+namespace lldb_private {
+
+class RegisterContextDummy : public lldb_private::RegisterContext
+{
+public:
+ typedef std::shared_ptr<RegisterContextDummy> SharedPtr;
+
+ RegisterContextDummy (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size);
+
+ ///
+ // pure virtual functions from the base class that we must implement
+ ///
+
+ virtual
+ ~RegisterContextDummy ();
+
+ 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 reg_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);
+
+private:
+ //------------------------------------------------------------------
+ // For RegisterContextLLDB only
+ //------------------------------------------------------------------
+
+ lldb_private::RegisterSet m_reg_set0; // register set 0 (PC only)
+ lldb_private::RegisterInfo m_pc_reg_info;
+
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextDummy);
+};
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextDummy_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
new file mode 100644
index 000000000000..1ffc30da5762
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -0,0 +1,1541 @@
+//===-- RegisterContextLLDB.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/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "RegisterContextLLDB.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextLLDB::RegisterContextLLDB
+(
+ Thread& thread,
+ const SharedPtr &next_frame,
+ SymbolContext& sym_ctx,
+ uint32_t frame_number,
+ UnwindLLDB& unwind_lldb
+) :
+ RegisterContext (thread, frame_number),
+ m_thread(thread),
+ m_fast_unwind_plan_sp (),
+ m_full_unwind_plan_sp (),
+ m_all_registers_available(false),
+ m_frame_type (-1),
+ m_cfa (LLDB_INVALID_ADDRESS),
+ m_start_pc (),
+ m_current_pc (),
+ m_current_offset (0),
+ m_current_offset_backed_up_one (0),
+ m_sym_ctx(sym_ctx),
+ m_sym_ctx_valid (false),
+ m_frame_number (frame_number),
+ m_registers(),
+ m_parent_unwind (unwind_lldb)
+{
+ m_sym_ctx.Clear(false);
+ m_sym_ctx_valid = false;
+
+ if (IsFrameZero ())
+ {
+ InitializeZerothFrame ();
+ }
+ else
+ {
+ InitializeNonZerothFrame ();
+ }
+
+ // This same code exists over in the GetFullUnwindPlanForFrame() but it may not have been executed yet
+ if (IsFrameZero()
+ || next_frame->m_frame_type == eSigtrampFrame
+ || next_frame->m_frame_type == eDebuggerFrame)
+ {
+ m_all_registers_available = true;
+ }
+}
+
+// Initialize a RegisterContextLLDB which is the first frame of a stack -- the zeroth frame or currently
+// executing frame.
+
+void
+RegisterContextLLDB::InitializeZerothFrame()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ RegisterContextSP reg_ctx_sp = m_thread.GetRegisterContext();
+
+ if (reg_ctx_sp.get() == NULL)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ addr_t current_pc = reg_ctx_sp->GetPC();
+
+ if (current_pc == LLDB_INVALID_ADDRESS)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
+ // this will strip bit zero in case we read a PC from memory or from the LR.
+ // (which would be a no-op in frame 0 where we get it from the register set,
+ // but still a good idea to make the call here for other ABIs that may exist.)
+ ABI *abi = process->GetABI().get();
+ if (abi)
+ current_pc = abi->FixCodeAddress(current_pc);
+
+ // Initialize m_current_pc, an Address object, based on current_pc, an addr_t.
+ process->GetTarget().GetSectionLoadList().ResolveLoadAddress (current_pc, m_current_pc);
+
+ // If we don't have a Module for some reason, we're not going to find symbol/function information - just
+ // stick in some reasonable defaults and hope we can unwind past this frame.
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp)
+ {
+ UnwindLogMsg ("using architectural default unwind method");
+ }
+
+ // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us.
+ if (pc_module_sp.get()
+ && (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
+ {
+ m_sym_ctx_valid = true;
+ }
+
+ AddressRange addr_range;
+ m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range);
+
+ static ConstString g_sigtramp_name ("_sigtramp");
+ if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == g_sigtramp_name) ||
+ (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == g_sigtramp_name))
+ {
+ m_frame_type = eSigtrampFrame;
+ }
+ else
+ {
+ // FIXME: Detect eDebuggerFrame here.
+ m_frame_type = eNormalFrame;
+ }
+
+ // If we were able to find a symbol/function, set addr_range to the bounds of that symbol/function.
+ // else treat the current pc value as the start_pc and record no offset.
+ if (addr_range.GetBaseAddress().IsValid())
+ {
+ m_start_pc = addr_range.GetBaseAddress();
+ if (m_current_pc.GetSection() == m_start_pc.GetSection())
+ {
+ m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
+ }
+ else if (m_current_pc.GetModule() == m_start_pc.GetModule())
+ {
+ // This means that whatever symbol we kicked up isn't really correct
+ // --- we should not cross section boundaries ... We really should NULL out
+ // the function/symbol in this case unless there is a bad assumption
+ // here due to inlined functions?
+ m_current_offset = m_current_pc.GetFileAddress() - m_start_pc.GetFileAddress();
+ }
+ m_current_offset_backed_up_one = m_current_offset;
+ }
+ else
+ {
+ m_start_pc = m_current_pc;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ }
+
+ // We've set m_frame_type and m_sym_ctx before these calls.
+
+ m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
+
+ UnwindPlan::RowSP active_row;
+ int cfa_offset = 0;
+ int row_register_kind = -1;
+ if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ if (active_row.get() && log)
+ {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg ("%s", active_row_strm.GetString().c_str());
+ }
+ }
+
+ if (!active_row.get())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ cfa_offset = active_row->GetCFAOffset ();
+ m_cfa = cfa_regval + cfa_offset;
+
+ UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset);
+ UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64 " using %s UnwindPlan",
+ (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()),
+ (uint64_t) m_cfa,
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+}
+
+// Initialize a RegisterContextLLDB for the non-zeroth frame -- rely on the RegisterContextLLDB "below" it
+// to provide things like its current pc value.
+
+void
+RegisterContextLLDB::InitializeNonZerothFrame()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (IsFrameZero ())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ if (!GetNextFrame().get() || !GetNextFrame()->IsValid())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ if (!m_thread.GetRegisterContext())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ addr_t pc;
+ if (!ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc))
+ {
+ UnwindLogMsg ("could not get pc value");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ if (log)
+ {
+ UnwindLogMsg ("pc = 0x%16.16" PRIx64, pc);
+ addr_t reg_val;
+ if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val))
+ UnwindLogMsg ("fp = 0x%16.16" PRIx64, reg_val);
+ if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val))
+ UnwindLogMsg ("sp = 0x%16.16" PRIx64, reg_val);
+ }
+
+ // A pc of 0x0 means it's the end of the stack crawl
+ if (pc == 0)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
+ // this will strip bit zero in case we read a PC from memory or from the LR.
+ ABI *abi = process->GetABI().get();
+ if (abi)
+ pc = abi->FixCodeAddress(pc);
+
+ process->GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, m_current_pc);
+
+ // If we don't have a Module for some reason, we're not going to find symbol/function information - just
+ // stick in some reasonable defaults and hope we can unwind past this frame.
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp)
+ {
+ UnwindLogMsg ("using architectural default unwind method");
+
+ // Test the pc value to see if we know it's in an unmapped/non-executable region of memory.
+ uint32_t permissions;
+ if (process->GetLoadAddressPermissions(pc, permissions)
+ && (permissions & ePermissionsExecutable) == 0)
+ {
+ // If this is the second frame off the stack, we may have unwound the first frame
+ // incorrectly. But using the architecture default unwind plan may get us back on
+ // track -- albeit possibly skipping a real frame. Give this frame a clearly-invalid
+ // pc and see if we can get any further.
+ if (GetNextFrame().get() && GetNextFrame()->IsValid() && GetNextFrame()->IsFrameZero())
+ {
+ UnwindLogMsg ("had a pc of 0x%" PRIx64 " which is not in executable memory but on frame 1 -- allowing it once.",
+ (uint64_t) pc);
+ m_frame_type = eSkipFrame;
+ }
+ else
+ {
+ // anywhere other than the second frame, a non-executable pc means we're off in the weeds -- stop now.
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+
+ if (abi)
+ {
+ m_fast_unwind_plan_sp.reset ();
+ m_full_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateDefaultUnwindPlan(*m_full_unwind_plan_sp);
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ m_all_registers_available = false;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ int row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0);
+ if (row.get())
+ {
+ uint32_t cfa_regnum = row->GetCFARegister();
+ int cfa_offset = row->GetCFAOffset();
+ if (!ReadGPRValue (row_register_kind, cfa_regnum, cfa_regval))
+ {
+ UnwindLogMsg ("failed to get cfa value");
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ return;
+ }
+ m_cfa = cfa_regval + cfa_offset;
+
+ // A couple of sanity checks..
+ if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
+ {
+ UnwindLogMsg ("could not find a valid cfa address");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ // cfa_regval should point into the stack memory; if we can query memory region permissions,
+ // see if the memory is allocated & readable.
+ if (process->GetLoadAddressPermissions(cfa_regval, permissions)
+ && (permissions & ePermissionsReadable) == 0)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+ else
+ {
+ UnwindLogMsg ("could not find a row for function offset zero");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ UnwindLogMsg ("initialized frame cfa is 0x%" PRIx64, (uint64_t) m_cfa);
+ return;
+ }
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us.
+ if ((pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
+ {
+ m_sym_ctx_valid = true;
+ }
+
+ AddressRange addr_range;
+ if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range))
+ {
+ m_sym_ctx_valid = false;
+ }
+
+ bool decr_pc_and_recompute_addr_range = false;
+
+ // If the symbol lookup failed...
+ if (m_sym_ctx_valid == false)
+ decr_pc_and_recompute_addr_range = true;
+
+ // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp),
+ // and our "current" pc is the start of a function...
+ if (m_sym_ctx_valid
+ && GetNextFrame()->m_frame_type != eSigtrampFrame
+ && GetNextFrame()->m_frame_type != eDebuggerFrame
+ && addr_range.GetBaseAddress().IsValid()
+ && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()
+ && addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset())
+ {
+ decr_pc_and_recompute_addr_range = true;
+ }
+
+ // We need to back up the pc by 1 byte and re-search for the Symbol to handle the case where the "saved pc"
+ // value is pointing to the next function, e.g. if a function ends with a CALL instruction.
+ // FIXME this may need to be an architectural-dependent behavior; if so we'll need to add a member function
+ // to the ABI plugin and consult that.
+ if (decr_pc_and_recompute_addr_range)
+ {
+ Address temporary_pc(m_current_pc);
+ temporary_pc.SetOffset(m_current_pc.GetOffset() - 1);
+ m_sym_ctx.Clear(false);
+ m_sym_ctx_valid = false;
+ if ((pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
+ {
+ m_sym_ctx_valid = true;
+ }
+ if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range))
+ {
+ m_sym_ctx_valid = false;
+ }
+ }
+
+ // If we were able to find a symbol/function, set addr_range_ptr to the bounds of that symbol/function.
+ // else treat the current pc value as the start_pc and record no offset.
+ if (addr_range.GetBaseAddress().IsValid())
+ {
+ m_start_pc = addr_range.GetBaseAddress();
+ m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
+ m_current_offset_backed_up_one = m_current_offset;
+ if (decr_pc_and_recompute_addr_range && m_current_offset_backed_up_one > 0)
+ {
+ m_current_offset_backed_up_one--;
+ if (m_sym_ctx_valid)
+ m_current_pc.SetOffset(m_current_pc.GetOffset() - 1);
+ }
+ }
+ else
+ {
+ m_start_pc = m_current_pc;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ }
+
+ static ConstString sigtramp_name ("_sigtramp");
+ if ((m_sym_ctx.function && m_sym_ctx.function->GetMangled().GetMangledName() == sigtramp_name)
+ || (m_sym_ctx.symbol && m_sym_ctx.symbol->GetMangled().GetMangledName() == sigtramp_name))
+ {
+ m_frame_type = eSigtrampFrame;
+ }
+ else
+ {
+ // FIXME: Detect eDebuggerFrame here.
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ }
+
+ // We've set m_frame_type and m_sym_ctx before this call.
+ m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
+
+ UnwindPlan::RowSP active_row;
+ int cfa_offset = 0;
+ int row_register_kind = -1;
+
+ // Try to get by with just the fast UnwindPlan if possible - the full UnwindPlan may be expensive to get
+ // (e.g. if we have to parse the entire eh_frame section of an ObjectFile for the first time.)
+
+ if (m_fast_unwind_plan_sp && m_fast_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ row_register_kind = m_fast_unwind_plan_sp->GetRegisterKind ();
+ if (active_row.get() && log)
+ {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_fast_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str());
+ }
+ }
+ else
+ {
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
+ if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ if (active_row.get() && log)
+ {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str());
+ }
+ }
+ }
+
+ if (!active_row.get())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
+ {
+ UnwindLogMsg ("failed to get cfa reg %d/%d", row_register_kind, active_row->GetCFARegister());
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ cfa_offset = active_row->GetCFAOffset ();
+ m_cfa = cfa_regval + cfa_offset;
+
+ UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset);
+
+ // A couple of sanity checks..
+ if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
+ {
+ UnwindLogMsg ("could not find a valid cfa address");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ // If we have a bad stack setup, we can get the same CFA value multiple times -- or even
+ // more devious, we can actually oscillate between two CFA values. Detect that here and
+ // break out to avoid a possible infinite loop in lldb trying to unwind the stack.
+ addr_t next_frame_cfa;
+ addr_t next_next_frame_cfa = LLDB_INVALID_ADDRESS;
+ if (GetNextFrame().get() && GetNextFrame()->GetCFA(next_frame_cfa))
+ {
+ bool repeating_frames = false;
+ if (next_frame_cfa == m_cfa)
+ {
+ repeating_frames = true;
+ }
+ else
+ {
+ if (GetNextFrame()->GetNextFrame() && GetNextFrame()->GetNextFrame()->GetCFA(next_next_frame_cfa)
+ && next_next_frame_cfa == m_cfa)
+ {
+ repeating_frames = true;
+ }
+ }
+ if (repeating_frames && abi->FunctionCallsChangeCFA())
+ {
+ UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+
+ UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64,
+ (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()), (uint64_t) m_cfa);
+}
+
+
+bool
+RegisterContextLLDB::IsFrameZero () const
+{
+ return m_frame_number == 0;
+}
+
+
+// Find a fast unwind plan for this frame, if possible.
+//
+// On entry to this method,
+//
+// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct,
+// 2. m_sym_ctx should already be filled in, and
+// 3. m_current_pc should have the current pc value for this frame
+// 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
+
+UnwindPlanSP
+RegisterContextLLDB::GetFastUnwindPlanForFrame ()
+{
+ UnwindPlanSP unwind_plan_sp;
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+
+ if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL)
+ return unwind_plan_sp;
+
+ if (IsFrameZero ())
+ return unwind_plan_sp;
+
+ FuncUnwindersSP func_unwinders_sp (pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx));
+ if (!func_unwinders_sp)
+ return unwind_plan_sp;
+
+ // If we're in _sigtramp(), unwinding past this frame requires special knowledge.
+ if (m_frame_type == eSigtrampFrame || m_frame_type == eDebuggerFrame)
+ return unwind_plan_sp;
+
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread);
+ if (unwind_plan_sp)
+ {
+ if (unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log && log->GetVerbose())
+ {
+ if (m_fast_unwind_plan_sp)
+ UnwindLogMsgVerbose ("frame, and has a fast UnwindPlan");
+ else
+ UnwindLogMsgVerbose ("frame");
+ }
+ m_frame_type = eNormalFrame;
+ return unwind_plan_sp;
+ }
+ else
+ {
+ unwind_plan_sp.reset();
+ }
+ }
+ return unwind_plan_sp;
+}
+
+// On entry to this method,
+//
+// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct,
+// 2. m_sym_ctx should already be filled in, and
+// 3. m_current_pc should have the current pc value for this frame
+// 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
+
+UnwindPlanSP
+RegisterContextLLDB::GetFullUnwindPlanForFrame ()
+{
+ UnwindPlanSP unwind_plan_sp;
+ UnwindPlanSP arch_default_unwind_plan_sp;
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ ABI *abi = process ? process->GetABI().get() : NULL;
+ if (abi)
+ {
+ arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp);
+ }
+
+ bool behaves_like_zeroth_frame = false;
+ if (IsFrameZero ()
+ || GetNextFrame()->m_frame_type == eSigtrampFrame
+ || GetNextFrame()->m_frame_type == eDebuggerFrame)
+ {
+ behaves_like_zeroth_frame = true;
+ // If this frame behaves like a 0th frame (currently executing or
+ // interrupted asynchronously), all registers can be retrieved.
+ m_all_registers_available = true;
+ }
+
+ // If we've done a jmp 0x0 / bl 0x0 (called through a null function pointer) so the pc is 0x0
+ // in the zeroth frame, we need to use the "unwind at first instruction" arch default UnwindPlan
+ // Also, if this Process can report on memory region attributes, any non-executable region means
+ // we jumped through a bad function pointer - handle the same way as 0x0.
+ // Note, if the symbol context has a function for the symbol, then we don't need to do this check.
+
+ if ((!m_sym_ctx_valid || m_sym_ctx.function == NULL) && behaves_like_zeroth_frame && m_current_pc.IsValid())
+ {
+ uint32_t permissions;
+ addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr());
+ if (current_pc_addr == 0
+ || (process->GetLoadAddressPermissions(current_pc_addr, permissions)
+ && (permissions & ePermissionsExecutable) == 0))
+ {
+ unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp);
+ m_frame_type = eNormalFrame;
+ return unwind_plan_sp;
+ }
+ }
+
+ // No Module for the current pc, try using the architecture default unwind.
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL)
+ {
+ m_frame_type = eNormalFrame;
+ return arch_default_unwind_plan_sp;
+ }
+
+ FuncUnwindersSP func_unwinders_sp;
+ if (m_sym_ctx_valid)
+ {
+ func_unwinders_sp = pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
+ }
+
+ // No FuncUnwinders available for this pc (i.e. a stripped function symbol and -fomit-frame-pointer).
+ // Try using the eh_frame information relative to the current PC,
+ // and finally fall back on the architectural default unwind.
+ if (!func_unwinders_sp)
+ {
+ DWARFCallFrameInfo *eh_frame = pc_module_sp && pc_module_sp->GetObjectFile() ?
+ pc_module_sp->GetObjectFile()->GetUnwindTable().GetEHFrameInfo() : nullptr;
+
+ m_frame_type = eNormalFrame;
+ if (eh_frame && m_current_pc.IsValid())
+ {
+ unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ // Even with -fomit-frame-pointer, we can try eh_frame to get back on track.
+ if (eh_frame->GetUnwindPlan (m_current_pc, *unwind_plan_sp))
+ return unwind_plan_sp;
+ else
+ unwind_plan_sp.reset();
+ }
+ return arch_default_unwind_plan_sp;
+ }
+
+ // If we're in _sigtramp(), unwinding past this frame requires special knowledge. On Mac OS X this knowledge
+ // is properly encoded in the eh_frame section, so prefer that if available.
+ // On other platforms we may need to provide a platform-specific UnwindPlan which encodes the details of
+ // how to unwind out of sigtramp.
+ if (m_frame_type == eSigtrampFrame)
+ {
+ m_fast_unwind_plan_sp.reset();
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ return unwind_plan_sp;
+ }
+
+ // Ask the DynamicLoader if the eh_frame CFI should be trusted in this frame even when it's frame zero
+ // This comes up if we have hand-written functions in a Module and hand-written eh_frame. The assembly
+ // instruction inspection may fail and the eh_frame CFI were probably written with some care to do the
+ // right thing. It'd be nice if there was a way to ask the eh_frame directly if it is asynchronous
+ // (can be trusted at every instruction point) or synchronous (the normal case - only at call sites).
+ // But there is not.
+ if (process && process->GetDynamicLoader() && process->GetDynamicLoader()->AlwaysRelyOnEHUnwindInfo (m_sym_ctx))
+ {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan because the DynamicLoader suggested we prefer it",
+ unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+ }
+
+ // Typically the NonCallSite UnwindPlan is the unwind created by inspecting the assembly language instructions
+ if (behaves_like_zeroth_frame)
+ {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+ }
+
+ // Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+
+ // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've
+ // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible.
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+
+ // If nothing else, use the architectural default UnwindPlan and hope that does the job.
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", arch_default_unwind_plan_sp->GetSourceName().GetCString());
+ return arch_default_unwind_plan_sp;
+}
+
+
+void
+RegisterContextLLDB::InvalidateAllRegisters ()
+{
+ m_frame_type = eNotAValidFrame;
+}
+
+size_t
+RegisterContextLLDB::GetRegisterCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterCount();
+}
+
+const RegisterInfo *
+RegisterContextLLDB::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex (reg);
+}
+
+size_t
+RegisterContextLLDB::GetRegisterSetCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterSetCount ();
+}
+
+const RegisterSet *
+RegisterContextLLDB::GetRegisterSet (size_t reg_set)
+{
+ return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
+}
+
+uint32_t
+RegisterContextLLDB::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
+bool
+RegisterContextLLDB::ReadRegisterValueFromRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+ bool success = false;
+
+ switch (regloc.type)
+ {
+ case UnwindLLDB::RegisterLocation::eRegisterInRegister:
+ {
+ const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
+
+ if (!other_reg_info)
+ return false;
+
+ if (IsFrameZero ())
+ {
+ success = m_thread.GetRegisterContext()->ReadRegister (other_reg_info, value);
+ }
+ else
+ {
+ success = GetNextFrame()->ReadRegister (other_reg_info, value);
+ }
+ }
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
+ success = value.SetUInt (regloc.location.inferred_value, reg_info->byte_size);
+ break;
+
+ case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
+ assert ("FIXME debugger inferior function call unwind");
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation:
+ {
+ Error error (ReadRegisterValueFromMemory(reg_info,
+ regloc.location.target_memory_location,
+ reg_info->byte_size,
+ value));
+ success = error.Success();
+ }
+ break;
+ default:
+ assert ("Unknown RegisterLocation type.");
+ break;
+ }
+ return success;
+}
+
+bool
+RegisterContextLLDB::WriteRegisterValueToRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+
+ bool success = false;
+
+ switch (regloc.type)
+ {
+ case UnwindLLDB::RegisterLocation::eRegisterInRegister:
+ {
+ const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
+ if (IsFrameZero ())
+ {
+ success = m_thread.GetRegisterContext()->WriteRegister (other_reg_info, value);
+ }
+ else
+ {
+ success = GetNextFrame()->WriteRegister (other_reg_info, value);
+ }
+ }
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
+ case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
+ assert ("FIXME debugger inferior function call unwind");
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation:
+ {
+ Error error (WriteRegisterValueToMemory (reg_info,
+ regloc.location.target_memory_location,
+ reg_info->byte_size,
+ value));
+ success = error.Success();
+ }
+ break;
+ default:
+ assert ("Unknown RegisterLocation type.");
+ break;
+ }
+ return success;
+}
+
+
+bool
+RegisterContextLLDB::IsValid () const
+{
+ return m_frame_type != eNotAValidFrame;
+}
+
+// A skip frame is a bogus frame on the stack -- but one where we're likely to find a real frame farther
+// up the stack if we keep looking. It's always the second frame in an unwind (i.e. the first frame after
+// frame zero) where unwinding can be the trickiest. Ideally we'll mark up this frame in some way so the
+// user knows we're displaying bad data and we may have skipped one frame of their real program in the
+// process of getting back on track.
+
+bool
+RegisterContextLLDB::IsSkipFrame () const
+{
+ return m_frame_type == eSkipFrame;
+}
+
+// Answer the question: Where did THIS frame save the CALLER frame ("previous" frame)'s register value?
+
+enum UnwindLLDB::RegisterSearchResult
+RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc)
+{
+ // Have we already found this register location?
+ if (!m_registers.empty())
+ {
+ std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation>::const_iterator iterator;
+ iterator = m_registers.find (lldb_regnum);
+ if (iterator != m_registers.end())
+ {
+ regloc = iterator->second;
+ UnwindLogMsg ("supplying caller's saved reg %d's location, cached", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+
+ uint32_t sp_regnum = LLDB_INVALID_REGNUM;
+ uint32_t pc_regnum = LLDB_INVALID_REGNUM;
+ m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, eRegisterKindLLDB, sp_regnum);
+ m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, eRegisterKindLLDB, pc_regnum);
+
+ // Are we looking for the CALLER's stack pointer? The stack pointer is defined to be the same as THIS frame's
+ // CFA so just return the CFA value. This is true on x86-32/x86-64 at least.
+ if (sp_regnum != LLDB_INVALID_REGNUM && sp_regnum == lldb_regnum)
+ {
+ // make sure we won't lose precision copying an addr_t (m_cfa) into a uint64_t (.inferred_value)
+ assert (sizeof (addr_t) <= sizeof (uint64_t));
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = m_cfa;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's stack pointer (%d) value, computed from CFA", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ // Look through the available UnwindPlans for the register location.
+
+ UnwindPlan::Row::RegisterLocation unwindplan_regloc;
+ bool have_unwindplan_regloc = false;
+ RegisterKind unwindplan_registerkind = (RegisterKind)-1;
+
+ if (m_fast_unwind_plan_sp)
+ {
+ UnwindPlan::RowSP active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind ();
+ uint32_t row_regnum;
+ if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
+ {
+ UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
+ lldb_regnum, (int) unwindplan_registerkind);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
+ {
+ UnwindLogMsg ("supplying caller's saved reg %d's location using FastUnwindPlan", lldb_regnum);
+ have_unwindplan_regloc = true;
+ }
+ }
+
+ if (!have_unwindplan_regloc)
+ {
+ // m_full_unwind_plan_sp being NULL means that we haven't tried to find a full UnwindPlan yet
+ if (!m_full_unwind_plan_sp)
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
+
+ if (m_full_unwind_plan_sp)
+ {
+ UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind ();
+ uint32_t row_regnum;
+ bool row_register_rewritten_to_return_address_reg = false;
+
+ // If we're fetching the saved pc and this UnwindPlan defines a ReturnAddress register (e.g. lr on arm),
+ // look for the return address register number in the UnwindPlan's row.
+ if (lldb_regnum == pc_regnum && m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM)
+ {
+ row_regnum = m_full_unwind_plan_sp->GetReturnAddressRegister();
+ row_register_rewritten_to_return_address_reg = true;
+ UnwindLogMsg ("requested caller's saved PC but this UnwindPlan uses a RA reg; getting reg %d instead",
+ row_regnum);
+ }
+ else
+ {
+ if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
+ {
+ if (unwindplan_registerkind == eRegisterKindGeneric)
+ UnwindLogMsg ("could not convert lldb regnum %d into eRegisterKindGeneric reg numbering scheme", lldb_regnum);
+ else
+ UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
+ lldb_regnum, (int) unwindplan_registerkind);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ }
+
+ if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
+ {
+ have_unwindplan_regloc = true;
+ UnwindLogMsg ("supplying caller's saved reg %d's location using %s UnwindPlan", lldb_regnum,
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+ }
+
+ // This is frame 0 and we're retrieving the PC and it's saved in a Return Address register and
+ // it hasn't been saved anywhere yet -- that is, it's still live in the actual register.
+ // Handle this specially.
+
+ if (have_unwindplan_regloc == false
+ && row_register_rewritten_to_return_address_reg == true
+ && IsFrameZero()
+ && row_regnum != LLDB_INVALID_REGNUM)
+ {
+ uint32_t ra_regnum_in_lldb_reg_numbering;
+ if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, row_regnum, eRegisterKindLLDB, ra_regnum_in_lldb_reg_numbering))
+ {
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ new_regloc.location.register_number = ra_regnum_in_lldb_reg_numbering;
+ m_registers[lldb_regnum] = new_regloc;
+ regloc = new_regloc;
+ UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0, saved in %d", lldb_regnum, ra_regnum_in_lldb_reg_numbering);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+
+ // If this architecture stores the return address in a register (it defines a Return Address register)
+ // and we're on a non-zero stack frame and the Full UnwindPlan says that the pc is stored in the
+ // RA registers (e.g. lr on arm), then we know that the full unwindplan is not trustworthy -- this
+ // is an impossible situation and the instruction emulation code has likely been misled.
+ // If this stack frame meets those criteria, we need to throw away the Full UnwindPlan that the
+ // instruction emulation came up with and fall back to the architecture's Default UnwindPlan so
+ // the stack walk can get past this point.
+
+ // Special note: If the Full UnwindPlan was generated from the compiler, don't second-guess it
+ // when we're at a call site location.
+
+ // arch_default_ra_regnum is the return address register # in the Full UnwindPlan register numbering
+ uint32_t arch_default_ra_regnum = LLDB_INVALID_REGNUM;
+ if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, unwindplan_registerkind, arch_default_ra_regnum)
+ && arch_default_ra_regnum != LLDB_INVALID_REGNUM
+ && pc_regnum != LLDB_INVALID_REGNUM
+ && pc_regnum == lldb_regnum
+ && unwindplan_regloc.IsInOtherRegister()
+ && unwindplan_regloc.GetRegisterNumber() == arch_default_ra_regnum
+ && m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes
+ && !m_all_registers_available)
+ {
+ UnwindLogMsg ("%s UnwindPlan tried to restore the pc from the link register but this is a non-zero frame",
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+
+ // Throw away the full unwindplan; install the arch default unwindplan
+ InvalidateFullUnwindPlan();
+
+ // Now re-fetch the pc value we're searching for
+ uint32_t arch_default_pc_reg = LLDB_INVALID_REGNUM;
+ UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, m_full_unwind_plan_sp->GetRegisterKind(), arch_default_pc_reg)
+ && arch_default_pc_reg != LLDB_INVALID_REGNUM
+ && active_row
+ && active_row->GetRegisterInfo (arch_default_pc_reg, unwindplan_regloc))
+ {
+ have_unwindplan_regloc = true;
+ }
+ else
+ {
+ have_unwindplan_regloc = false;
+ }
+ }
+ }
+ }
+
+
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (have_unwindplan_regloc == false)
+ {
+ // 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.
+ ABI *abi = process ? process->GetABI().get() : NULL;
+ if (abi)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
+ if (reg_info && abi->RegisterIsVolatile (reg_info))
+ {
+ UnwindLogMsg ("did not supply reg location for %d because it is volatile", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile;
+ }
+ }
+
+ if (IsFrameZero ())
+ {
+ // This is frame 0 - we should return the actual live register context value
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ new_regloc.location.register_number = lldb_regnum;
+ m_registers[lldb_regnum] = new_regloc;
+ regloc = new_regloc;
+ UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ else
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ // unwindplan_regloc has valid contents about where to retrieve the register
+ if (unwindplan_regloc.IsUnspecified())
+ {
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterNotSaved;
+ m_registers[lldb_regnum] = new_regloc;
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ if (unwindplan_regloc.IsSame())
+ {
+ if (IsFrameZero ())
+ {
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ else
+ {
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ }
+
+ if (unwindplan_regloc.IsCFAPlusOffset())
+ {
+ int offset = unwindplan_regloc.GetOffset();
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = m_cfa + offset;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsAtCFAPlusOffset())
+ {
+ int offset = unwindplan_regloc.GetOffset();
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
+ regloc.location.target_memory_location = m_cfa + offset;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsInOtherRegister())
+ {
+ uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber();
+ uint32_t row_regnum_in_lldb;
+ if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, unwindplan_regnum, eRegisterKindLLDB, row_regnum_in_lldb))
+ {
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ regloc.location.register_number = row_regnum_in_lldb;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's register %d, saved in register %d", lldb_regnum, row_regnum_in_lldb);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsDWARFExpression() || unwindplan_regloc.IsAtDWARFExpression())
+ {
+ DataExtractor dwarfdata (unwindplan_regloc.GetDWARFExpressionBytes(),
+ unwindplan_regloc.GetDWARFExpressionLength(),
+ process->GetByteOrder(), process->GetAddressByteSize());
+ DWARFExpression dwarfexpr (dwarfdata, 0, unwindplan_regloc.GetDWARFExpressionLength());
+ dwarfexpr.SetRegisterKind (unwindplan_registerkind);
+ Value result;
+ Error error;
+ if (dwarfexpr.Evaluate (&exe_ctx, NULL, NULL, this, 0, NULL, result, &error))
+ {
+ addr_t val;
+ val = result.GetScalar().ULongLong();
+ if (unwindplan_regloc.IsDWARFExpression())
+ {
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = val;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsDWARFExpression)", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ else
+ {
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
+ regloc.location.target_memory_location = val;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsAtDWARFExpression)", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+ UnwindLogMsg ("tried to use IsDWARFExpression or IsAtDWARFExpression for reg %d but failed", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+
+ // FIXME UnwindPlan::Row types atDWARFExpression and isDWARFExpression are unsupported.
+
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+}
+
+// If the Full unwindplan has been determined to be incorrect, this method will
+// replace it with the architecture's default unwindplna, if one is defined.
+// It will also find the FuncUnwinders object for this function and replace the
+// Full unwind method for the function there so we don't use the errant Full unwindplan
+// again in the future of this debug session.
+// We're most likely doing this because the Full unwindplan was generated by assembly
+// instruction profiling and the profiler got something wrong.
+
+void
+RegisterContextLLDB::InvalidateFullUnwindPlan ()
+{
+ UnwindPlan::Row::RegisterLocation unwindplan_regloc;
+ ExecutionContext exe_ctx (m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ ABI *abi = process ? process->GetABI().get() : NULL;
+ if (abi)
+ {
+ UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp;
+ UnwindPlanSP arch_default_unwind_plan_sp;
+ arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp);
+ if (arch_default_unwind_plan_sp)
+ {
+ UnwindPlan::RowSP active_row = arch_default_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+
+ if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM)
+ {
+ FuncUnwindersSP func_unwinders_sp;
+ if (m_sym_ctx_valid && m_current_pc.IsValid() && m_current_pc.GetModule())
+ {
+ func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
+ if (func_unwinders_sp)
+ {
+ func_unwinders_sp->InvalidateNonCallSiteUnwindPlan (m_thread);
+ }
+ }
+ m_registers.clear();
+ m_full_unwind_plan_sp = arch_default_unwind_plan_sp;
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ if (ReadGPRValue (arch_default_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval))
+ {
+ m_cfa = cfa_regval + active_row->GetCFAOffset ();
+ }
+
+ UnwindLogMsg ("full unwind plan '%s' has been replaced by architecture default unwind plan '%s' for this function from now on.",
+ original_full_unwind_plan_sp->GetSourceName().GetCString(), arch_default_unwind_plan_sp->GetSourceName().GetCString());
+ }
+ }
+ }
+}
+
+// Retrieve a general purpose register value for THIS frame, as saved by the NEXT frame, i.e. the frame that
+// this frame called. e.g.
+//
+// foo () { }
+// bar () { foo (); }
+// main () { bar (); }
+//
+// stopped in foo() so
+// frame 0 - foo
+// frame 1 - bar
+// frame 2 - main
+// and this RegisterContext is for frame 1 (bar) - if we want to get the pc value for frame 1, we need to ask
+// where frame 0 (the "next" frame) saved that and retrieve the value.
+
+bool
+RegisterContextLLDB::ReadGPRValue (int register_kind, uint32_t regnum, addr_t &value)
+{
+ if (!IsValid())
+ return false;
+
+ uint32_t lldb_regnum;
+ if (register_kind == eRegisterKindLLDB)
+ {
+ lldb_regnum = regnum;
+ }
+ else if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindLLDB, lldb_regnum))
+ {
+ return false;
+ }
+
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
+ RegisterValue reg_value;
+ // if this is frame 0 (currently executing frame), get the requested reg contents from the actual thread registers
+ if (IsFrameZero ())
+ {
+ if (m_thread.GetRegisterContext()->ReadRegister (reg_info, reg_value))
+ {
+ value = reg_value.GetAsUInt64();
+ return true;
+ }
+ return false;
+ }
+
+ bool pc_register = false;
+ uint32_t generic_regnum;
+ if (register_kind == eRegisterKindGeneric && regnum == LLDB_REGNUM_GENERIC_PC)
+ {
+ pc_register = true;
+ }
+ else if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindGeneric, generic_regnum)
+ && generic_regnum == LLDB_REGNUM_GENERIC_PC)
+ {
+ pc_register = true;
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, pc_register))
+ {
+ return false;
+ }
+ if (ReadRegisterValueFromRegisterLocation (regloc, reg_info, reg_value))
+ {
+ value = reg_value.GetAsUInt64();
+ return true;
+ }
+ return false;
+}
+
+// Find the value of a register in THIS frame
+
+bool
+RegisterContextLLDB::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+
+ const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
+ UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum);
+
+ // If this is the 0th frame, hand this over to the live register context
+ if (IsFrameZero ())
+ {
+ UnwindLogMsgVerbose ("passing along to the live register context for reg %d", lldb_regnum);
+ return m_thread.GetRegisterContext()->ReadRegister (reg_info, value);
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ // Find out where the NEXT frame saved THIS frame's register contents
+ if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, false))
+ return false;
+
+ return ReadRegisterValueFromRegisterLocation (regloc, reg_info, value);
+}
+
+bool
+RegisterContextLLDB::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+
+ const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
+ UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum);
+
+ // If this is the 0th frame, hand this over to the live register context
+ if (IsFrameZero ())
+ {
+ UnwindLogMsgVerbose ("passing along to the live register context for reg %d", lldb_regnum);
+ return m_thread.GetRegisterContext()->WriteRegister (reg_info, value);
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ // Find out where the NEXT frame saved THIS frame's register contents
+ if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, false))
+ return false;
+
+ return WriteRegisterValueToRegisterLocation (regloc, reg_info, value);
+}
+
+// Don't need to implement this one
+bool
+RegisterContextLLDB::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+// Don't need to implement this one
+bool
+RegisterContextLLDB::WriteAllRegisterValues (const lldb::DataBufferSP& data_sp)
+{
+ return false;
+}
+
+// Retrieve the pc value for THIS from
+
+bool
+RegisterContextLLDB::GetCFA (addr_t& cfa)
+{
+ if (!IsValid())
+ {
+ return false;
+ }
+ if (m_cfa == LLDB_INVALID_ADDRESS)
+ {
+ return false;
+ }
+ cfa = m_cfa;
+ return true;
+}
+
+
+RegisterContextLLDB::SharedPtr
+RegisterContextLLDB::GetNextFrame () const
+{
+ RegisterContextLLDB::SharedPtr regctx;
+ if (m_frame_number == 0)
+ return regctx;
+ return m_parent_unwind.GetRegisterContextForFrameNum (m_frame_number - 1);
+}
+
+RegisterContextLLDB::SharedPtr
+RegisterContextLLDB::GetPrevFrame () const
+{
+ RegisterContextLLDB::SharedPtr regctx;
+ return m_parent_unwind.GetRegisterContextForFrameNum (m_frame_number + 1);
+}
+
+// Retrieve the address of the start of the function of THIS frame
+
+bool
+RegisterContextLLDB::GetStartPC (addr_t& start_pc)
+{
+ if (!IsValid())
+ return false;
+
+ if (!m_start_pc.IsValid())
+ {
+ return ReadPC (start_pc);
+ }
+ start_pc = m_start_pc.GetLoadAddress (CalculateTarget().get());
+ return true;
+}
+
+// Retrieve the current pc value for THIS frame, as saved by the NEXT frame.
+
+bool
+RegisterContextLLDB::ReadPC (addr_t& pc)
+{
+ if (!IsValid())
+ return false;
+
+ if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc))
+ {
+ // A pc value of 0 or 1 is impossible in the middle of the stack -- it indicates the end of a stack walk.
+ // On the currently executing frame (or such a frame interrupted asynchronously by sigtramp et al) this may
+ // occur if code has jumped through a NULL pointer -- we want to be able to unwind past that frame to help
+ // find the bug.
+
+ if (m_all_registers_available == false
+ && (pc == 0 || pc == 1))
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+void
+RegisterContextLLDB::UnwindLogMsg (const char *fmt, ...)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log)
+ {
+ va_list args;
+ va_start (args, fmt);
+
+ char *logmsg;
+ if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL)
+ {
+ if (logmsg)
+ free (logmsg);
+ va_end (args);
+ return;
+ }
+ va_end (args);
+
+ log->Printf ("%*sth%d/fr%u %s",
+ m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number,
+ logmsg);
+ free (logmsg);
+ }
+}
+
+void
+RegisterContextLLDB::UnwindLogMsgVerbose (const char *fmt, ...)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log && log->GetVerbose())
+ {
+ va_list args;
+ va_start (args, fmt);
+
+ char *logmsg;
+ if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL)
+ {
+ if (logmsg)
+ free (logmsg);
+ va_end (args);
+ return;
+ }
+ va_end (args);
+
+ log->Printf ("%*sth%d/fr%u %s",
+ m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number,
+ logmsg);
+ free (logmsg);
+ }
+}
+
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.h b/source/Plugins/Process/Utility/RegisterContextLLDB.h
new file mode 100644
index 000000000000..dc6d8c61fa4a
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.h
@@ -0,0 +1,212 @@
+//===-- RegisterContextLLDB.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_RegisterContextLLDB_h_
+#define lldb_RegisterContextLLDB_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "UnwindLLDB.h"
+
+namespace lldb_private {
+
+class UnwindLLDB;
+
+class RegisterContextLLDB : public lldb_private::RegisterContext
+{
+public:
+ typedef std::shared_ptr<RegisterContextLLDB> SharedPtr;
+
+ RegisterContextLLDB (lldb_private::Thread &thread,
+ const SharedPtr& next_frame,
+ lldb_private::SymbolContext& sym_ctx,
+ uint32_t frame_number, lldb_private::UnwindLLDB& unwind_lldb);
+
+ ///
+ // pure virtual functions from the base class that we must implement
+ ///
+
+ virtual
+ ~RegisterContextLLDB () { }
+
+ 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 reg_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);
+
+ bool
+ IsValid () const;
+
+ bool
+ GetCFA (lldb::addr_t& cfa);
+
+ bool
+ GetStartPC (lldb::addr_t& start_pc);
+
+ bool
+ ReadPC (lldb::addr_t& start_pc);
+
+private:
+
+ enum FrameType
+ {
+ eNormalFrame,
+ eSigtrampFrame,
+ eDebuggerFrame, // a debugger inferior function call frame; we get caller's registers from debugger
+ eSkipFrame, // The unwind resulted in a bogus frame but may get back on track so we don't want to give up yet
+ eNotAValidFrame // this frame is invalid for some reason - most likely it is past the top (end) of the stack
+ };
+
+ // UnwindLLDB needs to pass around references to RegisterLocations
+ friend class UnwindLLDB;
+
+ // Indicates whether this frame is frame zero -- the currently
+ // executing frame -- or not.
+ bool
+ IsFrameZero () const;
+
+ void
+ InitializeZerothFrame ();
+
+ void
+ InitializeNonZerothFrame();
+
+ SharedPtr
+ GetNextFrame () const;
+
+ SharedPtr
+ GetPrevFrame () const;
+
+ // A SkipFrame occurs when the unwind out of frame 0 didn't go right -- we've got one bogus frame at frame #1.
+ // There is a good chance we'll get back on track if we follow the frame pointer chain (or whatever is appropriate
+ // on this ABI) so we allow one invalid frame to be in the stack. Ideally we'll mark this frame specially at some
+ // point and indicate to the user that the unwinder had a hiccup. Often when this happens we will miss a frame of
+ // the program's actual stack in the unwind and we want to flag that for the user somehow.
+ bool
+ IsSkipFrame () const;
+
+ // Provide a location for where THIS function saved the CALLER's register value
+ // Or a frame "below" this one saved it, i.e. a function called by this one, preserved a register that this
+ // function didn't modify/use.
+ //
+ // The RegisterLocation type may be set to eRegisterNotAvailable -- this will happen for a volatile register
+ // being queried mid-stack. Instead of floating frame 0's contents of that register up the stack (which may
+ // or may not be the value of that reg when the function was executing), we won't return any value.
+ //
+ // If a non-volatile register (a "preserved" register) is requested mid-stack and no frames "below" the requested
+ // stack have saved the register anywhere, it is safe to assume that frame 0's register values are still the same
+ // as the requesting frame's.
+ lldb_private::UnwindLLDB::RegisterSearchResult
+ SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc);
+
+ bool
+ ReadRegisterValueFromRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegisterValueToRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value);
+
+ void
+ InvalidateFullUnwindPlan ();
+
+ // Get the contents of a general purpose (address-size) register for this frame
+ // (usually retrieved from the next frame)
+ bool
+ ReadGPRValue (int register_kind, uint32_t regnum, lldb::addr_t &value);
+
+ lldb::UnwindPlanSP
+ GetFastUnwindPlanForFrame ();
+
+ lldb::UnwindPlanSP
+ GetFullUnwindPlanForFrame ();
+
+ void
+ UnwindLogMsg (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ UnwindLogMsgVerbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ lldb_private::Thread& m_thread;
+
+ ///
+ // The following tell us how to retrieve the CALLER's register values (ie the "previous" frame, aka the frame above)
+ // i.e. where THIS frame saved them
+ ///
+
+ lldb::UnwindPlanSP m_fast_unwind_plan_sp; // may be NULL
+ lldb::UnwindPlanSP m_full_unwind_plan_sp;
+ bool m_all_registers_available; // Can we retrieve all regs or just nonvolatile regs?
+ int m_frame_type; // enum FrameType
+
+ lldb::addr_t m_cfa;
+ lldb_private::Address m_start_pc;
+ lldb_private::Address m_current_pc;
+
+ int m_current_offset; // how far into the function we've executed; -1 if unknown
+ // 0 if no instructions have been executed yet.
+
+ int m_current_offset_backed_up_one; // how far into the function we've executed; -1 if unknown
+ // 0 if no instructions have been executed yet.
+ // On architectures where the return address on the stack points
+ // to the instruction after the CALL, this value will have 1
+ // subtracted from it. Else a function that ends in a CALL will
+ // have an offset pointing into the next function's address range.
+ // m_current_pc has the actual address of the "current" pc.
+
+ lldb_private::SymbolContext& m_sym_ctx;
+ bool m_sym_ctx_valid; // if ResolveSymbolContextForAddress fails, don't try to use m_sym_ctx
+
+ uint32_t m_frame_number; // What stack frame this RegisterContext is
+
+ std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation> m_registers; // where to find reg values for this frame
+
+ lldb_private::UnwindLLDB& m_parent_unwind; // The UnwindLLDB that is creating this RegisterContextLLDB
+
+ //------------------------------------------------------------------
+ // For RegisterContextLLDB only
+ //------------------------------------------------------------------
+
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextLLDB);
+};
+
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextLLDB_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
new file mode 100644
index 000000000000..2c3eee452488
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
@@ -0,0 +1,206 @@
+//===-- RegisterContextMacOSXFrameBackchain.cpp -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMacOSXFrameBackchain.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Thread.h"
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RegisterContextMacOSXFrameBackchain constructor
+//----------------------------------------------------------------------
+RegisterContextMacOSXFrameBackchain::RegisterContextMacOSXFrameBackchain
+(
+ Thread &thread,
+ uint32_t concrete_frame_idx,
+ const UnwindMacOSXFrameBackchain::Cursor &cursor
+) :
+ RegisterContext (thread, concrete_frame_idx),
+ m_cursor (cursor),
+ m_cursor_is_valid (true)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RegisterContextMacOSXFrameBackchain::~RegisterContextMacOSXFrameBackchain()
+{
+}
+
+void
+RegisterContextMacOSXFrameBackchain::InvalidateAllRegisters ()
+{
+ m_cursor_is_valid = false;
+}
+
+size_t
+RegisterContextMacOSXFrameBackchain::GetRegisterCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterCount();
+}
+
+const RegisterInfo *
+RegisterContextMacOSXFrameBackchain::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex(reg);
+}
+
+size_t
+RegisterContextMacOSXFrameBackchain::GetRegisterSetCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterSetCount();
+}
+
+
+
+const RegisterSet *
+RegisterContextMacOSXFrameBackchain::GetRegisterSet (size_t reg_set)
+{
+ return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
+}
+
+
+
+bool
+RegisterContextMacOSXFrameBackchain::ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ if (!m_cursor_is_valid)
+ return false;
+
+ uint64_t reg_value = LLDB_INVALID_ADDRESS;
+
+ switch (reg_info->kinds[eRegisterKindGeneric])
+ {
+ case LLDB_REGNUM_GENERIC_PC:
+ if (m_cursor.pc == LLDB_INVALID_ADDRESS)
+ return false;
+ reg_value = m_cursor.pc;
+ break;
+
+ case LLDB_REGNUM_GENERIC_FP:
+ if (m_cursor.fp == LLDB_INVALID_ADDRESS)
+ return false;
+ reg_value = m_cursor.fp;
+ break;
+
+ default:
+ return false;
+ }
+
+ switch (reg_info->encoding)
+ {
+ case eEncodingInvalid:
+ case eEncodingVector:
+ break;
+
+ case eEncodingUint:
+ case eEncodingSint:
+ value.SetUInt(reg_value, reg_info->byte_size);
+ return true;
+
+ case eEncodingIEEE754:
+ switch (reg_info->byte_size)
+ {
+ case sizeof (float):
+ if (sizeof (float) == sizeof(uint32_t))
+ {
+ value.SetUInt32(reg_value, RegisterValue::eTypeFloat);
+ return true;
+ }
+ else if (sizeof (float) == sizeof(uint64_t))
+ {
+ value.SetUInt64(reg_value, RegisterValue::eTypeFloat);
+ return true;
+ }
+ break;
+
+ case sizeof (double):
+ if (sizeof (double) == sizeof(uint32_t))
+ {
+ value.SetUInt32(reg_value, RegisterValue::eTypeDouble);
+ return true;
+ }
+ else if (sizeof (double) == sizeof(uint64_t))
+ {
+ value.SetUInt64(reg_value, RegisterValue::eTypeDouble);
+ return true;
+ }
+ break;
+
+ // TOOD: need a better way to detect when "long double" types are
+ // the same bytes size as "double"
+#if !defined(__arm__)
+ case sizeof (long double):
+ if (sizeof (long double) == sizeof(uint32_t))
+ {
+ value.SetUInt32(reg_value, RegisterValue::eTypeLongDouble);
+ return true;
+ }
+ else if (sizeof (long double) == sizeof(uint64_t))
+ {
+ value.SetUInt64(reg_value, RegisterValue::eTypeLongDouble);
+ return true;
+ }
+ break;
+#endif
+ }
+ break;
+ }
+ return false;
+}
+
+bool
+RegisterContextMacOSXFrameBackchain::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ // Not supported yet. We could easily add support for this by remembering
+ // the address of each entry (it would need to be part of the cursor)
+ return false;
+}
+
+bool
+RegisterContextMacOSXFrameBackchain::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ // libunwind frames can't handle this it doesn't always have all register
+ // values. This call should only be called on frame zero anyway so there
+ // shouldn't be any problem
+ return false;
+}
+
+bool
+RegisterContextMacOSXFrameBackchain::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ // Since this class doesn't respond to "ReadAllRegisterValues()", it must
+ // not have been the one that saved all the register values. So we just let
+ // the thread's register context (the register context for frame zero) do
+ // the writing.
+ return m_thread.GetRegisterContext()->WriteAllRegisterValues(data_sp);
+}
+
+
+uint32_t
+RegisterContextMacOSXFrameBackchain::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
new file mode 100644
index 000000000000..449e053e5ef1
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
@@ -0,0 +1,77 @@
+//===-- RegisterContextMacOSXFrameBackchain.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_RegisterContextMacOSXFrameBackchain_h_
+#define lldb_RegisterContextMacOSXFrameBackchain_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "UnwindMacOSXFrameBackchain.h"
+
+class RegisterContextMacOSXFrameBackchain : public lldb_private::RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextMacOSXFrameBackchain (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ const UnwindMacOSXFrameBackchain::Cursor &cursor);
+
+ virtual
+ ~RegisterContextMacOSXFrameBackchain ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ 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 reg_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);
+
+private:
+ UnwindMacOSXFrameBackchain::Cursor m_cursor;
+ bool m_cursor_is_valid;
+ //------------------------------------------------------------------
+ // For RegisterContextMacOSXFrameBackchain only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextMacOSXFrameBackchain);
+};
+
+#endif // lldb_RegisterContextMacOSXFrameBackchain_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp b/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp
new file mode 100644
index 000000000000..7ceb536272f4
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp
@@ -0,0 +1,87 @@
+//===-- RegisterContextMach_arm.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 "RegisterContextMach_arm.h"
+
+// C Includes
+#include <mach/mach_types.h>
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextMach_arm::RegisterContextMach_arm(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_arm (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextMach_arm::~RegisterContextMach_arm()
+{
+}
+
+int
+RegisterContextMach_arm::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextMach_arm::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextMach_arm::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextMach_arm::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg)
+{
+ mach_msg_type_number_t count = DBGWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&dbg, &count);
+}
+
+int
+RegisterContextMach_arm::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextMach_arm::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextMach_arm::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+int
+RegisterContextMach_arm::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&dbg, DBGWordCount);
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_arm.h b/source/Plugins/Process/Utility/RegisterContextMach_arm.h
new file mode 100644
index 000000000000..e97a4bfff2b6
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_arm.h
@@ -0,0 +1,56 @@
+//===-- RegisterContextMach_arm.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_RegisterContextMach_arm_h_
+#define liblldb_RegisterContextMach_arm_h_
+
+// C Includes
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextDarwin_arm.h"
+
+class RegisterContextMach_arm : public RegisterContextDarwin_arm
+{
+public:
+
+ RegisterContextMach_arm(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextMach_arm();
+
+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);
+};
+
+#endif // liblldb_RegisterContextMach_arm_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp b/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp
new file mode 100644
index 000000000000..3d6c9a6baca6
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp
@@ -0,0 +1,72 @@
+//===-- RegisterContextMach_i386.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__)
+
+// C Includes
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextMach_i386.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextMach_i386::RegisterContextMach_i386(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_i386 (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextMach_i386::~RegisterContextMach_i386()
+{
+}
+
+int
+RegisterContextMach_i386::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextMach_i386::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextMach_i386::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextMach_i386::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextMach_i386::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextMach_i386::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_i386.h b/source/Plugins/Process/Utility/RegisterContextMach_i386.h
new file mode 100644
index 000000000000..ad0f69d1c052
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_i386.h
@@ -0,0 +1,49 @@
+//===-- RegisterContextMach_i386.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_RegisterContextMach_i386_h_
+#define liblldb_RegisterContextMach_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextDarwin_i386.h"
+
+class RegisterContextMach_i386 : public RegisterContextDarwin_i386
+{
+public:
+
+ RegisterContextMach_i386(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextMach_i386();
+
+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
+ 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);
+};
+
+#endif // liblldb_RegisterContextMach_i386_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp
new file mode 100644
index 000000000000..f03685e1313f
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp
@@ -0,0 +1,72 @@
+//===-- RegisterContextMach_x86_64.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__)
+
+// C Includes
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextMach_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextMach_x86_64::RegisterContextMach_x86_64(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_x86_64 (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextMach_x86_64::~RegisterContextMach_x86_64()
+{
+}
+
+int
+RegisterContextMach_x86_64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextMach_x86_64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextMach_x86_64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextMach_x86_64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextMach_x86_64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextMach_x86_64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h
new file mode 100644
index 000000000000..9e6dfa395500
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h
@@ -0,0 +1,49 @@
+//===-- RegisterContextMach_x86_64.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_RegisterContextMach_x86_64_h_
+#define liblldb_RegisterContextMach_x86_64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextDarwin_x86_64.h"
+
+class RegisterContextMach_x86_64 : public RegisterContextDarwin_x86_64
+{
+public:
+
+ RegisterContextMach_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextMach_x86_64();
+
+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
+ 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);
+};
+
+#endif // liblldb_RegisterContextMach_x86_64_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMemory.cpp b/source/Plugins/Process/Utility/RegisterContextMemory.cpp
new file mode 100644
index 000000000000..8c33a6814acc
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMemory.cpp
@@ -0,0 +1,174 @@
+//===-- RegisterContextMemory.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMemory.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "DynamicRegisterInfo.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RegisterContextMemory constructor
+//----------------------------------------------------------------------
+RegisterContextMemory::RegisterContextMemory
+(
+ Thread &thread,
+ uint32_t concrete_frame_idx,
+ DynamicRegisterInfo &reg_infos,
+ addr_t reg_data_addr
+) :
+ RegisterContext (thread, concrete_frame_idx),
+ m_reg_infos (reg_infos),
+ m_reg_valid (),
+ m_reg_data (),
+ m_reg_data_addr (reg_data_addr)
+{
+ // Resize our vector of bools to contain one bool for every register.
+ // We will use these boolean values to know when a register value
+ // is valid in m_reg_data.
+ const size_t num_regs = reg_infos.GetNumRegisters();
+ assert (num_regs > 0);
+ m_reg_valid.resize (num_regs);
+
+ // Make a heap based buffer that is big enough to store all registers
+ DataBufferSP reg_data_sp(new DataBufferHeap (reg_infos.GetRegisterDataByteSize(), 0));
+ m_reg_data.SetData (reg_data_sp);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RegisterContextMemory::~RegisterContextMemory()
+{
+}
+
+void
+RegisterContextMemory::InvalidateAllRegisters ()
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ SetAllRegisterValid (false);
+}
+
+void
+RegisterContextMemory::SetAllRegisterValid (bool b)
+{
+ std::vector<bool>::iterator pos, end = m_reg_valid.end();
+ for (pos = m_reg_valid.begin(); pos != end; ++pos)
+ *pos = b;
+}
+
+size_t
+RegisterContextMemory::GetRegisterCount ()
+{
+ return m_reg_infos.GetNumRegisters ();
+}
+
+const RegisterInfo *
+RegisterContextMemory::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_reg_infos.GetRegisterInfoAtIndex (reg);
+}
+
+size_t
+RegisterContextMemory::GetRegisterSetCount ()
+{
+ return m_reg_infos.GetNumRegisterSets ();
+}
+
+const RegisterSet *
+RegisterContextMemory::GetRegisterSet (size_t reg_set)
+{
+ return m_reg_infos.GetRegisterSet (reg_set);
+}
+
+uint32_t
+RegisterContextMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_reg_infos.ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
+bool
+RegisterContextMemory::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB];
+ if (!m_reg_valid[reg_num])
+ {
+ if (!ReadAllRegisterValues(m_reg_data.GetSharedDataBuffer ()))
+ return false;
+ }
+ const bool partial_data_ok = false;
+ return reg_value.SetValueFromData(reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok).Success();
+}
+
+bool
+RegisterContextMemory::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB];
+ addr_t reg_addr = m_reg_data_addr + reg_info->byte_offset;
+ Error error (WriteRegisterValueToMemory(reg_info, reg_addr, reg_info->byte_size, reg_value));
+ m_reg_valid[reg_num] = false;
+ return error.Success();
+ }
+ return false;
+}
+
+bool
+RegisterContextMemory::ReadAllRegisterValues (DataBufferSP &data_sp)
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (process_sp->ReadMemory(m_reg_data_addr, data_sp->GetBytes(), data_sp->GetByteSize(), error) == data_sp->GetByteSize())
+ {
+ SetAllRegisterValid (true);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+RegisterContextMemory::WriteAllRegisterValues (const DataBufferSP &data_sp)
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ SetAllRegisterValid (false);
+ if (process_sp->WriteMemory(m_reg_data_addr, data_sp->GetBytes(), data_sp->GetByteSize(), error) == data_sp->GetByteSize())
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+RegisterContextMemory::SetAllRegisterData (const lldb::DataBufferSP &data_sp)
+{
+ m_reg_data.SetData(data_sp);
+ SetAllRegisterValid (true);
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextMemory.h b/source/Plugins/Process/Utility/RegisterContextMemory.h
new file mode 100644
index 000000000000..8bba52c627f3
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMemory.h
@@ -0,0 +1,102 @@
+//===-- RegisterContextMemory.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_RegisterContextMemory_h_
+#define lldb_RegisterContextMemory_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/RegisterContext.h"
+
+class DynamicRegisterInfo;
+
+class RegisterContextMemory : public lldb_private::RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextMemory (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ DynamicRegisterInfo &reg_info,
+ lldb::addr_t reg_data_addr);
+
+ virtual
+ ~RegisterContextMemory ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ 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 reg_set);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+
+ //------------------------------------------------------------------
+ // If all of the thread register are in a contiguous buffer in
+ // memory, then the default ReadRegister/WriteRegister and
+ // ReadAllRegisterValues/WriteAllRegisterValues will work. If thread
+ // registers are not contiguous, clients will want to subclass this
+ // class and modify the read/write functions as needed.
+ //------------------------------------------------------------------
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ void
+ SetAllRegisterData (const lldb::DataBufferSP &data_sp);
+protected:
+
+ void
+ SetAllRegisterValid (bool b);
+
+ DynamicRegisterInfo &m_reg_infos;
+ std::vector<bool> m_reg_valid;
+ lldb_private::DataExtractor m_reg_data;
+ lldb::addr_t m_reg_data_addr; // If this is valid, then we have a register context that is stored in memmory
+
+private:
+ //------------------------------------------------------------------
+ // For RegisterContextMemory only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextMemory);
+};
+
+#endif // lldb_RegisterContextMemory_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
new file mode 100644
index 000000000000..d35a5d095705
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
@@ -0,0 +1,261 @@
+//===-- RegisterContextThreadMemory.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/lldb-private.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+#include "RegisterContextThreadMemory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextThreadMemory::RegisterContextThreadMemory (Thread &thread,
+ lldb::addr_t register_data_addr) :
+ RegisterContext (thread, 0),
+ m_thread_wp (thread.shared_from_this()),
+ m_reg_ctx_sp (),
+ m_register_data_addr (register_data_addr),
+ m_stop_id(0)
+{
+}
+
+RegisterContextThreadMemory::~RegisterContextThreadMemory()
+{
+}
+
+void
+RegisterContextThreadMemory::UpdateRegisterContext ()
+{
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ {
+ ProcessSP process_sp (thread_sp->GetProcess());
+
+ if (process_sp)
+ {
+ const uint32_t stop_id = process_sp->GetModID().GetStopID();
+ if (m_stop_id != stop_id)
+ {
+ m_stop_id = stop_id;
+ m_reg_ctx_sp.reset();
+ }
+ if (!m_reg_ctx_sp)
+ {
+ ThreadSP backing_thread_sp (thread_sp->GetBackingThread());
+ if (backing_thread_sp)
+ {
+ m_reg_ctx_sp = backing_thread_sp->GetRegisterContext();
+ }
+ else
+ {
+ OperatingSystem *os = process_sp->GetOperatingSystem ();
+ if (os->IsOperatingSystemPluginThread (thread_sp))
+ m_reg_ctx_sp = os->CreateRegisterContextForThread (thread_sp.get(), LLDB_INVALID_ADDRESS);
+ }
+ }
+ }
+ else
+ {
+ m_reg_ctx_sp.reset();
+ }
+ }
+ else
+ {
+ m_reg_ctx_sp.reset();
+ }
+}
+
+//------------------------------------------------------------------
+// Subclasses must override these functions
+//------------------------------------------------------------------
+void
+RegisterContextThreadMemory::InvalidateAllRegisters ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ m_reg_ctx_sp->InvalidateAllRegisters();
+}
+
+size_t
+RegisterContextThreadMemory::GetRegisterCount ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterCount();
+ return 0;
+}
+
+const RegisterInfo *
+RegisterContextThreadMemory::GetRegisterInfoAtIndex (size_t reg)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterInfoAtIndex(reg);
+ return NULL;
+}
+
+size_t
+RegisterContextThreadMemory::GetRegisterSetCount ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterSetCount();
+ return 0;
+}
+
+const RegisterSet *
+RegisterContextThreadMemory::GetRegisterSet (size_t reg_set)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterSet(reg_set);
+ return NULL;
+}
+
+bool
+RegisterContextThreadMemory::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadRegister(reg_info, reg_value);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteRegister (reg_info, reg_value);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadAllRegisterValues(data_sp);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteAllRegisterValues (data_sp);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::CopyFromRegisterContext (lldb::RegisterContextSP reg_ctx_sp)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->CopyFromRegisterContext(reg_ctx_sp);
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ConvertRegisterKindToRegisterNumber(kind, num);
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::NumSupportedHardwareBreakpoints ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->NumSupportedHardwareBreakpoints();
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->SetHardwareBreakpoint(addr, size);
+ return 0;
+}
+
+bool
+RegisterContextThreadMemory::ClearHardwareBreakpoint (uint32_t hw_idx)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ClearHardwareBreakpoint (hw_idx);
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::NumSupportedHardwareWatchpoints ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->NumSupportedHardwareWatchpoints();
+ return 0;
+}
+
+uint32_t
+RegisterContextThreadMemory::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->SetHardwareWatchpoint(addr, size, read, write);
+ return 0;
+}
+
+bool
+RegisterContextThreadMemory::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ClearHardwareWatchpoint(hw_index);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::HardwareSingleStep (bool enable)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->HardwareSingleStep(enable);
+ return false;
+}
+
+Error
+RegisterContextThreadMemory::ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadRegisterValueFromMemory (reg_info, src_addr, src_len, reg_value);
+ Error error;
+ error.SetErrorString("invalid register context");
+ return error;
+}
+
+Error
+RegisterContextThreadMemory::WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteRegisterValueToMemory (reg_info, dst_addr, dst_len, reg_value);
+ Error error;
+ error.SetErrorString("invalid register context");
+ return error;
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextThreadMemory.h b/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
new file mode 100644
index 000000000000..8d7a4b622fe8
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
@@ -0,0 +1,114 @@
+//===-- RegisterContextThreadMemory.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_RegisterContextThreadMemory_h_
+#define lldb_RegisterContextThreadMemory_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+namespace lldb_private {
+
+class RegisterContextThreadMemory : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextThreadMemory (Thread &thread,
+ lldb::addr_t register_data_addr);
+
+ virtual ~RegisterContextThreadMemory();
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value);
+
+ // These two functions are used to implement "push" and "pop" of register states. They are used primarily
+ // for expression evaluation, where we need to push a new state (storing the old one in data_sp) and then
+ // restoring the original state by passing the data_sp we got from ReadAllRegisters to WriteAllRegisterValues.
+ // ReadAllRegisters will do what is necessary to return a coherent set of register values for this thread, which
+ // may mean e.g. interrupting a thread that is sitting in a kernel trap. That is a somewhat disruptive operation,
+ // so these API's should only be used when this behavior is needed.
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ bool
+ CopyFromRegisterContext (lldb::RegisterContextSP context);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ //------------------------------------------------------------------
+ // Subclasses can override these functions if desired
+ //------------------------------------------------------------------
+ virtual uint32_t
+ NumSupportedHardwareBreakpoints ();
+
+ virtual uint32_t
+ SetHardwareBreakpoint (lldb::addr_t addr, size_t size);
+
+ virtual bool
+ ClearHardwareBreakpoint (uint32_t hw_idx);
+
+ 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);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ virtual Error
+ ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue &reg_value);
+
+ virtual Error
+ WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue &reg_value);
+
+protected:
+ void
+ UpdateRegisterContext ();
+
+ lldb::ThreadWP m_thread_wp;
+ lldb::RegisterContextSP m_reg_ctx_sp;
+ lldb::addr_t m_register_data_addr;
+ uint32_t m_stop_id;
+private:
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextThreadMemory);
+};
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextThreadMemory_h_
diff --git a/source/Plugins/Process/Utility/StopInfoMachException.cpp b/source/Plugins/Process/Utility/StopInfoMachException.cpp
new file mode 100644
index 000000000000..51d2052e1931
--- /dev/null
+++ b/source/Plugins/Process/Utility/StopInfoMachException.cpp
@@ -0,0 +1,482 @@
+//===-- StopInfoMachException.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StopInfoMachException.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/UnixSignals.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *
+StopInfoMachException::GetDescription ()
+{
+ if (m_description.empty() && m_value != 0)
+ {
+ ExecutionContext exe_ctx (m_thread_wp.lock());
+ Target *target = exe_ctx.GetTargetPtr();
+ const llvm::Triple::ArchType cpu = target ? target->GetArchitecture().GetMachine() : llvm::Triple::UnknownArch;
+
+ const char *exc_desc = NULL;
+ const char *code_label = "code";
+ const char *code_desc = NULL;
+ const char *subcode_label = "subcode";
+ const char *subcode_desc = NULL;
+ switch (m_value)
+ {
+ case 1: // EXC_BAD_ACCESS
+ exc_desc = "EXC_BAD_ACCESS";
+ subcode_label = "address";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code)
+ {
+ case 0xd: code_desc = "EXC_I386_GPFLT"; m_exc_data_count = 1; break;
+ }
+ break;
+ case llvm::Triple::arm:
+ switch (m_exc_code)
+ {
+ case 0x101: code_desc = "EXC_ARM_DA_ALIGN"; break;
+ case 0x102: code_desc = "EXC_ARM_DA_DEBUG"; break;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 0x101: code_desc = "EXC_PPC_VM_PROT_READ"; break;
+ case 0x102: code_desc = "EXC_PPC_BADSPACE"; break;
+ case 0x103: code_desc = "EXC_PPC_UNALIGNED"; break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 2: // EXC_BAD_INSTRUCTION
+ exc_desc = "EXC_BAD_INSTRUCTION";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (m_exc_code == 1)
+ code_desc = "EXC_I386_INVOP";
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_PPC_INVALID_SYSCALL"; break;
+ case 2: code_desc = "EXC_PPC_UNIPL_INST"; break;
+ case 3: code_desc = "EXC_PPC_PRIVINST"; break;
+ case 4: code_desc = "EXC_PPC_PRIVREG"; break;
+ case 5: code_desc = "EXC_PPC_TRACE"; break;
+ case 6: code_desc = "EXC_PPC_PERFMON"; break;
+ }
+ break;
+
+ case llvm::Triple::arm:
+ if (m_exc_code == 1)
+ code_desc = "EXC_ARM_UNDEFINED";
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 3: // EXC_ARITHMETIC
+ exc_desc = "EXC_ARITHMETIC";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_I386_DIV"; break;
+ case 2: code_desc = "EXC_I386_INTO"; break;
+ case 3: code_desc = "EXC_I386_NOEXT"; break;
+ case 4: code_desc = "EXC_I386_EXTOVR"; break;
+ case 5: code_desc = "EXC_I386_EXTERR"; break;
+ case 6: code_desc = "EXC_I386_EMERR"; break;
+ case 7: code_desc = "EXC_I386_BOUND"; break;
+ case 8: code_desc = "EXC_I386_SSEEXTERR"; break;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_PPC_OVERFLOW"; break;
+ case 2: code_desc = "EXC_PPC_ZERO_DIVIDE"; break;
+ case 3: code_desc = "EXC_PPC_FLT_INEXACT"; break;
+ case 4: code_desc = "EXC_PPC_FLT_ZERO_DIVIDE"; break;
+ case 5: code_desc = "EXC_PPC_FLT_UNDERFLOW"; break;
+ case 6: code_desc = "EXC_PPC_FLT_OVERFLOW"; break;
+ case 7: code_desc = "EXC_PPC_FLT_NOT_A_NUMBER"; break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 4: // EXC_EMULATION
+ exc_desc = "EXC_EMULATION";
+ break;
+
+
+ case 5: // EXC_SOFTWARE
+ exc_desc = "EXC_SOFTWARE";
+ if (m_exc_code == 0x10003)
+ {
+ subcode_desc = "EXC_SOFT_SIGNAL";
+ subcode_label = "signo";
+ }
+ break;
+
+ case 6: // EXC_BREAKPOINT
+ {
+ exc_desc = "EXC_BREAKPOINT";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_I386_SGL"; break;
+ case 2: code_desc = "EXC_I386_BPT"; break;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_PPC_BREAKPOINT"; break;
+ }
+ break;
+
+ case llvm::Triple::arm:
+ switch (m_exc_code)
+ {
+ case 0x101: code_desc = "EXC_ARM_DA_ALIGN"; break;
+ case 0x102: code_desc = "EXC_ARM_DA_DEBUG"; break;
+ case 1: code_desc = "EXC_ARM_BREAKPOINT"; break;
+ // FIXME temporary workaround, exc_code 0 does not really mean EXC_ARM_BREAKPOINT
+ case 0: code_desc = "EXC_ARM_BREAKPOINT"; break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case 7:
+ exc_desc = "EXC_SYSCALL";
+ break;
+
+ case 8:
+ exc_desc = "EXC_MACH_SYSCALL";
+ break;
+
+ case 9:
+ exc_desc = "EXC_RPC_ALERT";
+ break;
+
+ case 10:
+ exc_desc = "EXC_CRASH";
+ break;
+ case 11:
+ exc_desc = "EXC_RESOURCE";
+ break;
+ case 12:
+ exc_desc = "EXC_GUARD";
+ break;
+ }
+
+ StreamString strm;
+
+ if (exc_desc)
+ strm.PutCString(exc_desc);
+ else
+ strm.Printf("EXC_??? (%" PRIu64 ")", m_value);
+
+ if (m_exc_data_count >= 1)
+ {
+ if (code_desc)
+ strm.Printf(" (%s=%s", code_label, code_desc);
+ else
+ strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code);
+ }
+
+ if (m_exc_data_count >= 2)
+ {
+ if (subcode_desc)
+ strm.Printf(", %s=%s", subcode_label, subcode_desc);
+ else
+ strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode);
+ }
+
+ if (m_exc_data_count > 0)
+ strm.PutChar(')');
+
+ m_description.swap (strm.GetString());
+ }
+ return m_description.c_str();
+}
+
+
+
+
+
+StopInfoSP
+StopInfoMachException::CreateStopReasonWithMachException
+(
+ Thread &thread,
+ uint32_t exc_type,
+ uint32_t exc_data_count,
+ uint64_t exc_code,
+ uint64_t exc_sub_code,
+ uint64_t exc_sub_sub_code,
+ bool pc_already_adjusted,
+ bool adjust_pc_if_needed
+)
+{
+ if (exc_type != 0)
+ {
+ uint32_t pc_decrement = 0;
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ const llvm::Triple::ArchType cpu = target ? target->GetArchitecture().GetMachine() : llvm::Triple::UnknownArch;
+
+ switch (exc_type)
+ {
+ case 1: // EXC_BAD_ACCESS
+ break;
+
+ case 2: // EXC_BAD_INSTRUCTION
+ switch (cpu)
+ {
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (exc_code)
+ {
+ case 1: // EXC_PPC_INVALID_SYSCALL
+ case 2: // EXC_PPC_UNIPL_INST
+ case 3: // EXC_PPC_PRIVINST
+ case 4: // EXC_PPC_PRIVREG
+ break;
+ case 5: // EXC_PPC_TRACE
+ return StopInfo::CreateStopReasonToTrace (thread);
+ case 6: // EXC_PPC_PERFMON
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 3: // EXC_ARITHMETIC
+ case 4: // EXC_EMULATION
+ break;
+
+ case 5: // EXC_SOFTWARE
+ if (exc_code == 0x10003) // EXC_SOFT_SIGNAL
+ {
+ if (exc_sub_code == 5)
+ {
+ // On MacOSX, a SIGTRAP can signify that a process has called
+ // exec, so we should check with our dynamic loader to verify.
+ ProcessSP process_sp (thread.GetProcess());
+ if (process_sp)
+ {
+ DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader();
+ if (dynamic_loader && dynamic_loader->ProcessDidExec())
+ {
+ // The program was re-exec'ed
+ return StopInfo::CreateStopReasonWithExec (thread);
+ }
+// if (!process_did_exec)
+// {
+// // We have a SIGTRAP, make sure we didn't exec by checking
+// // for the PC being at "_dyld_start"...
+// lldb::StackFrameSP frame_sp (thread.GetStackFrameAtIndex(0));
+// if (frame_sp)
+// {
+// const Symbol *symbol = frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol;
+// if (symbol)
+// {
+// if (symbol->GetName() == ConstString("_dyld_start"))
+// process_did_exec = true;
+// }
+// }
+// }
+ }
+ }
+ return StopInfo::CreateStopReasonWithSignal (thread, exc_sub_code);
+ }
+ break;
+
+ case 6: // EXC_BREAKPOINT
+ {
+ bool is_actual_breakpoint = false;
+ bool is_trace_if_actual_breakpoint_missing = false;
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (exc_code == 1) // EXC_I386_SGL
+ {
+ if (!exc_sub_code)
+ return StopInfo::CreateStopReasonToTrace(thread);
+
+ // It's a watchpoint, then.
+ // The exc_sub_code indicates the data break address.
+ 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());
+ }
+ }
+ else if (exc_code == 2 || // EXC_I386_BPT
+ exc_code == 3) // EXC_I386_BPTFLT
+ {
+ // KDP returns EXC_I386_BPTFLT for trace breakpoints
+ if (exc_code == 3)
+ is_trace_if_actual_breakpoint_missing = true;
+
+ is_actual_breakpoint = true;
+ if (!pc_already_adjusted)
+ pc_decrement = 1;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ is_actual_breakpoint = exc_code == 1; // EXC_PPC_BREAKPOINT
+ break;
+
+ case llvm::Triple::arm:
+ 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);
+ }
+ else if (exc_code == 1) // EXC_ARM_BREAKPOINT
+ {
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
+ else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel is currently returning this so accept it as indicating a breakpoint until the kernel is fixed
+ {
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (is_actual_breakpoint)
+ {
+ RegisterContextSP reg_ctx_sp (thread.GetRegisterContext());
+ addr_t pc = reg_ctx_sp->GetPC() - pc_decrement;
+
+ ProcessSP process_sp (thread.CalculateProcess());
+
+ lldb::BreakpointSiteSP bp_site_sp;
+ if (process_sp)
+ bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc);
+ if (bp_site_sp && bp_site_sp->IsEnabled())
+ {
+ // Update the PC if we were asked to do so, but only do
+ // so if we find a breakpoint that we know about cause
+ // this could be a trap instruction in the code
+ if (pc_decrement > 0 && adjust_pc_if_needed)
+ reg_ctx_sp->SetPC (pc);
+
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ if (bp_site_sp->ValidForThisThread (&thread))
+ return StopInfo::CreateStopReasonWithBreakpointSiteID (thread, bp_site_sp->GetID());
+ else
+ return StopInfoSP();
+ }
+
+ // Don't call this a trace if we weren't single stepping this thread.
+ if (is_trace_if_actual_breakpoint_missing && thread.GetTemporaryResumeState() == eStateStepping)
+ {
+ return StopInfo::CreateStopReasonToTrace (thread);
+ }
+ }
+ }
+ break;
+
+ case 7: // EXC_SYSCALL
+ case 8: // EXC_MACH_SYSCALL
+ case 9: // EXC_RPC_ALERT
+ case 10: // EXC_CRASH
+ break;
+ }
+
+ return StopInfoSP(new StopInfoMachException (thread, exc_type, exc_data_count, exc_code, exc_sub_code));
+ }
+ return StopInfoSP();
+}
diff --git a/source/Plugins/Process/Utility/StopInfoMachException.h b/source/Plugins/Process/Utility/StopInfoMachException.h
new file mode 100644
index 000000000000..130ee0b709b0
--- /dev/null
+++ b/source/Plugins/Process/Utility/StopInfoMachException.h
@@ -0,0 +1,77 @@
+//===-- StopInfoMachException.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_StopInfoMachException_h_
+#define liblldb_StopInfoMachException_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/StopInfo.h"
+
+namespace lldb_private {
+
+class StopInfoMachException : public StopInfo
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StopInfoMachException (Thread &thread,
+ uint32_t exc_type,
+ uint32_t exc_data_count,
+ uint64_t exc_code,
+ uint64_t exc_subcode) :
+ StopInfo (thread, exc_type),
+ m_exc_data_count (exc_data_count),
+ m_exc_code (exc_code),
+ m_exc_subcode (exc_subcode)
+ {
+ }
+
+ virtual ~StopInfoMachException()
+ {
+ }
+
+
+ virtual lldb::StopReason
+ GetStopReason () const
+ {
+ return lldb::eStopReasonException;
+ }
+
+ virtual const char *
+ GetDescription ();
+
+ // Since some mach exceptions will be reported as breakpoints, signals,
+ // or trace, we use this static accessor which will translate the mach
+ // exception into the correct StopInfo.
+ static lldb::StopInfoSP
+ CreateStopReasonWithMachException (Thread &thread,
+ uint32_t exc_type,
+ uint32_t exc_data_count,
+ uint64_t exc_code,
+ uint64_t exc_sub_code,
+ uint64_t exc_sub_sub_code,
+ bool pc_already_adjusted = true,
+ bool adjust_pc_if_needed = false);
+
+protected:
+ uint32_t m_exc_data_count;
+ uint64_t m_exc_code;
+ uint64_t m_exc_subcode;
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_StopInfoMachException_h_
diff --git a/source/Plugins/Process/Utility/ThreadMemory.cpp b/source/Plugins/Process/Utility/ThreadMemory.cpp
new file mode 100644
index 000000000000..56e5a9a59fab
--- /dev/null
+++ b/source/Plugins/Process/Utility/ThreadMemory.cpp
@@ -0,0 +1,140 @@
+//===-- ThreadMemory.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Process/Utility/ThreadMemory.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Unwind.h"
+#include "Plugins/Process/Utility/RegisterContextThreadMemory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ThreadMemory::ThreadMemory (Process &process,
+ tid_t tid,
+ const ValueObjectSP &thread_info_valobj_sp) :
+ Thread (process, tid),
+ m_backing_thread_sp (),
+ m_thread_info_valobj_sp (thread_info_valobj_sp),
+ m_name(),
+ m_queue()
+{
+}
+
+
+ThreadMemory::ThreadMemory (Process &process,
+ lldb::tid_t tid,
+ const char *name,
+ const char *queue,
+ lldb::addr_t register_data_addr) :
+ Thread (process, tid),
+ m_backing_thread_sp (),
+ m_thread_info_valobj_sp (),
+ m_name(),
+ m_queue(),
+ m_register_data_addr (register_data_addr)
+{
+ if (name)
+ m_name = name;
+ if (queue)
+ m_queue = queue;
+}
+
+
+ThreadMemory::~ThreadMemory()
+{
+ DestroyThread();
+}
+
+void
+ThreadMemory::WillResume (StateType resume_state)
+{
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->WillResume(resume_state);
+}
+
+void
+ThreadMemory::ClearStackFrames ()
+{
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->ClearStackFrames();
+ Thread::ClearStackFrames();
+}
+
+RegisterContextSP
+ThreadMemory::GetRegisterContext ()
+{
+ if (!m_reg_context_sp)
+ m_reg_context_sp.reset (new RegisterContextThreadMemory (*this, m_register_data_addr));
+ return m_reg_context_sp;
+}
+
+RegisterContextSP
+ThreadMemory::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex ();
+
+ if (concrete_frame_idx == 0)
+ {
+ reg_ctx_sp = GetRegisterContext ();
+ }
+ else
+ {
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ reg_ctx_sp = unwinder->CreateRegisterContextForFrame (frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool
+ThreadMemory::CalculateStopInfo ()
+{
+ if (m_backing_thread_sp)
+ {
+ lldb::StopInfoSP backing_stop_info_sp (m_backing_thread_sp->GetPrivateStopInfo());
+ if (backing_stop_info_sp)
+ {
+ backing_stop_info_sp->SetThread (shared_from_this());
+ SetStopInfo (backing_stop_info_sp);
+ return true;
+ }
+ }
+ else
+ {
+ ProcessSP process_sp (GetProcess());
+
+ if (process_sp)
+ {
+ OperatingSystem *os = process_sp->GetOperatingSystem ();
+ if (os)
+ {
+ SetStopInfo (os->CreateThreadStopReason (this));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void
+ThreadMemory::RefreshStateAfterStop()
+{
+ if (m_backing_thread_sp)
+ return m_backing_thread_sp->RefreshStateAfterStop();
+
+ if (m_reg_context_sp)
+ m_reg_context_sp->InvalidateAllRegisters();
+}
diff --git a/source/Plugins/Process/Utility/ThreadMemory.h b/source/Plugins/Process/Utility/ThreadMemory.h
new file mode 100644
index 000000000000..07eb45dcb431
--- /dev/null
+++ b/source/Plugins/Process/Utility/ThreadMemory.h
@@ -0,0 +1,152 @@
+//===-- ThreadMemory.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_ThreadMemory_h_
+#define liblldb_ThreadMemory_h_
+
+#include "lldb/Target/Thread.h"
+
+class ThreadMemory :
+ public lldb_private::Thread
+{
+public:
+
+ ThreadMemory (lldb_private::Process &process,
+ lldb::tid_t tid,
+ const lldb::ValueObjectSP &thread_info_valobj_sp);
+
+ ThreadMemory (lldb_private::Process &process,
+ lldb::tid_t tid,
+ const char *name,
+ const char *queue,
+ lldb::addr_t register_data_addr);
+
+ virtual
+ ~ThreadMemory();
+
+ //------------------------------------------------------------------
+ // lldb_private::Thread methods
+ //------------------------------------------------------------------
+ virtual lldb::RegisterContextSP
+ GetRegisterContext ();
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ virtual bool
+ CalculateStopInfo ();
+
+ virtual const char *
+ GetInfo ()
+ {
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->GetInfo();
+ return NULL;
+ }
+
+ virtual const char *
+ GetName ()
+ {
+ if (!m_name.empty())
+ return m_name.c_str();
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->GetName();
+ return NULL;
+ }
+
+ virtual const char *
+ GetQueueName ()
+ {
+ if (!m_queue.empty())
+ return m_queue.c_str();
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->GetQueueName();
+ return NULL;
+ }
+
+ virtual void
+ WillResume (lldb::StateType resume_state);
+
+ virtual void
+ DidResume ()
+ {
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->DidResume();
+ }
+
+ virtual lldb::user_id_t
+ GetProtocolID () const
+ {
+ if (m_backing_thread_sp)
+ return m_backing_thread_sp->GetProtocolID();
+ return Thread::GetProtocolID();
+ }
+
+ virtual void
+ RefreshStateAfterStop();
+
+ lldb::ValueObjectSP &
+ GetValueObject ()
+ {
+ return m_thread_info_valobj_sp;
+ }
+
+ virtual void
+ ClearStackFrames ();
+
+ virtual void
+ ClearBackingThread ()
+ {
+ m_backing_thread_sp.reset();
+ }
+
+ virtual bool
+ SetBackingThread (const lldb::ThreadSP &thread_sp)
+ {
+ //printf ("Thread 0x%llx is being backed by thread 0x%llx\n", GetID(), thread_sp->GetID());
+ m_backing_thread_sp = thread_sp;
+ return (bool)thread_sp;
+ }
+
+ virtual lldb::ThreadSP
+ GetBackingThread () const
+ {
+ return m_backing_thread_sp;
+ }
+
+protected:
+
+ virtual bool
+ IsOperatingSystemPluginThread () const
+ {
+ return true;
+ }
+
+
+ //------------------------------------------------------------------
+ // For ThreadMemory and subclasses
+ //------------------------------------------------------------------
+ // If this memory thread is actually represented by a thread from the
+ // lldb_private::Process subclass, then fill in the thread here and
+ // all APIs will be routed through this thread object. If m_backing_thread_sp
+ // is empty, then this thread is simply in memory with no representation
+ // through the process plug-in.
+ lldb::ThreadSP m_backing_thread_sp;
+ lldb::ValueObjectSP m_thread_info_valobj_sp;
+ std::string m_name;
+ std::string m_queue;
+ lldb::addr_t m_register_data_addr;
+private:
+ //------------------------------------------------------------------
+ // For ThreadMemory only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ThreadMemory);
+};
+
+#endif // liblldb_ThreadMemory_h_
diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp
new file mode 100644
index 000000000000..0eea00363498
--- /dev/null
+++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp
@@ -0,0 +1,322 @@
+//===-- UnwindLLDB.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/Module.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "UnwindLLDB.h"
+#include "RegisterContextLLDB.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindLLDB::UnwindLLDB (Thread &thread) :
+ Unwind (thread),
+ m_frames(),
+ m_unwind_complete(false)
+{
+}
+
+uint32_t
+UnwindLLDB::DoGetFrameCount()
+{
+ if (!m_unwind_complete)
+ {
+//#define DEBUG_FRAME_SPEED 1
+#if DEBUG_FRAME_SPEED
+#define FRAME_COUNT 10000
+ TimeValue time_value (TimeValue::Now());
+#endif
+ if (!AddFirstFrame ())
+ return 0;
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+
+ while (AddOneMoreFrame (abi))
+ {
+#if DEBUG_FRAME_SPEED
+ if ((m_frames.size() % FRAME_COUNT) == 0)
+ {
+ TimeValue now(TimeValue::Now());
+ uint64_t delta_t = now - time_value;
+ printf ("%u frames in %" PRIu64 ".%09llu ms (%g frames/sec)\n",
+ FRAME_COUNT,
+ delta_t / TimeValue::NanoSecPerSec,
+ delta_t % TimeValue::NanoSecPerSec,
+ (float)FRAME_COUNT / ((float)delta_t / (float)TimeValue::NanoSecPerSec));
+ time_value = now;
+ }
+#endif
+ }
+ }
+ return m_frames.size ();
+}
+
+bool
+UnwindLLDB::AddFirstFrame ()
+{
+ if (m_frames.size() > 0)
+ return true;
+
+ // First, set up the 0th (initial) frame
+ CursorSP first_cursor_sp(new Cursor ());
+ RegisterContextLLDBSP reg_ctx_sp (new RegisterContextLLDB (m_thread,
+ RegisterContextLLDBSP(),
+ first_cursor_sp->sctx,
+ 0, *this));
+ if (reg_ctx_sp.get() == NULL)
+ goto unwind_done;
+
+ if (!reg_ctx_sp->IsValid())
+ goto unwind_done;
+
+ if (!reg_ctx_sp->GetCFA (first_cursor_sp->cfa))
+ goto unwind_done;
+
+ if (!reg_ctx_sp->ReadPC (first_cursor_sp->start_pc))
+ goto unwind_done;
+
+ // Everything checks out, so release the auto pointer value and let the
+ // cursor own it in its shared pointer
+ first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;
+ m_frames.push_back (first_cursor_sp);
+ return true;
+unwind_done:
+ m_unwind_complete = true;
+ return false;
+}
+
+// For adding a non-zero stack frame to m_frames.
+bool
+UnwindLLDB::AddOneMoreFrame (ABI *abi)
+{
+ // If we've already gotten to the end of the stack, don't bother to try again...
+ if (m_unwind_complete)
+ return false;
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ CursorSP cursor_sp(new Cursor ());
+
+ // Frame zero is a little different
+ if (m_frames.size() == 0)
+ return false;
+
+ uint32_t cur_idx = m_frames.size ();
+ RegisterContextLLDBSP reg_ctx_sp(new RegisterContextLLDB (m_thread,
+ m_frames[cur_idx - 1]->reg_ctx_lldb_sp,
+ cursor_sp->sctx,
+ cur_idx,
+ *this));
+
+ // We want to detect an unwind that cycles erronously and stop backtracing.
+ // Don't want this maximum unwind limit to be too low -- if you have a backtrace
+ // with an "infinitely recursing" bug, it will crash when the stack blows out
+ // and the first 35,000 frames are uninteresting - it's the top most 5 frames that
+ // you actually care about. So you can't just cap the unwind at 10,000 or something.
+ // Realistically anything over around 200,000 is going to blow out the stack space.
+ // If we're still unwinding at that point, we're probably never going to finish.
+ if (cur_idx > 300000)
+ {
+ if (log)
+ log->Printf ("%*sFrame %d unwound too many frames, assuming unwind has gone astray, stopping.",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ goto unwind_done;
+ }
+
+ if (reg_ctx_sp.get() == NULL)
+ goto unwind_done;
+
+ if (!reg_ctx_sp->IsValid())
+ {
+ if (log)
+ {
+ log->Printf("%*sFrame %d invalid RegisterContext for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
+ }
+ if (!reg_ctx_sp->GetCFA (cursor_sp->cfa))
+ {
+ if (log)
+ {
+ log->Printf("%*sFrame %d did not get CFA for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
+ }
+ if (abi && !abi->CallFrameAddressIsValid(cursor_sp->cfa))
+ {
+ if (log)
+ {
+ log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
+ }
+ if (!reg_ctx_sp->ReadPC (cursor_sp->start_pc))
+ {
+ if (log)
+ {
+ log->Printf("%*sFrame %d did not get PC for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
+ }
+ if (abi && !abi->CodeAddressIsValid (cursor_sp->start_pc))
+ {
+ if (log)
+ {
+ log->Printf("%*sFrame %d did not get a valid PC, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
+ }
+ if (!m_frames.empty())
+ {
+ if (m_frames.back()->start_pc == cursor_sp->start_pc)
+ {
+ if (m_frames.back()->cfa == cursor_sp->cfa)
+ goto unwind_done; // Infinite loop where the current cursor is the same as the previous one...
+ else if (abi && abi->StackUsesFrames())
+ {
+ // We might have a CFA that is not using the frame pointer and
+ // we want to validate that the frame pointer is valid.
+ if (reg_ctx_sp->GetFP() == 0)
+ goto unwind_done;
+ }
+ }
+ }
+ cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;
+ m_frames.push_back (cursor_sp);
+ return true;
+
+unwind_done:
+ m_unwind_complete = true;
+ return false;
+}
+
+bool
+UnwindLLDB::DoGetFrameInfoAtIndex (uint32_t idx, addr_t& cfa, addr_t& pc)
+{
+ if (m_frames.size() == 0)
+ {
+ if (!AddFirstFrame())
+ return false;
+ }
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+
+ while (idx >= m_frames.size() && AddOneMoreFrame (abi))
+ ;
+
+ if (idx < m_frames.size ())
+ {
+ cfa = m_frames[idx]->cfa;
+ pc = m_frames[idx]->start_pc;
+ return true;
+ }
+ return false;
+}
+
+lldb::RegisterContextSP
+UnwindLLDB::DoCreateRegisterContextForFrame (StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t idx = frame->GetConcreteFrameIndex ();
+
+ if (idx == 0)
+ {
+ return m_thread.GetRegisterContext();
+ }
+
+ if (m_frames.size() == 0)
+ {
+ if (!AddFirstFrame())
+ return reg_ctx_sp;
+ }
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+
+ while (idx >= m_frames.size())
+ {
+ if (!AddOneMoreFrame (abi))
+ break;
+ }
+
+ const uint32_t num_frames = m_frames.size();
+ if (idx < num_frames)
+ {
+ Cursor *frame_cursor = m_frames[idx].get();
+ reg_ctx_sp = frame_cursor->reg_ctx_lldb_sp;
+ }
+ return reg_ctx_sp;
+}
+
+UnwindLLDB::RegisterContextLLDBSP
+UnwindLLDB::GetRegisterContextForFrameNum (uint32_t frame_num)
+{
+ RegisterContextLLDBSP reg_ctx_sp;
+ if (frame_num < m_frames.size())
+ reg_ctx_sp = m_frames[frame_num]->reg_ctx_lldb_sp;
+ return reg_ctx_sp;
+}
+
+bool
+UnwindLLDB::SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc, uint32_t starting_frame_num, bool pc_reg)
+{
+ int64_t frame_num = starting_frame_num;
+ if (frame_num >= m_frames.size())
+ return false;
+
+ // Never interrogate more than one level while looking for the saved pc value. If the value
+ // isn't saved by frame_num, none of the frames lower on the stack will have a useful value.
+ if (pc_reg)
+ {
+ UnwindLLDB::RegisterSearchResult result;
+ result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister (lldb_regnum, regloc);
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound)
+ return true;
+ else
+ return false;
+ }
+ while (frame_num >= 0)
+ {
+ UnwindLLDB::RegisterSearchResult result;
+ result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister (lldb_regnum, regloc);
+
+ // If we have unwind instructions saying that register N is saved in register M in the middle of
+ // the stack (and N can equal M here, meaning the register was not used in this function), then
+ // change the register number we're looking for to M and keep looking for a concrete location
+ // down the stack, or an actual value from a live RegisterContext at frame 0.
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound
+ && regloc.type == UnwindLLDB::RegisterLocation::eRegisterInRegister
+ && frame_num > 0)
+ {
+ result = UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ lldb_regnum = regloc.location.register_number;
+ }
+
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound)
+ return true;
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile)
+ return false;
+ frame_num--;
+ }
+ return false;
+}
diff --git a/source/Plugins/Process/Utility/UnwindLLDB.h b/source/Plugins/Process/Utility/UnwindLLDB.h
new file mode 100644
index 000000000000..5725654a6869
--- /dev/null
+++ b/source/Plugins/Process/Utility/UnwindLLDB.h
@@ -0,0 +1,125 @@
+//===-- UnwindLLDB.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_UnwindLLDB_h_
+#define lldb_UnwindLLDB_h_
+
+#include <vector>
+
+#include "lldb/lldb-public.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Unwind.h"
+
+namespace lldb_private {
+
+class RegisterContextLLDB;
+
+class UnwindLLDB : public lldb_private::Unwind
+{
+public:
+ UnwindLLDB (lldb_private::Thread &thread);
+
+ virtual
+ ~UnwindLLDB() { }
+
+ enum RegisterSearchResult
+ {
+ eRegisterFound = 0,
+ eRegisterNotFound,
+ eRegisterIsVolatile
+ };
+
+protected:
+ friend class lldb_private::RegisterContextLLDB;
+
+ struct RegisterLocation {
+ enum RegisterLocationTypes
+ {
+ eRegisterNotSaved = 0, // register was not preserved by callee. If volatile reg, is unavailable
+ eRegisterSavedAtMemoryLocation, // register is saved at a specific word of target mem (target_memory_location)
+ eRegisterInRegister, // register is available in a (possible other) register (register_number)
+ eRegisterSavedAtHostMemoryLocation, // register is saved at a word in lldb's address space
+ eRegisterValueInferred // register val was computed (and is in inferred_value)
+ };
+ int type;
+ union
+ {
+ lldb::addr_t target_memory_location;
+ uint32_t register_number; // in eRegisterKindLLDB register numbering system
+ void* host_memory_location;
+ uint64_t inferred_value; // eRegisterValueInferred - e.g. stack pointer == cfa + offset
+ } location;
+ };
+
+ void
+ DoClear()
+ {
+ m_frames.clear();
+ m_unwind_complete = false;
+ }
+
+ virtual uint32_t
+ DoGetFrameCount();
+
+ bool
+ DoGetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& start_pc);
+
+ lldb::RegisterContextSP
+ DoCreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ typedef std::shared_ptr<RegisterContextLLDB> RegisterContextLLDBSP;
+
+ // Needed to retrieve the "next" frame (e.g. frame 2 needs to retrieve frame 1's RegisterContextLLDB)
+ // The RegisterContext for frame_num must already exist or this returns an empty shared pointer.
+ RegisterContextLLDBSP
+ GetRegisterContextForFrameNum (uint32_t frame_num);
+
+ // Iterate over the RegisterContextLLDB's in our m_frames vector, look for the first one that
+ // has a saved location for this reg.
+ bool
+ SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc, uint32_t starting_frame_num, bool pc_register);
+
+
+private:
+
+ struct Cursor
+ {
+ lldb::addr_t start_pc; // The start address of the function/symbol for this frame - current pc if unknown
+ lldb::addr_t cfa; // The canonical frame address for this stack frame
+ lldb_private::SymbolContext sctx; // A symbol context we'll contribute to & provide to the StackFrame creation
+ RegisterContextLLDBSP reg_ctx_lldb_sp; // These are all RegisterContextLLDB's
+
+ Cursor () : start_pc (LLDB_INVALID_ADDRESS), cfa (LLDB_INVALID_ADDRESS), sctx(), reg_ctx_lldb_sp() { }
+ private:
+ DISALLOW_COPY_AND_ASSIGN (Cursor);
+ };
+
+ typedef std::shared_ptr<Cursor> CursorSP;
+ std::vector<CursorSP> m_frames;
+ bool m_unwind_complete; // If this is true, we've enumerated all the frames in the stack, and m_frames.size() is the
+ // number of frames, etc. Otherwise we've only gone as far as directly asked, and m_frames.size()
+ // is how far we've currently gone.
+
+
+ bool AddOneMoreFrame (ABI *abi);
+ bool AddFirstFrame ();
+
+ //------------------------------------------------------------------
+ // For UnwindLLDB only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (UnwindLLDB);
+};
+
+} // namespace lldb_private
+
+#endif // lldb_UnwindLLDB_h_
diff --git a/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
new file mode 100644
index 000000000000..d011314b0963
--- /dev/null
+++ b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
@@ -0,0 +1,275 @@
+//===-- UnwindMacOSXFrameBackchain.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "RegisterContextMacOSXFrameBackchain.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindMacOSXFrameBackchain::UnwindMacOSXFrameBackchain (Thread &thread) :
+ Unwind (thread),
+ m_cursors()
+{
+}
+
+uint32_t
+UnwindMacOSXFrameBackchain::DoGetFrameCount()
+{
+ if (m_cursors.empty())
+ {
+ ExecutionContext exe_ctx (m_thread.shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ const ArchSpec& target_arch = target->GetArchitecture ();
+ // Frame zero should always be supplied by the thread...
+ exe_ctx.SetFrameSP (m_thread.GetStackFrameAtIndex (0));
+
+ if (target_arch.GetAddressByteSize() == 8)
+ GetStackFrameData_x86_64 (exe_ctx);
+ else
+ GetStackFrameData_i386 (exe_ctx);
+ }
+ }
+ return m_cursors.size();
+}
+
+bool
+UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex (uint32_t idx, addr_t& cfa, addr_t& pc)
+{
+ const uint32_t frame_count = GetFrameCount();
+ if (idx < frame_count)
+ {
+ if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS)
+ return false;
+ if (m_cursors[idx].fp == LLDB_INVALID_ADDRESS)
+ return false;
+
+ pc = m_cursors[idx].pc;
+ cfa = m_cursors[idx].fp;
+
+ return true;
+ }
+ return false;
+}
+
+lldb::RegisterContextSP
+UnwindMacOSXFrameBackchain::DoCreateRegisterContextForFrame (StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_idx = frame->GetConcreteFrameIndex ();
+ const uint32_t frame_count = GetFrameCount();
+ if (concrete_idx < frame_count)
+ reg_ctx_sp.reset (new RegisterContextMacOSXFrameBackchain (m_thread, concrete_idx, m_cursors[concrete_idx]));
+ return reg_ctx_sp;
+}
+
+size_t
+UnwindMacOSXFrameBackchain::GetStackFrameData_i386 (const ExecutionContext &exe_ctx)
+{
+ m_cursors.clear();
+
+ StackFrame *first_frame = exe_ctx.GetFramePtr();
+
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ return 0;
+
+ std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
+
+ struct Frame_i386
+ {
+ uint32_t fp;
+ uint32_t pc;
+ };
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+ assert (reg_ctx);
+
+ Cursor cursor;
+ cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
+ cursor.fp = reg_ctx->GetFP (0);
+
+ Frame_i386 frame = { static_cast<uint32_t>(cursor.fp), static_cast<uint32_t>(cursor.pc) };
+
+ m_cursors.push_back(cursor);
+
+ const size_t k_frame_size = sizeof(frame);
+ Error error;
+ while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
+ {
+ // Read both the FP and PC (8 bytes)
+ if (process->ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
+ break;
+ if (frame.pc >= 0x1000)
+ {
+ cursor.pc = frame.pc;
+ cursor.fp = frame.fp;
+ m_cursors.push_back (cursor);
+ }
+ }
+ if (!m_cursors.empty())
+ {
+ lldb::addr_t first_frame_pc = m_cursors.front().pc;
+ if (first_frame_pc != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t resolve_scope = eSymbolContextModule |
+ eSymbolContextCompUnit |
+ eSymbolContextFunction |
+ eSymbolContextSymbol;
+
+ SymbolContext first_frame_sc (first_frame->GetSymbolContext(resolve_scope));
+ const AddressRange *addr_range_ptr = NULL;
+ AddressRange range;
+ if (first_frame_sc.function)
+ addr_range_ptr = &first_frame_sc.function->GetAddressRange();
+ else if (first_frame_sc.symbol)
+ {
+ range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
+ range.SetByteSize (first_frame_sc.symbol->GetByteSize());
+ addr_range_ptr = &range;
+ }
+
+ if (addr_range_ptr)
+ {
+ if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
+ {
+ // We are at the first instruction, so we can recover the
+ // previous PC by dereferencing the SP
+ lldb::addr_t first_frame_sp = reg_ctx->GetSP (0);
+ // Read the real second frame return address into frame.pc
+ if (first_frame_sp && process->ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
+ {
+ cursor.fp = m_cursors.front().fp;
+ cursor.pc = frame.pc; // Set the new second frame PC
+
+ // Insert the second frame
+ m_cursors.insert(m_cursors.begin()+1, cursor);
+
+ m_cursors.front().fp = first_frame_sp;
+ }
+ }
+ }
+ }
+ }
+// uint32_t i=0;
+// printf(" PC FP\n");
+// printf(" ------------------ ------------------ \n");
+// for (i=0; i<m_cursors.size(); ++i)
+// {
+// printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 "\n", i, m_cursors[i].pc, m_cursors[i].fp);
+// }
+ return m_cursors.size();
+}
+
+
+size_t
+UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64 (const ExecutionContext &exe_ctx)
+{
+ m_cursors.clear();
+
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ return 0;
+
+ StackFrame *first_frame = exe_ctx.GetFramePtr();
+
+ std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
+
+ struct Frame_x86_64
+ {
+ uint64_t fp;
+ uint64_t pc;
+ };
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+ assert (reg_ctx);
+
+ Cursor cursor;
+ cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
+ cursor.fp = reg_ctx->GetFP (0);
+
+ Frame_x86_64 frame = { cursor.fp, cursor.pc };
+
+ m_cursors.push_back(cursor);
+ Error error;
+ const size_t k_frame_size = sizeof(frame);
+ while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
+ {
+ // Read both the FP and PC (16 bytes)
+ if (process->ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
+ break;
+
+ if (frame.pc >= 0x1000)
+ {
+ cursor.pc = frame.pc;
+ cursor.fp = frame.fp;
+ m_cursors.push_back (cursor);
+ }
+ }
+ if (!m_cursors.empty())
+ {
+ lldb::addr_t first_frame_pc = m_cursors.front().pc;
+ if (first_frame_pc != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t resolve_scope = eSymbolContextModule |
+ eSymbolContextCompUnit |
+ eSymbolContextFunction |
+ eSymbolContextSymbol;
+
+ SymbolContext first_frame_sc(first_frame->GetSymbolContext(resolve_scope));
+ const AddressRange *addr_range_ptr = NULL;
+ AddressRange range;
+ if (first_frame_sc.function)
+ addr_range_ptr = &first_frame_sc.function->GetAddressRange();
+ else if (first_frame_sc.symbol)
+ {
+ range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
+ range.SetByteSize (first_frame_sc.symbol->GetByteSize());
+ addr_range_ptr = &range;
+ }
+
+ if (addr_range_ptr)
+ {
+ if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
+ {
+ // We are at the first instruction, so we can recover the
+ // previous PC by dereferencing the SP
+ lldb::addr_t first_frame_sp = reg_ctx->GetSP (0);
+ // Read the real second frame return address into frame.pc
+ if (process->ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
+ {
+ cursor.fp = m_cursors.front().fp;
+ cursor.pc = frame.pc; // Set the new second frame PC
+
+ // Insert the second frame
+ m_cursors.insert(m_cursors.begin()+1, cursor);
+
+ m_cursors.front().fp = first_frame_sp;
+ }
+ }
+ }
+ }
+ }
+ return m_cursors.size();
+}
+
diff --git a/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h
new file mode 100644
index 000000000000..2695376fd6e0
--- /dev/null
+++ b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h
@@ -0,0 +1,74 @@
+//===-- UnwindMacOSXFrameBackchain.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_UnwindMacOSXFrameBackchain_h_
+#define lldb_UnwindMacOSXFrameBackchain_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/Unwind.h"
+
+class UnwindMacOSXFrameBackchain : public lldb_private::Unwind
+{
+public:
+ UnwindMacOSXFrameBackchain (lldb_private::Thread &thread);
+
+ virtual
+ ~UnwindMacOSXFrameBackchain()
+ {
+ }
+
+protected:
+ virtual void
+ DoClear()
+ {
+ m_cursors.clear();
+ }
+
+ virtual uint32_t
+ DoGetFrameCount();
+
+ bool
+ DoGetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& pc);
+
+ lldb::RegisterContextSP
+ DoCreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ friend class RegisterContextMacOSXFrameBackchain;
+
+ struct Cursor
+ {
+ lldb::addr_t pc; // Program counter
+ lldb::addr_t fp; // Frame pointer for us with backchain
+ };
+
+private:
+ std::vector<Cursor> m_cursors;
+
+ size_t
+ GetStackFrameData_i386 (const lldb_private::ExecutionContext &exe_ctx);
+
+ size_t
+ GetStackFrameData_x86_64 (const lldb_private::ExecutionContext &exe_ctx);
+
+ //------------------------------------------------------------------
+ // For UnwindMacOSXFrameBackchain only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (UnwindMacOSXFrameBackchain);
+};
+
+#endif // lldb_UnwindMacOSXFrameBackchain_h_