Home | History | Annotate | Line # | Download | only in i386
linux_ptrace.c revision 1.17
      1  1.17  christos /*	$NetBSD: linux_ptrace.c,v 1.17 2007/03/04 06:01:19 christos Exp $	*/
      2   1.1      tron 
      3   1.1      tron /*-
      4   1.1      tron  * Copyright (c) 1999 The NetBSD Foundation, Inc.
      5   1.1      tron  * All rights reserved.
      6   1.1      tron  *
      7   1.1      tron  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1      tron  * by Matthias Scheler.
      9   1.1      tron  *
     10   1.1      tron  * Redistribution and use in source and binary forms, with or without
     11   1.1      tron  * modification, are permitted provided that the following conditions
     12   1.1      tron  * are met:
     13   1.1      tron  * 1. Redistributions of source code must retain the above copyright
     14   1.1      tron  *    notice, this list of conditions and the following disclaimer.
     15   1.1      tron  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1      tron  *    notice, this list of conditions and the following disclaimer in the
     17   1.1      tron  *    documentation and/or other materials provided with the distribution.
     18   1.1      tron  * 3. All advertising materials mentioning features or use of this software
     19   1.1      tron  *    must display the following acknowledgement:
     20   1.1      tron  *	This product includes software developed by the NetBSD
     21   1.1      tron  *	Foundation, Inc. and its contributors.
     22   1.1      tron  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23   1.1      tron  *    contributors may be used to endorse or promote products derived
     24   1.1      tron  *    from this software without specific prior written permission.
     25   1.1      tron  *
     26   1.1      tron  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27   1.1      tron  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28   1.1      tron  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29   1.1      tron  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30   1.1      tron  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31   1.1      tron  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32   1.1      tron  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33   1.1      tron  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34   1.1      tron  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35   1.1      tron  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36   1.1      tron  * POSSIBILITY OF SUCH DAMAGE.
     37   1.1      tron  */
     38   1.7     lukem 
     39   1.7     lukem #include <sys/cdefs.h>
     40  1.17  christos __KERNEL_RCSID(0, "$NetBSD: linux_ptrace.c,v 1.17 2007/03/04 06:01:19 christos Exp $");
     41   1.1      tron 
     42   1.1      tron #include <sys/param.h>
     43   1.5  jdolecek #include <sys/malloc.h>
     44   1.1      tron #include <sys/mount.h>
     45   1.1      tron #include <sys/proc.h>
     46   1.1      tron #include <sys/ptrace.h>
     47   1.1      tron #include <sys/systm.h>
     48  1.15      matt #include <sys/syscall.h>
     49   1.1      tron #include <sys/syscallargs.h>
     50   1.5  jdolecek #include <uvm/uvm_extern.h>
     51   1.1      tron 
     52   1.3      tron #include <machine/reg.h>
     53   1.3      tron 
     54   1.1      tron #include <compat/linux/common/linux_types.h>
     55   1.1      tron #include <compat/linux/common/linux_ptrace.h>
     56   1.1      tron #include <compat/linux/common/linux_signal.h>
     57   1.1      tron 
     58   1.1      tron #include <compat/linux/common/linux_util.h>
     59   1.1      tron #include <compat/linux/common/linux_machdep.h>
     60   1.5  jdolecek #include <compat/linux/common/linux_emuldata.h>
     61   1.5  jdolecek #include <compat/linux/common/linux_exec.h>	/* for emul_linux */
     62   1.1      tron 
     63   1.1      tron #include <compat/linux/linux_syscallargs.h>
     64   1.2      tron 
     65   1.5  jdolecek #include <lib/libkern/libkern.h>	/* for offsetof() */
     66   1.5  jdolecek 
     67   1.2      tron struct linux_reg {
     68   1.2      tron 	long ebx;
     69   1.2      tron 	long ecx;
     70   1.2      tron 	long edx;
     71   1.2      tron 	long esi;
     72   1.2      tron 	long edi;
     73   1.2      tron 	long ebp;
     74   1.2      tron 	long eax;
     75   1.6     lukem 	long xds, xes;		/* unsigned short ds, __ds, es, __es; */
     76   1.6     lukem 	long __fs, __gs;	/* unsigned short fs, __fs, gs, __gs; */
     77   1.2      tron 	long orig_eax;
     78   1.2      tron 	long eip;
     79   1.6     lukem 	long xcs;		/* unsigned short cs, __cs; */
     80   1.2      tron 	long eflags;
     81   1.2      tron 	long esp;
     82   1.6     lukem 	long xss;		/* unsigned short ss, __ss; */
     83   1.5  jdolecek };
     84   1.5  jdolecek 
     85   1.5  jdolecek /* structure used for storing floating point context */
     86  1.10  junyoung struct linux_fpctx {
     87  1.10  junyoung 	long cwd;
     88  1.10  junyoung 	long swd;
     89  1.10  junyoung 	long twd;
     90  1.10  junyoung 	long fip;
     91  1.10  junyoung 	long fcs;
     92  1.10  junyoung 	long foo;
     93  1.10  junyoung 	long fos;
     94  1.10  junyoung 	long st_space[20];
     95   1.2      tron };
     96   1.2      tron 
     97   1.5  jdolecek /* user struct for linux process - this is used for Linux ptrace emulation */
     98   1.5  jdolecek /* most of it is junk only used by gdb */
     99   1.5  jdolecek struct linux_user {
    100  1.10  junyoung 	struct linux_reg regs;		/* registers */
    101  1.10  junyoung 	int u_fpvalid;		/* true if math co-processor being used. */
    102  1.10  junyoung 	struct linux_fpctx i387;	/* Math Co-processor registers. */
    103   1.5  jdolecek /* The rest of this junk is to help gdb figure out what goes where */
    104   1.5  jdolecek #define lusr_startgdb	u_tsize
    105  1.10  junyoung 	unsigned long int u_tsize;	/* Text segment size (pages). */
    106  1.10  junyoung 	unsigned long int u_dsize;	/* Data segment size (pages). */
    107  1.10  junyoung 	unsigned long int u_ssize;	/* Stack segment size (pages). */
    108  1.10  junyoung 	unsigned long start_code;	/* Starting virtual address of text. */
    109  1.12     perry 	unsigned long start_stack;	/* Starting virtual address of stack
    110  1.10  junyoung 					   area. This is actually the bottom of
    111  1.10  junyoung 					   the stack, the top of the stack is
    112  1.10  junyoung 					   always found in the esp register. */
    113  1.10  junyoung 	long int __signal;  		/* Signal that caused the core dump. */
    114  1.10  junyoung 	int __reserved;			/* unused */
    115  1.10  junyoung 	void *u_ar0;			/* Used by gdb to help find the values
    116  1.10  junyoung 					   for the registers. */
    117  1.10  junyoung 	struct linux_fpctx *u_fpstate;	/* Math Co-processor pointer. */
    118  1.10  junyoung 	unsigned long __magic;		/* To uniquely identify a core file */
    119  1.10  junyoung 	char u_comm[32];		/* User command that was responsible */
    120  1.10  junyoung 	int u_debugreg[8];
    121   1.5  jdolecek #define u_debugreg_end	u_debugreg[7]
    122   1.5  jdolecek };
    123   1.5  jdolecek 
    124   1.5  jdolecek #define LUSR_OFF(member)	offsetof(struct linux_user, member)
    125   1.5  jdolecek #define ISSET(t, f)		((t) & (f))
    126   1.3      tron 
    127   1.1      tron int
    128  1.11   thorpej linux_sys_ptrace_arch(l, v, retval)
    129  1.11   thorpej 	struct lwp *l;
    130   1.1      tron 	void *v;
    131   1.1      tron 	register_t *retval;
    132   1.1      tron {
    133   1.1      tron 	struct linux_sys_ptrace_args /* {
    134   1.1      tron 		syscallarg(int) request;
    135   1.1      tron 		syscallarg(int) pid;
    136   1.1      tron 		syscallarg(int) addr;
    137   1.1      tron 		syscallarg(int) data;
    138   1.1      tron 	} */ *uap = v;
    139  1.11   thorpej 	struct proc *p = l->l_proc;
    140   1.3      tron 	int request, error;
    141   1.3      tron 	struct proc *t;				/* target process */
    142  1.11   thorpej 	struct lwp *lt;
    143   1.5  jdolecek 	struct reg *regs = NULL;
    144   1.5  jdolecek 	struct fpreg *fpregs = NULL;
    145   1.5  jdolecek 	struct linux_reg *linux_regs = NULL;
    146  1.10  junyoung 	struct linux_fpctx *linux_fpregs = NULL;
    147   1.5  jdolecek 	int addr;
    148   1.3      tron 
    149   1.3      tron 	request = SCARG(uap, request);
    150   1.3      tron 
    151   1.5  jdolecek 	if ((request != LINUX_PTRACE_PEEKUSR) &&
    152   1.5  jdolecek 	    (request != LINUX_PTRACE_POKEUSR) &&
    153   1.5  jdolecek 	    (request != LINUX_PTRACE_GETREGS) &&
    154   1.3      tron 	    (request != LINUX_PTRACE_SETREGS) &&
    155   1.3      tron 	    (request != LINUX_PTRACE_GETFPREGS) &&
    156   1.3      tron 	    (request != LINUX_PTRACE_SETFPREGS))
    157   1.3      tron 		return EIO;
    158   1.1      tron 
    159  1.16        ad 	/* XXXAD locking */
    160  1.16        ad 
    161   1.3      tron 	/* Find the process we're supposed to be operating on. */
    162   1.3      tron 	if ((t = pfind(SCARG(uap, pid))) == NULL)
    163   1.3      tron 		return ESRCH;
    164   1.3      tron 
    165   1.3      tron 	/*
    166   1.3      tron 	 * You can't do what you want to the process if:
    167   1.3      tron 	 *	(1) It's not being traced at all,
    168   1.3      tron 	 */
    169  1.16        ad 	if (!ISSET(t->p_slflag, PSL_TRACED))
    170   1.3      tron 		return EPERM;
    171   1.3      tron 
    172   1.3      tron 	/*
    173   1.3      tron 	 *	(2) it's being traced by procfs (which has
    174   1.3      tron 	 *	    different signal delivery semantics),
    175   1.3      tron 	 */
    176  1.16        ad 	if (ISSET(t->p_slflag, PSL_FSTRACE))
    177   1.3      tron 		return EBUSY;
    178   1.3      tron 
    179   1.3      tron 	/*
    180   1.3      tron 	 *	(3) it's not being traced by _you_, or
    181   1.3      tron 	 */
    182   1.3      tron 	if (t->p_pptr != p)
    183   1.3      tron 		return EBUSY;
    184   1.3      tron 
    185   1.3      tron 	/*
    186   1.3      tron 	 *	(4) it's not currently stopped.
    187   1.3      tron 	 */
    188  1.16        ad 	if (t->p_stat != SSTOP || !t->p_waited /* XXXSMP */)
    189   1.3      tron 		return EBUSY;
    190   1.3      tron 
    191  1.11   thorpej 	/* XXX NJWLWP
    192  1.11   thorpej 	 * The entire ptrace interface needs work to be useful to
    193  1.12     perry 	 * a process with multiple LWPs. For the moment, we'll
    194  1.11   thorpej 	 * just kluge this and fail on others.
    195  1.11   thorpej 	 */
    196  1.11   thorpej 
    197  1.11   thorpej 	if (p->p_nlwps > 1)
    198  1.11   thorpej 		return (ENOSYS);
    199  1.11   thorpej 
    200  1.11   thorpej 	lt = LIST_FIRST(&t->p_lwps);
    201  1.11   thorpej 
    202   1.3      tron 	*retval = 0;
    203   1.3      tron 
    204   1.3      tron 	switch (request) {
    205   1.3      tron 	case  LINUX_PTRACE_GETREGS:
    206   1.5  jdolecek 		MALLOC(regs, struct reg*, sizeof(struct reg), M_TEMP, M_WAITOK);
    207   1.5  jdolecek 		MALLOC(linux_regs, struct linux_reg*, sizeof(struct linux_reg),
    208   1.5  jdolecek 			M_TEMP, M_WAITOK);
    209   1.5  jdolecek 
    210  1.11   thorpej 		error = process_read_regs(lt, regs);
    211   1.3      tron 		if (error != 0)
    212   1.5  jdolecek 			goto out;
    213   1.3      tron 
    214   1.5  jdolecek 		linux_regs->ebx = regs->r_ebx;
    215   1.5  jdolecek 		linux_regs->ecx = regs->r_ecx;
    216   1.5  jdolecek 		linux_regs->edx = regs->r_edx;
    217   1.5  jdolecek 		linux_regs->esi = regs->r_esi;
    218   1.5  jdolecek 		linux_regs->edi = regs->r_edi;
    219   1.5  jdolecek 		linux_regs->ebp = regs->r_ebp;
    220   1.5  jdolecek 		linux_regs->eax = regs->r_eax;
    221   1.5  jdolecek 		linux_regs->xds = regs->r_ds;
    222   1.5  jdolecek 		linux_regs->xes = regs->r_es;
    223   1.5  jdolecek 		linux_regs->orig_eax = regs->r_eax; /* XXX is this correct? */
    224   1.5  jdolecek 		linux_regs->eip = regs->r_cs + regs->r_eip;
    225   1.5  jdolecek 		linux_regs->xcs = regs->r_cs;
    226   1.5  jdolecek 		linux_regs->eflags = regs->r_eflags;
    227   1.5  jdolecek 		linux_regs->esp = regs->r_esp;
    228   1.5  jdolecek 		linux_regs->xss = regs->r_ss;
    229   1.3      tron 
    230  1.17  christos 		error = copyout(linux_regs, (void *)SCARG(uap, data),
    231   1.3      tron 		    sizeof(struct linux_reg));
    232   1.5  jdolecek 		goto out;
    233   1.5  jdolecek 
    234   1.3      tron 	case  LINUX_PTRACE_SETREGS:
    235   1.5  jdolecek 		MALLOC(regs, struct reg*, sizeof(struct reg), M_TEMP, M_WAITOK);
    236   1.5  jdolecek 		MALLOC(linux_regs, struct linux_reg *, sizeof(struct linux_reg),
    237   1.5  jdolecek 			M_TEMP, M_WAITOK);
    238   1.5  jdolecek 
    239  1.17  christos 		error = copyin((void *)SCARG(uap, data), linux_regs,
    240   1.3      tron 		    sizeof(struct linux_reg));
    241   1.3      tron 		if (error != 0)
    242   1.5  jdolecek 			goto out;
    243   1.5  jdolecek 
    244   1.5  jdolecek 		regs->r_ebx = linux_regs->ebx;
    245   1.5  jdolecek 		regs->r_ecx = linux_regs->ecx;
    246   1.5  jdolecek 		regs->r_edx = linux_regs->edx;
    247   1.5  jdolecek 		regs->r_esi = linux_regs->esi;
    248   1.5  jdolecek 		regs->r_edi = linux_regs->edi;
    249   1.5  jdolecek 		regs->r_ebp = linux_regs->ebp;
    250   1.5  jdolecek 		regs->r_eax = linux_regs->eax;
    251   1.5  jdolecek 		regs->r_ds = linux_regs->xds;
    252   1.5  jdolecek 		regs->r_es = linux_regs->xes;
    253   1.5  jdolecek 		regs->r_eip = linux_regs->eip - linux_regs->xcs;
    254   1.5  jdolecek 		regs->r_cs = linux_regs->xcs;
    255   1.5  jdolecek 		regs->r_eflags = linux_regs->eflags;
    256   1.5  jdolecek 		regs->r_esp = linux_regs->esp;
    257   1.5  jdolecek 		regs->r_ss = linux_regs->xss;
    258   1.5  jdolecek 
    259  1.11   thorpej 		error = process_write_regs(lt, regs);
    260   1.5  jdolecek 		goto out;
    261   1.5  jdolecek 
    262   1.5  jdolecek 	case  LINUX_PTRACE_GETFPREGS:
    263   1.5  jdolecek 		MALLOC(fpregs, struct fpreg *, sizeof(struct fpreg),
    264   1.5  jdolecek 			M_TEMP, M_WAITOK);
    265  1.10  junyoung 		MALLOC(linux_fpregs, struct linux_fpctx *,
    266  1.10  junyoung 			sizeof(struct linux_fpctx), M_TEMP, M_WAITOK);
    267   1.5  jdolecek 
    268  1.11   thorpej 		error = process_read_fpregs(lt, fpregs);
    269   1.5  jdolecek 		if (error != 0)
    270   1.5  jdolecek 			goto out;
    271   1.3      tron 
    272   1.5  jdolecek 		/* zero the contents if NetBSD fpreg structure is smaller */
    273  1.10  junyoung 		if (sizeof(struct fpreg) < sizeof(struct linux_fpctx))
    274  1.10  junyoung 			memset(linux_fpregs, '\0', sizeof(struct linux_fpctx));
    275   1.5  jdolecek 
    276   1.5  jdolecek 		memcpy(linux_fpregs, fpregs,
    277  1.10  junyoung 			min(sizeof(struct linux_fpctx), sizeof(struct fpreg)));
    278  1.17  christos 		error = copyout(linux_fpregs, (void *)SCARG(uap, data),
    279  1.10  junyoung 		    sizeof(struct linux_fpctx));
    280   1.5  jdolecek 		goto out;
    281   1.5  jdolecek 
    282   1.5  jdolecek 	case  LINUX_PTRACE_SETFPREGS:
    283   1.5  jdolecek 		MALLOC(fpregs, struct fpreg *, sizeof(struct fpreg),
    284   1.5  jdolecek 			M_TEMP, M_WAITOK);
    285  1.10  junyoung 		MALLOC(linux_fpregs, struct linux_fpctx *,
    286  1.10  junyoung 			sizeof(struct linux_fpctx), M_TEMP, M_WAITOK);
    287  1.17  christos 		error = copyin((void *)SCARG(uap, data), linux_fpregs,
    288  1.10  junyoung 		    sizeof(struct linux_fpctx));
    289   1.5  jdolecek 		if (error != 0)
    290   1.5  jdolecek 			goto out;
    291   1.1      tron 
    292   1.5  jdolecek 		memset(fpregs, '\0', sizeof(struct fpreg));
    293   1.5  jdolecek 		memcpy(fpregs, linux_fpregs,
    294  1.10  junyoung 			min(sizeof(struct linux_fpctx), sizeof(struct fpreg)));
    295   1.5  jdolecek 
    296  1.11   thorpej 		error = process_write_regs(lt, regs);
    297   1.5  jdolecek 		goto out;
    298   1.5  jdolecek 
    299   1.5  jdolecek 	case  LINUX_PTRACE_PEEKUSR:
    300   1.5  jdolecek 		addr = SCARG(uap, addr);
    301   1.5  jdolecek 
    302  1.11   thorpej 		PHOLD(lt);	/* need full process info */
    303   1.5  jdolecek 		error = 0;
    304   1.5  jdolecek 		if (addr < LUSR_OFF(lusr_startgdb)) {
    305   1.5  jdolecek 			/* XXX should provide appropriate register */
    306   1.5  jdolecek 			error = 1;
    307   1.5  jdolecek 		} else if (addr == LUSR_OFF(u_tsize))
    308   1.5  jdolecek 			*retval = p->p_vmspace->vm_tsize;
    309   1.5  jdolecek 		else if (addr == LUSR_OFF(u_dsize))
    310   1.5  jdolecek 			*retval = p->p_vmspace->vm_dsize;
    311   1.5  jdolecek 		else if (addr == LUSR_OFF(u_ssize))
    312   1.5  jdolecek 			*retval = p->p_vmspace->vm_ssize;
    313   1.5  jdolecek 		else if (addr == LUSR_OFF(start_code))
    314   1.5  jdolecek 			*retval = (register_t) p->p_vmspace->vm_taddr;
    315   1.5  jdolecek 		else if (addr == LUSR_OFF(start_stack))
    316   1.5  jdolecek 			*retval = (register_t) p->p_vmspace->vm_minsaddr;
    317   1.5  jdolecek 		else if (addr == LUSR_OFF(u_ar0))
    318   1.5  jdolecek 			*retval = LUSR_OFF(regs);
    319   1.5  jdolecek 		else if (addr >= LUSR_OFF(u_debugreg)
    320   1.5  jdolecek 			   && addr <= LUSR_OFF(u_debugreg_end)) {
    321   1.5  jdolecek 			int off = (addr - LUSR_OFF(u_debugreg)) / sizeof(int);
    322   1.5  jdolecek 
    323   1.5  jdolecek 			/* only do this for Linux processes */
    324   1.5  jdolecek 			if (t->p_emul != &emul_linux)
    325   1.5  jdolecek 				error = EINVAL;
    326   1.5  jdolecek 			else {
    327   1.5  jdolecek 				*retval = ((struct linux_emuldata *)
    328   1.5  jdolecek 						t->p_emuldata)->debugreg[off];
    329   1.5  jdolecek 			}
    330   1.5  jdolecek 		} else if (addr == LUSR_OFF(__signal)) {
    331   1.5  jdolecek 			error = 1;
    332   1.5  jdolecek 		} else if (addr == LUSR_OFF(__signal)) {
    333   1.5  jdolecek 			error = 1;
    334   1.5  jdolecek 		} else if (addr == LUSR_OFF(u_fpstate)) {
    335   1.5  jdolecek 			error = 1;
    336   1.5  jdolecek 		} else if (addr == LUSR_OFF(__magic)) {
    337   1.5  jdolecek 			error = 1;
    338   1.5  jdolecek 		} else if (addr == LUSR_OFF(u_comm)) {
    339   1.5  jdolecek 			error = 1;
    340   1.5  jdolecek 		} else {
    341   1.5  jdolecek #ifdef DEBUG_LINUX
    342   1.5  jdolecek 			printf("linux_ptrace: unsupported address: %d\n", addr);
    343   1.5  jdolecek #endif
    344   1.5  jdolecek 			error = 1;
    345   1.5  jdolecek 		}
    346   1.5  jdolecek 
    347  1.11   thorpej 		PRELE(lt);
    348   1.5  jdolecek 
    349   1.5  jdolecek 		if (!error)
    350   1.5  jdolecek 			return 0;
    351   1.5  jdolecek 
    352   1.5  jdolecek 	case  LINUX_PTRACE_POKEUSR:
    353   1.5  jdolecek 		/* we only support setting debugregs for now */
    354   1.5  jdolecek 		addr = SCARG(uap, addr);
    355   1.5  jdolecek 		if (addr >= LUSR_OFF(u_debugreg)
    356   1.5  jdolecek 			   && addr <= LUSR_OFF(u_debugreg_end)) {
    357   1.5  jdolecek 			int off = (addr - LUSR_OFF(u_debugreg)) / sizeof(int);
    358   1.5  jdolecek 			int data = SCARG(uap, data);
    359   1.5  jdolecek 
    360   1.5  jdolecek 			/* only do this for Linux processes */
    361   1.5  jdolecek 			if (t->p_emul != &emul_linux)
    362   1.5  jdolecek 				return EINVAL;
    363   1.5  jdolecek 
    364  1.11   thorpej 			PHOLD(lt);
    365   1.5  jdolecek 			((struct linux_emuldata *)t->p_emuldata)->debugreg[off] = data;
    366  1.11   thorpej 			PRELE(lt);
    367   1.5  jdolecek 			return (0);
    368   1.5  jdolecek 		}
    369   1.5  jdolecek 
    370   1.5  jdolecek 		break;
    371   1.5  jdolecek 	default:
    372   1.5  jdolecek 		/* never reached */
    373   1.5  jdolecek 		break;
    374   1.1      tron 	}
    375   1.1      tron 
    376   1.3      tron 	return EIO;
    377   1.5  jdolecek 
    378   1.5  jdolecek     out:
    379   1.5  jdolecek 	if (regs)
    380   1.5  jdolecek 		FREE(regs, M_TEMP);
    381   1.5  jdolecek 	if (fpregs)
    382   1.5  jdolecek 		FREE(fpregs, M_TEMP);
    383   1.5  jdolecek 	if (linux_regs)
    384   1.5  jdolecek 		FREE(linux_regs, M_TEMP);
    385   1.5  jdolecek 	if (linux_fpregs)
    386   1.5  jdolecek 		FREE(linux_fpregs, M_TEMP);
    387   1.5  jdolecek 	return (error);
    388   1.1      tron }
    389