Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* ptrace.c: Sparc process tracing support.
0003  *
0004  * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
0005  *
0006  * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
0007  * and David Mosberger.
0008  *
0009  * Added Linux support -miguel (weird, eh?, the original code was meant
0010  * to emulate SunOS).
0011  */
0012 
0013 #include <linux/kernel.h>
0014 #include <linux/sched.h>
0015 #include <linux/mm.h>
0016 #include <linux/errno.h>
0017 #include <linux/ptrace.h>
0018 #include <linux/user.h>
0019 #include <linux/smp.h>
0020 #include <linux/security.h>
0021 #include <linux/signal.h>
0022 #include <linux/regset.h>
0023 #include <linux/elf.h>
0024 
0025 #include <linux/uaccess.h>
0026 #include <asm/cacheflush.h>
0027 
0028 #include "kernel.h"
0029 
0030 /* #define ALLOW_INIT_TRACING */
0031 
0032 /*
0033  * Called by kernel/ptrace.c when detaching..
0034  *
0035  * Make sure single step bits etc are not set.
0036  */
0037 void ptrace_disable(struct task_struct *child)
0038 {
0039     /* nothing to do */
0040 }
0041 
0042 enum sparc_regset {
0043     REGSET_GENERAL,
0044     REGSET_FP,
0045 };
0046 
0047 static int regwindow32_get(struct task_struct *target,
0048                const struct pt_regs *regs,
0049                u32 *uregs)
0050 {
0051     unsigned long reg_window = regs->u_regs[UREG_I6];
0052     int size = 16 * sizeof(u32);
0053 
0054     if (target == current) {
0055         if (copy_from_user(uregs, (void __user *)reg_window, size))
0056             return -EFAULT;
0057     } else {
0058         if (access_process_vm(target, reg_window, uregs, size,
0059                       FOLL_FORCE) != size)
0060             return -EFAULT;
0061     }
0062     return 0;
0063 }
0064 
0065 static int regwindow32_set(struct task_struct *target,
0066                const struct pt_regs *regs,
0067                u32 *uregs)
0068 {
0069     unsigned long reg_window = regs->u_regs[UREG_I6];
0070     int size = 16 * sizeof(u32);
0071 
0072     if (target == current) {
0073         if (copy_to_user((void __user *)reg_window, uregs, size))
0074             return -EFAULT;
0075     } else {
0076         if (access_process_vm(target, reg_window, uregs, size,
0077                       FOLL_FORCE | FOLL_WRITE) != size)
0078             return -EFAULT;
0079     }
0080     return 0;
0081 }
0082 
0083 static int genregs32_get(struct task_struct *target,
0084              const struct user_regset *regset,
0085              struct membuf to)
0086 {
0087     const struct pt_regs *regs = target->thread.kregs;
0088     u32 uregs[16];
0089 
0090     if (target == current)
0091         flush_user_windows();
0092 
0093     membuf_write(&to, regs->u_regs, 16 * sizeof(u32));
0094     if (!to.left)
0095         return 0;
0096     if (regwindow32_get(target, regs, uregs))
0097         return -EFAULT;
0098     membuf_write(&to, uregs, 16 * sizeof(u32));
0099     membuf_store(&to, regs->psr);
0100     membuf_store(&to, regs->pc);
0101     membuf_store(&to, regs->npc);
0102     membuf_store(&to, regs->y);
0103     return membuf_zero(&to, 2 * sizeof(u32));
0104 }
0105 
0106 static int genregs32_set(struct task_struct *target,
0107              const struct user_regset *regset,
0108              unsigned int pos, unsigned int count,
0109              const void *kbuf, const void __user *ubuf)
0110 {
0111     struct pt_regs *regs = target->thread.kregs;
0112     u32 uregs[16];
0113     u32 psr;
0114     int ret;
0115 
0116     if (target == current)
0117         flush_user_windows();
0118 
0119     ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0120                  regs->u_regs,
0121                  0, 16 * sizeof(u32));
0122     if (ret || !count)
0123         return ret;
0124 
0125     if (regwindow32_get(target, regs, uregs))
0126         return -EFAULT;
0127     ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0128                  uregs,
0129                  16 * sizeof(u32), 32 * sizeof(u32));
0130     if (ret)
0131         return ret;
0132     if (regwindow32_set(target, regs, uregs))
0133         return -EFAULT;
0134     if (!count)
0135         return 0;
0136 
0137     ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0138                  &psr,
0139                  32 * sizeof(u32), 33 * sizeof(u32));
0140     if (ret)
0141         return ret;
0142     regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) |
0143             (psr & (PSR_ICC | PSR_SYSCALL));
0144     if (!count)
0145         return 0;
0146     ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0147                  &regs->pc,
0148                  33 * sizeof(u32), 34 * sizeof(u32));
0149     if (ret || !count)
0150         return ret;
0151     ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0152                  &regs->npc,
0153                  34 * sizeof(u32), 35 * sizeof(u32));
0154     if (ret || !count)
0155         return ret;
0156     ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0157                  &regs->y,
0158                  35 * sizeof(u32), 36 * sizeof(u32));
0159     if (ret || !count)
0160         return ret;
0161     return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
0162                      36 * sizeof(u32), 38 * sizeof(u32));
0163 }
0164 
0165 static int fpregs32_get(struct task_struct *target,
0166             const struct user_regset *regset,
0167             struct membuf to)
0168 {
0169 #if 0
0170     if (target == current)
0171         save_and_clear_fpu();
0172 #endif
0173 
0174     membuf_write(&to, target->thread.float_regs, 32 * sizeof(u32));
0175     membuf_zero(&to, sizeof(u32));
0176     membuf_write(&to, &target->thread.fsr, sizeof(u32));
0177     membuf_store(&to, (u32)((1 << 8) | (8 << 16)));
0178     return membuf_zero(&to, 64 * sizeof(u32));
0179 }
0180 
0181 static int fpregs32_set(struct task_struct *target,
0182             const struct user_regset *regset,
0183             unsigned int pos, unsigned int count,
0184             const void *kbuf, const void __user *ubuf)
0185 {
0186     unsigned long *fpregs = target->thread.float_regs;
0187     int ret;
0188 
0189 #if 0
0190     if (target == current)
0191         save_and_clear_fpu();
0192 #endif
0193     ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0194                  fpregs,
0195                  0, 32 * sizeof(u32));
0196     if (!ret)
0197         user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
0198                       32 * sizeof(u32),
0199                       33 * sizeof(u32));
0200     if (!ret)
0201         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0202                      &target->thread.fsr,
0203                      33 * sizeof(u32),
0204                      34 * sizeof(u32));
0205     if (!ret)
0206         ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
0207                         34 * sizeof(u32), -1);
0208     return ret;
0209 }
0210 
0211 static const struct user_regset sparc32_regsets[] = {
0212     /* Format is:
0213      *  G0 --> G7
0214      *  O0 --> O7
0215      *  L0 --> L7
0216      *  I0 --> I7
0217      *  PSR, PC, nPC, Y, WIM, TBR
0218      */
0219     [REGSET_GENERAL] = {
0220         .core_note_type = NT_PRSTATUS,
0221         .n = 38,
0222         .size = sizeof(u32), .align = sizeof(u32),
0223         .regset_get = genregs32_get, .set = genregs32_set
0224     },
0225     /* Format is:
0226      *  F0 --> F31
0227      *  empty 32-bit word
0228      *  FSR (32--bit word)
0229      *  FPU QUEUE COUNT (8-bit char)
0230      *  FPU QUEUE ENTRYSIZE (8-bit char)
0231      *  FPU ENABLED (8-bit char)
0232      *  empty 8-bit char
0233      *  FPU QUEUE (64 32-bit ints)
0234      */
0235     [REGSET_FP] = {
0236         .core_note_type = NT_PRFPREG,
0237         .n = 99,
0238         .size = sizeof(u32), .align = sizeof(u32),
0239         .regset_get = fpregs32_get, .set = fpregs32_set
0240     },
0241 };
0242 
0243 static int getregs_get(struct task_struct *target,
0244              const struct user_regset *regset,
0245              struct membuf to)
0246 {
0247     const struct pt_regs *regs = target->thread.kregs;
0248 
0249     if (target == current)
0250         flush_user_windows();
0251 
0252     membuf_store(&to, regs->psr);
0253     membuf_store(&to, regs->pc);
0254     membuf_store(&to, regs->npc);
0255     membuf_store(&to, regs->y);
0256     return membuf_write(&to, regs->u_regs + 1, 15 * sizeof(u32));
0257 }
0258 
0259 static int setregs_set(struct task_struct *target,
0260              const struct user_regset *regset,
0261              unsigned int pos, unsigned int count,
0262              const void *kbuf, const void __user *ubuf)
0263 {
0264     struct pt_regs *regs = target->thread.kregs;
0265     u32 v[4];
0266     int ret;
0267 
0268     if (target == current)
0269         flush_user_windows();
0270 
0271     ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0272                  v,
0273                  0, 4 * sizeof(u32));
0274     if (ret)
0275         return ret;
0276     regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) |
0277             (v[0] & (PSR_ICC | PSR_SYSCALL));
0278     regs->pc = v[1];
0279     regs->npc = v[2];
0280     regs->y = v[3];
0281     return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0282                  regs->u_regs + 1,
0283                  4 * sizeof(u32) , 19 * sizeof(u32));
0284 }
0285 
0286 static int getfpregs_get(struct task_struct *target,
0287             const struct user_regset *regset,
0288             struct membuf to)
0289 {
0290 #if 0
0291     if (target == current)
0292         save_and_clear_fpu();
0293 #endif
0294     membuf_write(&to, &target->thread.float_regs, 32 * sizeof(u32));
0295     membuf_write(&to, &target->thread.fsr, sizeof(u32));
0296     return membuf_zero(&to, 35 * sizeof(u32));
0297 }
0298 
0299 static int setfpregs_set(struct task_struct *target,
0300             const struct user_regset *regset,
0301             unsigned int pos, unsigned int count,
0302             const void *kbuf, const void __user *ubuf)
0303 {
0304     unsigned long *fpregs = target->thread.float_regs;
0305     int ret;
0306 
0307 #if 0
0308     if (target == current)
0309         save_and_clear_fpu();
0310 #endif
0311     ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0312                  fpregs,
0313                  0, 32 * sizeof(u32));
0314     if (ret)
0315         return ret;
0316     return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0317                  &target->thread.fsr,
0318                  32 * sizeof(u32),
0319                  33 * sizeof(u32));
0320 }
0321 
0322 static const struct user_regset ptrace32_regsets[] = {
0323     [REGSET_GENERAL] = {
0324         .n = 19, .size = sizeof(u32),
0325         .regset_get = getregs_get, .set = setregs_set,
0326     },
0327     [REGSET_FP] = {
0328         .n = 68, .size = sizeof(u32),
0329         .regset_get = getfpregs_get, .set = setfpregs_set,
0330     },
0331 };
0332 
0333 static const struct user_regset_view ptrace32_view = {
0334     .regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets)
0335 };
0336 
0337 static const struct user_regset_view user_sparc32_view = {
0338     .name = "sparc", .e_machine = EM_SPARC,
0339     .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
0340 };
0341 
0342 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
0343 {
0344     return &user_sparc32_view;
0345 }
0346 
0347 struct fps {
0348     unsigned long regs[32];
0349     unsigned long fsr;
0350     unsigned long flags;
0351     unsigned long extra;
0352     unsigned long fpqd;
0353     struct fq {
0354         unsigned long *insnaddr;
0355         unsigned long insn;
0356     } fpq[16];
0357 };
0358 
0359 long arch_ptrace(struct task_struct *child, long request,
0360          unsigned long addr, unsigned long data)
0361 {
0362     unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
0363     void __user *addr2p;
0364     struct pt_regs __user *pregs;
0365     struct fps __user *fps;
0366     int ret;
0367 
0368     addr2p = (void __user *) addr2;
0369     pregs = (struct pt_regs __user *) addr;
0370     fps = (struct fps __user *) addr;
0371 
0372     switch(request) {
0373     case PTRACE_GETREGS: {
0374         ret = copy_regset_to_user(child, &ptrace32_view,
0375                       REGSET_GENERAL, 0,
0376                       19 * sizeof(u32),
0377                       pregs);
0378         break;
0379     }
0380 
0381     case PTRACE_SETREGS: {
0382         ret = copy_regset_from_user(child, &ptrace32_view,
0383                         REGSET_GENERAL, 0,
0384                         19 * sizeof(u32),
0385                         pregs);
0386         break;
0387     }
0388 
0389     case PTRACE_GETFPREGS: {
0390         ret = copy_regset_to_user(child, &ptrace32_view,
0391                       REGSET_FP, 0,
0392                       68 * sizeof(u32),
0393                       fps);
0394         break;
0395     }
0396 
0397     case PTRACE_SETFPREGS: {
0398         ret = copy_regset_from_user(child, &ptrace32_view,
0399                       REGSET_FP, 0,
0400                       33 * sizeof(u32),
0401                       fps);
0402         break;
0403     }
0404 
0405     case PTRACE_READTEXT:
0406     case PTRACE_READDATA:
0407         ret = ptrace_readdata(child, addr, addr2p, data);
0408 
0409         if (ret == data)
0410             ret = 0;
0411         else if (ret >= 0)
0412             ret = -EIO;
0413         break;
0414 
0415     case PTRACE_WRITETEXT:
0416     case PTRACE_WRITEDATA:
0417         ret = ptrace_writedata(child, addr2p, addr, data);
0418 
0419         if (ret == data)
0420             ret = 0;
0421         else if (ret >= 0)
0422             ret = -EIO;
0423         break;
0424 
0425     default:
0426         if (request == PTRACE_SPARC_DETACH)
0427             request = PTRACE_DETACH;
0428         ret = ptrace_request(child, request, addr, data);
0429         break;
0430     }
0431 
0432     return ret;
0433 }
0434 
0435 asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
0436 {
0437     int ret = 0;
0438 
0439     if (test_thread_flag(TIF_SYSCALL_TRACE)) {
0440         if (syscall_exit_p)
0441             ptrace_report_syscall_exit(regs, 0);
0442         else
0443             ret = ptrace_report_syscall_entry(regs);
0444     }
0445 
0446     return ret;
0447 }