Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/compat/linux/arch/i386 implement PTRACE_{GET|SET}FPREGS ...
details: https://anonhg.NetBSD.org/src/rev/3aca8d946fed
branches: trunk
changeset: 499509:3aca8d946fed
user: jdolecek <jdolecek%NetBSD.org@localhost>
date: Tue Nov 21 12:28:15 2000 +0000
description:
implement PTRACE_{GET|SET}FPREGS and framework for PTRACE_{PEEK|POKE}USER
this makes it possible to attach to linux process with linux gdb and
see top-most function on traceback; lower functions are not available,
probably due to bad frame setup
it's not possible to setup breakpoints - Linux gdb uses hw breakpoints,
so support for them would need to be written
diffstat:
sys/compat/linux/arch/i386/linux_ptrace.c | 274 +++++++++++++++++++++++++----
1 files changed, 230 insertions(+), 44 deletions(-)
diffs (truncated from 343 to 300 lines):
diff -r dd8a4a0cddff -r 3aca8d946fed sys/compat/linux/arch/i386/linux_ptrace.c
--- a/sys/compat/linux/arch/i386/linux_ptrace.c Tue Nov 21 12:23:29 2000 +0000
+++ b/sys/compat/linux/arch/i386/linux_ptrace.c Tue Nov 21 12:28:15 2000 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: linux_ptrace.c,v 1.4 2000/11/01 21:02:08 jdolecek Exp $ */
+/* $NetBSD: linux_ptrace.c,v 1.5 2000/11/21 12:28:15 jdolecek Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -38,11 +38,13 @@
#include <sys/types.h>
#include <sys/param.h>
+#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/ptrace.h>
#include <sys/systm.h>
#include <sys/syscallargs.h>
+#include <uvm/uvm_extern.h>
#include <machine/reg.h>
@@ -52,9 +54,13 @@
#include <compat/linux/common/linux_util.h>
#include <compat/linux/common/linux_machdep.h>
+#include <compat/linux/common/linux_emuldata.h>
+#include <compat/linux/common/linux_exec.h> /* for emul_linux */
#include <compat/linux/linux_syscallargs.h>
+#include <lib/libkern/libkern.h> /* for offsetof() */
+
struct linux_reg {
long ebx;
long ecx;
@@ -63,17 +69,57 @@
long edi;
long ebp;
long eax;
- int xds;
- int xes;
+ long xds, xes; // unsigned short ds, __ds, es, __es;
+ long __fs, __gs; // unsigned short fs, __fs, gs, __gs;
long orig_eax;
long eip;
- int xcs;
+ long xcs; // unsigned short cs, __cs;
long eflags;
long esp;
- int xss;
+ long xss; // unsigned short ss, __ss
+};
+
+/* structure used for storing floating point context */
+struct linux_fpreg {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long st_space [20];
};
-#define ISSET(t, f) ((t) & (f))
+/* user struct for linux process - this is used for Linux ptrace emulation */
+/* most of it is junk only used by gdb */
+struct linux_user {
+ struct linux_reg regs; /* registers */
+ int u_fpvalid; /* true if math co-processor being used. */
+ struct linux_fpreg i387; /* Math Co-processor registers. */
+/* The rest of this junk is to help gdb figure out what goes where */
+#define lusr_startgdb u_tsize
+ unsigned long int u_tsize; /* Text segment size (pages). */
+ unsigned long int u_dsize; /* Data segment size (pages). */
+ unsigned long int u_ssize; /* Stack segment size (pages). */
+ unsigned long start_code; /* Starting virtual address of text. */
+ unsigned long start_stack; /* Starting virtual address of stack area.
+ This is actually the bottom of the stack,
+ the top of the stack is always found in the
+ esp register. */
+ long int __signal; /* Signal that caused the core dump. */
+ int __reserved; /* unused */
+ void * u_ar0; /* Used by gdb to help find the values for */
+ /* the registers. */
+ struct linux_fpreg* u_fpstate;/* Math Co-processor pointer. */
+ unsigned long __magic; /* To uniquely identify a core file */
+ char u_comm[32]; /* User command that was responsible */
+ int u_debugreg[8];
+#define u_debugreg_end u_debugreg[7]
+};
+
+#define LUSR_OFF(member) offsetof(struct linux_user, member)
+#define ISSET(t, f) ((t) & (f))
int
linux_sys_ptrace_arch(p, v, retval)
@@ -89,12 +135,17 @@
} */ *uap = v;
int request, error;
struct proc *t; /* target process */
- struct reg regs;
- struct linux_reg linux_regs;
+ struct reg *regs = NULL;
+ struct fpreg *fpregs = NULL;
+ struct linux_reg *linux_regs = NULL;
+ struct linux_fpreg *linux_fpregs = NULL;
+ int addr;
request = SCARG(uap, request);
- if ((request != LINUX_PTRACE_GETREGS) &&
+ if ((request != LINUX_PTRACE_PEEKUSR) &&
+ (request != LINUX_PTRACE_POKEUSR) &&
+ (request != LINUX_PTRACE_GETREGS) &&
(request != LINUX_PTRACE_SETREGS) &&
(request != LINUX_PTRACE_GETFPREGS) &&
(request != LINUX_PTRACE_SETFPREGS))
@@ -134,51 +185,186 @@
switch (request) {
case LINUX_PTRACE_GETREGS:
- error = process_read_regs(t, ®s);
+ MALLOC(regs, struct reg*, sizeof(struct reg), M_TEMP, M_WAITOK);
+ MALLOC(linux_regs, struct linux_reg*, sizeof(struct linux_reg),
+ M_TEMP, M_WAITOK);
+
+ error = process_read_regs(t, regs);
if (error != 0)
- return error;
+ goto out;
- linux_regs.ebx = regs.r_ebx;
- linux_regs.ecx = regs.r_ecx;
- linux_regs.edx = regs.r_edx;
- linux_regs.esi = regs.r_esi;
- linux_regs.edi = regs.r_edi;
- linux_regs.ebp = regs.r_ebp;
- linux_regs.eax = regs.r_eax;
- linux_regs.xds = regs.r_ds;
- linux_regs.xes = regs.r_es;
- linux_regs.orig_eax = regs.r_eax; /* XXX is this correct? */
- linux_regs.eip = regs.r_eip;
- linux_regs.xcs = regs.r_cs;
- linux_regs.eflags = regs.r_eflags;
- linux_regs.esp = regs.r_esp;
- linux_regs.xss = regs.r_ss;
+ linux_regs->ebx = regs->r_ebx;
+ linux_regs->ecx = regs->r_ecx;
+ linux_regs->edx = regs->r_edx;
+ linux_regs->esi = regs->r_esi;
+ linux_regs->edi = regs->r_edi;
+ linux_regs->ebp = regs->r_ebp;
+ linux_regs->eax = regs->r_eax;
+ linux_regs->xds = regs->r_ds;
+ linux_regs->xes = regs->r_es;
+ linux_regs->orig_eax = regs->r_eax; /* XXX is this correct? */
+ linux_regs->eip = regs->r_cs + regs->r_eip;
+ linux_regs->xcs = regs->r_cs;
+ linux_regs->eflags = regs->r_eflags;
+ linux_regs->esp = regs->r_esp;
+ linux_regs->xss = regs->r_ss;
- return copyout(&linux_regs, (caddr_t)SCARG(uap, data),
+ error = copyout(linux_regs, (caddr_t)SCARG(uap, data),
sizeof(struct linux_reg));
+ goto out;
+
case LINUX_PTRACE_SETREGS:
- error = copyin((caddr_t)SCARG(uap, data), &linux_regs,
+ MALLOC(regs, struct reg*, sizeof(struct reg), M_TEMP, M_WAITOK);
+ MALLOC(linux_regs, struct linux_reg *, sizeof(struct linux_reg),
+ M_TEMP, M_WAITOK);
+
+ error = copyin((caddr_t)SCARG(uap, data), linux_regs,
sizeof(struct linux_reg));
if (error != 0)
- return error;
+ goto out;
+
+ regs->r_ebx = linux_regs->ebx;
+ regs->r_ecx = linux_regs->ecx;
+ regs->r_edx = linux_regs->edx;
+ regs->r_esi = linux_regs->esi;
+ regs->r_edi = linux_regs->edi;
+ regs->r_ebp = linux_regs->ebp;
+ regs->r_eax = linux_regs->eax;
+ regs->r_ds = linux_regs->xds;
+ regs->r_es = linux_regs->xes;
+ regs->r_eip = linux_regs->eip - linux_regs->xcs;
+ regs->r_cs = linux_regs->xcs;
+ regs->r_eflags = linux_regs->eflags;
+ regs->r_esp = linux_regs->esp;
+ regs->r_ss = linux_regs->xss;
+
+ error = process_write_regs(t, regs);
+ goto out;
+
+ case LINUX_PTRACE_GETFPREGS:
+ MALLOC(fpregs, struct fpreg *, sizeof(struct fpreg),
+ M_TEMP, M_WAITOK);
+ MALLOC(linux_fpregs, struct linux_fpreg *,
+ sizeof(struct linux_fpreg), M_TEMP, M_WAITOK);
+
+ error = process_read_fpregs(t, fpregs);
+ if (error != 0)
+ goto out;
+
+ /* zero the contents if NetBSD fpreg structure is smaller */
+ if (sizeof(struct fpreg) < sizeof(struct linux_fpreg))
+ memset(linux_fpregs, '\0', sizeof(struct linux_fpreg));
+
+ memcpy(linux_fpregs, fpregs,
+ min(sizeof(struct linux_fpreg), sizeof(struct fpreg)));
+ error = copyout(linux_fpregs, (caddr_t)SCARG(uap, data),
+ sizeof(struct linux_fpreg));
+ goto out;
+
+ case LINUX_PTRACE_SETFPREGS:
+ MALLOC(fpregs, struct fpreg *, sizeof(struct fpreg),
+ M_TEMP, M_WAITOK);
+ MALLOC(linux_fpregs, struct linux_fpreg *,
+ sizeof(struct linux_fpreg), M_TEMP, M_WAITOK);
+ error = copyin((caddr_t)SCARG(uap, data), linux_fpregs,
+ sizeof(struct linux_fpreg));
+ if (error != 0)
+ goto out;
+
+ memset(fpregs, '\0', sizeof(struct fpreg));
+ memcpy(fpregs, linux_fpregs,
+ min(sizeof(struct linux_fpreg), sizeof(struct fpreg)));
+
+ error = process_write_regs(t, regs);
+ goto out;
+
+ case LINUX_PTRACE_PEEKUSR:
+ addr = SCARG(uap, addr);
- regs.r_ebx = linux_regs.ebx;
- regs.r_ecx = linux_regs.ecx;
- regs.r_edx = linux_regs.edx;
- regs.r_esi = linux_regs.esi;
- regs.r_edi = linux_regs.edi;
- regs.r_ebp = linux_regs.ebp;
- regs.r_eax = linux_regs.eax;
- regs.r_ds = linux_regs.xds;
- regs.r_es = linux_regs.xes;
- regs.r_eip = linux_regs.eip;
- regs.r_cs = linux_regs.xcs;
- regs.r_eflags = linux_regs.eflags;
- regs.r_esp = linux_regs.esp;
- regs.r_ss = linux_regs.xss;
+ PHOLD(t); /* need full process info */
+ error = 0;
+ if (addr < LUSR_OFF(lusr_startgdb)) {
+ /* XXX should provide appropriate register */
+ error = 1;
+ } else if (addr == LUSR_OFF(u_tsize))
+ *retval = p->p_vmspace->vm_tsize;
+ else if (addr == LUSR_OFF(u_dsize))
+ *retval = p->p_vmspace->vm_dsize;
+ else if (addr == LUSR_OFF(u_ssize))
+ *retval = p->p_vmspace->vm_ssize;
+ else if (addr == LUSR_OFF(start_code))
+ *retval = (register_t) p->p_vmspace->vm_taddr;
+ else if (addr == LUSR_OFF(start_stack))
+ *retval = (register_t) p->p_vmspace->vm_minsaddr;
+ else if (addr == LUSR_OFF(u_ar0))
+ *retval = LUSR_OFF(regs);
+ else if (addr >= LUSR_OFF(u_debugreg)
+ && addr <= LUSR_OFF(u_debugreg_end)) {
+ int off = (addr - LUSR_OFF(u_debugreg)) / sizeof(int);
- return process_write_regs(t, ®s);
+ /* only do this for Linux processes */
+ if (t->p_emul != &emul_linux)
+ error = EINVAL;
+ else {
+ *retval = ((struct linux_emuldata *)
+ t->p_emuldata)->debugreg[off];
+ }
+ } else if (addr == LUSR_OFF(__signal)) {
+ error = 1;
+ } else if (addr == LUSR_OFF(__signal)) {
+ error = 1;
+ } else if (addr == LUSR_OFF(u_fpstate)) {
+ error = 1;
+ } else if (addr == LUSR_OFF(__magic)) {
+ error = 1;
+ } else if (addr == LUSR_OFF(u_comm)) {
+ error = 1;
+ } else {
+#ifdef DEBUG_LINUX
+ printf("linux_ptrace: unsupported address: %d\n", addr);
+#endif
+ error = 1;
+ }
Home |
Main Index |
Thread Index |
Old Index