Commit 6dea1ba1c82013c108d235ec32c6d8bd9ff6b48d

Authored by GuanXuetao
1 parent d9bc15794d

unicore32 additional architecture files: ptrace handling

This patch adds ptrace support.

Changed from previous version:
    1. disable arch_has_single_step and remove single-step instruction handler
    2. add 'Ross Biro 1/23/92' contributor information
    3. clean unused codes

Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
Acked-by: Arnd Bergmann <arnd@arndb.de>

Showing 2 changed files with 282 additions and 0 deletions Side-by-side Diff

arch/unicore32/include/asm/ptrace.h
  1 +/*
  2 + * linux/arch/unicore32/include/asm/ptrace.h
  3 + *
  4 + * Code specific to PKUnity SoC and UniCore ISA
  5 + *
  6 + * Copyright (C) 2001-2010 GUAN Xue-tao
  7 + *
  8 + * This program is free software; you can redistribute it and/or modify
  9 + * it under the terms of the GNU General Public License version 2 as
  10 + * published by the Free Software Foundation.
  11 + */
  12 +#ifndef __UNICORE_PTRACE_H__
  13 +#define __UNICORE_PTRACE_H__
  14 +
  15 +#define PTRACE_GET_THREAD_AREA 22
  16 +
  17 +/*
  18 + * PSR bits
  19 + */
  20 +#define USER_MODE 0x00000010
  21 +#define REAL_MODE 0x00000011
  22 +#define INTR_MODE 0x00000012
  23 +#define PRIV_MODE 0x00000013
  24 +#define ABRT_MODE 0x00000017
  25 +#define EXTN_MODE 0x0000001b
  26 +#define SUSR_MODE 0x0000001f
  27 +#define MODE_MASK 0x0000001f
  28 +#define PSR_R_BIT 0x00000040
  29 +#define PSR_I_BIT 0x00000080
  30 +#define PSR_V_BIT 0x10000000
  31 +#define PSR_C_BIT 0x20000000
  32 +#define PSR_Z_BIT 0x40000000
  33 +#define PSR_S_BIT 0x80000000
  34 +
  35 +/*
  36 + * Groups of PSR bits
  37 + */
  38 +#define PSR_f 0xff000000 /* Flags */
  39 +#define PSR_c 0x000000ff /* Control */
  40 +
  41 +#ifndef __ASSEMBLY__
  42 +
  43 +/*
  44 + * This struct defines the way the registers are stored on the
  45 + * stack during a system call. Note that sizeof(struct pt_regs)
  46 + * has to be a multiple of 8.
  47 + */
  48 +struct pt_regs {
  49 + unsigned long uregs[34];
  50 +};
  51 +
  52 +#define UCreg_asr uregs[32]
  53 +#define UCreg_pc uregs[31]
  54 +#define UCreg_lr uregs[30]
  55 +#define UCreg_sp uregs[29]
  56 +#define UCreg_ip uregs[28]
  57 +#define UCreg_fp uregs[27]
  58 +#define UCreg_26 uregs[26]
  59 +#define UCreg_25 uregs[25]
  60 +#define UCreg_24 uregs[24]
  61 +#define UCreg_23 uregs[23]
  62 +#define UCreg_22 uregs[22]
  63 +#define UCreg_21 uregs[21]
  64 +#define UCreg_20 uregs[20]
  65 +#define UCreg_19 uregs[19]
  66 +#define UCreg_18 uregs[18]
  67 +#define UCreg_17 uregs[17]
  68 +#define UCreg_16 uregs[16]
  69 +#define UCreg_15 uregs[15]
  70 +#define UCreg_14 uregs[14]
  71 +#define UCreg_13 uregs[13]
  72 +#define UCreg_12 uregs[12]
  73 +#define UCreg_11 uregs[11]
  74 +#define UCreg_10 uregs[10]
  75 +#define UCreg_09 uregs[9]
  76 +#define UCreg_08 uregs[8]
  77 +#define UCreg_07 uregs[7]
  78 +#define UCreg_06 uregs[6]
  79 +#define UCreg_05 uregs[5]
  80 +#define UCreg_04 uregs[4]
  81 +#define UCreg_03 uregs[3]
  82 +#define UCreg_02 uregs[2]
  83 +#define UCreg_01 uregs[1]
  84 +#define UCreg_00 uregs[0]
  85 +#define UCreg_ORIG_00 uregs[33]
  86 +
  87 +#ifdef __KERNEL__
  88 +
  89 +#define user_mode(regs) \
  90 + (processor_mode(regs) == USER_MODE)
  91 +
  92 +#define processor_mode(regs) \
  93 + ((regs)->UCreg_asr & MODE_MASK)
  94 +
  95 +#define interrupts_enabled(regs) \
  96 + (!((regs)->UCreg_asr & PSR_I_BIT))
  97 +
  98 +#define fast_interrupts_enabled(regs) \
  99 + (!((regs)->UCreg_asr & PSR_R_BIT))
  100 +
  101 +/* Are the current registers suitable for user mode?
  102 + * (used to maintain security in signal handlers)
  103 + */
  104 +static inline int valid_user_regs(struct pt_regs *regs)
  105 +{
  106 + unsigned long mode = regs->UCreg_asr & MODE_MASK;
  107 +
  108 + /*
  109 + * Always clear the R (REAL) bits
  110 + */
  111 + regs->UCreg_asr &= ~(PSR_R_BIT);
  112 +
  113 + if ((regs->UCreg_asr & PSR_I_BIT) == 0) {
  114 + if (mode == USER_MODE)
  115 + return 1;
  116 + }
  117 +
  118 + /*
  119 + * Force ASR to something logical...
  120 + */
  121 + regs->UCreg_asr &= PSR_f | USER_MODE;
  122 +
  123 + return 0;
  124 +}
  125 +
  126 +#define instruction_pointer(regs) ((regs)->UCreg_pc)
  127 +
  128 +#endif /* __KERNEL__ */
  129 +
  130 +#endif /* __ASSEMBLY__ */
  131 +
  132 +#endif
arch/unicore32/kernel/ptrace.c
  1 +/*
  2 + * linux/arch/unicore32/kernel/ptrace.c
  3 + *
  4 + * Code specific to PKUnity SoC and UniCore ISA
  5 + *
  6 + * Copyright (C) 2001-2010 GUAN Xue-tao
  7 + *
  8 + * By Ross Biro 1/23/92
  9 + *
  10 + * This program is free software; you can redistribute it and/or modify
  11 + * it under the terms of the GNU General Public License version 2 as
  12 + * published by the Free Software Foundation.
  13 + */
  14 +#include <linux/kernel.h>
  15 +#include <linux/ptrace.h>
  16 +#include <linux/signal.h>
  17 +#include <linux/uaccess.h>
  18 +
  19 +/*
  20 + * this routine will get a word off of the processes privileged stack.
  21 + * the offset is how far from the base addr as stored in the THREAD.
  22 + * this routine assumes that all the privileged stacks are in our
  23 + * data space.
  24 + */
  25 +static inline long get_user_reg(struct task_struct *task, int offset)
  26 +{
  27 + return task_pt_regs(task)->uregs[offset];
  28 +}
  29 +
  30 +/*
  31 + * this routine will put a word on the processes privileged stack.
  32 + * the offset is how far from the base addr as stored in the THREAD.
  33 + * this routine assumes that all the privileged stacks are in our
  34 + * data space.
  35 + */
  36 +static inline int
  37 +put_user_reg(struct task_struct *task, int offset, long data)
  38 +{
  39 + struct pt_regs newregs, *regs = task_pt_regs(task);
  40 + int ret = -EINVAL;
  41 +
  42 + newregs = *regs;
  43 + newregs.uregs[offset] = data;
  44 +
  45 + if (valid_user_regs(&newregs)) {
  46 + regs->uregs[offset] = data;
  47 + ret = 0;
  48 + }
  49 +
  50 + return ret;
  51 +}
  52 +
  53 +/*
  54 + * Called by kernel/ptrace.c when detaching..
  55 + */
  56 +void ptrace_disable(struct task_struct *child)
  57 +{
  58 +}
  59 +
  60 +/*
  61 + * We actually access the pt_regs stored on the kernel stack.
  62 + */
  63 +static int ptrace_read_user(struct task_struct *tsk, unsigned long off,
  64 + unsigned long __user *ret)
  65 +{
  66 + unsigned long tmp;
  67 +
  68 + tmp = 0;
  69 + if (off < sizeof(struct pt_regs))
  70 + tmp = get_user_reg(tsk, off >> 2);
  71 +
  72 + return put_user(tmp, ret);
  73 +}
  74 +
  75 +/*
  76 + * We actually access the pt_regs stored on the kernel stack.
  77 + */
  78 +static int ptrace_write_user(struct task_struct *tsk, unsigned long off,
  79 + unsigned long val)
  80 +{
  81 + if (off >= sizeof(struct pt_regs))
  82 + return 0;
  83 +
  84 + return put_user_reg(tsk, off >> 2, val);
  85 +}
  86 +
  87 +long arch_ptrace(struct task_struct *child, long request,
  88 + unsigned long addr, unsigned long data)
  89 +{
  90 + int ret;
  91 + unsigned long __user *datap = (unsigned long __user *) data;
  92 +
  93 + switch (request) {
  94 + case PTRACE_PEEKUSR:
  95 + ret = ptrace_read_user(child, addr, datap);
  96 + break;
  97 +
  98 + case PTRACE_POKEUSR:
  99 + ret = ptrace_write_user(child, addr, data);
  100 + break;
  101 +
  102 + case PTRACE_GET_THREAD_AREA:
  103 + ret = put_user(task_pt_regs(child)->UCreg_16,
  104 + datap);
  105 + break;
  106 +
  107 + default:
  108 + ret = ptrace_request(child, request, addr, data);
  109 + break;
  110 + }
  111 +
  112 + return ret;
  113 +}
  114 +
  115 +asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
  116 +{
  117 + unsigned long ip;
  118 +
  119 + if (!test_thread_flag(TIF_SYSCALL_TRACE))
  120 + return scno;
  121 + if (!(current->ptrace & PT_PTRACED))
  122 + return scno;
  123 +
  124 + /*
  125 + * Save IP. IP is used to denote syscall entry/exit:
  126 + * IP = 0 -> entry, = 1 -> exit
  127 + */
  128 + ip = regs->UCreg_ip;
  129 + regs->UCreg_ip = why;
  130 +
  131 + current_thread_info()->syscall = scno;
  132 +
  133 + /* the 0x80 provides a way for the tracing parent to distinguish
  134 + between a syscall stop and SIGTRAP delivery */
  135 + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
  136 + ? 0x80 : 0));
  137 + /*
  138 + * this isn't the same as continuing with a signal, but it will do
  139 + * for normal use. strace only continues with a signal if the
  140 + * stopping signal is not SIGTRAP. -brl
  141 + */
  142 + if (current->exit_code) {
  143 + send_sig(current->exit_code, current, 1);
  144 + current->exit_code = 0;
  145 + }
  146 + regs->UCreg_ip = ip;
  147 +
  148 + return current_thread_info()->syscall;
  149 +}