diff --git a/Kernel/Arch/i386/CPU.cpp b/Kernel/Arch/i386/CPU.cpp index f47f0da7f2..17ee736a92 100644 --- a/Kernel/Arch/i386/CPU.cpp +++ b/Kernel/Arch/i386/CPU.cpp @@ -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); diff --git a/Kernel/Syscalls/ptrace.cpp b/Kernel/Syscalls/ptrace.cpp index 922f96c299..994f7ecfc6 100644 --- a/Kernel/Syscalls/ptrace.cpp +++ b/Kernel/Syscalls/ptrace.cpp @@ -153,6 +153,19 @@ static KResultOr handle_ptrace(const Kernel::Syscall::SC_ptrace_params& par return EFAULT; return peer->process().poke_user_data(Userspace { (FlatPtr)params.addr }, params.data); + case PT_PEEKDEBUG: { + Kernel::Syscall::SC_ptrace_peek_params peek_params {}; + if (!copy_from_user(&peek_params, reinterpret_cast(params.addr))) + return EFAULT; + auto result = peer->peek_debug_register(reinterpret_cast(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(params.addr), params.data); default: return EINVAL; } @@ -229,4 +242,56 @@ KResult Process::poke_user_data(Userspace address, u32 data) return KSuccess; } +KResultOr 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; +} + } diff --git a/Kernel/Thread.h b/Kernel/Thread.h index 6a7078c5a6..29bfd0db3b 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -972,6 +972,9 @@ public: u32 signal_mask() const; void clear_signals(); + KResultOr 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(); diff --git a/Kernel/UnixTypes.h b/Kernel/UnixTypes.h index b0614e5375..c3955f1119 100644 --- a/Kernel/UnixTypes.h +++ b/Kernel/UnixTypes.h @@ -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 { diff --git a/Userland/Libraries/LibC/sys/ptrace.cpp b/Userland/Libraries/LibC/sys/ptrace.cpp index b53bb48465..0fb623f42e 100644 --- a/Userland/Libraries/LibC/sys/ptrace.cpp +++ b/Userland/Libraries/LibC/sys/ptrace.cpp @@ -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(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, ¶ms); - if (request == PT_PEEK) { + if (is_peek_type) { if (rc < 0) { errno = -rc; return -1; diff --git a/Userland/Libraries/LibC/sys/ptrace.h b/Userland/Libraries/LibC/sys/ptrace.h index edb45aeec9..ad5de3fb6e 100644 --- a/Userland/Libraries/LibC/sys/ptrace.h +++ b/Userland/Libraries/LibC/sys/ptrace.h @@ -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.