Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+282
+133
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 133 +
+149
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 + }