Root/target/linux/ubicom32/files/arch/ubicom32/kernel/ptrace.c

1/*
2 * arch/ubicom32/kernel/ptrace.c
3 * Ubicom32 architecture ptrace implementation.
4 *
5 * (C) Copyright 2009, Ubicom, Inc.
6 * (C) 1994 by Hamish Macdonald
7 * Taken from linux/kernel/ptrace.c and modified for M680x0.
8 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
9 *
10 * This file is part of the Ubicom32 Linux Kernel Port.
11 *
12 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
13 * it and/or modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
18 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
19 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
20 * the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with the Ubicom32 Linux Kernel Port. If not,
24 * see <http://www.gnu.org/licenses/>.
25 *
26 * Ubicom32 implementation derived from (with many thanks):
27 * arch/m68knommu
28 * arch/blackfin
29 * arch/parisc
30 */
31
32#include <linux/module.h>
33#include <linux/kernel.h>
34#include <linux/sched.h>
35#include <linux/mm.h>
36#include <linux/smp.h>
37#include <linux/errno.h>
38#include <linux/ptrace.h>
39#include <linux/user.h>
40#include <linux/signal.h>
41#include <linux/uaccess.h>
42
43#include <asm/page.h>
44#include <asm/pgtable.h>
45#include <asm/system.h>
46#include <asm/cacheflush.h>
47#include <asm/processor.h>
48
49/*
50 * ptrace_getregs()
51 *
52 * Get all user integer registers.
53 */
54static inline int ptrace_getregs(struct task_struct *task, void __user *uregs)
55{
56    struct pt_regs *regs = task_pt_regs(task);
57    return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
58}
59
60/*
61 * ptrace_get_reg()
62 *
63 * Get contents of register REGNO in task TASK.
64 */
65static unsigned long ptrace_get_reg(struct task_struct *task, int regno)
66{
67    if (regno < sizeof(struct pt_regs)) {
68        struct pt_regs *pt_regs = task_pt_regs(task);
69        return *(unsigned long *)((long) pt_regs + regno);
70    }
71
72    return -EIO;
73}
74
75/*
76 * ptrace_put_reg()
77 * Write contents of register REGNO in task TASK.
78 */
79static int ptrace_put_reg(struct task_struct *task, int regno,
80              unsigned long data)
81{
82    if (regno <= sizeof(struct pt_regs) && regno != PT_FRAME_TYPE) {
83        struct pt_regs *pt_regs = task_pt_regs(task);
84        *(unsigned long *)((long) pt_regs + regno) = data;
85        return 0;
86    }
87    return -EIO;
88}
89
90/*
91 * ptrace_disable_single_step()
92 * Disable Single Step
93 */
94static int ptrace_disable_single_step(struct task_struct *task)
95{
96    /*
97     * Single Step not yet implemented, so must always be disabled
98     */
99    return 0;
100}
101
102/*
103 * ptrace_disable()
104 * Make sure the single step bit is not set.
105 * Called by kernel/ptrace.c when detaching..
106 */
107void ptrace_disable(struct task_struct *child)
108{
109    ptrace_disable_single_step(child);
110}
111
112/*
113 * arch_ptrace()
114 * architecture specific ptrace routine.
115 */
116long arch_ptrace(struct task_struct *child, long request, long addr, long data)
117{
118    int ret;
119    switch (request) {
120    /* when I and D space are separate, these will need to be fixed. */
121    case PTRACE_PEEKTEXT: /* read word at location addr. */
122    case PTRACE_PEEKDATA:
123        ret = generic_ptrace_peekdata(child, addr, data);
124        break;
125
126    /* read the word at location addr in the USER area. */
127    case PTRACE_PEEKUSR: {
128        unsigned long tmp;
129
130        ret = -EIO;
131        if (((unsigned long) addr > PT_INTERP_FDPIC_LOADMAP)
132            || (addr & 3))
133            break;
134
135        tmp = 0; /* Default return condition */
136
137        ret = -EIO;
138        if (addr < sizeof(struct pt_regs)) {
139            tmp = ptrace_get_reg(child, addr);
140        } else if (addr == PT_TEXT_ADDR) {
141            tmp = child->mm->start_code;
142        } else if (addr == PT_TEXT_END_ADDR) {
143            tmp = child->mm->end_code;
144        } else if (addr == PT_DATA_ADDR) {
145            tmp = child->mm->start_data;
146        } else if (addr == PT_EXEC_FDPIC_LOADMAP) {
147#ifdef CONFIG_BINFMT_ELF_FDPIC
148            tmp = child->mm->context.exec_fdpic_loadmap;
149#endif
150        } else if (addr == PT_INTERP_FDPIC_LOADMAP) {
151#ifdef CONFIG_BINFMT_ELF_FDPIC
152            tmp = child->mm->context.interp_fdpic_loadmap;
153#endif
154        } else {
155            break;
156        }
157
158        ret = put_user(tmp, (unsigned long *)data);
159        break;
160    }
161
162    case PTRACE_POKETEXT: /* write the word at location addr. */
163    case PTRACE_POKEDATA:
164        ret = generic_ptrace_pokedata(child, addr, data);
165
166        /*
167         * If we just changed some code so we need to
168         * correct the caches
169         */
170        if (request == PTRACE_POKETEXT && ret == 0) {
171            flush_icache_range(addr, addr + 4);
172        }
173        break;
174
175    case PTRACE_POKEUSR: /* write the word at location addr
176                  * in the USER area */
177        ret = -EIO;
178
179        if (((unsigned long) addr > PT_DATA_ADDR) || (addr & 3))
180            break;
181
182        if (addr < sizeof(struct pt_regs)) {
183            ret = ptrace_put_reg(child, addr, data);
184        }
185        break;
186
187    case PTRACE_SYSCALL: /* continue and stop at next (return from)
188                  * syscall */
189    case PTRACE_CONT: { /* restart after signal. */
190
191        ret = -EIO;
192        if (!valid_signal(data))
193            break;
194        if (request == PTRACE_SYSCALL)
195            set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
196        else
197            clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
198        child->exit_code = data;
199        /* make sure the single step bit is not set. */
200        ptrace_disable_single_step(child);
201        wake_up_process(child);
202        ret = 0;
203        break;
204    }
205
206    /*
207     * make the child exit. Best I can do is send it a sigkill.
208     * perhaps it should be put in the status that it wants to exit.
209     */
210    case PTRACE_KILL: {
211        ret = 0;
212        if (child->exit_state == EXIT_ZOMBIE) /* already dead */
213            break;
214        child->exit_code = SIGKILL;
215        /* make sure the single step bit is not set. */
216        ptrace_disable_single_step(child);
217        wake_up_process(child);
218        break;
219    }
220
221    case PTRACE_DETACH: /* detach a process that was attached. */
222        ret = ptrace_detach(child, data);
223        break;
224
225    case PTRACE_GETREGS: /* Get all gp regs from the child. */
226        ptrace_getregs(child, (unsigned long *)data);
227        ret = 0;
228        break;
229
230    case PTRACE_SETREGS: { /* Set all gp regs in the child. */
231        int i;
232        unsigned long tmp;
233        int count = sizeof(struct pt_regs) / sizeof(unsigned long);
234        for (i = 0; i < count; i++) {
235            if (get_user(tmp, (unsigned long *) data)) {
236                ret = -EFAULT;
237                break;
238            }
239            ptrace_put_reg(child, sizeof(unsigned long) * i, tmp);
240            data += sizeof(long);
241        }
242        ret = 0;
243        break;
244    }
245
246    default:
247        return ptrace_request(child, request, addr, data);
248        break;
249    }
250    return ret;
251}
252/*
253 * syscall_trace
254 *
255 * called by syscall enter/exit when the TIF_SYSCALL_TRACE bit is set.
256 */
257asmlinkage void syscall_trace(void)
258{
259    struct task_struct *cur = current;
260    if (!test_thread_flag(TIF_SYSCALL_TRACE))
261        return;
262    if (!(cur->ptrace & PT_PTRACED))
263        return;
264    ptrace_notify(SIGTRAP | ((cur->ptrace & PT_TRACESYSGOOD)
265                 ? 0x80 : 0));
266    /*
267     * this isn't the same as continuing with a signal, but it will do
268     * for normal use. strace only continues with a signal if the
269     * stopping signal is not SIGTRAP. -brl
270     */
271    if (cur->exit_code) {
272        send_sig(cur->exit_code, current, 1);
273        current->exit_code = 0;
274    }
275}
276

Archive Download this file



interactive