root/arch/microblaze/kernel/ptrace.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. reg_save_addr
  2. arch_ptrace
  3. do_syscall_trace_enter
  4. do_syscall_trace_leave
  5. ptrace_disable

   1 /*
   2  * `ptrace' system call
   3  *
   4  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
   5  * Copyright (C) 2007-2009 PetaLogix
   6  * Copyright (C) 2004-2007 John Williams <john.williams@petalogix.com>
   7  *
   8  * derived from arch/v850/kernel/ptrace.c
   9  *
  10  * Copyright (C) 2002,03 NEC Electronics Corporation
  11  * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
  12  *
  13  * Derived from arch/mips/kernel/ptrace.c:
  14  *
  15  * Copyright (C) 1992 Ross Biro
  16  * Copyright (C) Linus Torvalds
  17  * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
  18  * Copyright (C) 1996 David S. Miller
  19  * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
  20  * Copyright (C) 1999 MIPS Technologies, Inc.
  21  *
  22  * This file is subject to the terms and conditions of the GNU General
  23  * Public License. See the file COPYING in the main directory of this
  24  * archive for more details.
  25  */
  26 
  27 #include <linux/kernel.h>
  28 #include <linux/mm.h>
  29 #include <linux/sched.h>
  30 #include <linux/sched/task_stack.h>
  31 #include <linux/ptrace.h>
  32 #include <linux/signal.h>
  33 #include <linux/elf.h>
  34 #include <linux/audit.h>
  35 #include <linux/seccomp.h>
  36 #include <linux/tracehook.h>
  37 
  38 #include <linux/errno.h>
  39 #include <asm/processor.h>
  40 #include <linux/uaccess.h>
  41 #include <asm/asm-offsets.h>
  42 #include <asm/cacheflush.h>
  43 #include <asm/syscall.h>
  44 #include <linux/io.h>
  45 
  46 /* Returns the address where the register at REG_OFFS in P is stashed away. */
  47 static microblaze_reg_t *reg_save_addr(unsigned reg_offs,
  48                                         struct task_struct *t)
  49 {
  50         struct pt_regs *regs;
  51 
  52         /*
  53          * Three basic cases:
  54          *
  55          * (1)  A register normally saved before calling the scheduler, is
  56          *      available in the kernel entry pt_regs structure at the top
  57          *      of the kernel stack. The kernel trap/irq exit path takes
  58          *      care to save/restore almost all registers for ptrace'd
  59          *      processes.
  60          *
  61          * (2)  A call-clobbered register, where the process P entered the
  62          *      kernel via [syscall] trap, is not stored anywhere; that's
  63          *      OK, because such registers are not expected to be preserved
  64          *      when the trap returns anyway (so we don't actually bother to
  65          *      test for this case).
  66          *
  67          * (3)  A few registers not used at all by the kernel, and so
  68          *      normally never saved except by context-switches, are in the
  69          *      context switch state.
  70          */
  71 
  72         /* Register saved during kernel entry (or not available). */
  73         regs = task_pt_regs(t);
  74 
  75         return (microblaze_reg_t *)((char *)regs + reg_offs);
  76 }
  77 
  78 long arch_ptrace(struct task_struct *child, long request,
  79                  unsigned long addr, unsigned long data)
  80 {
  81         int rval;
  82         unsigned long val = 0;
  83 
  84         switch (request) {
  85         /* Read/write the word at location ADDR in the registers. */
  86         case PTRACE_PEEKUSR:
  87         case PTRACE_POKEUSR:
  88                 pr_debug("PEEKUSR/POKEUSR : 0x%08lx\n", addr);
  89                 rval = 0;
  90                 if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) {
  91                         /*
  92                          * Special requests that don't actually correspond
  93                          * to offsets in struct pt_regs.
  94                          */
  95                         if (addr == PT_TEXT_ADDR) {
  96                                 val = child->mm->start_code;
  97                         } else if (addr == PT_DATA_ADDR) {
  98                                 val = child->mm->start_data;
  99                         } else if (addr == PT_TEXT_LEN) {
 100                                 val = child->mm->end_code
 101                                         - child->mm->start_code;
 102                         } else {
 103                                 rval = -EIO;
 104                         }
 105                 } else if (addr < PT_SIZE && (addr & 0x3) == 0) {
 106                         microblaze_reg_t *reg_addr = reg_save_addr(addr, child);
 107                         if (request == PTRACE_PEEKUSR)
 108                                 val = *reg_addr;
 109                         else {
 110 #if 1
 111                                 *reg_addr = data;
 112 #else
 113                                 /* MS potential problem on WB system
 114                                  * Be aware that reg_addr is virtual address
 115                                  * virt_to_phys conversion is necessary.
 116                                  * This could be sensible solution.
 117                                  */
 118                                 u32 paddr = virt_to_phys((u32)reg_addr);
 119                                 invalidate_icache_range(paddr, paddr + 4);
 120                                 *reg_addr = data;
 121                                 flush_dcache_range(paddr, paddr + 4);
 122 #endif
 123                         }
 124                 } else
 125                         rval = -EIO;
 126 
 127                 if (rval == 0 && request == PTRACE_PEEKUSR)
 128                         rval = put_user(val, (unsigned long __user *)data);
 129                 break;
 130         default:
 131                 rval = ptrace_request(child, request, addr, data);
 132         }
 133         return rval;
 134 }
 135 
 136 asmlinkage unsigned long do_syscall_trace_enter(struct pt_regs *regs)
 137 {
 138         unsigned long ret = 0;
 139 
 140         secure_computing_strict(regs->r12);
 141 
 142         if (test_thread_flag(TIF_SYSCALL_TRACE) &&
 143             tracehook_report_syscall_entry(regs))
 144                 /*
 145                  * Tracing decided this syscall should not happen.
 146                  * We'll return a bogus call number to get an ENOSYS
 147                  * error, but leave the original number in regs->regs[0].
 148                  */
 149                 ret = -1L;
 150 
 151         audit_syscall_entry(regs->r12, regs->r5, regs->r6, regs->r7, regs->r8);
 152 
 153         return ret ?: regs->r12;
 154 }
 155 
 156 asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
 157 {
 158         int step;
 159 
 160         audit_syscall_exit(regs);
 161 
 162         step = test_thread_flag(TIF_SINGLESTEP);
 163         if (step || test_thread_flag(TIF_SYSCALL_TRACE))
 164                 tracehook_report_syscall_exit(regs, step);
 165 }
 166 
 167 void ptrace_disable(struct task_struct *child)
 168 {
 169         /* nothing to do */
 170 }

/* [<][>][^][v][top][bottom][index][help] */