Skip to content

Commit 7d57ba0

Browse files
committed
[a64] Implement b bl br blr cbnz cbz instruction-stepping
1 parent 58d285d commit 7d57ba0

File tree

1 file changed

+147
-10
lines changed

1 file changed

+147
-10
lines changed

src/xenia/cpu/backend/a64/a64_backend.cc

Lines changed: 147 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -212,12 +212,120 @@ uint64_t ReadCapstoneReg(HostThreadContext* context, arm64_reg reg) {
212212
return context->x[29];
213213
case ARM64_REG_X30:
214214
return context->x[30];
215+
case ARM64_REG_W0:
216+
return uint32_t(context->x[0]);
217+
case ARM64_REG_W1:
218+
return uint32_t(context->x[1]);
219+
case ARM64_REG_W2:
220+
return uint32_t(context->x[2]);
221+
case ARM64_REG_W3:
222+
return uint32_t(context->x[3]);
223+
case ARM64_REG_W4:
224+
return uint32_t(context->x[4]);
225+
case ARM64_REG_W5:
226+
return uint32_t(context->x[5]);
227+
case ARM64_REG_W6:
228+
return uint32_t(context->x[6]);
229+
case ARM64_REG_W7:
230+
return uint32_t(context->x[7]);
231+
case ARM64_REG_W8:
232+
return uint32_t(context->x[8]);
233+
case ARM64_REG_W9:
234+
return uint32_t(context->x[9]);
235+
case ARM64_REG_W10:
236+
return uint32_t(context->x[10]);
237+
case ARM64_REG_W11:
238+
return uint32_t(context->x[11]);
239+
case ARM64_REG_W12:
240+
return uint32_t(context->x[12]);
241+
case ARM64_REG_W13:
242+
return uint32_t(context->x[13]);
243+
case ARM64_REG_W14:
244+
return uint32_t(context->x[14]);
245+
case ARM64_REG_W15:
246+
return uint32_t(context->x[15]);
247+
case ARM64_REG_W16:
248+
return uint32_t(context->x[16]);
249+
case ARM64_REG_W17:
250+
return uint32_t(context->x[17]);
251+
case ARM64_REG_W18:
252+
return uint32_t(context->x[18]);
253+
case ARM64_REG_W19:
254+
return uint32_t(context->x[19]);
255+
case ARM64_REG_W20:
256+
return uint32_t(context->x[20]);
257+
case ARM64_REG_W21:
258+
return uint32_t(context->x[21]);
259+
case ARM64_REG_W22:
260+
return uint32_t(context->x[22]);
261+
case ARM64_REG_W23:
262+
return uint32_t(context->x[23]);
263+
case ARM64_REG_W24:
264+
return uint32_t(context->x[24]);
265+
case ARM64_REG_W25:
266+
return uint32_t(context->x[25]);
267+
case ARM64_REG_W26:
268+
return uint32_t(context->x[26]);
269+
case ARM64_REG_W27:
270+
return uint32_t(context->x[27]);
271+
case ARM64_REG_W28:
272+
return uint32_t(context->x[28]);
273+
case ARM64_REG_W29:
274+
return uint32_t(context->x[29]);
275+
case ARM64_REG_W30:
276+
return uint32_t(context->x[30]);
215277
default:
216278
assert_unhandled_case(reg);
217279
return 0;
218280
}
219281
}
220282

283+
bool TestCapstonePstate(arm64_cc cond, uint32_t pstate) {
284+
// https://devblogs.microsoft.com/oldnewthing/20220815-00/?p=106975
285+
// Upper 4 bits of pstate are NZCV
286+
const bool N = !!(pstate & 0x80000000);
287+
const bool Z = !!(pstate & 0x40000000);
288+
const bool C = !!(pstate & 0x20000000);
289+
const bool V = !!(pstate & 0x10000000);
290+
switch (cond) {
291+
case ARM64_CC_EQ:
292+
return (Z == true);
293+
case ARM64_CC_NE:
294+
return (Z == false);
295+
case ARM64_CC_HS:
296+
return (C == true);
297+
case ARM64_CC_LO:
298+
return (C == false);
299+
case ARM64_CC_MI:
300+
return (N == true);
301+
case ARM64_CC_PL:
302+
return (N == false);
303+
case ARM64_CC_VS:
304+
return (V == true);
305+
case ARM64_CC_VC:
306+
return (V == false);
307+
case ARM64_CC_HI:
308+
return ((C == true) && (Z == false));
309+
case ARM64_CC_LS:
310+
return ((C == false) || (Z == true));
311+
case ARM64_CC_GE:
312+
return (N == V);
313+
case ARM64_CC_LT:
314+
return (N != V);
315+
case ARM64_CC_GT:
316+
return ((Z == false) && (N == V));
317+
case ARM64_CC_LE:
318+
return ((Z == true) || (N != V));
319+
case ARM64_CC_AL:
320+
return true;
321+
case ARM64_CC_NV:
322+
return false;
323+
default:
324+
assert_unhandled_case(cond);
325+
return false;
326+
}
327+
}
328+
221329
uint64_t A64Backend::CalculateNextHostInstruction(ThreadDebugInfo* thread_info,
222330
uint64_t current_pc) {
223331
auto machine_code_ptr = reinterpret_cast<const uint8_t*>(current_pc);
@@ -233,23 +341,52 @@ uint64_t A64Backend::CalculateNextHostInstruction(ThreadDebugInfo* thread_info,
233341
case ARM64_INS_B:
234342
case ARM64_INS_BL: {
235343
assert_true(detail.operands[0].type == ARM64_OP_IMM);
236-
uint64_t target_pc = static_cast<uint64_t>(detail.operands[0].imm);
237-
return current_pc + target_pc;
344+
const int64_t pc_offset = static_cast<int64_t>(detail.operands[0].imm);
345+
const bool test_passed =
346+
TestCapstonePstate(detail.cc, thread_info->host_context.cpsr);
347+
if (test_passed) {
348+
return current_pc + pc_offset;
349+
} else {
350+
return current_pc + insn.size;
351+
}
238352
} break;
239-
case ARM64_INS_BLR:
240-
case ARM64_INS_BR: {
353+
case ARM64_INS_BR:
354+
case ARM64_INS_BLR: {
241355
assert_true(detail.operands[0].type == ARM64_OP_REG);
242-
uint64_t target_pc =
356+
const uint64_t target_pc =
243357
ReadCapstoneReg(&thread_info->host_context, detail.operands[0].reg);
244358
return target_pc;
245359
} break;
246360
case ARM64_INS_RET: {
247-
assert_zero(detail.op_count);
248-
// Jump to link register
249-
return thread_info->host_context.x[30];
361+
assert_true(detail.operands[0].type == ARM64_OP_REG);
362+
const uint64_t target_pc =
363+
ReadCapstoneReg(&thread_info->host_context, detail.operands[0].reg);
364+
return target_pc;
365+
} break;
366+
case ARM64_INS_CBNZ: {
367+
assert_true(detail.operands[0].type == ARM64_OP_REG);
368+
assert_true(detail.operands[1].type == ARM64_OP_IMM);
369+
const int64_t pc_offset = static_cast<int64_t>(detail.operands[1].imm);
370+
const bool test_passed = (0 != ReadCapstoneReg(&thread_info->host_context,
371+
detail.operands[0].reg));
372+
if (test_passed) {
373+
return current_pc + pc_offset;
374+
} else {
375+
return current_pc + insn.size;
376+
}
377+
} break;
378+
case ARM64_INS_CBZ: {
379+
assert_true(detail.operands[0].type == ARM64_OP_REG);
380+
assert_true(detail.operands[1].type == ARM64_OP_IMM);
381+
const int64_t pc_offset = static_cast<int64_t>(detail.operands[1].imm);
382+
const bool test_passed = (0 == ReadCapstoneReg(&thread_info->host_context,
383+
detail.operands[0].reg));
384+
if (test_passed) {
385+
return current_pc + pc_offset;
386+
} else {
387+
return current_pc + insn.size;
388+
}
250389
} break;
251-
case ARM64_INS_CBNZ:
252-
case ARM64_INS_CBZ:
253390
default: {
254391
// Not a branching instruction - just move over it.
255392
return current_pc + insn.size;

0 commit comments

Comments
 (0)