mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 02:57:36 +00:00
LibDebug: Add ContinueBreakAtSyscall decision
When the user of the DebugSession uses this decision, the debugged program will be continued until it is either stopped by a singal (e.g as a reuslt of a breakpoint), or enters a syscall.
This commit is contained in:
parent
f4418361c4
commit
af338a34c0
2 changed files with 58 additions and 23 deletions
|
@ -184,14 +184,26 @@ void DebugSession::set_registers(const PtraceRegisters& regs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugSession::continue_debugee()
|
void DebugSession::continue_debugee(ContinueType type)
|
||||||
{
|
{
|
||||||
if (ptrace(PT_CONTINUE, m_debugee_pid, 0, 0) < 0) {
|
int command = (type == ContinueType::FreeRun) ? PT_CONTINUE : PT_SYSCALL;
|
||||||
|
if (ptrace(command, m_debugee_pid, 0, 0) < 0) {
|
||||||
perror("continue");
|
perror("continue");
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int DebugSession::continue_debugee_and_wait(ContinueType type)
|
||||||
|
{
|
||||||
|
continue_debugee(type);
|
||||||
|
int wstatus = 0;
|
||||||
|
if (waitpid(m_debugee_pid, &wstatus, WSTOPPED | WEXITED) != m_debugee_pid) {
|
||||||
|
perror("waitpid");
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
return wstatus;
|
||||||
|
}
|
||||||
|
|
||||||
void* DebugSession::single_step()
|
void* DebugSession::single_step()
|
||||||
{
|
{
|
||||||
auto regs = get_registers();
|
auto regs = get_registers();
|
||||||
|
|
|
@ -71,7 +71,15 @@ public:
|
||||||
PtraceRegisters get_registers() const;
|
PtraceRegisters get_registers() const;
|
||||||
void set_registers(const PtraceRegisters&);
|
void set_registers(const PtraceRegisters&);
|
||||||
|
|
||||||
void continue_debugee();
|
enum class ContinueType {
|
||||||
|
FreeRun,
|
||||||
|
Syscall,
|
||||||
|
};
|
||||||
|
void continue_debugee(ContinueType type = ContinueType::FreeRun);
|
||||||
|
|
||||||
|
//returns the wstatus result of waitpid()
|
||||||
|
int continue_debugee_and_wait(ContinueType type = ContinueType::FreeRun);
|
||||||
|
|
||||||
void* single_step();
|
void* single_step();
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
|
@ -83,12 +91,14 @@ public:
|
||||||
enum DebugDecision {
|
enum DebugDecision {
|
||||||
Continue,
|
Continue,
|
||||||
SingleStep,
|
SingleStep,
|
||||||
|
ContinueBreakAtSyscall,
|
||||||
Detach,
|
Detach,
|
||||||
Kill,
|
Kill,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DebugBreakReason {
|
enum DebugBreakReason {
|
||||||
Breakpoint,
|
Breakpoint,
|
||||||
|
Syscall,
|
||||||
Exited,
|
Exited,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -112,36 +122,39 @@ void DebugSession::run(Callback callback)
|
||||||
|
|
||||||
enum class State {
|
enum class State {
|
||||||
FreeRun,
|
FreeRun,
|
||||||
|
Syscall,
|
||||||
ConsecutiveBreakpoint,
|
ConsecutiveBreakpoint,
|
||||||
SingleStep,
|
SingleStep,
|
||||||
};
|
};
|
||||||
|
|
||||||
State state { State::FreeRun };
|
State state { State::FreeRun };
|
||||||
|
|
||||||
|
auto do_continue_and_wait = [&]() {
|
||||||
|
int wstatus = continue_debugee_and_wait((state == State::FreeRun) ? ContinueType::FreeRun : ContinueType::Syscall);
|
||||||
|
|
||||||
|
// FIXME: This check actually only checks whether the debugee
|
||||||
|
// stopped because it hit a breakpoint/syscall/is in single stepping mode or not
|
||||||
|
if (WSTOPSIG(wstatus) != SIGTRAP) {
|
||||||
|
callback(DebugBreakReason::Exited, Optional<PtraceRegisters>());
|
||||||
|
m_is_debugee_dead = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (state == State::FreeRun) {
|
if (state == State::FreeRun || state == State::Syscall) {
|
||||||
continue_debugee();
|
if (do_continue_and_wait())
|
||||||
|
|
||||||
int wstatus = 0;
|
|
||||||
if (waitpid(m_debugee_pid, &wstatus, WSTOPPED | WEXITED) != m_debugee_pid) {
|
|
||||||
perror("waitpid");
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: This check actually only checks whether the debugee
|
|
||||||
// stopped because it hit a breakpoint/is in single stepping mode or not
|
|
||||||
if (WSTOPSIG(wstatus) != SIGTRAP) {
|
|
||||||
callback(DebugBreakReason::Exited, Optional<PtraceRegisters>());
|
|
||||||
m_is_debugee_dead = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto regs = get_registers();
|
auto regs = get_registers();
|
||||||
Optional<BreakPoint> current_breakpoint;
|
Optional<BreakPoint> current_breakpoint;
|
||||||
|
|
||||||
if (state == State::FreeRun) {
|
if (state == State::FreeRun || state == State::Syscall) {
|
||||||
current_breakpoint = m_breakpoints.get((void*)((u32)regs.eip - 1));
|
current_breakpoint = m_breakpoints.get((void*)((u32)regs.eip - 1));
|
||||||
|
if (current_breakpoint.has_value())
|
||||||
|
state = State::FreeRun;
|
||||||
} else {
|
} else {
|
||||||
current_breakpoint = m_breakpoints.get((void*)regs.eip);
|
current_breakpoint = m_breakpoints.get((void*)regs.eip);
|
||||||
}
|
}
|
||||||
|
@ -153,10 +166,19 @@ void DebugSession::run(Callback callback)
|
||||||
disable_breakpoint(current_breakpoint.value());
|
disable_breakpoint(current_breakpoint.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugDecision decision = callback(DebugBreakReason::Breakpoint, regs);
|
DebugBreakReason reason = (state == State::Syscall && !current_breakpoint.has_value()) ? DebugBreakReason::Syscall : DebugBreakReason::Breakpoint;
|
||||||
|
DebugDecision decision = callback(reason, regs);
|
||||||
|
|
||||||
|
if (reason == DebugBreakReason::Syscall) {
|
||||||
|
// skip the exit from the syscall
|
||||||
|
if (do_continue_and_wait())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (decision == DebugDecision::Continue) {
|
if (decision == DebugDecision::Continue) {
|
||||||
state = State::FreeRun;
|
state = State::FreeRun;
|
||||||
|
} else if (decision == DebugDecision::ContinueBreakAtSyscall) {
|
||||||
|
state = State::Syscall;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_breakpoint.has_value()) {
|
if (current_breakpoint.has_value()) {
|
||||||
|
@ -174,9 +196,10 @@ void DebugSession::run(Callback callback)
|
||||||
|
|
||||||
if (decision == DebugDecision::SingleStep) {
|
if (decision == DebugDecision::SingleStep) {
|
||||||
state = State::SingleStep;
|
state = State::SingleStep;
|
||||||
} else {
|
}
|
||||||
// TODO: implement DebugDecision:: Kill, Detach
|
|
||||||
ASSERT(decision == DebugDecision::Continue);
|
if (decision == DebugDecision::Kill || decision == DebugDecision::Detach) {
|
||||||
|
ASSERT_NOT_REACHED(); // TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == State::SingleStep) {
|
if (state == State::SingleStep) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue