Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * ptrace for 32-bit processes running on a 64-bit kernel.
0003  *
0004  *  PowerPC version
0005  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
0006  *
0007  *  Derived from "arch/m68k/kernel/ptrace.c"
0008  *  Copyright (C) 1994 by Hamish Macdonald
0009  *  Taken from linux/kernel/ptrace.c and modified for M680x0.
0010  *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
0011  *
0012  * Modified by Cort Dougan (cort@hq.fsmlabs.com)
0013  * and Paul Mackerras (paulus@samba.org).
0014  *
0015  * This file is subject to the terms and conditions of the GNU General
0016  * Public License.  See the file COPYING in the main directory of
0017  * this archive for more details.
0018  */
0019 
0020 #include <linux/ptrace.h>
0021 #include <linux/regset.h>
0022 #include <linux/compat.h>
0023 
0024 #include <asm/switch_to.h>
0025 
0026 #include "ptrace-decl.h"
0027 
0028 /*
0029  * does not yet catch signals sent when the child dies.
0030  * in exit.c or in signal.c.
0031  */
0032 
0033 /* Macros to workout the correct index for the FPR in the thread struct */
0034 #define FPRNUMBER(i) (((i) - PT_FPR0) >> 1)
0035 #define FPRHALF(i) (((i) - PT_FPR0) & 1)
0036 #define FPRINDEX(i) TS_FPRWIDTH * FPRNUMBER(i) * 2 + FPRHALF(i)
0037 
0038 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
0039             compat_ulong_t caddr, compat_ulong_t cdata)
0040 {
0041     unsigned long addr = caddr;
0042     unsigned long data = cdata;
0043     int ret;
0044 
0045     switch (request) {
0046     /*
0047      * Read 4 bytes of the other process' storage
0048      *  data is a pointer specifying where the user wants the
0049      *  4 bytes copied into
0050      *  addr is a pointer in the user's storage that contains an 8 byte
0051      *  address in the other process of the 4 bytes that is to be read
0052      * (this is run in a 32-bit process looking at a 64-bit process)
0053      * when I and D space are separate, these will need to be fixed.
0054      */
0055     case PPC_PTRACE_PEEKTEXT_3264:
0056     case PPC_PTRACE_PEEKDATA_3264: {
0057         u32 tmp;
0058         int copied;
0059         u32 __user * addrOthers;
0060 
0061         ret = -EIO;
0062 
0063         /* Get the addr in the other process that we want to read */
0064         if (get_user(addrOthers, (u32 __user * __user *)addr) != 0)
0065             break;
0066 
0067         copied = ptrace_access_vm(child, (u64)addrOthers, &tmp,
0068                 sizeof(tmp), FOLL_FORCE);
0069         if (copied != sizeof(tmp))
0070             break;
0071         ret = put_user(tmp, (u32 __user *)data);
0072         break;
0073     }
0074 
0075     /* Read a register (specified by ADDR) out of the "user area" */
0076     case PTRACE_PEEKUSR: {
0077         int index;
0078         unsigned long tmp;
0079 
0080         ret = -EIO;
0081         /* convert to index and check */
0082         index = (unsigned long) addr >> 2;
0083         if ((addr & 3) || (index > PT_FPSCR32))
0084             break;
0085 
0086         if (index < PT_FPR0) {
0087             ret = ptrace_get_reg(child, index, &tmp);
0088             if (ret)
0089                 break;
0090         } else {
0091             flush_fp_to_thread(child);
0092             /*
0093              * the user space code considers the floating point
0094              * to be an array of unsigned int (32 bits) - the
0095              * index passed in is based on this assumption.
0096              */
0097             tmp = ((unsigned int *)child->thread.fp_state.fpr)
0098                 [FPRINDEX(index)];
0099         }
0100         ret = put_user((unsigned int)tmp, (u32 __user *)data);
0101         break;
0102     }
0103   
0104     /*
0105      * Read 4 bytes out of the other process' pt_regs area
0106      *  data is a pointer specifying where the user wants the
0107      *  4 bytes copied into
0108      *  addr is the offset into the other process' pt_regs structure
0109      *  that is to be read
0110      * (this is run in a 32-bit process looking at a 64-bit process)
0111      */
0112     case PPC_PTRACE_PEEKUSR_3264: {
0113         u32 index;
0114         u32 reg32bits;
0115         u64 tmp;
0116         u32 numReg;
0117         u32 part;
0118 
0119         ret = -EIO;
0120         /* Determine which register the user wants */
0121         index = (u64)addr >> 2;
0122         numReg = index / 2;
0123         /* Determine which part of the register the user wants */
0124         if (index % 2)
0125             part = 1;  /* want the 2nd half of the register (right-most). */
0126         else
0127             part = 0;  /* want the 1st half of the register (left-most). */
0128 
0129         /* Validate the input - check to see if address is on the wrong boundary
0130          * or beyond the end of the user area
0131          */
0132         if ((addr & 3) || numReg > PT_FPSCR)
0133             break;
0134 
0135         if (numReg >= PT_FPR0) {
0136             flush_fp_to_thread(child);
0137             /* get 64 bit FPR */
0138             tmp = child->thread.fp_state.fpr[numReg - PT_FPR0][0];
0139         } else { /* register within PT_REGS struct */
0140             unsigned long tmp2;
0141             ret = ptrace_get_reg(child, numReg, &tmp2);
0142             if (ret)
0143                 break;
0144             tmp = tmp2;
0145         } 
0146         reg32bits = ((u32*)&tmp)[part];
0147         ret = put_user(reg32bits, (u32 __user *)data);
0148         break;
0149     }
0150 
0151     /*
0152      * Write 4 bytes into the other process' storage
0153      *  data is the 4 bytes that the user wants written
0154      *  addr is a pointer in the user's storage that contains an
0155      *  8 byte address in the other process where the 4 bytes
0156      *  that is to be written
0157      * (this is run in a 32-bit process looking at a 64-bit process)
0158      * when I and D space are separate, these will need to be fixed.
0159      */
0160     case PPC_PTRACE_POKETEXT_3264:
0161     case PPC_PTRACE_POKEDATA_3264: {
0162         u32 tmp = data;
0163         u32 __user * addrOthers;
0164 
0165         /* Get the addr in the other process that we want to write into */
0166         ret = -EIO;
0167         if (get_user(addrOthers, (u32 __user * __user *)addr) != 0)
0168             break;
0169         ret = 0;
0170         if (ptrace_access_vm(child, (u64)addrOthers, &tmp,
0171                     sizeof(tmp),
0172                     FOLL_FORCE | FOLL_WRITE) == sizeof(tmp))
0173             break;
0174         ret = -EIO;
0175         break;
0176     }
0177 
0178     /* write the word at location addr in the USER area */
0179     case PTRACE_POKEUSR: {
0180         unsigned long index;
0181 
0182         ret = -EIO;
0183         /* convert to index and check */
0184         index = (unsigned long) addr >> 2;
0185         if ((addr & 3) || (index > PT_FPSCR32))
0186             break;
0187 
0188         if (index < PT_FPR0) {
0189             ret = ptrace_put_reg(child, index, data);
0190         } else {
0191             flush_fp_to_thread(child);
0192             /*
0193              * the user space code considers the floating point
0194              * to be an array of unsigned int (32 bits) - the
0195              * index passed in is based on this assumption.
0196              */
0197             ((unsigned int *)child->thread.fp_state.fpr)
0198                 [FPRINDEX(index)] = data;
0199             ret = 0;
0200         }
0201         break;
0202     }
0203 
0204     /*
0205      * Write 4 bytes into the other process' pt_regs area
0206      *  data is the 4 bytes that the user wants written
0207      *  addr is the offset into the other process' pt_regs structure
0208      *  that is to be written into
0209      * (this is run in a 32-bit process looking at a 64-bit process)
0210      */
0211     case PPC_PTRACE_POKEUSR_3264: {
0212         u32 index;
0213         u32 numReg;
0214 
0215         ret = -EIO;
0216         /* Determine which register the user wants */
0217         index = (u64)addr >> 2;
0218         numReg = index / 2;
0219 
0220         /*
0221          * Validate the input - check to see if address is on the
0222          * wrong boundary or beyond the end of the user area
0223          */
0224         if ((addr & 3) || (numReg > PT_FPSCR))
0225             break;
0226         if (numReg < PT_FPR0) {
0227             unsigned long freg;
0228             ret = ptrace_get_reg(child, numReg, &freg);
0229             if (ret)
0230                 break;
0231             if (index % 2)
0232                 freg = (freg & ~0xfffffffful) | (data & 0xfffffffful);
0233             else
0234                 freg = (freg & 0xfffffffful) | (data << 32);
0235             ret = ptrace_put_reg(child, numReg, freg);
0236         } else {
0237             u64 *tmp;
0238             flush_fp_to_thread(child);
0239             /* get 64 bit FPR ... */
0240             tmp = &child->thread.fp_state.fpr[numReg - PT_FPR0][0];
0241             /* ... write the 32 bit part we want */
0242             ((u32 *)tmp)[index % 2] = data;
0243             ret = 0;
0244         }
0245         break;
0246     }
0247 
0248     case PTRACE_GET_DEBUGREG: {
0249 #ifndef CONFIG_PPC_ADV_DEBUG_REGS
0250         unsigned long dabr_fake;
0251 #endif
0252         ret = -EINVAL;
0253         /* We only support one DABR and no IABRS at the moment */
0254         if (addr > 0)
0255             break;
0256 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
0257         ret = put_user(child->thread.debug.dac1, (u32 __user *)data);
0258 #else
0259         dabr_fake = (
0260             (child->thread.hw_brk[0].address & (~HW_BRK_TYPE_DABR)) |
0261             (child->thread.hw_brk[0].type & HW_BRK_TYPE_DABR));
0262         ret = put_user(dabr_fake, (u32 __user *)data);
0263 #endif
0264         break;
0265     }
0266 
0267     case PTRACE_GETREGS:    /* Get all pt_regs from the child. */
0268         return copy_regset_to_user(
0269             child, task_user_regset_view(current), 0,
0270             0, PT_REGS_COUNT * sizeof(compat_long_t),
0271             compat_ptr(data));
0272 
0273     case PTRACE_SETREGS:    /* Set all gp regs in the child. */
0274         return copy_regset_from_user(
0275             child, task_user_regset_view(current), 0,
0276             0, PT_REGS_COUNT * sizeof(compat_long_t),
0277             compat_ptr(data));
0278 
0279     case PTRACE_GETFPREGS:
0280     case PTRACE_SETFPREGS:
0281     case PTRACE_GETVRREGS:
0282     case PTRACE_SETVRREGS:
0283     case PTRACE_GETVSRREGS:
0284     case PTRACE_SETVSRREGS:
0285     case PTRACE_GETREGS64:
0286     case PTRACE_SETREGS64:
0287     case PTRACE_KILL:
0288     case PTRACE_SINGLESTEP:
0289     case PTRACE_DETACH:
0290     case PTRACE_SET_DEBUGREG:
0291     case PTRACE_SYSCALL:
0292     case PTRACE_CONT:
0293     case PPC_PTRACE_GETHWDBGINFO:
0294     case PPC_PTRACE_SETHWDEBUG:
0295     case PPC_PTRACE_DELHWDEBUG:
0296         ret = arch_ptrace(child, request, addr, data);
0297         break;
0298 
0299     default:
0300         ret = compat_ptrace_request(child, request, addr, data);
0301         break;
0302     }
0303 
0304     return ret;
0305 }