Kernel: Add ptrace commands for reading/writing the debug registers

This adds PT_PEEKDEBUG and PT_POKEDEBUG to allow for reading/writing
the debug registers, and updates the Kernel's debug handler to read the
new information from the debug status register.
This commit is contained in:
FalseHonesty 2021-04-15 12:34:51 -04:00 committed by Andreas Kling
parent 97a4c627cb
commit 3123ffb19d
6 changed files with 79 additions and 5 deletions

View file

@ -363,14 +363,15 @@ void debug_handler(TrapFrame* trap)
PANIC("Debug exception in ring 0");
}
constexpr u8 REASON_SINGLESTEP = 14;
bool is_reason_singlestep = (read_dr6() & (1 << REASON_SINGLESTEP));
if (!is_reason_singlestep)
auto debug_status = read_dr6();
auto should_trap_mask = (1 << REASON_SINGLESTEP) | 0b1111;
if ((debug_status & should_trap_mask) == 0)
return;
if (auto tracer = process.tracer()) {
tracer->set_regs(regs);
}
current_thread->send_urgent_signal_to_self(SIGTRAP);
write_dr6(debug_status & ~(should_trap_mask));
}
EH_ENTRY_NO_CODE(3, breakpoint);

View file

@ -153,6 +153,19 @@ static KResultOr<u32> handle_ptrace(const Kernel::Syscall::SC_ptrace_params& par
return EFAULT;
return peer->process().poke_user_data(Userspace<u32*> { (FlatPtr)params.addr }, params.data);
case PT_PEEKDEBUG: {
Kernel::Syscall::SC_ptrace_peek_params peek_params {};
if (!copy_from_user(&peek_params, reinterpret_cast<Kernel::Syscall::SC_ptrace_peek_params*>(params.addr)))
return EFAULT;
auto result = peer->peek_debug_register(reinterpret_cast<uintptr_t>(peek_params.address));
if (result.is_error())
return result.error();
if (!copy_to_user(peek_params.out_data, &result.value()))
return EFAULT;
break;
}
case PT_POKEDEBUG:
return peer->poke_debug_register(reinterpret_cast<uintptr_t>(params.addr), params.data);
default:
return EINVAL;
}
@ -229,4 +242,56 @@ KResult Process::poke_user_data(Userspace<u32*> address, u32 data)
return KSuccess;
}
KResultOr<u32> Thread::peek_debug_register(u32 register_index)
{
u32 data;
switch (register_index) {
case 0:
data = m_debug_register_state.dr0;
break;
case 1:
data = m_debug_register_state.dr1;
break;
case 2:
data = m_debug_register_state.dr2;
break;
case 3:
data = m_debug_register_state.dr3;
break;
case 6:
data = m_debug_register_state.dr6;
break;
case 7:
data = m_debug_register_state.dr7;
break;
default:
return EINVAL;
}
return data;
}
KResult Thread::poke_debug_register(u32 register_index, u32 data)
{
switch (register_index) {
case 0:
m_debug_register_state.dr0 = data;
break;
case 1:
m_debug_register_state.dr1 = data;
break;
case 2:
m_debug_register_state.dr2 = data;
break;
case 3:
m_debug_register_state.dr3 = data;
break;
case 7:
m_debug_register_state.dr7 = data;
break;
default:
return EINVAL;
}
return KSuccess;
}
}

View file

@ -972,6 +972,9 @@ public:
u32 signal_mask() const;
void clear_signals();
KResultOr<u32> peek_debug_register(u32 register_index);
KResult poke_debug_register(u32 register_index, u32 data);
void set_dump_backtrace_on_finalization() { m_dump_backtrace_on_finalization = true; }
DispatchSignalResult dispatch_one_pending_signal();

View file

@ -690,6 +690,8 @@ struct rtentry {
#define PT_PEEK 7
#define PT_POKE 8
#define PT_SETREGS 9
#define PT_POKEDEBUG 10
#define PT_PEEKDEBUG 11
// Used in struct dirent
enum {

View file

@ -40,7 +40,8 @@ int ptrace(int request, pid_t tid, void* addr, int data)
u32 out_data;
Syscall::SC_ptrace_peek_params peek_params;
if (request == PT_PEEK) {
auto is_peek_type = request == PT_PEEK || request == PT_PEEKDEBUG;
if (is_peek_type) {
peek_params.address = reinterpret_cast<u32*>(addr);
peek_params.out_data = &out_data;
addr = &peek_params;
@ -54,7 +55,7 @@ int ptrace(int request, pid_t tid, void* addr, int data)
};
int rc = syscall(SC_ptrace, &params);
if (request == PT_PEEK) {
if (is_peek_type) {
if (rc < 0) {
errno = -rc;
return -1;

View file

@ -39,6 +39,8 @@ __BEGIN_DECLS
#define PT_PEEK 7
#define PT_POKE 8
#define PT_SETREGS 9
#define PT_POKEDEBUG 10
#define PT_PEEKDEBUG 11
// FIXME: PID/TID ISSUE
// Affects the entirety of LibDebug and Userland/strace.cpp.