Add x86 PT_GETFSBASE, PT_GETGSBASE machine-depended ptrace requests to
obtain the thread %fs and %gs bases. Add x86 PT_SETFSBASE and PT_SETGSBASE requests to set the bases from debuggers. The set requests, similarly to the sysarch({I386,AMD64}_SET_FSBASE), override the corresponding segment registers. The main purpose of the operations is to retrieve and modify the tcb address for debuggee. Sponsored by: The FreeBSD Foundation MFC after: 2 weeks
This commit is contained in:
parent
06d058bd23
commit
1817023775
@ -36,8 +36,12 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/proc.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/sysent.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/pcb.h>
|
||||
#include <machine/frame.h>
|
||||
#include <machine/vmparam.h>
|
||||
|
||||
static int
|
||||
cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data)
|
||||
@ -110,6 +114,20 @@ cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data)
|
||||
return (error);
|
||||
}
|
||||
|
||||
static void
|
||||
cpu_ptrace_setbase(struct thread *td, int req, register_t r)
|
||||
{
|
||||
|
||||
if (req == PT_SETFSBASE) {
|
||||
td->td_pcb->pcb_fsbase = r;
|
||||
td->td_frame->tf_fs = _ufssel;
|
||||
} else {
|
||||
td->td_pcb->pcb_gsbase = r;
|
||||
td->td_frame->tf_gs = _ugssel;
|
||||
}
|
||||
set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
|
||||
}
|
||||
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
#define PT_I386_GETXMMREGS (PT_FIRSTMACH + 0)
|
||||
#define PT_I386_SETXMMREGS (PT_FIRSTMACH + 1)
|
||||
@ -118,6 +136,7 @@ static int
|
||||
cpu32_ptrace(struct thread *td, int req, void *addr, int data)
|
||||
{
|
||||
struct savefpu *fpstate;
|
||||
uint32_t r;
|
||||
int error;
|
||||
|
||||
switch (req) {
|
||||
@ -142,6 +161,29 @@ cpu32_ptrace(struct thread *td, int req, void *addr, int data)
|
||||
error = cpu_ptrace_xstate(td, req, addr, data);
|
||||
break;
|
||||
|
||||
case PT_GETFSBASE:
|
||||
case PT_GETGSBASE:
|
||||
if (!SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
r = req == PT_GETFSBASE ? td->td_pcb->pcb_fsbase :
|
||||
td->td_pcb->pcb_gsbase;
|
||||
error = copyout(&r, addr, sizeof(r));
|
||||
break;
|
||||
|
||||
case PT_SETFSBASE:
|
||||
case PT_SETGSBASE:
|
||||
if (!SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
error = copyin(addr, &r, sizeof(r));
|
||||
if (error != 0)
|
||||
break;
|
||||
cpu_ptrace_setbase(td, req, r);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EINVAL;
|
||||
break;
|
||||
@ -154,6 +196,7 @@ cpu32_ptrace(struct thread *td, int req, void *addr, int data)
|
||||
int
|
||||
cpu_ptrace(struct thread *td, int req, void *addr, int data)
|
||||
{
|
||||
register_t *r, rv;
|
||||
int error;
|
||||
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
@ -176,6 +219,25 @@ cpu_ptrace(struct thread *td, int req, void *addr, int data)
|
||||
error = cpu_ptrace_xstate(td, req, addr, data);
|
||||
break;
|
||||
|
||||
case PT_GETFSBASE:
|
||||
case PT_GETGSBASE:
|
||||
r = req == PT_GETFSBASE ? &td->td_pcb->pcb_fsbase :
|
||||
&td->td_pcb->pcb_gsbase;
|
||||
error = copyout(r, addr, sizeof(*r));
|
||||
break;
|
||||
|
||||
case PT_SETFSBASE:
|
||||
case PT_SETGSBASE:
|
||||
error = copyin(addr, &rv, sizeof(rv));
|
||||
if (error != 0)
|
||||
break;
|
||||
if (rv >= VM_MAXUSER_ADDRESS) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
cpu_ptrace_setbase(td, req, rv);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EINVAL;
|
||||
break;
|
||||
|
@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/frame.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/pcb.h>
|
||||
|
||||
@ -115,8 +116,8 @@ cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data)
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
cpu_ptrace(struct thread *td, int req, void *addr, int data)
|
||||
static int
|
||||
cpu_ptrace_xmm(struct thread *td, int req, void *addr, int data)
|
||||
{
|
||||
#ifdef CPU_ENABLE_SSE
|
||||
struct savexmm *fpstate;
|
||||
@ -155,3 +156,51 @@ cpu_ptrace(struct thread *td, int req, void *addr, int data)
|
||||
return (EINVAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
cpu_ptrace(struct thread *td, int req, void *addr, int data)
|
||||
{
|
||||
struct segment_descriptor *sdp, sd;
|
||||
register_t r;
|
||||
int error;
|
||||
|
||||
switch (req) {
|
||||
case PT_GETXMMREGS:
|
||||
case PT_SETXMMREGS:
|
||||
case PT_GETXSTATE_OLD:
|
||||
case PT_SETXSTATE_OLD:
|
||||
case PT_GETXSTATE_INFO:
|
||||
case PT_GETXSTATE:
|
||||
case PT_SETXSTATE:
|
||||
error = cpu_ptrace_xmm(td, req, addr, data);
|
||||
break;
|
||||
|
||||
case PT_GETFSBASE:
|
||||
case PT_GETGSBASE:
|
||||
sdp = req == PT_GETFSBASE ? &td->td_pcb->pcb_fsd :
|
||||
&td->td_pcb->pcb_gsd;
|
||||
r = sdp->sd_hibase << 24 | sdp->sd_lobase;
|
||||
error = copyout(&r, addr, sizeof(r));
|
||||
break;
|
||||
|
||||
case PT_SETFSBASE:
|
||||
case PT_SETGSBASE:
|
||||
error = copyin(addr, &r, sizeof(r));
|
||||
if (error != 0)
|
||||
break;
|
||||
fill_based_sd(&sd, r);
|
||||
if (req == PT_SETFSBASE) {
|
||||
td->td_pcb->pcb_fsd = sd;
|
||||
td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL);
|
||||
} else {
|
||||
td->td_pcb->pcb_gsd = sd;
|
||||
td->td_pcb->pcb_gs = GSEL(GUGS_SEL, SEL_UPL);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
@ -51,6 +51,10 @@
|
||||
#define PT_GETXSTATE_INFO (PT_FIRSTMACH + 4)
|
||||
#define PT_GETXSTATE (PT_FIRSTMACH + 5)
|
||||
#define PT_SETXSTATE (PT_FIRSTMACH + 6)
|
||||
#define PT_GETFSBASE (PT_FIRSTMACH + 7)
|
||||
#define PT_SETFSBASE (PT_FIRSTMACH + 8)
|
||||
#define PT_GETGSBASE (PT_FIRSTMACH + 9)
|
||||
#define PT_SETGSBASE (PT_FIRSTMACH + 10)
|
||||
|
||||
/* Argument structure for PT_GETXSTATE_INFO. */
|
||||
struct ptrace_xstate_info {
|
||||
|
Loading…
Reference in New Issue
Block a user