static void gdb_read_command() { u8 c; u8 chk_read, chk_calc; cmd_len = 0; memset(cmd_bfr, 0, sizeof cmd_bfr); c = gdb_read_byte(); if (c == '+') { // ignore ack return; } else if (c == 0x03) { CPU::Break(); gdb_signal(GDB_SIGTRAP); return; } else if (c != GDB_STUB_START) { DEBUG_LOG(GDB_STUB, "gdb: read invalid byte %02x", c); return; } while ((c = gdb_read_byte()) != GDB_STUB_END) { cmd_bfr[cmd_len++] = c; if (cmd_len == sizeof cmd_bfr) { ERROR_LOG(GDB_STUB, "gdb: cmd_bfr overflow"); gdb_nak(); return; } } chk_read = hex2char(gdb_read_byte()) << 4; chk_read |= hex2char(gdb_read_byte()); chk_calc = gdb_calc_chksum(); if (chk_calc != chk_read) { ERROR_LOG(GDB_STUB, "gdb: invalid checksum: calculated %02x and read %02x for $%s# (length: %d)", chk_calc, chk_read, cmd_bfr, cmd_len); cmd_len = 0; gdb_nak(); return; } DEBUG_LOG(GDB_STUB, "gdb: read command %c with a length of %d: %s", cmd_bfr[0], cmd_len, cmd_bfr); gdb_ack(); }
int gdb_trap(struct trap_state *ts) { struct gdb_state r; int signo, orig_signo; oskit_u32_t pc; if (gdb_signal == 0) return -1; /* If a recovery address has been set, use it and return immediately. */ if (gdb_trap_recover) { ts->pc = gdb_trap_recover; return 0; } pc = ts->pc; /* Convert the arm32 trap code into a generic signal number. */ /* XXX some of these are probably not really right. */ switch (ts->trapno) { #define TRAP(trap, sig, adjust) case trap: signo = sig; pc += adjust; break TRAP(-1, SIGINT, 0); TRAP(T_SWI, SIGEMT, -4); TRAP(T_PREFETCH_ABORT, SIGSEGV, -4); TRAP(T_DATA_ABORT, SIGSEGV, -8); TRAP(T_ADDREXC, SIGSEGV, -4); TRAP(T_FIQ, SIGTRAP, -4); TRAP(T_STACK_OVERFLOW, SIGBUS, -8); case T_UNDEF: /* * Check for GDB breakpoint */ if (*((unsigned *) (ts->pc - 4)) == 0xe7ffdefe) { signo = SIGTRAP; pc -= 4; } else if (*((unsigned *) (ts->pc - 4)) == 0xe7ffdefd) { /* See gdb_set_bkpt() */ signo = SIGTRAP; } else { signo = SIGILL; pc -= 4; } break; default: signo = SIGEMT; /* "software generated"*/ #undef TRAP } orig_signo = signo; /* Convert the trap state into GDB's format. */ memset((void *) &r, 0, sizeof(r)); r.r0 = ts->r0; r.r1 = ts->r1; r.r2 = ts->r2; r.r3 = ts->r3; r.r4 = ts->r4; r.r5 = ts->r5; r.r6 = ts->r6; r.r7 = ts->r7; r.r8 = ts->r8; r.r9 = ts->r9; r.r10 = ts->r10; r.r11 = ts->r11; r.r12 = ts->r12; r.ps = ts->spsr; r.pc = pc; /* * XXX Not bothering with user mode stuff */ r.sp = ts->svc_sp; r.lr = ts->svc_lr; /* Call the appropriate GDB stub to do its thing. */ gdb_signal(&signo, &r); /* Stuff GDB's modified state into our trap_state. */ ts->r0 = r.r0; ts->r1 = r.r1; ts->r2 = r.r2; ts->r3 = r.r3; ts->r4 = r.r4; ts->r5 = r.r5; ts->r6 = r.r6; ts->r7 = r.r7; ts->r8 = r.r8; ts->r9 = r.r9; ts->r10 = r.r10; ts->r11 = r.r11; ts->r12 = r.r12; ts->pc = r.pc; ts->svc_lr = r.lr; /* * XXX Not bothering with user mode stuff */ { /* XXX currently we don't know how to change the kernel esp. We could do it by physically moving the trap frame. */ if (r.sp != (unsigned)ts->svc_sp) panic("gdb_trap: can't change stack pointer"); } if (r.ps != ts->spsr) panic("gdb_trap: can't change PSR: 0x%x 0x%x", r.ps, ts->spsr); /* If GDB sent us back a signal number, convert that back into a trap number. */ if (signo != 0) { /* If the signal number was unchanged from what we sent, leave the trap number unchanged as well. */ if (signo == orig_signo) return -1; /* Otherwise, try to guess an appropriate trap number. We can't do much, but try to get the common ones. If we can't make a decent guess, just leave the trap number unchanged. */ switch (signo) { case SIGTRAP: ts->trapno = T_UNDEF; break; case SIGILL: ts->trapno = T_UNDEF; break; case SIGSEGV: ts->trapno = T_DATA_ABORT; break; } return -1; } /* GDB consumed the signal - just resume execution normally. */ return 0; }
int Interpreter::SingleStepInner() { static UGeckoInstruction instCode; u32 function = HLE::GetFunctionIndex(PC); if (function != 0) { int type = HLE::GetFunctionTypeByIndex(function); if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE) { int flags = HLE::GetFunctionFlagsByIndex(function); if (HLE::IsEnabled(flags)) { HLEFunction(function); if (type == HLE::HLE_HOOK_START) { // Run the original. function = 0; } } else { function = 0; } } } if (function == 0) { #ifdef USE_GDBSTUB if (gdb_active() && gdb_bp_x(PC)) { Host_UpdateDisasmDialog(); gdb_signal(SIGTRAP); gdb_handle_exception(); } #endif NPC = PC + sizeof(UGeckoInstruction); instCode.hex = PowerPC::Read_Opcode(PC); // Uncomment to trace the interpreter //if ((PC & 0xffffff)>=0x0ab54c && (PC & 0xffffff)<=0x0ab624) // startTrace = 1; //else // startTrace = 0; if (startTrace) { Trace(instCode); } if (instCode.hex != 0) { UReg_MSR& msr = (UReg_MSR&)MSR; if (msr.FP) //If FPU is enabled, just execute { m_opTable[instCode.OPCD](instCode); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) { PowerPC::CheckExceptions(); m_EndBlock = true; } } else { // check if we have to generate a FPU unavailable exception if (!PPCTables::UsesFPU(instCode)) { m_opTable[instCode.OPCD](instCode); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) { PowerPC::CheckExceptions(); m_EndBlock = true; } } else { PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE; PowerPC::CheckExceptions(); m_EndBlock = true; } } } else { // Memory exception on instruction fetch PowerPC::CheckExceptions(); m_EndBlock = true; } } last_pc = PC; PC = NPC; GekkoOPInfo *opinfo = GetOpInfo(instCode); return opinfo->numCycles; }
int main(int argc, char *argv[]) { u32 done; memset(&_ctx, 0x00, sizeof _ctx); ctx = &_ctx; parse_args(argc, argv); #if 0 u64 local_ptr; local_ptr = 0xdead0000dead0000ULL; ctx->reg[3][0] = (u32)(local_ptr >> 32); ctx->reg[3][1] = (u32)local_ptr; ctx->reg[4][0] = 0xdead0000; ctx->reg[4][1] = 0xdead0000; #endif ctx->ls = (u8*)malloc(LS_SIZE); if (ctx->ls == NULL) fail("Unable to allocate local storage."); memset(ctx->ls, 0, LS_SIZE); #if 0 wbe64(ctx->ls + 0x3f000, 0x100000000ULL); wbe32(ctx->ls + 0x3f008, 0x10000); wbe32(ctx->ls + 0x3e000, 0xff); #endif if (gdb_port < 0) { ctx->paused = 0; } else { gdb_init(gdb_port); ctx->paused = 1; gdb_signal(SIGABRT); } elf_load(elf_path); setup_context(); done = 0; while(done == 0) { if (ctx->paused == 0 || ctx->paused == 2) done = emulate(); // data watchpoints if (done == 2) { ctx->paused = 0; gdb_signal(SIGTRAP); done = 0; } if (done != 0) { printf("emulated() returned, sending SIGSEGV to gdb stub\n"); ctx->paused = 1; done = gdb_signal(SIGSEGV); } if (done != 0) { #ifdef STOP_DUMP_REGS dump_regs(); #endif #ifdef STOP_DUMP_LS dump_ls(); #endif } //if (ctx->paused == 1) gdb_handle_events(); } printf("emulate() returned. we're done!\n"); dump_ls(); free(ctx->ls); gdb_deinit(); return 0; }
int Interpreter::SingleStepInner(void) { static UGeckoInstruction instCode; u32 function = m_EndBlock ? HLE::GetFunctionIndex(PC) : 0; // Check for HLE functions after branches if (function != 0) { int type = HLE::GetFunctionTypeByIndex(function); if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE) { int flags = HLE::GetFunctionFlagsByIndex(function); if (HLE::IsEnabled(flags)) { HLEFunction(function); if (type == HLE::HLE_HOOK_START) { // Run the original. function = 0; } } else { function = 0; } } } if (function == 0) { #ifdef USE_GDBSTUB if (gdb_active() && gdb_bp_x(PC)) { Host_UpdateDisasmDialog(); gdb_signal(SIGTRAP); gdb_handle_exception(); } #endif NPC = PC + sizeof(UGeckoInstruction); instCode.hex = Memory::Read_Opcode(PC); // Uncomment to trace the interpreter //if ((PC & 0xffffff)>=0x0ab54c && (PC & 0xffffff)<=0x0ab624) // startTrace = 1; //else // startTrace = 0; if (startTrace) { Trace(instCode); } if (instCode.hex != 0) { UReg_MSR& msr = (UReg_MSR&)MSR; if (msr.FP) //If FPU is enabled, just execute { m_opTable[instCode.OPCD](instCode); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) { PowerPC::CheckExceptions(); m_EndBlock = true; } } else { // check if we have to generate a FPU unavailable exception if (!PPCTables::UsesFPU(instCode)) { m_opTable[instCode.OPCD](instCode); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) { PowerPC::CheckExceptions(); m_EndBlock = true; } } else { Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_FPU_UNAVAILABLE); PowerPC::CheckExceptions(); m_EndBlock = true; } } } else { // Memory exception on instruction fetch PowerPC::CheckExceptions(); m_EndBlock = true; } } last_pc = PC; PC = NPC; #if defined(_DEBUG) || defined(DEBUGFAST) if (PowerPC::ppcState.gpr[1] == 0) { WARN_LOG(POWERPC, "%i Corrupt stack", PowerPC::ppcState.DebugCount); } PowerPC::ppcState.DebugCount++; #endif patches(); GekkoOPInfo *opinfo = GetOpInfo(instCode); return opinfo->numCyclesMinusOne + 1; }
int Interpreter::SingleStepInner() { if (HandleFunctionHooking(PC)) { UpdatePC(); return PPCTables::GetOpInfo(m_prev_inst)->numCycles; } #ifdef USE_GDBSTUB if (gdb_active() && gdb_bp_x(PC)) { Host_UpdateDisasmDialog(); gdb_signal(GDB_SIGTRAP); gdb_handle_exception(); } #endif NPC = PC + sizeof(UGeckoInstruction); m_prev_inst.hex = PowerPC::Read_Opcode(PC); // Uncomment to trace the interpreter // if ((PC & 0xffffff)>=0x0ab54c && (PC & 0xffffff)<=0x0ab624) // startTrace = 1; // else // startTrace = 0; if (startTrace) { Trace(m_prev_inst); } if (m_prev_inst.hex != 0) { if (IsInvalidPairedSingleExecution(m_prev_inst)) { GenerateProgramException(); CheckExceptions(); } else if (MSR.FP) { m_op_table[m_prev_inst.OPCD](m_prev_inst); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) { CheckExceptions(); } } else { // check if we have to generate a FPU unavailable exception or a program exception. if (PPCTables::UsesFPU(m_prev_inst)) { PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE; CheckExceptions(); } else { m_op_table[m_prev_inst.OPCD](m_prev_inst); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) { CheckExceptions(); } } } } else { // Memory exception on instruction fetch CheckExceptions(); } UpdatePC(); return PPCTables::GetOpInfo(m_prev_inst)->numCycles; }
int Interpreter::SingleStepInner() { if (!HandleFunctionHooking(PC)) { #ifdef USE_GDBSTUB if (gdb_active() && gdb_bp_x(PC)) { Host_UpdateDisasmDialog(); gdb_signal(SIGTRAP); gdb_handle_exception(); } #endif NPC = PC + sizeof(UGeckoInstruction); m_prev_inst.hex = PowerPC::Read_Opcode(PC); // Uncomment to trace the interpreter // if ((PC & 0xffffff)>=0x0ab54c && (PC & 0xffffff)<=0x0ab624) // startTrace = 1; // else // startTrace = 0; if (startTrace) { Trace(m_prev_inst); } if (m_prev_inst.hex != 0) { if (MSR.FP) // If FPU is enabled, just execute { m_op_table[m_prev_inst.OPCD](m_prev_inst); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) { PowerPC::CheckExceptions(); m_end_block = true; } } else { // check if we have to generate a FPU unavailable exception if (!PPCTables::UsesFPU(m_prev_inst)) { m_op_table[m_prev_inst.OPCD](m_prev_inst); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) { PowerPC::CheckExceptions(); m_end_block = true; } } else { PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE; PowerPC::CheckExceptions(); m_end_block = true; } } } else { // Memory exception on instruction fetch PowerPC::CheckExceptions(); m_end_block = true; } } last_pc = PC; PC = NPC; const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(m_prev_inst); return opinfo->numCycles; }