1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 15:57:45 +00:00

Debugger: Add single step command

Also, this commit does some refactoring to the debugging loop logic.
This commit is contained in:
Itamar 2020-04-13 17:57:18 +03:00 committed by Andreas Kling
parent c3faaeb9b9
commit 312559b131
2 changed files with 50 additions and 24 deletions

View file

@ -81,6 +81,7 @@ public:
enum DebugDecision { enum DebugDecision {
Continue, Continue,
SingleStep,
Detach, Detach,
Kill, Kill,
}; };
@ -107,9 +108,17 @@ private:
template<typename Callback> template<typename Callback>
void DebugSession::run(Callback callback) void DebugSession::run(Callback callback)
{ {
bool in_consecutive_breakpoint = false;
enum class State {
FreeRun,
ConsecutiveBreakpoint,
SingleStep,
};
State state { State::FreeRun };
for (;;) { for (;;) {
if (!in_consecutive_breakpoint) { if (state == State::FreeRun) {
continue_debugee(); continue_debugee();
int wstatus = 0; int wstatus = 0;
@ -119,7 +128,7 @@ void DebugSession::run(Callback callback)
} }
// FIXME: This check actually only checks whether the debugee // FIXME: This check actually only checks whether the debugee
// Is stopped because it hit a breakpoint or not // stopped because it hit a breakpoint/is in single stepping mode or not
if (WSTOPSIG(wstatus) != SIGTRAP) { if (WSTOPSIG(wstatus) != SIGTRAP) {
callback(DebugBreakReason::Exited, Optional<PtraceRegisters>()); callback(DebugBreakReason::Exited, Optional<PtraceRegisters>());
m_is_debugee_dead = true; m_is_debugee_dead = true;
@ -130,34 +139,47 @@ void DebugSession::run(Callback callback)
auto regs = get_registers(); auto regs = get_registers();
Optional<BreakPoint> current_breakpoint; Optional<BreakPoint> current_breakpoint;
if (in_consecutive_breakpoint) { if (state == State::FreeRun) {
current_breakpoint = m_breakpoints.get((void*)regs.eip);
} else {
current_breakpoint = m_breakpoints.get((void*)((u32)regs.eip - 1)); current_breakpoint = m_breakpoints.get((void*)((u32)regs.eip - 1));
} else {
current_breakpoint = m_breakpoints.get((void*)regs.eip);
} }
ASSERT(current_breakpoint.has_value()); if (current_breakpoint.has_value()) {
// We want to make the breakpoint transparrent to the user of the debugger
// We want to make the breakpoint transparrent to the user of the debugger regs.eip = reinterpret_cast<u32>(current_breakpoint.value().address);
set_registers(regs);
regs.eip = reinterpret_cast<u32>(current_breakpoint.value().address); disable_breakpoint(current_breakpoint.value());
set_registers(regs); }
disable_breakpoint(current_breakpoint.value());
DebugDecision decision = callback(DebugBreakReason::Breakpoint, regs); DebugDecision decision = callback(DebugBreakReason::Breakpoint, regs);
if (decision != DebugDecision::Continue) {
// FIXME: implement detach & kill if (decision == DebugDecision::Continue) {
ASSERT_NOT_REACHED(); state = State::FreeRun;
} }
// Re-enable the breakpoint if (current_breakpoint.has_value()) {
auto stopped_address = single_step(); // Re-enable the breakpoint
enable_breakpoint(current_breakpoint.value()); auto stopped_address = single_step();
enable_breakpoint(current_breakpoint.value());
// If there is another breakpoint after the current one,
// Then we are already on it (because of single_step)
auto breakpoint_at_next_instruction = m_breakpoints.get(stopped_address);
if (breakpoint_at_next_instruction.has_value()
&& breakpoint_at_next_instruction.value().state == BreakPointState::Enabled) {
state = State::ConsecutiveBreakpoint;
}
}
// If there is another breakpoint after the current one, if (decision == DebugDecision::SingleStep) {
// Then we are already on it (because of single_step) state = State::SingleStep;
auto breakpoint_at_next_instruction = m_breakpoints.get(stopped_address); } else {
in_consecutive_breakpoint = breakpoint_at_next_instruction.has_value() // TODO: implement DebugDecision:: Kill, Detach
&& breakpoint_at_next_instruction.value().state == BreakPointState::Enabled; ASSERT(decision == DebugDecision::Continue);
}
if (state == State::SingleStep) {
single_step();
}
} }
} }

View file

@ -168,6 +168,7 @@ void print_help()
{ {
printf("Options:\n" printf("Options:\n"
"cont - Continue execution\n" "cont - Continue execution\n"
"s - step over the current instruction\n"
"regs - Print registers\n" "regs - Print registers\n"
"dis [number of instructions] - Print disassembly\n" "dis [number of instructions] - Print disassembly\n"
"bp <address/symbol> - Insert a breakpoint\n"); "bp <address/symbol> - Insert a breakpoint\n");
@ -222,6 +223,9 @@ int main(int argc, char** argv)
if (command == "cont") { if (command == "cont") {
return DebugSession::DebugDecision::Continue; return DebugSession::DebugDecision::Continue;
} }
if (command == "s") {
return DebugSession::DebugDecision::SingleStep;
}
if (command == "regs") { if (command == "regs") {
handle_print_registers(regs); handle_print_registers(regs);