debugger: Fix interrupt signal.

Typing Control-C in Terminal app causes an interrupt signal that should enter the DPPC debugger but this only worked once since the signal handler never returned. Even if the signal handler reenabled the signal somehow, it calls enter_debugger recursively which is strange since the earlier calls to enter_debugger would never return.

Now the signal handler just sets a flag (power_on) which can be used to exit any loop (emulator loops, stepping loops, disassembly loops, dumping loops).

Main always calls enter_debugger now which calls the ppc_exec loop. The power_on flag will exit the ppc_exec loop to return to the debugger. Recursion of enter_debugger is eliminated except for calls to loguru's ABORT_F.

An enum power_off_reason is used to indicate why the power_on flag is set to false and to determine what happens next.
This commit is contained in:
joevt 2023-11-21 16:57:28 -08:00 committed by dingusdev
parent 1e78512c95
commit 177098c957
6 changed files with 95 additions and 46 deletions

View File

@ -40,6 +40,7 @@ void EventManager::poll_events()
switch (event.type) {
case SDL_QUIT:
power_on = false;
power_off_reason = po_shut_down;
break;
case SDL_WINDOWEVENT: {

View File

@ -320,7 +320,20 @@ extern jmp_buf exc_env;
extern bool grab_return;
enum Po_Cause : int {
po_none,
po_starting_up,
po_shut_down,
po_shutting_down,
po_disassemble_on,
po_disassemble_off,
po_enter_debugger,
po_entered_debugger,
po_signal_interrupt,
};
extern bool power_on;
extern Po_Cause power_off_reason;
extern bool int_pin;
extern bool dec_exception_pending;

View File

@ -39,7 +39,8 @@ MemCtrlBase* mem_ctrl_instance = 0;
bool is_601 = false;
bool power_on = 1;
bool power_on = false;
Po_Cause power_off_reason = po_enter_debugger;
SetPRS ppc_state;
@ -340,15 +341,13 @@ static void ppc_exec_inner()
pc_real = mmu_translate_imem(eb_start);
// interpret execution block
while (ppc_state.pc < eb_end) {
while (power_on && ppc_state.pc < eb_end) {
ppc_main_opcode();
if (g_icycles++ >= max_cycles) {
max_cycles = process_events();
}
if (exec_flags) {
if (!power_on)
break;
// reload cycle counter if requested
if (exec_flags & EXEF_TIMER) {
max_cycles = process_events();
@ -445,7 +444,7 @@ static void ppc_exec_until_inner(const uint32_t goal_addr)
pc_real = mmu_translate_imem(eb_start);
// interpret execution block
while ((ppc_state.pc < eb_end)) {
while (power_on && ppc_state.pc < eb_end) {
ppc_main_opcode();
if (g_icycles++ >= max_cycles) {
max_cycles = process_events();
@ -484,7 +483,7 @@ static void ppc_exec_until_inner(const uint32_t goal_addr)
if (ppc_state.pc == goal_addr)
break;
}
} while (ppc_state.pc != goal_addr);
} while (power_on && ppc_state.pc != goal_addr);
}
// outer interpreter loop
@ -498,7 +497,7 @@ void ppc_exec_until(volatile uint32_t goal_addr)
do {
ppc_exec_until_inner(goal_addr);
} while (ppc_state.pc != goal_addr);
} while (power_on && ppc_state.pc != goal_addr);
}
/** Execute PPC code until control is reached the specified region. */
@ -512,7 +511,7 @@ static void ppc_exec_dbg_inner(const uint32_t start_addr, const uint32_t size)
max_cycles = 0;
while (ppc_state.pc < start_addr || ppc_state.pc >= start_addr + size) {
while (power_on && (ppc_state.pc < start_addr || ppc_state.pc >= start_addr + size)) {
// define boundaries of the next execution block
// max execution block length = one memory page
eb_start = ppc_state.pc;
@ -523,7 +522,7 @@ static void ppc_exec_dbg_inner(const uint32_t start_addr, const uint32_t size)
pc_real = mmu_translate_imem(eb_start);
// interpret execution block
while ((ppc_state.pc < start_addr || ppc_state.pc >= start_addr + size)
while (power_on && (ppc_state.pc < start_addr || ppc_state.pc >= start_addr + size)
&& (ppc_state.pc < eb_end)) {
ppc_main_opcode();
if (g_icycles++ >= max_cycles) {
@ -572,7 +571,7 @@ void ppc_exec_dbg(volatile uint32_t start_addr, volatile uint32_t size)
ppc_state.pc = ppc_next_instruction_address;
}
while (ppc_state.pc < start_addr || ppc_state.pc >= start_addr + size) {
while (power_on && (ppc_state.pc < start_addr || ppc_state.pc >= start_addr + size)) {
ppc_exec_dbg_inner(start_addr, size);
}
}

View File

@ -121,7 +121,7 @@ static void disasm_68k(uint32_t count, uint32_t address) {
cs_insn* insn = cs_malloc(cs_handle);
for (; count > 0; count--) {
for (; power_on && count > 0; count--) {
/* prefetch opcode bytes (a 68k instruction can occupy 2...10 bytes) */
for (int i = 0; i < sizeof(code); i++) {
code[i] = mem_read_dbg(address + i, 1);
@ -180,10 +180,10 @@ void exec_single_68k()
//printf("cur_instr_tab_entry = %X\n", cur_instr_tab_entry);
/* because the first two PPC instructions for each emulated 68k once
/* because the first two PPC instructions for each emulated 68k opcode
are resided in the emulator opcode table, we need to execute them
one by one until the execution goes outside the opcode table. */
while (ppc_pc >= cur_instr_tab_entry && ppc_pc < cur_instr_tab_entry + 8) {
while (power_on && ppc_pc >= cur_instr_tab_entry && ppc_pc < cur_instr_tab_entry + 8) {
ppc_exec_single();
ppc_pc = get_reg(string("PC"));
}
@ -200,8 +200,8 @@ void exec_until_68k(uint32_t target_addr)
emu_table_virt = get_reg(string("R29")) & 0xFFF80000;
while (target_addr != (get_reg(string("R24")) - 2)) {
ppc_pc = get_reg(string("PC"));
while (power_on && target_addr != (get_reg(string("R24")) - 2)) {
ppc_pc = static_cast<uint32_t>(get_reg(string("PC")));
if (ppc_pc >= emu_table_virt && ppc_pc < (emu_table_virt + EMU_68K_TABLE_SIZE - 1)) {
ppc_exec_single();
@ -442,44 +442,82 @@ void enter_debugger() {
std::stringstream ss;
int log_level, context;
size_t separator_pos;
bool did_message = false;
unique_ptr<OfConfigUtils> ofnvram = unique_ptr<OfConfigUtils>(new OfConfigUtils);
context = 1; /* start with the PowerPC context */
cout << "Welcome to the DingusPPC command line debugger." << endl;
cout << "Please enter a command or 'help'." << endl << endl;
#ifndef _WIN32
struct winsize win_size_previous;
ioctl(0, TIOCGWINSZ, &win_size_previous);
#endif
while (1) {
cout << "dingusdbg> ";
if (power_off_reason == po_shut_down) {
power_off_reason = po_shutting_down;
break;
}
power_on = true;
while (1) {
/* reset string stream */
if (power_off_reason == po_starting_up) {
power_off_reason = po_none;
cmd = "go";
}
else if (power_off_reason == po_disassemble_on) {
inp = "si 1000000000";
ss.str("");
ss.clear();
cmd = "";
std::cin.clear();
getline(cin, inp, '\n');
ss.str(inp);
ss >> cmd;
#ifndef _WIN32
struct winsize win_size_current;
ioctl(0, TIOCGWINSZ, &win_size_current);
if (win_size_current.ws_col != win_size_previous.ws_col || win_size_current.ws_row != win_size_previous.ws_row) {
win_size_previous = win_size_current;
if (cmd.empty()) {
continue;
}
}
else if (power_off_reason == po_disassemble_off) {
power_off_reason = po_none;
cmd = "go";
}
else
{
if (power_off_reason == po_enter_debugger) {
power_off_reason = po_entered_debugger;
}
#endif
break;
if (!did_message) {
cout << "Welcome to the DingusPPC command line debugger." << endl;
cout << "Please enter a command or 'help'." << endl << endl;
did_message = true;
}
printf("%08X: dingusdbg> ", ppc_state.pc);
while (power_on) {
/* reset string stream */
ss.str("");
ss.clear();
cmd = "";
std::cin.clear();
getline(cin, inp, '\n');
ss.str(inp);
ss >> cmd;
#ifndef _WIN32
struct winsize win_size_current;
ioctl(0, TIOCGWINSZ, &win_size_current);
if (win_size_current.ws_col != win_size_previous.ws_col || win_size_current.ws_row != win_size_previous.ws_row) {
win_size_previous = win_size_current;
if (cmd.empty()) {
continue;
}
}
#endif
break;
}
}
if (power_off_reason == po_signal_interrupt) {
power_off_reason = po_enter_debugger;
// ignore command if interrupt happens because the input line is probably incomplete.
last_cmd = "";
continue;
}
if (cmd.empty() && !last_cmd.empty()) {
@ -591,7 +629,7 @@ void enter_debugger() {
} else if (cmd == "go") {
cmd = "";
power_on = true;
ppc_exec(); // won't return!
ppc_exec();
} else if (cmd == "disas" || cmd == "da") {
expr_str = "";
ss >> expr_str;

View File

@ -22,6 +22,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef DEBUGGER_H_
#define DEBUGGER_H_
void enter_debugger(void);
void enter_debugger();
#endif // DEBUGGER_H_

View File

@ -41,13 +41,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
using namespace std;
void sigint_handler(int signum) {
enter_debugger();
LOG_F(INFO, "Shutting down...");
delete gMachineObj.release();
cleanup();
exit(0);
power_on = false;
power_off_reason = po_signal_interrupt;
}
void sigabrt_handler(int signum) {
@ -180,6 +175,7 @@ int main(int argc, char** argv) {
// Make sure the reason for the failure is visible (it may have been
// sent to the logfile only).
cerr << message.preamble << message.indentation << message.prefix << message.message << endl;
power_off_reason = po_enter_debugger;
enter_debugger();
abort();
@ -199,9 +195,11 @@ int main(int argc, char** argv) {
switch (execution_mode) {
case interpreter:
ppc_exec();
power_off_reason = po_starting_up;
enter_debugger();
break;
case debugger:
power_off_reason = po_enter_debugger;
enter_debugger();
break;
default: