~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/sh/kernel/ptrace.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /arch/sh/kernel/ptrace.c (Architecture ppc) and /arch/alpha/kernel/ptrace.c (Architecture alpha)


  1 // SPDX-License-Identifier: GPL-2.0                 1 // SPDX-License-Identifier: GPL-2.0
                                                   >>   2 /* ptrace.c */
                                                   >>   3 /* By Ross Biro 1/23/92 */
                                                   >>   4 /* edited by Linus Torvalds */
                                                   >>   5 /* mangled further by Bob Manson (manson@santafe.edu) */
                                                   >>   6 /* more mutilation by David Mosberger (davidm@azstarnet.com) */
                                                   >>   7 
                                                   >>   8 #include <linux/kernel.h>
                                                   >>   9 #include <linux/sched.h>
                                                   >>  10 #include <linux/sched/task_stack.h>
                                                   >>  11 #include <linux/mm.h>
                                                   >>  12 #include <linux/smp.h>
                                                   >>  13 #include <linux/errno.h>
  2 #include <linux/ptrace.h>                          14 #include <linux/ptrace.h>
                                                   >>  15 #include <linux/user.h>
                                                   >>  16 #include <linux/security.h>
                                                   >>  17 #include <linux/signal.h>
                                                   >>  18 #include <linux/audit.h>
                                                   >>  19 
                                                   >>  20 #include <linux/uaccess.h>
                                                   >>  21 #include <asm/fpu.h>
                                                   >>  22 
                                                   >>  23 #include "proto.h"
                                                   >>  24 
                                                   >>  25 #define DEBUG   DBG_MEM
                                                   >>  26 #undef DEBUG
                                                   >>  27 
                                                   >>  28 #ifdef DEBUG
                                                   >>  29 enum {
                                                   >>  30         DBG_MEM         = (1<<0),
                                                   >>  31         DBG_BPT         = (1<<1),
                                                   >>  32         DBG_MEM_ALL     = (1<<2)
                                                   >>  33 };
                                                   >>  34 #define DBG(fac,args)   {if ((fac) & DEBUG) printk args;}
                                                   >>  35 #else
                                                   >>  36 #define DBG(fac,args)
                                                   >>  37 #endif
                                                   >>  38 
                                                   >>  39 #define BREAKINST       0x00000080      /* call_pal bpt */
                                                   >>  40 
                                                   >>  41 /*
                                                   >>  42  * does not yet catch signals sent when the child dies.
                                                   >>  43  * in exit.c or in signal.c.
                                                   >>  44  */
  3                                                    45 
  4 /**                                            !!  46 /*
  5  * regs_query_register_offset() - query regist !!  47  * Processes always block with the following stack-layout:
  6  * @name:       the name of a register         << 
  7  *                                                 48  *
  8  * regs_query_register_offset() returns the of !!  49  *  +================================+ <---- task + 2*PAGE_SIZE
  9  * pt_regs from its name. If the name is inval !!  50  *  | PALcode saved frame (ps, pc,   | ^
                                                   >>  51  *  | gp, a0, a1, a2)                | |
                                                   >>  52  *  +================================+ | struct pt_regs
                                                   >>  53  *  |                                | |
                                                   >>  54  *  | frame generated by SAVE_ALL    | |
                                                   >>  55  *  |                                | v
                                                   >>  56  *  +================================+
                                                   >>  57  *  |                                | ^
                                                   >>  58  *  | frame saved by do_switch_stack | | struct switch_stack
                                                   >>  59  *  |                                | v
                                                   >>  60  *  +================================+
                                                   >>  61  */
                                                   >>  62 
                                                   >>  63 /* 
                                                   >>  64  * The following table maps a register index into the stack offset at
                                                   >>  65  * which the register is saved.  Register indices are 0-31 for integer
                                                   >>  66  * regs, 32-63 for fp regs, and 64 for the pc.  Notice that sp and
                                                   >>  67  * zero have no stack-slot and need to be treated specially (see
                                                   >>  68  * get_reg/put_reg below).
                                                   >>  69  */
                                                   >>  70 enum {
                                                   >>  71         REG_R0 = 0, REG_F0 = 32, REG_FPCR = 63, REG_PC = 64
                                                   >>  72 };
                                                   >>  73 
                                                   >>  74 #define PT_REG(reg) \
                                                   >>  75   (PAGE_SIZE*2 - sizeof(struct pt_regs) + offsetof(struct pt_regs, reg))
                                                   >>  76 
                                                   >>  77 #define SW_REG(reg) \
                                                   >>  78  (PAGE_SIZE*2 - sizeof(struct pt_regs) - sizeof(struct switch_stack) \
                                                   >>  79   + offsetof(struct switch_stack, reg))
                                                   >>  80 
                                                   >>  81 #define FP_REG(reg) (offsetof(struct thread_info, reg))
                                                   >>  82 
                                                   >>  83 static int regoff[] = {
                                                   >>  84         PT_REG(    r0), PT_REG(    r1), PT_REG(    r2), PT_REG(   r3),
                                                   >>  85         PT_REG(    r4), PT_REG(    r5), PT_REG(    r6), PT_REG(   r7),
                                                   >>  86         PT_REG(    r8), SW_REG(    r9), SW_REG(   r10), SW_REG(  r11),
                                                   >>  87         SW_REG(   r12), SW_REG(   r13), SW_REG(   r14), SW_REG(  r15),
                                                   >>  88         PT_REG(   r16), PT_REG(   r17), PT_REG(   r18), PT_REG(  r19),
                                                   >>  89         PT_REG(   r20), PT_REG(   r21), PT_REG(   r22), PT_REG(  r23),
                                                   >>  90         PT_REG(   r24), PT_REG(   r25), PT_REG(   r26), PT_REG(  r27),
                                                   >>  91         PT_REG(   r28), PT_REG(    gp),            -1,             -1,
                                                   >>  92         FP_REG(fp[ 0]), FP_REG(fp[ 1]), FP_REG(fp[ 2]), FP_REG(fp[ 3]),
                                                   >>  93         FP_REG(fp[ 4]), FP_REG(fp[ 5]), FP_REG(fp[ 6]), FP_REG(fp[ 7]),
                                                   >>  94         FP_REG(fp[ 8]), FP_REG(fp[ 9]), FP_REG(fp[10]), FP_REG(fp[11]),
                                                   >>  95         FP_REG(fp[12]), FP_REG(fp[13]), FP_REG(fp[14]), FP_REG(fp[15]),
                                                   >>  96         FP_REG(fp[16]), FP_REG(fp[17]), FP_REG(fp[18]), FP_REG(fp[19]),
                                                   >>  97         FP_REG(fp[20]), FP_REG(fp[21]), FP_REG(fp[22]), FP_REG(fp[23]),
                                                   >>  98         FP_REG(fp[24]), FP_REG(fp[25]), FP_REG(fp[26]), FP_REG(fp[27]),
                                                   >>  99         FP_REG(fp[28]), FP_REG(fp[29]), FP_REG(fp[30]), FP_REG(fp[31]),
                                                   >> 100         PT_REG(    pc)
                                                   >> 101 };
                                                   >> 102 
                                                   >> 103 static unsigned long zero;
                                                   >> 104 
                                                   >> 105 /*
                                                   >> 106  * Get address of register REGNO in task TASK.
                                                   >> 107  */
                                                   >> 108 static unsigned long *
                                                   >> 109 get_reg_addr(struct task_struct * task, unsigned long regno)
                                                   >> 110 {
                                                   >> 111         unsigned long *addr;
                                                   >> 112 
                                                   >> 113         if (regno == 30) {
                                                   >> 114                 addr = &task_thread_info(task)->pcb.usp;
                                                   >> 115         } else if (regno == 65) {
                                                   >> 116                 addr = &task_thread_info(task)->pcb.unique;
                                                   >> 117         } else if (regno == 31 || regno > 65) {
                                                   >> 118                 zero = 0;
                                                   >> 119                 addr = &zero;
                                                   >> 120         } else {
                                                   >> 121                 addr = task_stack_page(task) + regoff[regno];
                                                   >> 122         }
                                                   >> 123         return addr;
                                                   >> 124 }
                                                   >> 125 
                                                   >> 126 /*
                                                   >> 127  * Get contents of register REGNO in task TASK.
                                                   >> 128  */
                                                   >> 129 static unsigned long
                                                   >> 130 get_reg(struct task_struct * task, unsigned long regno)
                                                   >> 131 {
                                                   >> 132         /* Special hack for fpcr -- combine hardware and software bits.  */
                                                   >> 133         if (regno == 63) {
                                                   >> 134                 unsigned long fpcr = *get_reg_addr(task, regno);
                                                   >> 135                 unsigned long swcr
                                                   >> 136                   = task_thread_info(task)->ieee_state & IEEE_SW_MASK;
                                                   >> 137                 swcr = swcr_update_status(swcr, fpcr);
                                                   >> 138                 return fpcr | swcr;
                                                   >> 139         }
                                                   >> 140         return *get_reg_addr(task, regno);
                                                   >> 141 }
                                                   >> 142 
                                                   >> 143 /*
                                                   >> 144  * Write contents of register REGNO in task TASK.
                                                   >> 145  */
                                                   >> 146 static int
                                                   >> 147 put_reg(struct task_struct *task, unsigned long regno, unsigned long data)
                                                   >> 148 {
                                                   >> 149         if (regno == 63) {
                                                   >> 150                 task_thread_info(task)->ieee_state
                                                   >> 151                   = ((task_thread_info(task)->ieee_state & ~IEEE_SW_MASK)
                                                   >> 152                      | (data & IEEE_SW_MASK));
                                                   >> 153                 data = (data & FPCR_DYN_MASK) | ieee_swcr_to_fpcr(data);
                                                   >> 154         }
                                                   >> 155         *get_reg_addr(task, regno) = data;
                                                   >> 156         return 0;
                                                   >> 157 }
                                                   >> 158 
                                                   >> 159 static inline int
                                                   >> 160 read_int(struct task_struct *task, unsigned long addr, int * data)
                                                   >> 161 {
                                                   >> 162         int copied = access_process_vm(task, addr, data, sizeof(int),
                                                   >> 163                         FOLL_FORCE);
                                                   >> 164         return (copied == sizeof(int)) ? 0 : -EIO;
                                                   >> 165 }
                                                   >> 166 
                                                   >> 167 static inline int
                                                   >> 168 write_int(struct task_struct *task, unsigned long addr, int data)
                                                   >> 169 {
                                                   >> 170         int copied = access_process_vm(task, addr, &data, sizeof(int),
                                                   >> 171                         FOLL_FORCE | FOLL_WRITE);
                                                   >> 172         return (copied == sizeof(int)) ? 0 : -EIO;
                                                   >> 173 }
                                                   >> 174 
                                                   >> 175 /*
                                                   >> 176  * Set breakpoint.
                                                   >> 177  */
                                                   >> 178 int
                                                   >> 179 ptrace_set_bpt(struct task_struct * child)
                                                   >> 180 {
                                                   >> 181         int displ, i, res, reg_b, nsaved = 0;
                                                   >> 182         unsigned int insn, op_code;
                                                   >> 183         unsigned long pc;
                                                   >> 184 
                                                   >> 185         pc  = get_reg(child, REG_PC);
                                                   >> 186         res = read_int(child, pc, (int *) &insn);
                                                   >> 187         if (res < 0)
                                                   >> 188                 return res;
                                                   >> 189 
                                                   >> 190         op_code = insn >> 26;
                                                   >> 191         if (op_code >= 0x30) {
                                                   >> 192                 /*
                                                   >> 193                  * It's a branch: instead of trying to figure out
                                                   >> 194                  * whether the branch will be taken or not, we'll put
                                                   >> 195                  * a breakpoint at either location.  This is simpler,
                                                   >> 196                  * more reliable, and probably not a whole lot slower
                                                   >> 197                  * than the alternative approach of emulating the
                                                   >> 198                  * branch (emulation can be tricky for fp branches).
                                                   >> 199                  */
                                                   >> 200                 displ = ((s32)(insn << 11)) >> 9;
                                                   >> 201                 task_thread_info(child)->bpt_addr[nsaved++] = pc + 4;
                                                   >> 202                 if (displ)              /* guard against unoptimized code */
                                                   >> 203                         task_thread_info(child)->bpt_addr[nsaved++]
                                                   >> 204                           = pc + 4 + displ;
                                                   >> 205                 DBG(DBG_BPT, ("execing branch\n"));
                                                   >> 206         } else if (op_code == 0x1a) {
                                                   >> 207                 reg_b = (insn >> 16) & 0x1f;
                                                   >> 208                 task_thread_info(child)->bpt_addr[nsaved++] = get_reg(child, reg_b);
                                                   >> 209                 DBG(DBG_BPT, ("execing jump\n"));
                                                   >> 210         } else {
                                                   >> 211                 task_thread_info(child)->bpt_addr[nsaved++] = pc + 4;
                                                   >> 212                 DBG(DBG_BPT, ("execing normal insn\n"));
                                                   >> 213         }
                                                   >> 214 
                                                   >> 215         /* install breakpoints: */
                                                   >> 216         for (i = 0; i < nsaved; ++i) {
                                                   >> 217                 res = read_int(child, task_thread_info(child)->bpt_addr[i],
                                                   >> 218                                (int *) &insn);
                                                   >> 219                 if (res < 0)
                                                   >> 220                         return res;
                                                   >> 221                 task_thread_info(child)->bpt_insn[i] = insn;
                                                   >> 222                 DBG(DBG_BPT, ("    -> next_pc=%lx\n",
                                                   >> 223                               task_thread_info(child)->bpt_addr[i]));
                                                   >> 224                 res = write_int(child, task_thread_info(child)->bpt_addr[i],
                                                   >> 225                                 BREAKINST);
                                                   >> 226                 if (res < 0)
                                                   >> 227                         return res;
                                                   >> 228         }
                                                   >> 229         task_thread_info(child)->bpt_nsaved = nsaved;
                                                   >> 230         return 0;
                                                   >> 231 }
                                                   >> 232 
                                                   >> 233 /*
                                                   >> 234  * Ensure no single-step breakpoint is pending.  Returns non-zero
                                                   >> 235  * value if child was being single-stepped.
 10  */                                               236  */
 11 int regs_query_register_offset(const char *nam !! 237 int
                                                   >> 238 ptrace_cancel_bpt(struct task_struct * child)
                                                   >> 239 {
                                                   >> 240         int i, nsaved = task_thread_info(child)->bpt_nsaved;
                                                   >> 241 
                                                   >> 242         task_thread_info(child)->bpt_nsaved = 0;
                                                   >> 243 
                                                   >> 244         if (nsaved > 2) {
                                                   >> 245                 printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
                                                   >> 246                 nsaved = 2;
                                                   >> 247         }
                                                   >> 248 
                                                   >> 249         for (i = 0; i < nsaved; ++i) {
                                                   >> 250                 write_int(child, task_thread_info(child)->bpt_addr[i],
                                                   >> 251                           task_thread_info(child)->bpt_insn[i]);
                                                   >> 252         }
                                                   >> 253         return (nsaved != 0);
                                                   >> 254 }
                                                   >> 255 
                                                   >> 256 void user_enable_single_step(struct task_struct *child)
                                                   >> 257 {
                                                   >> 258         /* Mark single stepping.  */
                                                   >> 259         task_thread_info(child)->bpt_nsaved = -1;
                                                   >> 260 }
                                                   >> 261 
                                                   >> 262 void user_disable_single_step(struct task_struct *child)
 12 {                                                 263 {
 13         const struct pt_regs_offset *roff;     !! 264         ptrace_cancel_bpt(child);
 14         for (roff = regoffset_table; roff->nam << 
 15                 if (!strcmp(roff->name, name)) << 
 16                         return roff->offset;   << 
 17         return -EINVAL;                        << 
 18 }                                                 265 }
 19                                                   266 
 20 /**                                            !! 267 /*
 21  * regs_query_register_name() - query register !! 268  * Called by kernel/ptrace.c when detaching..
 22  * @offset:     the offset of a register in st << 
 23  *                                                269  *
 24  * regs_query_register_name() returns the name !! 270  * Make sure the single step bit is not set.
 25  * offset in struct pt_regs. If the @offset is << 
 26  */                                               271  */
 27 const char *regs_query_register_name(unsigned  !! 272 void ptrace_disable(struct task_struct *child)
                                                   >> 273 { 
                                                   >> 274         user_disable_single_step(child);
                                                   >> 275 }
                                                   >> 276 
                                                   >> 277 long arch_ptrace(struct task_struct *child, long request,
                                                   >> 278                  unsigned long addr, unsigned long data)
                                                   >> 279 {
                                                   >> 280         unsigned long tmp;
                                                   >> 281         size_t copied;
                                                   >> 282         long ret;
                                                   >> 283 
                                                   >> 284         switch (request) {
                                                   >> 285         /* When I and D space are separate, these will need to be fixed.  */
                                                   >> 286         case PTRACE_PEEKTEXT: /* read word at location addr. */
                                                   >> 287         case PTRACE_PEEKDATA:
                                                   >> 288                 copied = ptrace_access_vm(child, addr, &tmp, sizeof(tmp),
                                                   >> 289                                 FOLL_FORCE);
                                                   >> 290                 ret = -EIO;
                                                   >> 291                 if (copied != sizeof(tmp))
                                                   >> 292                         break;
                                                   >> 293                 
                                                   >> 294                 force_successful_syscall_return();
                                                   >> 295                 ret = tmp;
                                                   >> 296                 break;
                                                   >> 297 
                                                   >> 298         /* Read register number ADDR. */
                                                   >> 299         case PTRACE_PEEKUSR:
                                                   >> 300                 force_successful_syscall_return();
                                                   >> 301                 ret = get_reg(child, addr);
                                                   >> 302                 DBG(DBG_MEM, ("peek $%lu->%#lx\n", addr, ret));
                                                   >> 303                 break;
                                                   >> 304 
                                                   >> 305         /* When I and D space are separate, this will have to be fixed.  */
                                                   >> 306         case PTRACE_POKETEXT: /* write the word at location addr. */
                                                   >> 307         case PTRACE_POKEDATA:
                                                   >> 308                 ret = generic_ptrace_pokedata(child, addr, data);
                                                   >> 309                 break;
                                                   >> 310 
                                                   >> 311         case PTRACE_POKEUSR: /* write the specified register */
                                                   >> 312                 DBG(DBG_MEM, ("poke $%lu<-%#lx\n", addr, data));
                                                   >> 313                 ret = put_reg(child, addr, data);
                                                   >> 314                 break;
                                                   >> 315         default:
                                                   >> 316                 ret = ptrace_request(child, request, addr, data);
                                                   >> 317                 break;
                                                   >> 318         }
                                                   >> 319         return ret;
                                                   >> 320 }
                                                   >> 321 
                                                   >> 322 asmlinkage unsigned long syscall_trace_enter(void)
                                                   >> 323 {
                                                   >> 324         unsigned long ret = 0;
                                                   >> 325         struct pt_regs *regs = current_pt_regs();
                                                   >> 326         if (test_thread_flag(TIF_SYSCALL_TRACE) &&
                                                   >> 327             ptrace_report_syscall_entry(current_pt_regs()))
                                                   >> 328                 ret = -1UL;
                                                   >> 329         audit_syscall_entry(regs->r0, regs->r16, regs->r17, regs->r18, regs->r19);
                                                   >> 330         return ret ?: current_pt_regs()->r0;
                                                   >> 331 }
                                                   >> 332 
                                                   >> 333 asmlinkage void
                                                   >> 334 syscall_trace_leave(void)
 28 {                                                 335 {
 29         const struct pt_regs_offset *roff;     !! 336         audit_syscall_exit(current_pt_regs());
 30         for (roff = regoffset_table; roff->nam !! 337         if (test_thread_flag(TIF_SYSCALL_TRACE))
 31                 if (roff->offset == offset)    !! 338                 ptrace_report_syscall_exit(current_pt_regs(), 0);
 32                         return roff->name;     << 
 33         return NULL;                           << 
 34 }                                                 339 }
 35                                                   340 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php