aboutsummaryrefslogtreecommitdiff
path: root/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp')
-rw-r--r--source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp389
1 files changed, 347 insertions, 42 deletions
diff --git a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
index 3900af9b00d0..992df1fba59e 100644
--- a/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
+++ b/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
@@ -183,10 +183,10 @@ EmulateInstructionARM64::SetTargetTriple (const ArchSpec &arch)
return true;
else if (arch.GetTriple().getArch () == llvm::Triple::thumb)
return true;
-
+
return false;
}
-
+
bool
EmulateInstructionARM64::GetRegisterInfo (RegisterKind reg_kind, uint32_t reg_num, RegisterInfo &reg_info)
{
@@ -236,23 +236,53 @@ EmulateInstructionARM64::GetOpcodeForInstruction (const uint32_t opcode)
{ 0xff000000, 0x91000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADD <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}" },
{ 0xff000000, 0xb1000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADDS <Xd>, <Xn|SP>, #<imm> {, <shift>}" },
-
{ 0xff000000, 0x51000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUB <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}" },
{ 0xff000000, 0x71000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUBS <Wd>, <Wn|WSP>, #<imm> {, <shift>}" },
{ 0xff000000, 0x11000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADD <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}" },
{ 0xff000000, 0x31000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADDS <Wd>, <Wn|WSP>, #<imm> {, <shift>}" },
-
- { 0xffc00000, 0x29000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]" },
- { 0xffc00000, 0xa9000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]" },
- { 0xffc00000, 0x2d000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <St>, <St2>, [<Xn|SP>{, #<imm>}]" },
- { 0xffc00000, 0x6d000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]" },
- { 0xffc00000, 0xad000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]" },
-
- { 0xffc00000, 0xad800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!" },
- { 0xffc00000, 0x2d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <St>, <St2>, [<Xn|SP>, #<imm>]!" },
- { 0xffc00000, 0x29800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!" },
- { 0xffc00000, 0x6d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!" },
- { 0xffc00000, 0xa9800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!" },
+
+ { 0xffc00000, 0x29000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0xa9000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0x2d000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <St>, <St2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0x6d000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0xad000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]" },
+
+ { 0xffc00000, 0x29800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xa9800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x2d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <St>, <St2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x6d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xad800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!" },
+
+ { 0xffc00000, 0x28800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xa8800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x2c800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "STP <St>, <St2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x6c800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xac800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!" },
+
+ { 0xffc00000, 0x29400000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "LDP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0xa9400000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "LDP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0x2d400000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "LDP <St>, <St2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0x6d400000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "LDP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0xad400000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "LDP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]" },
+
+ { 0xffc00000, 0x29c00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xa9c00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x2dc00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "LDP <St>, <St2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x6dc00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xadc00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!" },
+
+ { 0xffc00000, 0x28c00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "LDP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xa8c00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "LDP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x2cc00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "LDP <St>, <St2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x6cc00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "LDP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xacc00000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_post, "LDP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!" },
+
+ { 0xfc000000, 0x14000000, No_VFP, &EmulateInstructionARM64::EmulateB, "B <label>" },
+ { 0xff000010, 0x54000000, No_VFP, &EmulateInstructionARM64::EmulateBcond, "B.<cond> <label>" },
+ { 0x7f000000, 0x34000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ, "CBZ <Wt>, <label>" },
+ { 0x7f000000, 0x35000000, No_VFP, &EmulateInstructionARM64::EmulateCBZ, "CBNZ <Wt>, <label>" },
+ { 0x7f000000, 0x36000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ, "TBZ <R><t>, #<imm>, <label>" },
+ { 0x7f000000, 0x37000000, No_VFP, &EmulateInstructionARM64::EmulateTBZ, "TBNZ <R><t>, #<imm>, <label>" },
};
static const size_t k_num_arm_opcodes = llvm::array_lengthof(g_opcodes);
@@ -262,10 +292,10 @@ EmulateInstructionARM64::GetOpcodeForInstruction (const uint32_t opcode)
if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value)
return &g_opcodes[i];
}
- return NULL;
+ return nullptr;
}
-bool
+bool
EmulateInstructionARM64::ReadInstruction ()
{
bool success = false;
@@ -346,25 +376,139 @@ EmulateInstructionARM64::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan)
unwind_plan.SetRegisterKind (eRegisterKindDWARF);
UnwindPlan::RowSP row(new UnwindPlan::Row);
- const bool can_replace = false;
// Our previous Call Frame Address is the stack pointer
- row->SetCFARegister (arm64_dwarf::sp);
-
- // Our previous PC is in the LR
- row->SetRegisterLocationToRegister(arm64_dwarf::pc, arm64_dwarf::lr, can_replace);
+ row->GetCFAValue().SetIsRegisterPlusOffset(arm64_dwarf::sp, 0);
unwind_plan.AppendRow (row);
-
- // All other registers are the same.
-
unwind_plan.SetSourceName ("EmulateInstructionARM64");
unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
+ unwind_plan.SetReturnAddressRegister (arm64_dwarf::lr);
return true;
}
+uint32_t
+EmulateInstructionARM64::GetFramePointerRegisterNumber () const
+{
+ if (m_arch.GetTriple().getEnvironment() == llvm::Triple::Android)
+ return LLDB_INVALID_REGNUM; // Don't use frame pointer on android
+ return arm64_dwarf::sp;
+}
+
+bool
+EmulateInstructionARM64::UsingAArch32()
+{
+ bool aarch32 = m_opcode_pstate.RW == 1;
+ // if !HaveAnyAArch32() then assert !aarch32;
+ // if HighestELUsingAArch32() then assert aarch32;
+ return aarch32;
+}
+
+bool
+EmulateInstructionARM64::BranchTo (const Context &context, uint32_t N, addr_t target)
+{
+#if 0
+ // Set program counter to a new address, with a branch reason hint
+ // for possible use by hardware fetching the next instruction.
+ BranchTo(bits(N) target, BranchType branch_type)
+ Hint_Branch(branch_type);
+ if N == 32 then
+ assert UsingAArch32();
+ _PC = ZeroExtend(target);
+ else
+ assert N == 64 && !UsingAArch32();
+ // Remove the tag bits from a tagged target
+ case PSTATE.EL of
+ when EL0, EL1
+ if target<55> == '1' && TCR_EL1.TBI1 == '1' then
+ target<63:56> = '11111111';
+ if target<55> == '0' && TCR_EL1.TBI0 == '1' then
+ target<63:56> = '00000000';
+ when EL2
+ if TCR_EL2.TBI == '1' then
+ target<63:56> = '00000000';
+ when EL3
+ if TCR_EL3.TBI == '1' then
+ target<63:56> = '00000000';
+ _PC = target<63:0>;
+ return;
+#endif
+
+ addr_t addr;
+
+ //Hint_Branch(branch_type);
+ if (N == 32)
+ {
+ if (!UsingAArch32())
+ return false;
+ addr = target;
+ }
+ else if (N == 64)
+ {
+ if (UsingAArch32())
+ return false;
+ // TODO: Remove the tag bits from a tagged target
+ addr = target;
+ }
+ else
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, addr))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionARM64::ConditionHolds (const uint32_t cond, bool *is_conditional)
+{
+ // If we are ignoring conditions, then always return true.
+ // this allows us to iterate over disassembly code and still
+ // emulate an instruction even if we don't have all the right
+ // bits set in the CPSR register...
+ if (m_ignore_conditions)
+ return true;
+
+ if (is_conditional)
+ *is_conditional = true;
+
+ bool result = false;
+ switch (UnsignedBits(cond, 3, 1))
+ {
+ case 0:
+ result = (m_opcode_pstate.Z == 1);
+ break;
+ case 1:
+ result = (m_opcode_pstate.C == 1);
+ break;
+ case 2:
+ result = (m_opcode_pstate.N == 1);
+ break;
+ case 3:
+ result = (m_opcode_pstate.V == 1);
+ break;
+ case 4:
+ result = (m_opcode_pstate.C == 1 && m_opcode_pstate.Z == 0);
+ break;
+ case 5:
+ result = (m_opcode_pstate.N == m_opcode_pstate.V);
+ break;
+ case 6:
+ result = (m_opcode_pstate.N == m_opcode_pstate.V && m_opcode_pstate.Z == 0);
+ break;
+ case 7:
+ result = true;
+ if (is_conditional)
+ *is_conditional = false;
+ break;
+ }
+
+ if (cond & 1 && cond != 15)
+ result = !result;
+ return result;
+}
bool
EmulateInstructionARM64::Emulate_addsub_imm (const uint32_t opcode)
@@ -460,13 +604,13 @@ EmulateInstructionARM64::Emulate_addsub_imm (const uint32_t opcode)
if (arm64_dwarf::GetRegisterInfo (n, reg_info_Rn))
context.SetRegisterPlusOffset (reg_info_Rn, imm);
- if ((n == arm64_dwarf::sp || n == arm64_dwarf::fp) &&
+ if ((n == arm64_dwarf::sp || n == GetFramePointerRegisterNumber()) &&
d == arm64_dwarf::sp &&
!setflags)
{
context.type = EmulateInstruction::eContextAdjustStackPointer;
}
- else if (d == arm64_dwarf::fp &&
+ else if (d == GetFramePointerRegisterNumber() &&
n == arm64_dwarf::sp &&
!setflags)
{
@@ -476,8 +620,11 @@ EmulateInstructionARM64::Emulate_addsub_imm (const uint32_t opcode)
{
context.type = EmulateInstruction::eContextImmediate;
}
- WriteRegisterUnsigned (context, eRegisterKindDWARF, arm64_dwarf::x0 + d, result);
-
+
+ // If setflags && d == arm64_dwarf::sp then d = WZR/XZR. See CMN, CMP
+ if (!setflags || d != arm64_dwarf::sp)
+ WriteRegisterUnsigned (context, eRegisterKindDWARF, arm64_dwarf::x0 + d, result);
+
return false;
}
@@ -487,7 +634,6 @@ EmulateInstructionARM64::Emulate_ldstpair_off (const uint32_t opcode)
return Emulate_ldstpair (opcode, AddrMode_OFF);
}
-
bool
EmulateInstructionARM64::Emulate_ldstpair_pre (const uint32_t opcode)
{
@@ -495,6 +641,12 @@ EmulateInstructionARM64::Emulate_ldstpair_pre (const uint32_t opcode)
}
bool
+EmulateInstructionARM64::Emulate_ldstpair_post (const uint32_t opcode)
+{
+ return Emulate_ldstpair (opcode, AddrMode_POST);
+}
+
+bool
EmulateInstructionARM64::Emulate_ldstpair (const uint32_t opcode, AddrMode a_mode)
{
uint32_t opc = Bits32(opcode, 31, 30);
@@ -623,26 +775,24 @@ EmulateInstructionARM64::Emulate_ldstpair (const uint32_t opcode, AddrMode a_mod
Context context_t;
Context context_t2;
-
- if (n == 31 || n == 29) // if this store is based off of the sp or fp register
- {
- context_t.type = eContextPushRegisterOnStack;
- context_t2.type = eContextPushRegisterOnStack;
- }
- else
- {
- context_t.type = eContextRegisterPlusOffset;
- context_t2.type = eContextRegisterPlusOffset;
- }
+
+ context_t.type = eContextRegisterPlusOffset;
+ context_t2.type = eContextRegisterPlusOffset;
context_t.SetRegisterToRegisterPlusOffset (reg_info_Rt, reg_info_base, 0);
context_t2.SetRegisterToRegisterPlusOffset (reg_info_Rt2, reg_info_base, size);
uint8_t buffer [RegisterValue::kMaxRegisterByteSize];
Error error;
-
+
switch (memop)
{
case MemOp_STORE:
{
+ if (n == 31 || n == GetFramePointerRegisterNumber()) // if this store is based off of the sp or fp register
+ {
+ context_t.type = eContextPushRegisterOnStack;
+ context_t2.type = eContextPushRegisterOnStack;
+ }
+
if (!ReadRegister (&reg_info_Rt, data_Rt))
return false;
@@ -665,6 +815,12 @@ EmulateInstructionARM64::Emulate_ldstpair (const uint32_t opcode, AddrMode a_mod
case MemOp_LOAD:
{
+ if (n == 31 || n == GetFramePointerRegisterNumber()) // if this load is based off of the sp or fp register
+ {
+ context_t.type = eContextPopRegisterOffStack;
+ context_t2.type = eContextPopRegisterOffStack;
+ }
+
if (rt_unknown)
memset (buffer, 'U', reg_info_Rt.byte_size);
else
@@ -717,3 +873,152 @@ EmulateInstructionARM64::Emulate_ldstpair (const uint32_t opcode, AddrMode a_mod
}
return true;
}
+
+bool
+EmulateInstructionARM64::EmulateB (const uint32_t opcode)
+{
+#if 0
+ // ARM64 pseudo code...
+ if branch_type == BranchType_CALL then X[30] = PC[] + 4;
+ BranchTo(PC[] + offset, branch_type);
+#endif
+
+ bool success = false;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ const uint64_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
+ if (!success)
+ return false;
+
+ int64_t offset = llvm::SignExtend64<28>(Bits32(opcode, 25, 0) << 2);
+ BranchType branch_type = Bit32(opcode, 31) ? BranchType_CALL : BranchType_JMP;
+ addr_t target = pc + offset;
+ context.SetImmediateSigned(offset);
+
+ switch (branch_type)
+ {
+ case BranchType_CALL:
+ {
+ addr_t x30 = pc + 4;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, arm64_dwarf::x30, x30))
+ return false;
+ }
+ break;
+ case BranchType_JMP:
+ break;
+ default:
+ return false;
+ }
+
+ if (!BranchTo(context, 64, target))
+ return false;
+ return true;
+}
+
+bool
+EmulateInstructionARM64::EmulateBcond (const uint32_t opcode)
+{
+#if 0
+ // ARM64 pseudo code...
+ bits(64) offset = SignExtend(imm19:'00', 64);
+ bits(4) condition = cond;
+ if ConditionHolds(condition) then
+ BranchTo(PC[] + offset, BranchType_JMP);
+#endif
+
+ if (ConditionHolds(Bits32(opcode, 3, 0)))
+ {
+ bool success = false;
+
+ const uint64_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
+ if (!success)
+ return false;
+
+ int64_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2);
+ addr_t target = pc + offset;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ context.SetImmediateSigned(offset);
+ if (!BranchTo(context, 64, target))
+ return false;
+ }
+ return true;
+}
+
+bool
+EmulateInstructionARM64::EmulateCBZ (const uint32_t opcode)
+{
+#if 0
+ integer t = UInt(Rt);
+ integer datasize = if sf == '1' then 64 else 32;
+ boolean iszero = (op == '0');
+ bits(64) offset = SignExtend(imm19:'00', 64);
+
+ bits(datasize) operand1 = X[t];
+ if IsZero(operand1) == iszero then
+ BranchTo(PC[] + offset, BranchType_JMP);
+#endif
+
+ bool success = false;
+
+ uint32_t t = Bits32(opcode, 4, 0);
+ bool is_zero = Bit32(opcode, 24) == 0;
+ int32_t offset = llvm::SignExtend64<21>(Bits32(opcode, 23, 5) << 2);
+
+ const uint64_t operand = ReadRegisterUnsigned(eRegisterKindDWARF, arm64_dwarf::x0 + t, 0, &success);
+ if (!success)
+ return false;
+
+ if (m_ignore_conditions || ((operand == 0) == is_zero))
+ {
+ const uint64_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ context.SetImmediateSigned(offset);
+ if (!BranchTo(context, 64, pc + offset))
+ return false;
+ }
+ return true;
+}
+
+bool
+EmulateInstructionARM64::EmulateTBZ (const uint32_t opcode)
+{
+#if 0
+ integer t = UInt(Rt);
+ integer datasize = if b5 == '1' then 64 else 32;
+ integer bit_pos = UInt(b5:b40);
+ bit bit_val = op;
+ bits(64) offset = SignExtend(imm14:'00', 64);
+#endif
+
+ bool success = false;
+
+ uint32_t t = Bits32(opcode, 4, 0);
+ uint32_t bit_pos = (Bit32(opcode, 31) << 6) | (Bits32(opcode, 23, 19));
+ uint32_t bit_val = Bit32(opcode, 24);
+ int64_t offset = llvm::SignExtend64<16>(Bits32(opcode, 18, 5) << 2);
+
+ const uint64_t operand = ReadRegisterUnsigned(eRegisterKindDWARF, arm64_dwarf::x0 + t, 0, &success);
+ if (!success)
+ return false;
+
+ if (m_ignore_conditions || Bit32(operand, bit_pos) == bit_val)
+ {
+ const uint64_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ context.SetImmediateSigned(offset);
+ if (!BranchTo(context, 64, pc + offset))
+ return false;
+ }
+ return true;
+}