Commit 6dea1ba1c82013c108d235ec32c6d8bd9ff6b48d
1 parent
d9bc15794d
Exists in
master
and in
7 other branches
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 | +} |