mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-11 01:06:01 +03: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
Notes:
sideshowbarker
2024-07-19 07:33:32 +09:00
Author: https://github.com/itamar8910 Commit: https://github.com/SerenityOS/serenity/commit/af338a34c04 Pull-request: https://github.com/SerenityOS/serenity/pull/1813
@ -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");
|
||||
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()
|
||||
{
|
||||
auto regs = get_registers();
|
||||
|
@ -71,7 +71,15 @@ public:
|
||||
PtraceRegisters get_registers() const;
|
||||
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();
|
||||
|
||||
template<typename Callback>
|
||||
@ -83,12 +91,14 @@ public:
|
||||
enum DebugDecision {
|
||||
Continue,
|
||||
SingleStep,
|
||||
ContinueBreakAtSyscall,
|
||||
Detach,
|
||||
Kill,
|
||||
};
|
||||
|
||||
enum DebugBreakReason {
|
||||
Breakpoint,
|
||||
Syscall,
|
||||
Exited,
|
||||
};
|
||||
|
||||
@ -112,36 +122,39 @@ void DebugSession::run(Callback callback)
|
||||
|
||||
enum class State {
|
||||
FreeRun,
|
||||
Syscall,
|
||||
ConsecutiveBreakpoint,
|
||||
SingleStep,
|
||||
};
|
||||
|
||||
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 (;;) {
|
||||
if (state == State::FreeRun) {
|
||||
continue_debugee();
|
||||
|
||||
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;
|
||||
if (state == State::FreeRun || state == State::Syscall) {
|
||||
if (do_continue_and_wait())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto regs = get_registers();
|
||||
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));
|
||||
if (current_breakpoint.has_value())
|
||||
state = State::FreeRun;
|
||||
} else {
|
||||
current_breakpoint = m_breakpoints.get((void*)regs.eip);
|
||||
}
|
||||
@ -153,10 +166,19 @@ void DebugSession::run(Callback callback)
|
||||
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) {
|
||||
state = State::FreeRun;
|
||||
} else if (decision == DebugDecision::ContinueBreakAtSyscall) {
|
||||
state = State::Syscall;
|
||||
}
|
||||
|
||||
if (current_breakpoint.has_value()) {
|
||||
@ -174,9 +196,10 @@ void DebugSession::run(Callback callback)
|
||||
|
||||
if (decision == DebugDecision::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) {
|
||||
|
Loading…
Reference in New Issue
Block a user