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>
10 #include <linux/sched/task_stack.h>
12 #include <linux/smp.h>
13 #include <linux/elf.h>
14 #include <linux/errno.h>
15 #include <linux/ptrace.h>
16 #include <linux/user.h>
17 #include <linux/regset.h>
18 #include <linux/signal.h>
19 #include <linux/tracehook.h>
20 #include <linux/uaccess.h>
23 #include <asm/pgtable.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
)
122 struct vm_area_struct
*vma
;
123 struct sram_list_struct
*sraml
;
126 if (start
+ len
< start
)
129 down_read(&child
->mm
->mmap_sem
);
130 vma
= find_vma(child
->mm
, start
);
131 valid
= vma
&& start
>= vma
->vm_start
&& start
+ len
<= vma
->vm_end
;
132 up_read(&child
->mm
->mmap_sem
);
136 for (sraml
= child
->mm
->context
.sram_list
; sraml
; sraml
= sraml
->next
)
137 if (start
>= (unsigned long)sraml
->addr
138 && start
+ len
< (unsigned long)sraml
->addr
+ sraml
->length
)
141 if (start
>= FIXED_CODE_START
&& start
+ len
< FIXED_CODE_END
)
144 #ifdef CONFIG_APP_STACK_L1
145 if (child
->mm
->context
.l1_stack_save
)
146 if (start
>= (unsigned long)l1_stack_base
&&
147 start
+ len
< (unsigned long)l1_stack_base
+ l1_stack_len
)
155 * retrieve the contents of Blackfin userspace general registers
157 static int genregs_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 struct pt_regs
*regs
= task_pt_regs(target
);
166 regs
->usp
= target
->thread
.usp
;
168 ret
= user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
169 regs
, 0, sizeof(*regs
));
173 return user_regset_copyout_zero(&pos
, &count
, &kbuf
, &ubuf
,
178 * update the contents of the Blackfin userspace general registers
180 static int genregs_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 pt_regs
*regs
= task_pt_regs(target
);
188 /* Don't let people set SYSCFG (it's at the end of pt_regs) */
189 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
195 target
->thread
.usp
= regs
->usp
;
196 /* regs->retx = regs->pc; */
198 return user_regset_copyin_ignore(&pos
, &count
, &kbuf
, &ubuf
,
203 * Define the register sets available on the Blackfin under Linux
209 static const struct user_regset bfin_regsets
[] = {
211 .core_note_type
= NT_PRSTATUS
,
212 .n
= sizeof(struct pt_regs
) / sizeof(long),
213 .size
= sizeof(long),
214 .align
= sizeof(long),
220 static const struct user_regset_view user_bfin_native_view
= {
222 .e_machine
= EM_BLACKFIN
,
223 .regsets
= bfin_regsets
,
224 .n
= ARRAY_SIZE(bfin_regsets
),
227 const struct user_regset_view
*task_user_regset_view(struct task_struct
*task
)
229 return &user_bfin_native_view
;
232 void user_enable_single_step(struct task_struct
*child
)
234 struct pt_regs
*regs
= task_pt_regs(child
);
235 regs
->syscfg
|= SYSCFG_SSSTEP
;
237 set_tsk_thread_flag(child
, TIF_SINGLESTEP
);
240 void user_disable_single_step(struct task_struct
*child
)
242 struct pt_regs
*regs
= task_pt_regs(child
);
243 regs
->syscfg
&= ~SYSCFG_SSSTEP
;
245 clear_tsk_thread_flag(child
, TIF_SINGLESTEP
);
248 long arch_ptrace(struct task_struct
*child
, long request
,
249 unsigned long addr
, unsigned long data
)
252 unsigned long __user
*datap
= (unsigned long __user
*)data
;
253 void *paddr
= (void *)addr
;
256 /* when I and D space are separate, these will need to be fixed. */
257 case PTRACE_PEEKDATA
:
258 pr_debug("ptrace: PEEKDATA\n");
260 case PTRACE_PEEKTEXT
: /* read word at location addr. */
262 unsigned long tmp
= 0;
263 int copied
= 0, to_copy
= sizeof(tmp
);
266 pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + %i\n", addr
, to_copy
);
267 if (is_user_addr_valid(child
, addr
, to_copy
) < 0)
269 pr_debug("ptrace: user address is valid\n");
271 switch (bfin_mem_access_type(addr
, to_copy
)) {
272 case BFIN_MEM_ACCESS_CORE
:
273 case BFIN_MEM_ACCESS_CORE_ONLY
:
274 copied
= ptrace_access_vm(child
, addr
, &tmp
,
275 to_copy
, FOLL_FORCE
);
279 /* hrm, why didn't that work ... maybe no mapping */
280 if (addr
>= FIXED_CODE_START
&&
281 addr
+ to_copy
<= FIXED_CODE_END
) {
282 copy_from_user_page(0, 0, 0, &tmp
, paddr
, to_copy
);
284 } else if (addr
>= BOOT_ROM_START
) {
285 memcpy(&tmp
, paddr
, to_copy
);
290 case BFIN_MEM_ACCESS_DMA
:
291 if (safe_dma_memcpy(&tmp
, paddr
, to_copy
))
294 case BFIN_MEM_ACCESS_ITEST
:
295 if (isram_memcpy(&tmp
, paddr
, to_copy
))
303 pr_debug("ptrace: copied size %d [0x%08lx]\n", copied
, tmp
);
304 if (copied
== to_copy
)
305 ret
= put_user(tmp
, datap
);
309 /* when I and D space are separate, this will have to be fixed. */
310 case PTRACE_POKEDATA
:
311 pr_debug("ptrace: PTRACE_PEEKDATA\n");
313 case PTRACE_POKETEXT
: /* write the word at location addr. */
315 int copied
= 0, to_copy
= sizeof(data
);
318 pr_debug("ptrace: POKETEXT at addr 0x%08lx + %i bytes %lx\n",
319 addr
, to_copy
, data
);
320 if (is_user_addr_valid(child
, addr
, to_copy
) < 0)
322 pr_debug("ptrace: user address is valid\n");
324 switch (bfin_mem_access_type(addr
, to_copy
)) {
325 case BFIN_MEM_ACCESS_CORE
:
326 case BFIN_MEM_ACCESS_CORE_ONLY
:
327 copied
= ptrace_access_vm(child
, addr
, &data
,
329 FOLL_FORCE
| FOLL_WRITE
);
331 case BFIN_MEM_ACCESS_DMA
:
332 if (safe_dma_memcpy(paddr
, &data
, to_copy
))
335 case BFIN_MEM_ACCESS_ITEST
:
336 if (isram_memcpy(paddr
, &data
, to_copy
))
344 pr_debug("ptrace: copied size %d\n", copied
);
345 if (copied
== to_copy
)
352 #ifdef CONFIG_BINFMT_ELF_FDPIC /* backwards compat */
354 request
= PTRACE_GETFDPIC
;
355 addr
= PTRACE_GETFDPIC_EXEC
;
357 case PT_FDPIC_INTERP
:
358 request
= PTRACE_GETFDPIC
;
359 addr
= PTRACE_GETFDPIC_INTERP
;
363 ret
= get_reg(child
, addr
, datap
);
365 pr_debug("ptrace: PEEKUSR reg %li with %#lx = %i\n", addr
, data
, ret
);
369 ret
= put_reg(child
, addr
, data
);
370 pr_debug("ptrace: POKEUSR reg %li with %li = %i\n", addr
, data
, ret
);
374 pr_debug("ptrace: PTRACE_GETREGS\n");
375 return copy_regset_to_user(child
, &user_bfin_native_view
,
377 0, sizeof(struct pt_regs
),
381 pr_debug("ptrace: PTRACE_SETREGS\n");
382 return copy_regset_from_user(child
, &user_bfin_native_view
,
384 0, sizeof(struct pt_regs
),
389 ret
= ptrace_request(child
, request
, addr
, data
);
396 asmlinkage
int syscall_trace_enter(struct pt_regs
*regs
)
400 if (test_thread_flag(TIF_SYSCALL_TRACE
))
401 ret
= tracehook_report_syscall_entry(regs
);
406 asmlinkage
void syscall_trace_leave(struct pt_regs
*regs
)
410 step
= test_thread_flag(TIF_SINGLESTEP
);
411 if (step
|| test_thread_flag(TIF_SYSCALL_TRACE
))
412 tracehook_report_syscall_exit(regs
, step
);