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/system.h>
25 #include <asm/processor.h>
26 #include <asm/cacheflush.h>
28 #include <asm/asm-offsets.h>
31 * translate ptrace register IDs into struct pt_regs offsets
33 static const u8 ptrace_regid_to_frame
[] = {
34 [PT_A3
<< 2] = REG_A3
,
35 [PT_A2
<< 2] = REG_A2
,
36 [PT_D3
<< 2] = REG_D3
,
37 [PT_D2
<< 2] = REG_D2
,
38 [PT_MCVF
<< 2] = REG_MCVF
,
39 [PT_MCRL
<< 2] = REG_MCRL
,
40 [PT_MCRH
<< 2] = REG_MCRH
,
41 [PT_MDRQ
<< 2] = REG_MDRQ
,
42 [PT_E1
<< 2] = REG_E1
,
43 [PT_E0
<< 2] = REG_E0
,
44 [PT_E7
<< 2] = REG_E7
,
45 [PT_E6
<< 2] = REG_E6
,
46 [PT_E5
<< 2] = REG_E5
,
47 [PT_E4
<< 2] = REG_E4
,
48 [PT_E3
<< 2] = REG_E3
,
49 [PT_E2
<< 2] = REG_E2
,
50 [PT_SP
<< 2] = REG_SP
,
51 [PT_LAR
<< 2] = REG_LAR
,
52 [PT_LIR
<< 2] = REG_LIR
,
53 [PT_MDR
<< 2] = REG_MDR
,
54 [PT_A1
<< 2] = REG_A1
,
55 [PT_A0
<< 2] = REG_A0
,
56 [PT_D1
<< 2] = REG_D1
,
57 [PT_D0
<< 2] = REG_D0
,
58 [PT_ORIG_D0
<< 2] = REG_ORIG_D0
,
59 [PT_EPSW
<< 2] = REG_EPSW
,
60 [PT_PC
<< 2] = REG_PC
,
63 static inline int get_stack_long(struct task_struct
*task
, int offset
)
65 return *(unsigned long *)
66 ((unsigned long) task
->thread
.uregs
+ offset
);
70 int put_stack_long(struct task_struct
*task
, int offset
, unsigned long data
)
74 stack
= (unsigned long) task
->thread
.uregs
+ offset
;
75 *(unsigned long *) stack
= data
;
80 * retrieve the contents of MN10300 userspace general registers
82 static int genregs_get(struct task_struct
*target
,
83 const struct user_regset
*regset
,
84 unsigned int pos
, unsigned int count
,
85 void *kbuf
, void __user
*ubuf
)
87 const struct pt_regs
*regs
= task_pt_regs(target
);
90 /* we need to skip regs->next */
91 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
92 regs
, 0, PT_ORIG_D0
* sizeof(long));
96 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
97 ®s
->orig_d0
, PT_ORIG_D0
* sizeof(long),
98 NR_PTREGS
* sizeof(long));
102 return user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
103 NR_PTREGS
* sizeof(long), -1);
107 * update the contents of the MN10300 userspace general registers
109 static int genregs_set(struct task_struct
*target
,
110 const struct user_regset
*regset
,
111 unsigned int pos
, unsigned int count
,
112 const void *kbuf
, const void __user
*ubuf
)
114 struct pt_regs
*regs
= task_pt_regs(target
);
118 /* we need to skip regs->next */
119 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
120 regs
, 0, PT_ORIG_D0
* sizeof(long));
124 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
125 ®s
->orig_d0
, PT_ORIG_D0
* sizeof(long),
126 PT_EPSW
* sizeof(long));
130 /* we need to mask off changes to EPSW */
132 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
133 &tmp
, PT_EPSW
* sizeof(long),
134 PT_PC
* sizeof(long));
135 tmp
&= EPSW_FLAG_V
| EPSW_FLAG_C
| EPSW_FLAG_N
| EPSW_FLAG_Z
;
136 tmp
|= regs
->epsw
& ~(EPSW_FLAG_V
| EPSW_FLAG_C
| EPSW_FLAG_N
|
143 /* and finally load the PC */
144 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
145 ®s
->pc
, PT_PC
* sizeof(long),
146 NR_PTREGS
* sizeof(long));
151 return user_regset_copyin_ignore(&pos
, &count
, &kbuf
, &ubuf
,
152 NR_PTREGS
* sizeof(long), -1);
156 * retrieve the contents of MN10300 userspace FPU registers
158 static int fpuregs_get(struct task_struct
*target
,
159 const struct user_regset
*regset
,
160 unsigned int pos
, unsigned int count
,
161 void *kbuf
, void __user
*ubuf
)
163 const struct fpu_state_struct
*fpregs
= &target
->thread
.fpu_state
;
168 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
169 fpregs
, 0, sizeof(*fpregs
));
173 return user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
174 sizeof(*fpregs
), -1);
178 * update the contents of the MN10300 userspace FPU registers
180 static int fpuregs_set(struct task_struct
*target
,
181 const struct user_regset
*regset
,
182 unsigned int pos
, unsigned int count
,
183 const void *kbuf
, const void __user
*ubuf
)
185 struct fpu_state_struct fpu_state
= target
->thread
.fpu_state
;
188 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
189 &fpu_state
, 0, sizeof(fpu_state
));
193 fpu_kill_state(target
);
194 target
->thread
.fpu_state
= fpu_state
;
195 set_using_fpu(target
);
197 return user_regset_copyin_ignore(&pos
, &count
, &kbuf
, &ubuf
,
198 sizeof(fpu_state
), -1);
202 * determine if the FPU registers have actually been used
204 static int fpuregs_active(struct task_struct
*target
,
205 const struct user_regset
*regset
)
207 return is_using_fpu(target
) ? regset
->n
: 0;
211 * Define the register sets available on the MN10300 under Linux
213 enum mn10300_regset
{
218 static const struct user_regset mn10300_regsets
[] = {
220 * General register format is:
221 * A3, A2, D3, D2, MCVF, MCRL, MCRH, MDRQ
222 * E1, E0, E7...E2, SP, LAR, LIR, MDR
223 * A1, A0, D1, D0, ORIG_D0, EPSW, PC
226 .core_note_type
= NT_PRSTATUS
,
228 .size
= sizeof(long),
229 .align
= sizeof(long),
234 * FPU register format is:
238 .core_note_type
= NT_PRFPREG
,
239 .n
= sizeof(struct fpu_state_struct
) / sizeof(long),
240 .size
= sizeof(long),
241 .align
= sizeof(long),
244 .active
= fpuregs_active
,
248 static const struct user_regset_view user_mn10300_native_view
= {
250 .e_machine
= EM_MN10300
,
251 .regsets
= mn10300_regsets
,
252 .n
= ARRAY_SIZE(mn10300_regsets
),
255 const struct user_regset_view
*task_user_regset_view(struct task_struct
*task
)
257 return &user_mn10300_native_view
;
261 * set the single-step bit
263 void user_enable_single_step(struct task_struct
*child
)
265 #ifndef CONFIG_MN10300_USING_JTAG
266 struct user
*dummy
= NULL
;
269 tmp
= get_stack_long(child
, (unsigned long) &dummy
->regs
.epsw
);
271 put_stack_long(child
, (unsigned long) &dummy
->regs
.epsw
, tmp
);
276 * make sure the single-step bit is not set
278 void user_disable_single_step(struct task_struct
*child
)
280 #ifndef CONFIG_MN10300_USING_JTAG
281 struct user
*dummy
= NULL
;
284 tmp
= get_stack_long(child
, (unsigned long) &dummy
->regs
.epsw
);
286 put_stack_long(child
, (unsigned long) &dummy
->regs
.epsw
, tmp
);
290 void ptrace_disable(struct task_struct
*child
)
292 user_disable_single_step(child
);
296 * handle the arch-specific side of process tracing
298 long arch_ptrace(struct task_struct
*child
, long request
,
299 unsigned long addr
, unsigned long data
)
303 unsigned long __user
*datap
= (unsigned long __user
*) data
;
306 /* read the word at location addr in the USER area. */
309 if ((addr
& 3) || addr
> sizeof(struct user
) - 3)
312 tmp
= 0; /* Default return condition */
313 if (addr
< NR_PTREGS
<< 2)
314 tmp
= get_stack_long(child
,
315 ptrace_regid_to_frame
[addr
]);
316 ret
= put_user(tmp
, datap
);
319 /* write the word at location addr in the USER area */
322 if ((addr
& 3) || addr
> sizeof(struct user
) - 3)
326 if (addr
< NR_PTREGS
<< 2)
327 ret
= put_stack_long(child
, ptrace_regid_to_frame
[addr
],
331 case PTRACE_GETREGS
: /* Get all integer regs from the child. */
332 return copy_regset_to_user(child
, &user_mn10300_native_view
,
334 0, NR_PTREGS
* sizeof(long),
337 case PTRACE_SETREGS
: /* Set all integer regs in the child. */
338 return copy_regset_from_user(child
, &user_mn10300_native_view
,
340 0, NR_PTREGS
* sizeof(long),
343 case PTRACE_GETFPREGS
: /* Get the child FPU state. */
344 return copy_regset_to_user(child
, &user_mn10300_native_view
,
346 0, sizeof(struct fpu_state_struct
),
349 case PTRACE_SETFPREGS
: /* Set the child FPU state. */
350 return copy_regset_from_user(child
, &user_mn10300_native_view
,
352 0, sizeof(struct fpu_state_struct
),
356 ret
= ptrace_request(child
, request
, addr
, data
);
364 * handle tracing of system call entry
365 * - return the revised system call number or ULONG_MAX to cause ENOSYS
367 asmlinkage
unsigned long syscall_trace_entry(struct pt_regs
*regs
)
369 if (tracehook_report_syscall_entry(regs
))
370 /* tracing decided this syscall should not happen, so
371 * We'll return a bogus call number to get an ENOSYS
372 * error, but leave the original number in
377 return regs
->orig_d0
;
381 * handle tracing of system call exit
383 asmlinkage
void syscall_trace_exit(struct pt_regs
*regs
)
385 tracehook_report_syscall_exit(regs
, 0);