1 /* MN10300 Process tracing
3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 * Modified by David Howells (dhowells@redhat.com)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
15 #include <linux/smp.h>
16 #include <linux/errno.h>
17 #include <linux/ptrace.h>
18 #include <linux/user.h>
19 #include <linux/regset.h>
20 #include <linux/elf.h>
21 #include <linux/tracehook.h>
22 #include <asm/uaccess.h>
23 #include <asm/pgtable.h>
24 #include <asm/processor.h>
25 #include <asm/cacheflush.h>
27 #include <asm/asm-offsets.h>
30 * translate ptrace register IDs into struct pt_regs offsets
32 static const u8 ptrace_regid_to_frame
[] = {
33 [PT_A3
<< 2] = REG_A3
,
34 [PT_A2
<< 2] = REG_A2
,
35 [PT_D3
<< 2] = REG_D3
,
36 [PT_D2
<< 2] = REG_D2
,
37 [PT_MCVF
<< 2] = REG_MCVF
,
38 [PT_MCRL
<< 2] = REG_MCRL
,
39 [PT_MCRH
<< 2] = REG_MCRH
,
40 [PT_MDRQ
<< 2] = REG_MDRQ
,
41 [PT_E1
<< 2] = REG_E1
,
42 [PT_E0
<< 2] = REG_E0
,
43 [PT_E7
<< 2] = REG_E7
,
44 [PT_E6
<< 2] = REG_E6
,
45 [PT_E5
<< 2] = REG_E5
,
46 [PT_E4
<< 2] = REG_E4
,
47 [PT_E3
<< 2] = REG_E3
,
48 [PT_E2
<< 2] = REG_E2
,
49 [PT_SP
<< 2] = REG_SP
,
50 [PT_LAR
<< 2] = REG_LAR
,
51 [PT_LIR
<< 2] = REG_LIR
,
52 [PT_MDR
<< 2] = REG_MDR
,
53 [PT_A1
<< 2] = REG_A1
,
54 [PT_A0
<< 2] = REG_A0
,
55 [PT_D1
<< 2] = REG_D1
,
56 [PT_D0
<< 2] = REG_D0
,
57 [PT_ORIG_D0
<< 2] = REG_ORIG_D0
,
58 [PT_EPSW
<< 2] = REG_EPSW
,
59 [PT_PC
<< 2] = REG_PC
,
62 static inline int get_stack_long(struct task_struct
*task
, int offset
)
64 return *(unsigned long *)
65 ((unsigned long) task
->thread
.uregs
+ offset
);
69 int put_stack_long(struct task_struct
*task
, int offset
, unsigned long data
)
73 stack
= (unsigned long) task
->thread
.uregs
+ offset
;
74 *(unsigned long *) stack
= data
;
79 * retrieve the contents of MN10300 userspace general registers
81 static int genregs_get(struct task_struct
*target
,
82 const struct user_regset
*regset
,
83 unsigned int pos
, unsigned int count
,
84 void *kbuf
, void __user
*ubuf
)
86 const struct pt_regs
*regs
= task_pt_regs(target
);
89 /* we need to skip regs->next */
90 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
91 regs
, 0, PT_ORIG_D0
* sizeof(long));
95 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
96 ®s
->orig_d0
, PT_ORIG_D0
* sizeof(long),
97 NR_PTREGS
* sizeof(long));
101 return user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
102 NR_PTREGS
* sizeof(long), -1);
106 * update the contents of the MN10300 userspace general registers
108 static int genregs_set(struct task_struct
*target
,
109 const struct user_regset
*regset
,
110 unsigned int pos
, unsigned int count
,
111 const void *kbuf
, const void __user
*ubuf
)
113 struct pt_regs
*regs
= task_pt_regs(target
);
117 /* we need to skip regs->next */
118 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
119 regs
, 0, PT_ORIG_D0
* sizeof(long));
123 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
124 ®s
->orig_d0
, PT_ORIG_D0
* sizeof(long),
125 PT_EPSW
* sizeof(long));
129 /* we need to mask off changes to EPSW */
131 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
132 &tmp
, PT_EPSW
* sizeof(long),
133 PT_PC
* sizeof(long));
134 tmp
&= EPSW_FLAG_V
| EPSW_FLAG_C
| EPSW_FLAG_N
| EPSW_FLAG_Z
;
135 tmp
|= regs
->epsw
& ~(EPSW_FLAG_V
| EPSW_FLAG_C
| EPSW_FLAG_N
|
142 /* and finally load the PC */
143 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
144 ®s
->pc
, PT_PC
* sizeof(long),
145 NR_PTREGS
* sizeof(long));
150 return user_regset_copyin_ignore(&pos
, &count
, &kbuf
, &ubuf
,
151 NR_PTREGS
* sizeof(long), -1);
155 * retrieve the contents of MN10300 userspace FPU registers
157 static int fpuregs_get(struct task_struct
*target
,
158 const struct user_regset
*regset
,
159 unsigned int pos
, unsigned int count
,
160 void *kbuf
, void __user
*ubuf
)
162 const struct fpu_state_struct
*fpregs
= &target
->thread
.fpu_state
;
167 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
168 fpregs
, 0, sizeof(*fpregs
));
172 return user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
173 sizeof(*fpregs
), -1);
177 * update the contents of the MN10300 userspace FPU registers
179 static int fpuregs_set(struct task_struct
*target
,
180 const struct user_regset
*regset
,
181 unsigned int pos
, unsigned int count
,
182 const void *kbuf
, const void __user
*ubuf
)
184 struct fpu_state_struct fpu_state
= target
->thread
.fpu_state
;
187 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
188 &fpu_state
, 0, sizeof(fpu_state
));
192 fpu_kill_state(target
);
193 target
->thread
.fpu_state
= fpu_state
;
194 set_using_fpu(target
);
196 return user_regset_copyin_ignore(&pos
, &count
, &kbuf
, &ubuf
,
197 sizeof(fpu_state
), -1);
201 * determine if the FPU registers have actually been used
203 static int fpuregs_active(struct task_struct
*target
,
204 const struct user_regset
*regset
)
206 return is_using_fpu(target
) ? regset
->n
: 0;
210 * Define the register sets available on the MN10300 under Linux
212 enum mn10300_regset
{
217 static const struct user_regset mn10300_regsets
[] = {
219 * General register format is:
220 * A3, A2, D3, D2, MCVF, MCRL, MCRH, MDRQ
221 * E1, E0, E7...E2, SP, LAR, LIR, MDR
222 * A1, A0, D1, D0, ORIG_D0, EPSW, PC
225 .core_note_type
= NT_PRSTATUS
,
227 .size
= sizeof(long),
228 .align
= sizeof(long),
233 * FPU register format is:
237 .core_note_type
= NT_PRFPREG
,
238 .n
= sizeof(struct fpu_state_struct
) / sizeof(long),
239 .size
= sizeof(long),
240 .align
= sizeof(long),
243 .active
= fpuregs_active
,
247 static const struct user_regset_view user_mn10300_native_view
= {
249 .e_machine
= EM_MN10300
,
250 .regsets
= mn10300_regsets
,
251 .n
= ARRAY_SIZE(mn10300_regsets
),
254 const struct user_regset_view
*task_user_regset_view(struct task_struct
*task
)
256 return &user_mn10300_native_view
;
260 * set the single-step bit
262 void user_enable_single_step(struct task_struct
*child
)
264 #ifndef CONFIG_MN10300_USING_JTAG
265 struct user
*dummy
= NULL
;
268 tmp
= get_stack_long(child
, (unsigned long) &dummy
->regs
.epsw
);
270 put_stack_long(child
, (unsigned long) &dummy
->regs
.epsw
, tmp
);
275 * make sure the single-step bit is not set
277 void user_disable_single_step(struct task_struct
*child
)
279 #ifndef CONFIG_MN10300_USING_JTAG
280 struct user
*dummy
= NULL
;
283 tmp
= get_stack_long(child
, (unsigned long) &dummy
->regs
.epsw
);
285 put_stack_long(child
, (unsigned long) &dummy
->regs
.epsw
, tmp
);
289 void ptrace_disable(struct task_struct
*child
)
291 user_disable_single_step(child
);
295 * handle the arch-specific side of process tracing
297 long arch_ptrace(struct task_struct
*child
, long request
,
298 unsigned long addr
, unsigned long data
)
302 unsigned long __user
*datap
= (unsigned long __user
*) data
;
305 /* read the word at location addr in the USER area. */
308 if ((addr
& 3) || addr
> sizeof(struct user
) - 3)
311 tmp
= 0; /* Default return condition */
312 if (addr
< NR_PTREGS
<< 2)
313 tmp
= get_stack_long(child
,
314 ptrace_regid_to_frame
[addr
]);
315 ret
= put_user(tmp
, datap
);
318 /* write the word at location addr in the USER area */
321 if ((addr
& 3) || addr
> sizeof(struct user
) - 3)
325 if (addr
< NR_PTREGS
<< 2)
326 ret
= put_stack_long(child
, ptrace_regid_to_frame
[addr
],
330 case PTRACE_GETREGS
: /* Get all integer regs from the child. */
331 return copy_regset_to_user(child
, &user_mn10300_native_view
,
333 0, NR_PTREGS
* sizeof(long),
336 case PTRACE_SETREGS
: /* Set all integer regs in the child. */
337 return copy_regset_from_user(child
, &user_mn10300_native_view
,
339 0, NR_PTREGS
* sizeof(long),
342 case PTRACE_GETFPREGS
: /* Get the child FPU state. */
343 return copy_regset_to_user(child
, &user_mn10300_native_view
,
345 0, sizeof(struct fpu_state_struct
),
348 case PTRACE_SETFPREGS
: /* Set the child FPU state. */
349 return copy_regset_from_user(child
, &user_mn10300_native_view
,
351 0, sizeof(struct fpu_state_struct
),
355 ret
= ptrace_request(child
, request
, addr
, data
);
363 * handle tracing of system call entry
364 * - return the revised system call number or ULONG_MAX to cause ENOSYS
366 asmlinkage
unsigned long syscall_trace_entry(struct pt_regs
*regs
)
368 if (tracehook_report_syscall_entry(regs
))
369 /* tracing decided this syscall should not happen, so
370 * We'll return a bogus call number to get an ENOSYS
371 * error, but leave the original number in
376 return regs
->orig_d0
;
380 * handle tracing of system call exit
382 asmlinkage
void syscall_trace_exit(struct pt_regs
*regs
)
384 tracehook_report_syscall_exit(regs
, 0);