Skip to content

Commit 58d285d

Browse files
committed
[a64] Implement instruction stepping.
Uses `0x0000'dead` as an instructon-stepping sentinel value. Support for basic jumping instructions like `b`, `bl`, `br`, and `blr`.
1 parent a864a7c commit 58d285d

File tree

1 file changed

+33
-18
lines changed

1 file changed

+33
-18
lines changed

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

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -228,26 +228,41 @@ uint64_t A64Backend::CalculateNextHostInstruction(ThreadDebugInfo* thread_info,
228228
insn.detail = &all_detail;
229229
cs_disasm_iter(capstone_handle_, &machine_code_ptr,
230230
&remaining_machine_code_size, &host_address, &insn);
231-
auto& detail = all_detail.x86;
231+
const auto& detail = all_detail.arm64;
232232
switch (insn.id) {
233233
case ARM64_INS_B:
234-
case ARM64_INS_BL:
234+
case ARM64_INS_BL: {
235+
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;
238+
} break;
235239
case ARM64_INS_BLR:
236-
case ARM64_INS_BR:
237-
case ARM64_INS_RET:
238-
// todo(wunkolo): determine next instruction
239-
default:
240+
case ARM64_INS_BR: {
241+
assert_true(detail.operands[0].type == ARM64_OP_REG);
242+
uint64_t target_pc =
243+
ReadCapstoneReg(&thread_info->host_context, detail.operands[0].reg);
244+
return target_pc;
245+
} break;
246+
case ARM64_INS_RET: {
247+
assert_zero(detail.op_count);
248+
// Jump to link register
249+
return thread_info->host_context.x[30];
250+
} break;
251+
case ARM64_INS_CBNZ:
252+
case ARM64_INS_CBZ:
253+
default: {
240254
// Not a branching instruction - just move over it.
241255
return current_pc + insn.size;
256+
} break;
242257
}
243258
}
244259

245260
void A64Backend::InstallBreakpoint(Breakpoint* breakpoint) {
246261
breakpoint->ForEachHostAddress([breakpoint](uint64_t host_address) {
247262
auto ptr = reinterpret_cast<void*>(host_address);
248-
auto original_bytes = xe::load_and_swap<uint16_t>(ptr);
249-
assert_true(original_bytes != 0x0F0B);
250-
xe::store_and_swap<uint16_t>(ptr, 0x0F0B);
263+
auto original_bytes = xe::load_and_swap<uint32_t>(ptr);
264+
assert_true(original_bytes != 0x0000'dead);
265+
xe::store_and_swap<uint32_t>(ptr, 0x0000'dead);
251266
breakpoint->backend_data().emplace_back(host_address, original_bytes);
252267
});
253268
}
@@ -265,18 +280,18 @@ void A64Backend::InstallBreakpoint(Breakpoint* breakpoint, Function* fn) {
265280

266281
// Assume we haven't already installed a breakpoint in this spot.
267282
auto ptr = reinterpret_cast<void*>(host_address);
268-
auto original_bytes = xe::load_and_swap<uint16_t>(ptr);
269-
assert_true(original_bytes != 0x0F0B);
270-
xe::store_and_swap<uint16_t>(ptr, 0x0F0B);
283+
auto original_bytes = xe::load_and_swap<uint32_t>(ptr);
284+
assert_true(original_bytes != 0x0000'dead);
285+
xe::store_and_swap<uint32_t>(ptr, 0x0000'dead);
271286
breakpoint->backend_data().emplace_back(host_address, original_bytes);
272287
}
273288

274289
void A64Backend::UninstallBreakpoint(Breakpoint* breakpoint) {
275290
for (auto& pair : breakpoint->backend_data()) {
276291
auto ptr = reinterpret_cast<uint8_t*>(pair.first);
277-
auto instruction_bytes = xe::load_and_swap<uint16_t>(ptr);
278-
assert_true(instruction_bytes == 0x0F0B);
279-
xe::store_and_swap<uint16_t>(ptr, static_cast<uint16_t>(pair.second));
292+
auto instruction_bytes = xe::load_and_swap<uint32_t>(ptr);
293+
assert_true(instruction_bytes == 0x0000'dead);
294+
xe::store_and_swap<uint32_t>(ptr, static_cast<uint32_t>(pair.second));
280295
}
281296
breakpoint->backend_data().clear();
282297
}
@@ -296,9 +311,9 @@ bool A64Backend::ExceptionCallback(Exception* ex) {
296311

297312
// Verify an expected illegal instruction.
298313
auto instruction_bytes =
299-
xe::load_and_swap<uint16_t>(reinterpret_cast<void*>(ex->pc()));
300-
if (instruction_bytes != 0x0F0B) {
301-
// Not our ud2 - not us.
314+
xe::load_and_swap<uint32_t>(reinterpret_cast<void*>(ex->pc()));
315+
if (instruction_bytes != 0x0000'dead) {
316+
// Not our `udf #0xdead` - not us.
302317
return false;
303318
}
304319

0 commit comments

Comments
 (0)