1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/arch/arm/kernel/ptrace.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * By Ross Biro 1/23/92
61da177e4SLinus Torvalds * edited by Linus Torvalds
71da177e4SLinus Torvalds * ARM modifications Copyright (C) 2000 Russell King
81da177e4SLinus Torvalds */
91da177e4SLinus Torvalds #include <linux/kernel.h>
103f07c014SIngo Molnar #include <linux/sched/signal.h>
1168db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
121da177e4SLinus Torvalds #include <linux/mm.h>
13ce8b9d25SPaul Gortmaker #include <linux/elf.h>
141da177e4SLinus Torvalds #include <linux/smp.h>
151da177e4SLinus Torvalds #include <linux/ptrace.h>
161da177e4SLinus Torvalds #include <linux/user.h>
171da177e4SLinus Torvalds #include <linux/security.h>
181da177e4SLinus Torvalds #include <linux/init.h>
197ed20e1aSJesper Juhl #include <linux/signal.h>
2033fa9b13SRussell King #include <linux/uaccess.h>
21864232faSWill Deacon #include <linux/perf_event.h>
22864232faSWill Deacon #include <linux/hw_breakpoint.h>
235be6f62bSDave Martin #include <linux/regset.h>
245180bb39SEric Paris #include <linux/audit.h>
25ad82cc08SWill Deacon #include <linux/unistd.h>
261da177e4SLinus Torvalds
274e57a4ddSArnd Bergmann #include <asm/syscall.h>
281da177e4SLinus Torvalds #include <asm/traps.h>
291da177e4SLinus Torvalds
301f66e06fSWade Farnsworth #define CREATE_TRACE_POINTS
311f66e06fSWade Farnsworth #include <trace/events/syscalls.h>
321f66e06fSWade Farnsworth
331da177e4SLinus Torvalds #define REG_PC 15
341da177e4SLinus Torvalds #define REG_PSR 16
351da177e4SLinus Torvalds /*
361da177e4SLinus Torvalds * does not yet catch signals sent when the child dies.
371da177e4SLinus Torvalds * in exit.c or in signal.c.
381da177e4SLinus Torvalds */
391da177e4SLinus Torvalds
401da177e4SLinus Torvalds #if 0
411da177e4SLinus Torvalds /*
421da177e4SLinus Torvalds * Breakpoint SWI instruction: SWI &9F0001
431da177e4SLinus Torvalds */
441da177e4SLinus Torvalds #define BREAKINST_ARM 0xef9f0001
451da177e4SLinus Torvalds #define BREAKINST_THUMB 0xdf00 /* fill this in later */
461da177e4SLinus Torvalds #else
471da177e4SLinus Torvalds /*
481da177e4SLinus Torvalds * New breakpoints - use an undefined instruction. The ARM architecture
491da177e4SLinus Torvalds * reference manual guarantees that the following instruction space
501da177e4SLinus Torvalds * will produce an undefined instruction exception on all CPUs:
511da177e4SLinus Torvalds *
521da177e4SLinus Torvalds * ARM: xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx
531da177e4SLinus Torvalds * Thumb: 1101 1110 xxxx xxxx
541da177e4SLinus Torvalds */
551da177e4SLinus Torvalds #define BREAKINST_ARM 0xe7f001f0
561da177e4SLinus Torvalds #define BREAKINST_THUMB 0xde01
571da177e4SLinus Torvalds #endif
581da177e4SLinus Torvalds
59e513f8bfSWill Deacon struct pt_regs_offset {
60e513f8bfSWill Deacon const char *name;
61e513f8bfSWill Deacon int offset;
62e513f8bfSWill Deacon };
63e513f8bfSWill Deacon
64e513f8bfSWill Deacon #define REG_OFFSET_NAME(r) \
65e513f8bfSWill Deacon {.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)}
66e513f8bfSWill Deacon #define REG_OFFSET_END {.name = NULL, .offset = 0}
67e513f8bfSWill Deacon
68e513f8bfSWill Deacon static const struct pt_regs_offset regoffset_table[] = {
69e513f8bfSWill Deacon REG_OFFSET_NAME(r0),
70e513f8bfSWill Deacon REG_OFFSET_NAME(r1),
71e513f8bfSWill Deacon REG_OFFSET_NAME(r2),
72e513f8bfSWill Deacon REG_OFFSET_NAME(r3),
73e513f8bfSWill Deacon REG_OFFSET_NAME(r4),
74e513f8bfSWill Deacon REG_OFFSET_NAME(r5),
75e513f8bfSWill Deacon REG_OFFSET_NAME(r6),
76e513f8bfSWill Deacon REG_OFFSET_NAME(r7),
77e513f8bfSWill Deacon REG_OFFSET_NAME(r8),
78e513f8bfSWill Deacon REG_OFFSET_NAME(r9),
79e513f8bfSWill Deacon REG_OFFSET_NAME(r10),
80e513f8bfSWill Deacon REG_OFFSET_NAME(fp),
81e513f8bfSWill Deacon REG_OFFSET_NAME(ip),
82e513f8bfSWill Deacon REG_OFFSET_NAME(sp),
83e513f8bfSWill Deacon REG_OFFSET_NAME(lr),
84e513f8bfSWill Deacon REG_OFFSET_NAME(pc),
85e513f8bfSWill Deacon REG_OFFSET_NAME(cpsr),
86e513f8bfSWill Deacon REG_OFFSET_NAME(ORIG_r0),
87e513f8bfSWill Deacon REG_OFFSET_END,
88e513f8bfSWill Deacon };
89e513f8bfSWill Deacon
90e513f8bfSWill Deacon /**
91e513f8bfSWill Deacon * regs_query_register_offset() - query register offset from its name
92e513f8bfSWill Deacon * @name: the name of a register
93e513f8bfSWill Deacon *
94e513f8bfSWill Deacon * regs_query_register_offset() returns the offset of a register in struct
95e513f8bfSWill Deacon * pt_regs from its name. If the name is invalid, this returns -EINVAL;
96e513f8bfSWill Deacon */
regs_query_register_offset(const char * name)97e513f8bfSWill Deacon int regs_query_register_offset(const char *name)
98e513f8bfSWill Deacon {
99e513f8bfSWill Deacon const struct pt_regs_offset *roff;
100e513f8bfSWill Deacon for (roff = regoffset_table; roff->name != NULL; roff++)
101e513f8bfSWill Deacon if (!strcmp(roff->name, name))
102e513f8bfSWill Deacon return roff->offset;
103e513f8bfSWill Deacon return -EINVAL;
104e513f8bfSWill Deacon }
105e513f8bfSWill Deacon
106e513f8bfSWill Deacon /**
107e513f8bfSWill Deacon * regs_query_register_name() - query register name from its offset
108e513f8bfSWill Deacon * @offset: the offset of a register in struct pt_regs.
109e513f8bfSWill Deacon *
110e513f8bfSWill Deacon * regs_query_register_name() returns the name of a register from its
111e513f8bfSWill Deacon * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
112e513f8bfSWill Deacon */
regs_query_register_name(unsigned int offset)113e513f8bfSWill Deacon const char *regs_query_register_name(unsigned int offset)
114e513f8bfSWill Deacon {
115e513f8bfSWill Deacon const struct pt_regs_offset *roff;
116e513f8bfSWill Deacon for (roff = regoffset_table; roff->name != NULL; roff++)
117e513f8bfSWill Deacon if (roff->offset == offset)
118e513f8bfSWill Deacon return roff->name;
119e513f8bfSWill Deacon return NULL;
120e513f8bfSWill Deacon }
121e513f8bfSWill Deacon
122e513f8bfSWill Deacon /**
123e513f8bfSWill Deacon * regs_within_kernel_stack() - check the address in the stack
124e513f8bfSWill Deacon * @regs: pt_regs which contains kernel stack pointer.
125e513f8bfSWill Deacon * @addr: address which is checked.
126e513f8bfSWill Deacon *
127e513f8bfSWill Deacon * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
128e513f8bfSWill Deacon * If @addr is within the kernel stack, it returns true. If not, returns false.
129e513f8bfSWill Deacon */
regs_within_kernel_stack(struct pt_regs * regs,unsigned long addr)130e513f8bfSWill Deacon bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
131e513f8bfSWill Deacon {
132e513f8bfSWill Deacon return ((addr & ~(THREAD_SIZE - 1)) ==
133e513f8bfSWill Deacon (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
134e513f8bfSWill Deacon }
135e513f8bfSWill Deacon
136e513f8bfSWill Deacon /**
137e513f8bfSWill Deacon * regs_get_kernel_stack_nth() - get Nth entry of the stack
138e513f8bfSWill Deacon * @regs: pt_regs which contains kernel stack pointer.
139e513f8bfSWill Deacon * @n: stack entry number.
140e513f8bfSWill Deacon *
141e513f8bfSWill Deacon * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
142e513f8bfSWill Deacon * is specified by @regs. If the @n th entry is NOT in the kernel stack,
143e513f8bfSWill Deacon * this returns 0.
144e513f8bfSWill Deacon */
regs_get_kernel_stack_nth(struct pt_regs * regs,unsigned int n)145e513f8bfSWill Deacon unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
146e513f8bfSWill Deacon {
147e513f8bfSWill Deacon unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
148e513f8bfSWill Deacon addr += n;
149e513f8bfSWill Deacon if (regs_within_kernel_stack(regs, (unsigned long)addr))
150e513f8bfSWill Deacon return *addr;
151e513f8bfSWill Deacon else
152e513f8bfSWill Deacon return 0;
153e513f8bfSWill Deacon }
154e513f8bfSWill Deacon
1551da177e4SLinus Torvalds /*
1561da177e4SLinus Torvalds * this routine will get a word off of the processes privileged stack.
1571da177e4SLinus Torvalds * the offset is how far from the base addr as stored in the THREAD.
1581da177e4SLinus Torvalds * this routine assumes that all the privileged stacks are in our
1591da177e4SLinus Torvalds * data space.
1601da177e4SLinus Torvalds */
get_user_reg(struct task_struct * task,int offset)1611da177e4SLinus Torvalds static inline long get_user_reg(struct task_struct *task, int offset)
1621da177e4SLinus Torvalds {
163815d5ec8SAl Viro return task_pt_regs(task)->uregs[offset];
1641da177e4SLinus Torvalds }
1651da177e4SLinus Torvalds
1661da177e4SLinus Torvalds /*
1671da177e4SLinus Torvalds * this routine will put a word on the processes privileged stack.
1681da177e4SLinus Torvalds * the offset is how far from the base addr as stored in the THREAD.
1691da177e4SLinus Torvalds * this routine assumes that all the privileged stacks are in our
1701da177e4SLinus Torvalds * data space.
1711da177e4SLinus Torvalds */
1721da177e4SLinus Torvalds static inline int
put_user_reg(struct task_struct * task,int offset,long data)1731da177e4SLinus Torvalds put_user_reg(struct task_struct *task, int offset, long data)
1741da177e4SLinus Torvalds {
175815d5ec8SAl Viro struct pt_regs newregs, *regs = task_pt_regs(task);
1761da177e4SLinus Torvalds int ret = -EINVAL;
1771da177e4SLinus Torvalds
1781da177e4SLinus Torvalds newregs = *regs;
1791da177e4SLinus Torvalds newregs.uregs[offset] = data;
1801da177e4SLinus Torvalds
1811da177e4SLinus Torvalds if (valid_user_regs(&newregs)) {
1821da177e4SLinus Torvalds regs->uregs[offset] = data;
1831da177e4SLinus Torvalds ret = 0;
1841da177e4SLinus Torvalds }
1851da177e4SLinus Torvalds
1861da177e4SLinus Torvalds return ret;
1871da177e4SLinus Torvalds }
1881da177e4SLinus Torvalds
1891da177e4SLinus Torvalds /*
1901da177e4SLinus Torvalds * Called by kernel/ptrace.c when detaching..
1911da177e4SLinus Torvalds */
ptrace_disable(struct task_struct * child)1921da177e4SLinus Torvalds void ptrace_disable(struct task_struct *child)
1931da177e4SLinus Torvalds {
194425fc47aSWill Deacon /* Nothing to do. */
1951da177e4SLinus Torvalds }
1961da177e4SLinus Torvalds
1971da177e4SLinus Torvalds /*
1981da177e4SLinus Torvalds * Handle hitting a breakpoint.
1991da177e4SLinus Torvalds */
ptrace_break(struct pt_regs * regs)200e9a06509SEric W. Biederman void ptrace_break(struct pt_regs *regs)
2011da177e4SLinus Torvalds {
2023ee6a449SEric W. Biederman force_sig_fault(SIGTRAP, TRAP_BRKPT,
2032e1661d2SEric W. Biederman (void __user *)instruction_pointer(regs));
2041da177e4SLinus Torvalds }
2051da177e4SLinus Torvalds
break_trap(struct pt_regs * regs,unsigned int instr)2061da177e4SLinus Torvalds static int break_trap(struct pt_regs *regs, unsigned int instr)
2071da177e4SLinus Torvalds {
208e9a06509SEric W. Biederman ptrace_break(regs);
2091da177e4SLinus Torvalds return 0;
2101da177e4SLinus Torvalds }
2111da177e4SLinus Torvalds
2121da177e4SLinus Torvalds static struct undef_hook arm_break_hook = {
2131da177e4SLinus Torvalds .instr_mask = 0x0fffffff,
2141da177e4SLinus Torvalds .instr_val = 0x07f001f0,
2151da177e4SLinus Torvalds .cpsr_mask = PSR_T_BIT,
2161da177e4SLinus Torvalds .cpsr_val = 0,
2171da177e4SLinus Torvalds .fn = break_trap,
2181da177e4SLinus Torvalds };
2191da177e4SLinus Torvalds
2201da177e4SLinus Torvalds static struct undef_hook thumb_break_hook = {
2213866f217SFredrik Strupe .instr_mask = 0xffffffff,
2223866f217SFredrik Strupe .instr_val = 0x0000de01,
2231da177e4SLinus Torvalds .cpsr_mask = PSR_T_BIT,
2241da177e4SLinus Torvalds .cpsr_val = PSR_T_BIT,
2251da177e4SLinus Torvalds .fn = break_trap,
2261da177e4SLinus Torvalds };
2271da177e4SLinus Torvalds
228d23bc1b3SDaniel Jacobowitz static struct undef_hook thumb2_break_hook = {
229592201a9SJon Medhurst .instr_mask = 0xffffffff,
230592201a9SJon Medhurst .instr_val = 0xf7f0a000,
231d23bc1b3SDaniel Jacobowitz .cpsr_mask = PSR_T_BIT,
232d23bc1b3SDaniel Jacobowitz .cpsr_val = PSR_T_BIT,
233592201a9SJon Medhurst .fn = break_trap,
234d23bc1b3SDaniel Jacobowitz };
235d23bc1b3SDaniel Jacobowitz
ptrace_break_init(void)2361da177e4SLinus Torvalds static int __init ptrace_break_init(void)
2371da177e4SLinus Torvalds {
2381da177e4SLinus Torvalds register_undef_hook(&arm_break_hook);
2391da177e4SLinus Torvalds register_undef_hook(&thumb_break_hook);
240d23bc1b3SDaniel Jacobowitz register_undef_hook(&thumb2_break_hook);
2411da177e4SLinus Torvalds return 0;
2421da177e4SLinus Torvalds }
2431da177e4SLinus Torvalds
2441da177e4SLinus Torvalds core_initcall(ptrace_break_init);
2451da177e4SLinus Torvalds
2461da177e4SLinus Torvalds /*
2471da177e4SLinus Torvalds * Read the word at offset "off" into the "struct user". We
2481da177e4SLinus Torvalds * actually access the pt_regs stored on the kernel stack.
2491da177e4SLinus Torvalds */
ptrace_read_user(struct task_struct * tsk,unsigned long off,unsigned long __user * ret)2501da177e4SLinus Torvalds static int ptrace_read_user(struct task_struct *tsk, unsigned long off,
2511da177e4SLinus Torvalds unsigned long __user *ret)
2521da177e4SLinus Torvalds {
2531da177e4SLinus Torvalds unsigned long tmp;
2541da177e4SLinus Torvalds
2555a4f5da5SWill Deacon if (off & 3)
2561da177e4SLinus Torvalds return -EIO;
2571da177e4SLinus Torvalds
2581da177e4SLinus Torvalds tmp = 0;
25968b7f715SPaul Brook if (off == PT_TEXT_ADDR)
26068b7f715SPaul Brook tmp = tsk->mm->start_code;
26168b7f715SPaul Brook else if (off == PT_DATA_ADDR)
26268b7f715SPaul Brook tmp = tsk->mm->start_data;
26368b7f715SPaul Brook else if (off == PT_TEXT_END_ADDR)
26468b7f715SPaul Brook tmp = tsk->mm->end_code;
26568b7f715SPaul Brook else if (off < sizeof(struct pt_regs))
2661da177e4SLinus Torvalds tmp = get_user_reg(tsk, off >> 2);
2675a4f5da5SWill Deacon else if (off >= sizeof(struct user))
2685a4f5da5SWill Deacon return -EIO;
2691da177e4SLinus Torvalds
2701da177e4SLinus Torvalds return put_user(tmp, ret);
2711da177e4SLinus Torvalds }
2721da177e4SLinus Torvalds
2731da177e4SLinus Torvalds /*
2741da177e4SLinus Torvalds * Write the word at offset "off" into "struct user". We
2751da177e4SLinus Torvalds * actually access the pt_regs stored on the kernel stack.
2761da177e4SLinus Torvalds */
ptrace_write_user(struct task_struct * tsk,unsigned long off,unsigned long val)2771da177e4SLinus Torvalds static int ptrace_write_user(struct task_struct *tsk, unsigned long off,
2781da177e4SLinus Torvalds unsigned long val)
2791da177e4SLinus Torvalds {
2801da177e4SLinus Torvalds if (off & 3 || off >= sizeof(struct user))
2811da177e4SLinus Torvalds return -EIO;
2821da177e4SLinus Torvalds
2831da177e4SLinus Torvalds if (off >= sizeof(struct pt_regs))
2841da177e4SLinus Torvalds return 0;
2851da177e4SLinus Torvalds
2861da177e4SLinus Torvalds return put_user_reg(tsk, off >> 2, val);
2871da177e4SLinus Torvalds }
2881da177e4SLinus Torvalds
2891da177e4SLinus Torvalds #ifdef CONFIG_IWMMXT
2901da177e4SLinus Torvalds
2911da177e4SLinus Torvalds /*
2921da177e4SLinus Torvalds * Get the child iWMMXt state.
2931da177e4SLinus Torvalds */
ptrace_getwmmxregs(struct task_struct * tsk,void __user * ufp)2941da177e4SLinus Torvalds static int ptrace_getwmmxregs(struct task_struct *tsk, void __user *ufp)
2951da177e4SLinus Torvalds {
296e7c1b32fSAl Viro struct thread_info *thread = task_thread_info(tsk);
2971da177e4SLinus Torvalds
2981da177e4SLinus Torvalds if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT))
2991da177e4SLinus Torvalds return -ENODATA;
3001da177e4SLinus Torvalds iwmmxt_task_disable(thread); /* force it to ram */
301cdaabbd7SRussell King return copy_to_user(ufp, &thread->fpstate.iwmmxt, IWMMXT_SIZE)
302cdaabbd7SRussell King ? -EFAULT : 0;
3031da177e4SLinus Torvalds }
3041da177e4SLinus Torvalds
3051da177e4SLinus Torvalds /*
3061da177e4SLinus Torvalds * Set the child iWMMXt state.
3071da177e4SLinus Torvalds */
ptrace_setwmmxregs(struct task_struct * tsk,void __user * ufp)3081da177e4SLinus Torvalds static int ptrace_setwmmxregs(struct task_struct *tsk, void __user *ufp)
3091da177e4SLinus Torvalds {
310e7c1b32fSAl Viro struct thread_info *thread = task_thread_info(tsk);
3111da177e4SLinus Torvalds
3121da177e4SLinus Torvalds if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT))
3131da177e4SLinus Torvalds return -EACCES;
3141da177e4SLinus Torvalds iwmmxt_task_release(thread); /* force a reload */
31517320a96SRussell King return copy_from_user(&thread->fpstate.iwmmxt, ufp, IWMMXT_SIZE)
316cdaabbd7SRussell King ? -EFAULT : 0;
3171da177e4SLinus Torvalds }
3181da177e4SLinus Torvalds
3191da177e4SLinus Torvalds #endif
3201da177e4SLinus Torvalds
321864232faSWill Deacon #ifdef CONFIG_HAVE_HW_BREAKPOINT
322864232faSWill Deacon /*
323864232faSWill Deacon * Convert a virtual register number into an index for a thread_info
324864232faSWill Deacon * breakpoint array. Breakpoints are identified using positive numbers
325864232faSWill Deacon * whilst watchpoints are negative. The registers are laid out as pairs
326864232faSWill Deacon * of (address, control), each pair mapping to a unique hw_breakpoint struct.
327864232faSWill Deacon * Register 0 is reserved for describing resource information.
328864232faSWill Deacon */
ptrace_hbp_num_to_idx(long num)329864232faSWill Deacon static int ptrace_hbp_num_to_idx(long num)
330864232faSWill Deacon {
331864232faSWill Deacon if (num < 0)
332864232faSWill Deacon num = (ARM_MAX_BRP << 1) - num;
333864232faSWill Deacon return (num - 1) >> 1;
334864232faSWill Deacon }
335864232faSWill Deacon
336864232faSWill Deacon /*
337864232faSWill Deacon * Returns the virtual register number for the address of the
338864232faSWill Deacon * breakpoint at index idx.
339864232faSWill Deacon */
ptrace_hbp_idx_to_num(int idx)340864232faSWill Deacon static long ptrace_hbp_idx_to_num(int idx)
341864232faSWill Deacon {
342864232faSWill Deacon long mid = ARM_MAX_BRP << 1;
343864232faSWill Deacon long num = (idx << 1) + 1;
344864232faSWill Deacon return num > mid ? mid - num : num;
345864232faSWill Deacon }
346864232faSWill Deacon
347864232faSWill Deacon /*
348864232faSWill Deacon * Handle hitting a HW-breakpoint.
349864232faSWill Deacon */
ptrace_hbptriggered(struct perf_event * bp,struct perf_sample_data * data,struct pt_regs * regs)350a8b0ca17SPeter Zijlstra static void ptrace_hbptriggered(struct perf_event *bp,
351864232faSWill Deacon struct perf_sample_data *data,
352864232faSWill Deacon struct pt_regs *regs)
353864232faSWill Deacon {
354864232faSWill Deacon struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
355864232faSWill Deacon long num;
356864232faSWill Deacon int i;
357864232faSWill Deacon
358864232faSWill Deacon for (i = 0; i < ARM_MAX_HBP_SLOTS; ++i)
359864232faSWill Deacon if (current->thread.debug.hbp[i] == bp)
360864232faSWill Deacon break;
361864232faSWill Deacon
362864232faSWill Deacon num = (i == ARM_MAX_HBP_SLOTS) ? 0 : ptrace_hbp_idx_to_num(i);
363864232faSWill Deacon
364f71dd7dcSEric W. Biederman force_sig_ptrace_errno_trap((int)num, (void __user *)(bkpt->trigger));
365864232faSWill Deacon }
366864232faSWill Deacon
367864232faSWill Deacon /*
368864232faSWill Deacon * Set ptrace breakpoint pointers to zero for this task.
369864232faSWill Deacon * This is required in order to prevent child processes from unregistering
370864232faSWill Deacon * breakpoints held by their parent.
371864232faSWill Deacon */
clear_ptrace_hw_breakpoint(struct task_struct * tsk)372864232faSWill Deacon void clear_ptrace_hw_breakpoint(struct task_struct *tsk)
373864232faSWill Deacon {
374864232faSWill Deacon memset(tsk->thread.debug.hbp, 0, sizeof(tsk->thread.debug.hbp));
375864232faSWill Deacon }
376864232faSWill Deacon
377864232faSWill Deacon /*
378864232faSWill Deacon * Unregister breakpoints from this task and reset the pointers in
379864232faSWill Deacon * the thread_struct.
380864232faSWill Deacon */
flush_ptrace_hw_breakpoint(struct task_struct * tsk)381864232faSWill Deacon void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
382864232faSWill Deacon {
383864232faSWill Deacon int i;
384864232faSWill Deacon struct thread_struct *t = &tsk->thread;
385864232faSWill Deacon
386864232faSWill Deacon for (i = 0; i < ARM_MAX_HBP_SLOTS; i++) {
387864232faSWill Deacon if (t->debug.hbp[i]) {
388864232faSWill Deacon unregister_hw_breakpoint(t->debug.hbp[i]);
389864232faSWill Deacon t->debug.hbp[i] = NULL;
390864232faSWill Deacon }
391864232faSWill Deacon }
392864232faSWill Deacon }
393864232faSWill Deacon
ptrace_get_hbp_resource_info(void)394864232faSWill Deacon static u32 ptrace_get_hbp_resource_info(void)
395864232faSWill Deacon {
396864232faSWill Deacon u8 num_brps, num_wrps, debug_arch, wp_len;
397864232faSWill Deacon u32 reg = 0;
398864232faSWill Deacon
399864232faSWill Deacon num_brps = hw_breakpoint_slots(TYPE_INST);
400864232faSWill Deacon num_wrps = hw_breakpoint_slots(TYPE_DATA);
401864232faSWill Deacon debug_arch = arch_get_debug_arch();
402864232faSWill Deacon wp_len = arch_get_max_wp_len();
403864232faSWill Deacon
404864232faSWill Deacon reg |= debug_arch;
405864232faSWill Deacon reg <<= 8;
406864232faSWill Deacon reg |= wp_len;
407864232faSWill Deacon reg <<= 8;
408864232faSWill Deacon reg |= num_wrps;
409864232faSWill Deacon reg <<= 8;
410864232faSWill Deacon reg |= num_brps;
411864232faSWill Deacon
412864232faSWill Deacon return reg;
413864232faSWill Deacon }
414864232faSWill Deacon
ptrace_hbp_create(struct task_struct * tsk,int type)415864232faSWill Deacon static struct perf_event *ptrace_hbp_create(struct task_struct *tsk, int type)
416864232faSWill Deacon {
417864232faSWill Deacon struct perf_event_attr attr;
418864232faSWill Deacon
419864232faSWill Deacon ptrace_breakpoint_init(&attr);
420864232faSWill Deacon
421864232faSWill Deacon /* Initialise fields to sane defaults. */
422864232faSWill Deacon attr.bp_addr = 0;
423864232faSWill Deacon attr.bp_len = HW_BREAKPOINT_LEN_4;
424864232faSWill Deacon attr.bp_type = type;
425864232faSWill Deacon attr.disabled = 1;
426864232faSWill Deacon
4274dc0da86SAvi Kivity return register_user_hw_breakpoint(&attr, ptrace_hbptriggered, NULL,
4284dc0da86SAvi Kivity tsk);
429864232faSWill Deacon }
430864232faSWill Deacon
ptrace_gethbpregs(struct task_struct * tsk,long num,unsigned long __user * data)431864232faSWill Deacon static int ptrace_gethbpregs(struct task_struct *tsk, long num,
432864232faSWill Deacon unsigned long __user *data)
433864232faSWill Deacon {
434864232faSWill Deacon u32 reg;
435864232faSWill Deacon int idx, ret = 0;
436864232faSWill Deacon struct perf_event *bp;
437864232faSWill Deacon struct arch_hw_breakpoint_ctrl arch_ctrl;
438864232faSWill Deacon
439864232faSWill Deacon if (num == 0) {
440864232faSWill Deacon reg = ptrace_get_hbp_resource_info();
441864232faSWill Deacon } else {
442864232faSWill Deacon idx = ptrace_hbp_num_to_idx(num);
443864232faSWill Deacon if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) {
444864232faSWill Deacon ret = -EINVAL;
445864232faSWill Deacon goto out;
446864232faSWill Deacon }
447864232faSWill Deacon
448864232faSWill Deacon bp = tsk->thread.debug.hbp[idx];
449864232faSWill Deacon if (!bp) {
450864232faSWill Deacon reg = 0;
451864232faSWill Deacon goto put;
452864232faSWill Deacon }
453864232faSWill Deacon
454864232faSWill Deacon arch_ctrl = counter_arch_bp(bp)->ctrl;
455864232faSWill Deacon
456864232faSWill Deacon /*
457864232faSWill Deacon * Fix up the len because we may have adjusted it
458864232faSWill Deacon * to compensate for an unaligned address.
459864232faSWill Deacon */
460864232faSWill Deacon while (!(arch_ctrl.len & 0x1))
461864232faSWill Deacon arch_ctrl.len >>= 1;
462864232faSWill Deacon
463ba55d3dbSWill Deacon if (num & 0x1)
464864232faSWill Deacon reg = bp->attr.bp_addr;
465ba55d3dbSWill Deacon else
466ba55d3dbSWill Deacon reg = encode_ctrl_reg(arch_ctrl);
467864232faSWill Deacon }
468864232faSWill Deacon
469864232faSWill Deacon put:
470864232faSWill Deacon if (put_user(reg, data))
471864232faSWill Deacon ret = -EFAULT;
472864232faSWill Deacon
473864232faSWill Deacon out:
474864232faSWill Deacon return ret;
475864232faSWill Deacon }
476864232faSWill Deacon
ptrace_sethbpregs(struct task_struct * tsk,long num,unsigned long __user * data)477864232faSWill Deacon static int ptrace_sethbpregs(struct task_struct *tsk, long num,
478864232faSWill Deacon unsigned long __user *data)
479864232faSWill Deacon {
480864232faSWill Deacon int idx, gen_len, gen_type, implied_type, ret = 0;
481864232faSWill Deacon u32 user_val;
482864232faSWill Deacon struct perf_event *bp;
483864232faSWill Deacon struct arch_hw_breakpoint_ctrl ctrl;
484864232faSWill Deacon struct perf_event_attr attr;
485864232faSWill Deacon
486864232faSWill Deacon if (num == 0)
487864232faSWill Deacon goto out;
488864232faSWill Deacon else if (num < 0)
489864232faSWill Deacon implied_type = HW_BREAKPOINT_RW;
490864232faSWill Deacon else
491864232faSWill Deacon implied_type = HW_BREAKPOINT_X;
492864232faSWill Deacon
493864232faSWill Deacon idx = ptrace_hbp_num_to_idx(num);
494864232faSWill Deacon if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) {
495864232faSWill Deacon ret = -EINVAL;
496864232faSWill Deacon goto out;
497864232faSWill Deacon }
498864232faSWill Deacon
499864232faSWill Deacon if (get_user(user_val, data)) {
500864232faSWill Deacon ret = -EFAULT;
501864232faSWill Deacon goto out;
502864232faSWill Deacon }
503864232faSWill Deacon
504864232faSWill Deacon bp = tsk->thread.debug.hbp[idx];
505864232faSWill Deacon if (!bp) {
506864232faSWill Deacon bp = ptrace_hbp_create(tsk, implied_type);
507864232faSWill Deacon if (IS_ERR(bp)) {
508864232faSWill Deacon ret = PTR_ERR(bp);
509864232faSWill Deacon goto out;
510864232faSWill Deacon }
511864232faSWill Deacon tsk->thread.debug.hbp[idx] = bp;
512864232faSWill Deacon }
513864232faSWill Deacon
514864232faSWill Deacon attr = bp->attr;
515864232faSWill Deacon
516864232faSWill Deacon if (num & 0x1) {
517864232faSWill Deacon /* Address */
518864232faSWill Deacon attr.bp_addr = user_val;
519864232faSWill Deacon } else {
520864232faSWill Deacon /* Control */
521864232faSWill Deacon decode_ctrl_reg(user_val, &ctrl);
522864232faSWill Deacon ret = arch_bp_generic_fields(ctrl, &gen_len, &gen_type);
523864232faSWill Deacon if (ret)
524864232faSWill Deacon goto out;
525864232faSWill Deacon
526864232faSWill Deacon if ((gen_type & implied_type) != gen_type) {
527864232faSWill Deacon ret = -EINVAL;
528864232faSWill Deacon goto out;
529864232faSWill Deacon }
530864232faSWill Deacon
531864232faSWill Deacon attr.bp_len = gen_len;
532864232faSWill Deacon attr.bp_type = gen_type;
533864232faSWill Deacon attr.disabled = !ctrl.enabled;
534864232faSWill Deacon }
535864232faSWill Deacon
536864232faSWill Deacon ret = modify_user_hw_breakpoint(bp, &attr);
537864232faSWill Deacon out:
538864232faSWill Deacon return ret;
539864232faSWill Deacon }
540864232faSWill Deacon #endif
541864232faSWill Deacon
5425be6f62bSDave Martin /* regset get/set implementations */
5435be6f62bSDave Martin
gpr_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)5445be6f62bSDave Martin static int gpr_get(struct task_struct *target,
5455be6f62bSDave Martin const struct user_regset *regset,
5463598e9f0SAl Viro struct membuf to)
5475be6f62bSDave Martin {
5483598e9f0SAl Viro return membuf_write(&to, task_pt_regs(target), sizeof(struct pt_regs));
5495be6f62bSDave Martin }
5505be6f62bSDave Martin
gpr_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)5515be6f62bSDave Martin static int gpr_set(struct task_struct *target,
5525be6f62bSDave Martin const struct user_regset *regset,
5535be6f62bSDave Martin unsigned int pos, unsigned int count,
5545be6f62bSDave Martin const void *kbuf, const void __user *ubuf)
5555be6f62bSDave Martin {
5565be6f62bSDave Martin int ret;
557228dbbfbSDave Martin struct pt_regs newregs = *task_pt_regs(target);
5585be6f62bSDave Martin
5595be6f62bSDave Martin ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
5605be6f62bSDave Martin &newregs,
5615be6f62bSDave Martin 0, sizeof(newregs));
5625be6f62bSDave Martin if (ret)
5635be6f62bSDave Martin return ret;
5645be6f62bSDave Martin
5655be6f62bSDave Martin if (!valid_user_regs(&newregs))
5665be6f62bSDave Martin return -EINVAL;
5675be6f62bSDave Martin
5685be6f62bSDave Martin *task_pt_regs(target) = newregs;
5695be6f62bSDave Martin return 0;
5705be6f62bSDave Martin }
5715be6f62bSDave Martin
fpa_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)5725be6f62bSDave Martin static int fpa_get(struct task_struct *target,
5735be6f62bSDave Martin const struct user_regset *regset,
5743598e9f0SAl Viro struct membuf to)
5755be6f62bSDave Martin {
5763598e9f0SAl Viro return membuf_write(&to, &task_thread_info(target)->fpstate,
5773598e9f0SAl Viro sizeof(struct user_fp));
5785be6f62bSDave Martin }
5795be6f62bSDave Martin
fpa_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)5805be6f62bSDave Martin static int fpa_set(struct task_struct *target,
5815be6f62bSDave Martin const struct user_regset *regset,
5825be6f62bSDave Martin unsigned int pos, unsigned int count,
5835be6f62bSDave Martin const void *kbuf, const void __user *ubuf)
5845be6f62bSDave Martin {
5855be6f62bSDave Martin struct thread_info *thread = task_thread_info(target);
5865be6f62bSDave Martin
5875be6f62bSDave Martin return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
5885be6f62bSDave Martin &thread->fpstate,
5895be6f62bSDave Martin 0, sizeof(struct user_fp));
5905be6f62bSDave Martin }
5915be6f62bSDave Martin
5925be6f62bSDave Martin #ifdef CONFIG_VFP
5935be6f62bSDave Martin /*
5945be6f62bSDave Martin * VFP register get/set implementations.
5955be6f62bSDave Martin *
5965be6f62bSDave Martin * With respect to the kernel, struct user_fp is divided into three chunks:
5975be6f62bSDave Martin * 16 or 32 real VFP registers (d0-d15 or d0-31)
5985be6f62bSDave Martin * These are transferred to/from the real registers in the task's
5995be6f62bSDave Martin * vfp_hard_struct. The number of registers depends on the kernel
6005be6f62bSDave Martin * configuration.
6015be6f62bSDave Martin *
6025be6f62bSDave Martin * 16 or 0 fake VFP registers (d16-d31 or empty)
6035be6f62bSDave Martin * i.e., the user_vfp structure has space for 32 registers even if
6045be6f62bSDave Martin * the kernel doesn't have them all.
6055be6f62bSDave Martin *
6065be6f62bSDave Martin * vfp_get() reads this chunk as zero where applicable
6075be6f62bSDave Martin * vfp_set() ignores this chunk
6085be6f62bSDave Martin *
6095be6f62bSDave Martin * 1 word for the FPSCR
6105be6f62bSDave Martin */
vfp_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)6115be6f62bSDave Martin static int vfp_get(struct task_struct *target,
6125be6f62bSDave Martin const struct user_regset *regset,
6133598e9f0SAl Viro struct membuf to)
6145be6f62bSDave Martin {
6155be6f62bSDave Martin struct thread_info *thread = task_thread_info(target);
6165be6f62bSDave Martin struct vfp_hard_struct const *vfp = &thread->vfpstate.hard;
6175be6f62bSDave Martin const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr);
6185be6f62bSDave Martin
6195be6f62bSDave Martin vfp_sync_hwstate(thread);
6205be6f62bSDave Martin
6213598e9f0SAl Viro membuf_write(&to, vfp->fpregs, sizeof(vfp->fpregs));
6223598e9f0SAl Viro membuf_zero(&to, user_fpscr_offset - sizeof(vfp->fpregs));
6233598e9f0SAl Viro return membuf_store(&to, vfp->fpscr);
6245be6f62bSDave Martin }
6255be6f62bSDave Martin
6265be6f62bSDave Martin /*
6275be6f62bSDave Martin * For vfp_set() a read-modify-write is done on the VFP registers,
6285be6f62bSDave Martin * in order to avoid writing back a half-modified set of registers on
6295be6f62bSDave Martin * failure.
6305be6f62bSDave Martin */
vfp_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)6315be6f62bSDave Martin static int vfp_set(struct task_struct *target,
6325be6f62bSDave Martin const struct user_regset *regset,
6335be6f62bSDave Martin unsigned int pos, unsigned int count,
6345be6f62bSDave Martin const void *kbuf, const void __user *ubuf)
6355be6f62bSDave Martin {
6365be6f62bSDave Martin int ret;
6375be6f62bSDave Martin struct thread_info *thread = task_thread_info(target);
638247f4993SDave Martin struct vfp_hard_struct new_vfp;
6395be6f62bSDave Martin const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs);
6405be6f62bSDave Martin const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr);
6415be6f62bSDave Martin
642247f4993SDave Martin vfp_sync_hwstate(thread);
643247f4993SDave Martin new_vfp = thread->vfpstate.hard;
644247f4993SDave Martin
6455be6f62bSDave Martin ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
6465be6f62bSDave Martin &new_vfp.fpregs,
6475be6f62bSDave Martin user_fpregs_offset,
6485be6f62bSDave Martin user_fpregs_offset + sizeof(new_vfp.fpregs));
6495be6f62bSDave Martin if (ret)
6505be6f62bSDave Martin return ret;
6515be6f62bSDave Martin
652dd127cf2SSergey Shtylyov user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
6535be6f62bSDave Martin user_fpregs_offset + sizeof(new_vfp.fpregs),
6545be6f62bSDave Martin user_fpscr_offset);
6555be6f62bSDave Martin
6565be6f62bSDave Martin ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
6575be6f62bSDave Martin &new_vfp.fpscr,
6585be6f62bSDave Martin user_fpscr_offset,
6595be6f62bSDave Martin user_fpscr_offset + sizeof(new_vfp.fpscr));
6605be6f62bSDave Martin if (ret)
6615be6f62bSDave Martin return ret;
6625be6f62bSDave Martin
6638130b9d7SWill Deacon thread->vfpstate.hard = new_vfp;
664e2dfb4b8SRussell King vfp_flush_hwstate(thread);
6655be6f62bSDave Martin
6665be6f62bSDave Martin return 0;
6675be6f62bSDave Martin }
6685be6f62bSDave Martin #endif /* CONFIG_VFP */
6695be6f62bSDave Martin
6705be6f62bSDave Martin enum arm_regset {
6715be6f62bSDave Martin REGSET_GPR,
6725be6f62bSDave Martin REGSET_FPR,
6735be6f62bSDave Martin #ifdef CONFIG_VFP
6745be6f62bSDave Martin REGSET_VFP,
6755be6f62bSDave Martin #endif
6765be6f62bSDave Martin };
6775be6f62bSDave Martin
6785be6f62bSDave Martin static const struct user_regset arm_regsets[] = {
6795be6f62bSDave Martin [REGSET_GPR] = {
6805be6f62bSDave Martin .core_note_type = NT_PRSTATUS,
6815be6f62bSDave Martin .n = ELF_NGREG,
6825be6f62bSDave Martin .size = sizeof(u32),
6835be6f62bSDave Martin .align = sizeof(u32),
6843598e9f0SAl Viro .regset_get = gpr_get,
6855be6f62bSDave Martin .set = gpr_set
6865be6f62bSDave Martin },
6875be6f62bSDave Martin [REGSET_FPR] = {
6885be6f62bSDave Martin /*
6895be6f62bSDave Martin * For the FPA regs in fpstate, the real fields are a mixture
6905be6f62bSDave Martin * of sizes, so pretend that the registers are word-sized:
6915be6f62bSDave Martin */
6925be6f62bSDave Martin .core_note_type = NT_PRFPREG,
6935be6f62bSDave Martin .n = sizeof(struct user_fp) / sizeof(u32),
6945be6f62bSDave Martin .size = sizeof(u32),
6955be6f62bSDave Martin .align = sizeof(u32),
6963598e9f0SAl Viro .regset_get = fpa_get,
6975be6f62bSDave Martin .set = fpa_set
6985be6f62bSDave Martin },
6995be6f62bSDave Martin #ifdef CONFIG_VFP
7005be6f62bSDave Martin [REGSET_VFP] = {
7015be6f62bSDave Martin /*
7025be6f62bSDave Martin * Pretend that the VFP regs are word-sized, since the FPSCR is
7035be6f62bSDave Martin * a single word dangling at the end of struct user_vfp:
7045be6f62bSDave Martin */
7055be6f62bSDave Martin .core_note_type = NT_ARM_VFP,
7065be6f62bSDave Martin .n = ARM_VFPREGS_SIZE / sizeof(u32),
7075be6f62bSDave Martin .size = sizeof(u32),
7085be6f62bSDave Martin .align = sizeof(u32),
7093598e9f0SAl Viro .regset_get = vfp_get,
7105be6f62bSDave Martin .set = vfp_set
7115be6f62bSDave Martin },
7125be6f62bSDave Martin #endif /* CONFIG_VFP */
7135be6f62bSDave Martin };
7145be6f62bSDave Martin
7155be6f62bSDave Martin static const struct user_regset_view user_arm_view = {
7165be6f62bSDave Martin .name = "arm", .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI,
7175be6f62bSDave Martin .regsets = arm_regsets, .n = ARRAY_SIZE(arm_regsets)
7185be6f62bSDave Martin };
7195be6f62bSDave Martin
task_user_regset_view(struct task_struct * task)7205be6f62bSDave Martin const struct user_regset_view *task_user_regset_view(struct task_struct *task)
7215be6f62bSDave Martin {
7225be6f62bSDave Martin return &user_arm_view;
7235be6f62bSDave Martin }
7245be6f62bSDave Martin
arch_ptrace(struct task_struct * child,long request,unsigned long addr,unsigned long data)7259b05a69eSNamhyung Kim long arch_ptrace(struct task_struct *child, long request,
7269b05a69eSNamhyung Kim unsigned long addr, unsigned long data)
7271da177e4SLinus Torvalds {
7281da177e4SLinus Torvalds int ret;
729b640a0d1SNamhyung Kim unsigned long __user *datap = (unsigned long __user *) data;
7301da177e4SLinus Torvalds
7311da177e4SLinus Torvalds switch (request) {
7321da177e4SLinus Torvalds case PTRACE_PEEKUSR:
733b640a0d1SNamhyung Kim ret = ptrace_read_user(child, addr, datap);
7341da177e4SLinus Torvalds break;
7351da177e4SLinus Torvalds
7361da177e4SLinus Torvalds case PTRACE_POKEUSR:
7371da177e4SLinus Torvalds ret = ptrace_write_user(child, addr, data);
7381da177e4SLinus Torvalds break;
7391da177e4SLinus Torvalds
7401da177e4SLinus Torvalds case PTRACE_GETREGS:
7415be6f62bSDave Martin ret = copy_regset_to_user(child,
7425be6f62bSDave Martin &user_arm_view, REGSET_GPR,
7435be6f62bSDave Martin 0, sizeof(struct pt_regs),
7445be6f62bSDave Martin datap);
7451da177e4SLinus Torvalds break;
7461da177e4SLinus Torvalds
7471da177e4SLinus Torvalds case PTRACE_SETREGS:
7485be6f62bSDave Martin ret = copy_regset_from_user(child,
7495be6f62bSDave Martin &user_arm_view, REGSET_GPR,
7505be6f62bSDave Martin 0, sizeof(struct pt_regs),
7515be6f62bSDave Martin datap);
7521da177e4SLinus Torvalds break;
7531da177e4SLinus Torvalds
7541da177e4SLinus Torvalds case PTRACE_GETFPREGS:
7555be6f62bSDave Martin ret = copy_regset_to_user(child,
7565be6f62bSDave Martin &user_arm_view, REGSET_FPR,
7575be6f62bSDave Martin 0, sizeof(union fp_state),
7585be6f62bSDave Martin datap);
7591da177e4SLinus Torvalds break;
7601da177e4SLinus Torvalds
7611da177e4SLinus Torvalds case PTRACE_SETFPREGS:
7625be6f62bSDave Martin ret = copy_regset_from_user(child,
7635be6f62bSDave Martin &user_arm_view, REGSET_FPR,
7645be6f62bSDave Martin 0, sizeof(union fp_state),
7655be6f62bSDave Martin datap);
7661da177e4SLinus Torvalds break;
7671da177e4SLinus Torvalds
7681da177e4SLinus Torvalds #ifdef CONFIG_IWMMXT
7691da177e4SLinus Torvalds case PTRACE_GETWMMXREGS:
770b640a0d1SNamhyung Kim ret = ptrace_getwmmxregs(child, datap);
7711da177e4SLinus Torvalds break;
7721da177e4SLinus Torvalds
7731da177e4SLinus Torvalds case PTRACE_SETWMMXREGS:
774b640a0d1SNamhyung Kim ret = ptrace_setwmmxregs(child, datap);
7751da177e4SLinus Torvalds break;
7761da177e4SLinus Torvalds #endif
7771da177e4SLinus Torvalds
7781da177e4SLinus Torvalds case PTRACE_GET_THREAD_AREA:
779a4780adeSAndré Hentschel ret = put_user(task_thread_info(child)->tp_value[0],
780b640a0d1SNamhyung Kim datap);
7811da177e4SLinus Torvalds break;
7821da177e4SLinus Torvalds
7833f471126SNicolas Pitre case PTRACE_SET_SYSCALL:
784*4697b584SKees Cook if (data != -1)
785*4697b584SKees Cook data &= __NR_SYSCALL_MASK;
786*4697b584SKees Cook task_thread_info(child)->abi_syscall = data;
7873f471126SNicolas Pitre ret = 0;
7883f471126SNicolas Pitre break;
7893f471126SNicolas Pitre
7903d1228eaSCatalin Marinas #ifdef CONFIG_VFP
7913d1228eaSCatalin Marinas case PTRACE_GETVFPREGS:
7925be6f62bSDave Martin ret = copy_regset_to_user(child,
7935be6f62bSDave Martin &user_arm_view, REGSET_VFP,
7945be6f62bSDave Martin 0, ARM_VFPREGS_SIZE,
7955be6f62bSDave Martin datap);
7963d1228eaSCatalin Marinas break;
7973d1228eaSCatalin Marinas
7983d1228eaSCatalin Marinas case PTRACE_SETVFPREGS:
7995be6f62bSDave Martin ret = copy_regset_from_user(child,
8005be6f62bSDave Martin &user_arm_view, REGSET_VFP,
8015be6f62bSDave Martin 0, ARM_VFPREGS_SIZE,
8025be6f62bSDave Martin datap);
8033d1228eaSCatalin Marinas break;
8043d1228eaSCatalin Marinas #endif
8053d1228eaSCatalin Marinas
806864232faSWill Deacon #ifdef CONFIG_HAVE_HW_BREAKPOINT
807864232faSWill Deacon case PTRACE_GETHBPREGS:
808864232faSWill Deacon ret = ptrace_gethbpregs(child, addr,
809864232faSWill Deacon (unsigned long __user *)data);
810864232faSWill Deacon break;
811864232faSWill Deacon case PTRACE_SETHBPREGS:
812864232faSWill Deacon ret = ptrace_sethbpregs(child, addr,
813864232faSWill Deacon (unsigned long __user *)data);
814864232faSWill Deacon break;
815864232faSWill Deacon #endif
816864232faSWill Deacon
8171da177e4SLinus Torvalds default:
8181da177e4SLinus Torvalds ret = ptrace_request(child, request, addr, data);
8191da177e4SLinus Torvalds break;
8201da177e4SLinus Torvalds }
8211da177e4SLinus Torvalds
8221da177e4SLinus Torvalds return ret;
8231da177e4SLinus Torvalds }
8241da177e4SLinus Torvalds
825ad722541SWill Deacon enum ptrace_syscall_dir {
826ad722541SWill Deacon PTRACE_SYSCALL_ENTER = 0,
827ad722541SWill Deacon PTRACE_SYSCALL_EXIT,
828ad722541SWill Deacon };
829ad722541SWill Deacon
report_syscall(struct pt_regs * regs,enum ptrace_syscall_dir dir)83042da6b7eSEric W. Biederman static void report_syscall(struct pt_regs *regs, enum ptrace_syscall_dir dir)
8311da177e4SLinus Torvalds {
8321da177e4SLinus Torvalds unsigned long ip;
8331da177e4SLinus Torvalds
8346a68b6f5SWill Deacon /*
8356a68b6f5SWill Deacon * IP is used to denote syscall entry/exit:
8366a68b6f5SWill Deacon * IP = 0 -> entry, =1 -> exit
8376a68b6f5SWill Deacon */
8386a68b6f5SWill Deacon ip = regs->ARM_ip;
839ad722541SWill Deacon regs->ARM_ip = dir;
8406a68b6f5SWill Deacon
841ad722541SWill Deacon if (dir == PTRACE_SYSCALL_EXIT)
842153474baSEric W. Biederman ptrace_report_syscall_exit(regs, 0);
843153474baSEric W. Biederman else if (ptrace_report_syscall_entry(regs))
8444e57a4ddSArnd Bergmann current_thread_info()->abi_syscall = -1;
8450693bf68SWade Farnsworth
8461da177e4SLinus Torvalds regs->ARM_ip = ip;
847ad722541SWill Deacon }
8483f471126SNicolas Pitre
syscall_trace_enter(struct pt_regs * regs)8494e57a4ddSArnd Bergmann asmlinkage int syscall_trace_enter(struct pt_regs *regs)
850ad722541SWill Deacon {
8514e57a4ddSArnd Bergmann int scno;
8529b790d71SKees Cook
8530f3912fdSKees Cook if (test_thread_flag(TIF_SYSCALL_TRACE))
85442da6b7eSEric W. Biederman report_syscall(regs, PTRACE_SYSCALL_ENTER);
8550f3912fdSKees Cook
8560f3912fdSKees Cook /* Do seccomp after ptrace; syscall may have changed. */
857a4412fc9SAndy Lutomirski #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
858fefad9efSChristian Brauner if (secure_computing() == -1)
8599b790d71SKees Cook return -1;
860a4412fc9SAndy Lutomirski #else
861a4412fc9SAndy Lutomirski /* XXX: remove this once OABI gets fixed */
8624e57a4ddSArnd Bergmann secure_computing_strict(syscall_get_nr(current, regs));
863a4412fc9SAndy Lutomirski #endif
8649b790d71SKees Cook
8650f3912fdSKees Cook /* Tracer or seccomp may have changed syscall. */
8664e57a4ddSArnd Bergmann scno = syscall_get_nr(current, regs);
8679b790d71SKees Cook
8681f66e06fSWade Farnsworth if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
869ebb5e15cSWill Deacon trace_sys_enter(regs, scno);
8709b790d71SKees Cook
87191397401SEric Paris audit_syscall_entry(scno, regs->ARM_r0, regs->ARM_r1, regs->ARM_r2,
87291397401SEric Paris regs->ARM_r3);
8739b790d71SKees Cook
874ebb5e15cSWill Deacon return scno;
875ad722541SWill Deacon }
876ad722541SWill Deacon
syscall_trace_exit(struct pt_regs * regs)877b10bca0bSWill Deacon asmlinkage void syscall_trace_exit(struct pt_regs *regs)
878ad722541SWill Deacon {
879b10bca0bSWill Deacon /*
880b10bca0bSWill Deacon * Audit the syscall before anything else, as a debugger may
881b10bca0bSWill Deacon * come in and change the current registers.
882b10bca0bSWill Deacon */
8835125430cSWill Deacon audit_syscall_exit(regs);
8849b790d71SKees Cook
885b10bca0bSWill Deacon /*
886b10bca0bSWill Deacon * Note that we haven't updated the ->syscall field for the
887b10bca0bSWill Deacon * current thread. This isn't a problem because it will have
888b10bca0bSWill Deacon * been set on syscall entry and there hasn't been an opportunity
889b10bca0bSWill Deacon * for a PTRACE_SET_SYSCALL since then.
890b10bca0bSWill Deacon */
891b10bca0bSWill Deacon if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
892b10bca0bSWill Deacon trace_sys_exit(regs, regs_return_value(regs));
893b10bca0bSWill Deacon
894b10bca0bSWill Deacon if (test_thread_flag(TIF_SYSCALL_TRACE))
89542da6b7eSEric W. Biederman report_syscall(regs, PTRACE_SYSCALL_EXIT);
8961da177e4SLinus Torvalds }
897