2 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
3 * these modifications are Copyright 2004-2010 Analog Devices Inc.
5 * Licensed under the GPL-2
8 #include <linux/kernel.h>
9 #include <linux/sched.h>
11 #include <linux/smp.h>
12 #include <linux/elf.h>
13 #include <linux/errno.h>
14 #include <linux/ptrace.h>
15 #include <linux/user.h>
16 #include <linux/regset.h>
17 #include <linux/signal.h>
18 #include <linux/tracehook.h>
19 #include <linux/uaccess.h>
22 #include <asm/pgtable.h>
23 #include <asm/system.h>
24 #include <asm/processor.h>
25 #include <asm/asm-offsets.h>
27 #include <asm/fixed_code.h>
28 #include <asm/cacheflush.h>
29 #include <asm/mem_map.h>
30 #include <asm/mmu_context.h>
33 * does not yet catch signals sent when the child dies.
34 * in exit.c or in signal.c.
38 * Get contents of register REGNO in task TASK.
41 get_reg(struct task_struct
*task
, unsigned long regno
,
42 unsigned long __user
*datap
)
45 struct pt_regs
*regs
= task_pt_regs(task
);
47 if (regno
& 3 || regno
> PT_LAST_PSEUDO
)
52 tmp
= task
->mm
->start_code
;
54 case PT_TEXT_END_ADDR
:
55 tmp
= task
->mm
->end_code
;
58 tmp
= task
->mm
->start_data
;
61 tmp
= task
->thread
.usp
;
64 if (regno
< sizeof(*regs
)) {
66 tmp
= *(long *)(reg_ptr
+ regno
);
71 return put_user(tmp
, datap
);
75 * Write contents of register REGNO in task TASK.
78 put_reg(struct task_struct
*task
, unsigned long regno
, unsigned long data
)
80 struct pt_regs
*regs
= task_pt_regs(task
);
82 if (regno
& 3 || regno
> PT_LAST_PSEUDO
)
87 /*********************************************************************/
88 /* At this point the kernel is most likely in exception. */
89 /* The RETX register will be used to populate the pc of the process. */
90 /*********************************************************************/
95 break; /* regs->retx = data; break; */
98 task
->thread
.usp
= data
;
100 case PT_SYSCFG
: /* don't let userspace screw with this */
101 if ((data
& ~1) != 0x6)
102 pr_warning("ptrace: ignore syscfg write of %#lx\n", data
);
103 break; /* regs->syscfg = data; break; */
105 if (regno
< sizeof(*regs
)) {
106 void *reg_offset
= regs
;
107 *(long *)(reg_offset
+ regno
) = data
;
109 /* Ignore writes to pseudo registers */
116 * check that an address falls within the bounds of the target process's memory mappings
119 is_user_addr_valid(struct task_struct
*child
, unsigned long start
, unsigned long len
)
121 struct vm_area_struct
*vma
;
122 struct sram_list_struct
*sraml
;
125 if (start
+ len
< start
)
128 vma
= find_vma(child
->mm
, start
);
129 if (vma
&& start
>= vma
->vm_start
&& start
+ len
<= vma
->vm_end
)
132 for (sraml
= child
->mm
->context
.sram_list
; sraml
; sraml
= sraml
->next
)
133 if (start
>= (unsigned long)sraml
->addr
134 && start
+ len
< (unsigned long)sraml
->addr
+ sraml
->length
)
137 if (start
>= FIXED_CODE_START
&& start
+ len
< FIXED_CODE_END
)
140 #ifdef CONFIG_APP_STACK_L1
141 if (child
->mm
->context
.l1_stack_save
)
142 if (start
>= (unsigned long)l1_stack_base
&&
143 start
+ len
< (unsigned long)l1_stack_base
+ l1_stack_len
)
151 * retrieve the contents of Blackfin userspace general registers
153 static int genregs_get(struct task_struct
*target
,
154 const struct user_regset
*regset
,
155 unsigned int pos
, unsigned int count
,
156 void *kbuf
, void __user
*ubuf
)
158 struct pt_regs
*regs
= task_pt_regs(target
);
162 regs
->usp
= target
->thread
.usp
;
164 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
165 regs
, 0, sizeof(*regs
));
169 return user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
174 * update the contents of the Blackfin userspace general registers
176 static int genregs_set(struct task_struct
*target
,
177 const struct user_regset
*regset
,
178 unsigned int pos
, unsigned int count
,
179 const void *kbuf
, const void __user
*ubuf
)
181 struct pt_regs
*regs
= task_pt_regs(target
);
184 /* Don't let people set SYSCFG (it's at the end of pt_regs) */
185 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
191 target
->thread
.usp
= regs
->usp
;
192 /* regs->retx = regs->pc; */
194 return user_regset_copyin_ignore(&pos
, &count
, &kbuf
, &ubuf
,
199 * Define the register sets available on the Blackfin under Linux
205 static const struct user_regset bfin_regsets
[] = {
207 .core_note_type
= NT_PRSTATUS
,
208 .n
= sizeof(struct pt_regs
) / sizeof(long),
209 .size
= sizeof(long),
210 .align
= sizeof(long),
216 static const struct user_regset_view user_bfin_native_view
= {
218 .e_machine
= EM_BLACKFIN
,
219 .regsets
= bfin_regsets
,
220 .n
= ARRAY_SIZE(bfin_regsets
),
223 const struct user_regset_view
*task_user_regset_view(struct task_struct
*task
)
225 return &user_bfin_native_view
;
228 void user_enable_single_step(struct task_struct
*child
)
230 struct pt_regs
*regs
= task_pt_regs(child
);
231 regs
->syscfg
|= SYSCFG_SSSTEP
;
233 set_tsk_thread_flag(child
, TIF_SINGLESTEP
);
236 void user_disable_single_step(struct task_struct
*child
)
238 struct pt_regs
*regs
= task_pt_regs(child
);
239 regs
->syscfg
&= ~SYSCFG_SSSTEP
;
241 clear_tsk_thread_flag(child
, TIF_SINGLESTEP
);
244 long arch_ptrace(struct task_struct
*child
, long request
,
245 unsigned long addr
, unsigned long data
)
248 unsigned long __user
*datap
= (unsigned long __user
*)data
;
249 void *paddr
= (void *)addr
;
252 /* when I and D space are separate, these will need to be fixed. */
253 case PTRACE_PEEKDATA
:
254 pr_debug("ptrace: PEEKDATA\n");
256 case PTRACE_PEEKTEXT
: /* read word at location addr. */
258 unsigned long tmp
= 0;
259 int copied
= 0, to_copy
= sizeof(tmp
);
262 pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + %i\n", addr
, to_copy
);
263 if (is_user_addr_valid(child
, addr
, to_copy
) < 0)
265 pr_debug("ptrace: user address is valid\n");
267 switch (bfin_mem_access_type(addr
, to_copy
)) {
268 case BFIN_MEM_ACCESS_CORE
:
269 case BFIN_MEM_ACCESS_CORE_ONLY
:
270 copied
= access_process_vm(child
, addr
, &tmp
,
275 /* hrm, why didn't that work ... maybe no mapping */
276 if (addr
>= FIXED_CODE_START
&&
277 addr
+ to_copy
<= FIXED_CODE_END
) {
278 copy_from_user_page(0, 0, 0, &tmp
, paddr
, to_copy
);
280 } else if (addr
>= BOOT_ROM_START
) {
281 memcpy(&tmp
, paddr
, to_copy
);
286 case BFIN_MEM_ACCESS_DMA
:
287 if (safe_dma_memcpy(&tmp
, paddr
, to_copy
))
290 case BFIN_MEM_ACCESS_ITEST
:
291 if (isram_memcpy(&tmp
, paddr
, to_copy
))
299 pr_debug("ptrace: copied size %d [0x%08lx]\n", copied
, tmp
);
300 if (copied
== to_copy
)
301 ret
= put_user(tmp
, datap
);
305 /* when I and D space are separate, this will have to be fixed. */
306 case PTRACE_POKEDATA
:
307 pr_debug("ptrace: PTRACE_PEEKDATA\n");
309 case PTRACE_POKETEXT
: /* write the word at location addr. */
311 int copied
= 0, to_copy
= sizeof(data
);
314 pr_debug("ptrace: POKETEXT at addr 0x%08lx + %i bytes %lx\n",
315 addr
, to_copy
, data
);
316 if (is_user_addr_valid(child
, addr
, to_copy
) < 0)
318 pr_debug("ptrace: user address is valid\n");
320 switch (bfin_mem_access_type(addr
, to_copy
)) {
321 case BFIN_MEM_ACCESS_CORE
:
322 case BFIN_MEM_ACCESS_CORE_ONLY
:
323 copied
= access_process_vm(child
, addr
, &data
,
326 case BFIN_MEM_ACCESS_DMA
:
327 if (safe_dma_memcpy(paddr
, &data
, to_copy
))
330 case BFIN_MEM_ACCESS_ITEST
:
331 if (isram_memcpy(paddr
, &data
, to_copy
))
339 pr_debug("ptrace: copied size %d\n", copied
);
340 if (copied
== to_copy
)
347 #ifdef CONFIG_BINFMT_ELF_FDPIC /* backwards compat */
349 request
= PTRACE_GETFDPIC
;
350 addr
= PTRACE_GETFDPIC_EXEC
;
352 case PT_FDPIC_INTERP
:
353 request
= PTRACE_GETFDPIC
;
354 addr
= PTRACE_GETFDPIC_INTERP
;
358 ret
= get_reg(child
, addr
, datap
);
360 pr_debug("ptrace: PEEKUSR reg %li with %#lx = %i\n", addr
, data
, ret
);
364 ret
= put_reg(child
, addr
, data
);
365 pr_debug("ptrace: POKEUSR reg %li with %li = %i\n", addr
, data
, ret
);
369 pr_debug("ptrace: PTRACE_GETREGS\n");
370 return copy_regset_to_user(child
, &user_bfin_native_view
,
372 0, sizeof(struct pt_regs
),
376 pr_debug("ptrace: PTRACE_SETREGS\n");
377 return copy_regset_from_user(child
, &user_bfin_native_view
,
379 0, sizeof(struct pt_regs
),
384 ret
= ptrace_request(child
, request
, addr
, data
);
391 asmlinkage
int syscall_trace_enter(struct pt_regs
*regs
)
395 if (test_thread_flag(TIF_SYSCALL_TRACE
))
396 ret
= tracehook_report_syscall_entry(regs
);
401 asmlinkage
void syscall_trace_leave(struct pt_regs
*regs
)
405 step
= test_thread_flag(TIF_SINGLESTEP
);
406 if (step
|| test_thread_flag(TIF_SYSCALL_TRACE
))
407 tracehook_report_syscall_exit(regs
, step
);