TCA smashableJccTarget(TCA jmp) { using namespace vixl; Instruction* b = Instruction::Cast(jmp); if (b->Bits(31, 24) != 0x54 || b->Bit(4) != 0) return nullptr; Instruction* br = Instruction::Cast(jmp + 8); if (br->Bits(31, 10) != 0x3587C0 || br->Bits(4, 0) != 0) return nullptr; uintptr_t dest = reinterpret_cast<uintptr_t>(jmp + 12); assertx((dest & 7) == 0); return *reinterpret_cast<TCA*>(dest); }
TCA smashableCallTarget(TCA call) { using namespace vixl; Instruction* ldr = Instruction::Cast(call); if (ldr->Bits(31, 24) != 0x58) return nullptr; Instruction* blr = Instruction::Cast(call + 4); if (blr->Bits(31, 10) != 0x358FC0 || blr->Bits(4, 0) != 0) return nullptr; uintptr_t dest = reinterpret_cast<uintptr_t>(blr + 8); assertx((dest & 7) == 0); return *reinterpret_cast<TCA*>(dest); }
TCA smashableJmpTarget(TCA jmp) { // This doesn't verify that each of the two or three instructions that make // up this sequence matches; just the first one and the indirect jump. using namespace vixl; Instruction* ldr = Instruction::Cast(jmp); if (ldr->Bits(31, 24) != 0x58) return nullptr; Instruction* br = Instruction::Cast(jmp + 4); if (br->Bits(31, 10) != 0x3587C0 || br->Bits(4, 0) != 0) return nullptr; uintptr_t dest = reinterpret_cast<uintptr_t>(jmp + 8); assertx((dest & 7) == 0); return *reinterpret_cast<TCA*>(dest); }
ConditionCode smashableJccCond(TCA inst) { using namespace vixl; Instruction* b = Instruction::Cast(inst); Instruction* ldr = b->NextInstruction();; Instruction* br = ldr->NextInstruction(); Instruction* target = br->NextInstruction(); DEBUG_ONLY Instruction* after = target->NextInstruction()->NextInstruction(); DEBUG_ONLY const auto rd = ldr->Rd(); assertx(b->IsCondBranchImm() && b->ImmPCOffsetTarget() == after && ldr->IsLoadLiteral() && ldr->Mask(LoadLiteralMask) == LDR_x_lit && ldr->ImmPCOffsetTarget() == target && br->Mask(UnconditionalBranchToRegisterMask) == BR && br->Rn() == rd); return arm::convertCC(InvertCondition(static_cast<Condition>(b->Bits(3, 0)))); }