aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arc
diff options
context:
space:
mode:
authorVineet Gupta <vgupta@synopsys.com>2013-01-18 04:42:22 -0500
committerVineet Gupta <vgupta@synopsys.com>2013-02-15 12:45:59 -0500
commit547f112571904da03589beb8434185294c77896a (patch)
tree0cf125fec3110091a208c0243173cfd150e332cd /arch/arc
parent080c37473eb671a037b3e9a315303851f0675be5 (diff)
ARC: ptrace support
Signed-off-by: Vineet Gupta <vgupta@synopsys.com> Acked-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/arc')
-rw-r--r--arch/arc/Kconfig1
-rw-r--r--arch/arc/kernel/Makefile3
-rw-r--r--arch/arc/kernel/entry.S68
-rw-r--r--arch/arc/kernel/ptrace.c136
4 files changed, 206 insertions, 2 deletions
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 03347cbde9bd..409b9378032e 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -22,6 +22,7 @@ config ARC
22 select GENERIC_PENDING_IRQ if SMP 22 select GENERIC_PENDING_IRQ if SMP
23 select GENERIC_SIGALTSTACK 23 select GENERIC_SIGALTSTACK
24 select GENERIC_SMP_IDLE_THREAD 24 select GENERIC_SMP_IDLE_THREAD
25 select HAVE_ARCH_TRACEHOOK
25 select HAVE_GENERIC_HARDIRQS 26 select HAVE_GENERIC_HARDIRQS
26 select HAVE_MEMBLOCK 27 select HAVE_MEMBLOCK
27 select IRQ_DOMAIN 28 select IRQ_DOMAIN
diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile
index c9ec0662a4ec..f4885891dabb 100644
--- a/arch/arc/kernel/Makefile
+++ b/arch/arc/kernel/Makefile
@@ -5,6 +5,9 @@
5# it under the terms of the GNU General Public License version 2 as 5# it under the terms of the GNU General Public License version 2 as
6# published by the Free Software Foundation. 6# published by the Free Software Foundation.
7 7
8# Pass UTS_MACHINE for user_regset definition
9CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
10
8obj-y := arcksyms.o setup.o irq.o time.o reset.o ptrace.o entry.o process.o 11obj-y := arcksyms.o setup.o irq.o time.o reset.o ptrace.o entry.o process.o
9obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o clk.o 12obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o clk.o
10obj-y += devtree.o 13obj-y += devtree.o
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S
index 69d0d376e28b..76697aecd165 100644
--- a/arch/arc/kernel/entry.S
+++ b/arch/arc/kernel/entry.S
@@ -7,6 +7,13 @@
7 * it under the terms of the GNU General Public License version 2 as 7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 * 9 *
10 * vineetg: Feb 2011 (ptrace low level code fixes)
11 * -traced syscall return code (r0) was not saved into pt_regs for restoring
12 * into user reg-file when traded task rets to user space.
13 * -syscalls needing arch-wrappers (mainly for passing sp as pt_regs)
14 * were not invoking post-syscall trace hook (jumping directly into
15 * ret_from_system_call)
16 *
10 * vineetg: Nov 2010: 17 * vineetg: Nov 2010:
11 * -Vector table jumps (@8 bytes) converted into branches (@4 bytes) 18 * -Vector table jumps (@8 bytes) converted into branches (@4 bytes)
12 * -To maintain the slot size of 8 bytes/vector, added nop, which is 19 * -To maintain the slot size of 8 bytes/vector, added nop, which is
@@ -347,6 +354,50 @@ ARC_ENTRY EV_Extension
347 b ret_from_exception 354 b ret_from_exception
348ARC_EXIT EV_Extension 355ARC_EXIT EV_Extension
349 356
357;######################### System Call Tracing #########################
358
359tracesys:
360 ; save EFA in case tracer wants the PC of traced task
361 ; using ERET won't work since next-PC has already committed
362 lr r12, [efa]
363 GET_CURR_TASK_FIELD_PTR TASK_THREAD, r11
364 st r12, [r11, THREAD_FAULT_ADDR]
365
366 ; PRE Sys Call Ptrace hook
367 mov r0, sp ; pt_regs needed
368 bl @syscall_trace_entry
369
370 ; Tracing code now returns the syscall num (orig or modif)
371 mov r8, r0
372
373 ; Do the Sys Call as we normally would.
374 ; Validate the Sys Call number
375 cmp r8, NR_syscalls
376 mov.hi r0, -ENOSYS
377 bhi tracesys_exit
378
379 ; Restore the sys-call args. Mere invocation of the hook abv could have
380 ; clobbered them (since they are in scratch regs). The tracer could also
381 ; have deliberately changed the syscall args: r0-r7
382 ld r0, [sp, PT_r0]
383 ld r1, [sp, PT_r1]
384 ld r2, [sp, PT_r2]
385 ld r3, [sp, PT_r3]
386 ld r4, [sp, PT_r4]
387 ld r5, [sp, PT_r5]
388 ld r6, [sp, PT_r6]
389 ld r7, [sp, PT_r7]
390 ld.as r9, [sys_call_table, r8]
391 jl [r9] ; Entry into Sys Call Handler
392
393tracesys_exit:
394 st r0, [sp, PT_r0] ; sys call return value in pt_regs
395
396 ;POST Sys Call Ptrace Hook
397 bl @syscall_trace_exit
398 b ret_from_exception ; NOT ret_from_system_call at is saves r0 which
399 ; we'd done before calling post hook above
400
350;################### Break Point TRAP ########################## 401;################### Break Point TRAP ##########################
351 402
352 ; ======= (5b) Trap is due to Break-Point ========= 403 ; ======= (5b) Trap is due to Break-Point =========
@@ -412,6 +463,11 @@ ARC_ENTRY EV_Trap
412 ; Before doing anything, return from CPU Exception Mode 463 ; Before doing anything, return from CPU Exception Mode
413 FAKE_RET_FROM_EXCPN r11 464 FAKE_RET_FROM_EXCPN r11
414 465
466 ; If syscall tracing ongoing, invoke pre-pos-hooks
467 GET_CURR_THR_INFO_FLAGS r10
468 btst r10, TIF_SYSCALL_TRACE
469 bnz tracesys ; this never comes back
470
415 ;============ This is normal System Call case ========== 471 ;============ This is normal System Call case ==========
416 ; Sys-call num shd not exceed the total system calls avail 472 ; Sys-call num shd not exceed the total system calls avail
417 cmp r8, NR_syscalls 473 cmp r8, NR_syscalls
@@ -608,6 +664,10 @@ ARC_ENTRY sys_fork_wrapper
608 bl @sys_fork 664 bl @sys_fork
609 DISCARD_CALLEE_SAVED_USER 665 DISCARD_CALLEE_SAVED_USER
610 666
667 GET_CURR_THR_INFO_FLAGS r10
668 btst r10, TIF_SYSCALL_TRACE
669 bnz tracesys_exit
670
611 b ret_from_system_call 671 b ret_from_system_call
612ARC_EXIT sys_fork_wrapper 672ARC_EXIT sys_fork_wrapper
613 673
@@ -616,6 +676,10 @@ ARC_ENTRY sys_vfork_wrapper
616 bl @sys_vfork 676 bl @sys_vfork
617 DISCARD_CALLEE_SAVED_USER 677 DISCARD_CALLEE_SAVED_USER
618 678
679 GET_CURR_THR_INFO_FLAGS r10
680 btst r10, TIF_SYSCALL_TRACE
681 bnz tracesys_exit
682
619 b ret_from_system_call 683 b ret_from_system_call
620ARC_EXIT sys_vfork_wrapper 684ARC_EXIT sys_vfork_wrapper
621 685
@@ -624,5 +688,9 @@ ARC_ENTRY sys_clone_wrapper
624 bl @sys_clone 688 bl @sys_clone
625 DISCARD_CALLEE_SAVED_USER 689 DISCARD_CALLEE_SAVED_USER
626 690
691 GET_CURR_THR_INFO_FLAGS r10
692 btst r10, TIF_SYSCALL_TRACE
693 bnz tracesys_exit
694
627 b ret_from_system_call 695 b ret_from_system_call
628ARC_EXIT sys_clone_wrapper 696ARC_EXIT sys_clone_wrapper
diff --git a/arch/arc/kernel/ptrace.c b/arch/arc/kernel/ptrace.c
index 1cf944a77f33..c6a81c58d0f3 100644
--- a/arch/arc/kernel/ptrace.c
+++ b/arch/arc/kernel/ptrace.c
@@ -7,6 +7,122 @@
7 */ 7 */
8 8
9#include <linux/ptrace.h> 9#include <linux/ptrace.h>
10#include <linux/tracehook.h>
11#include <linux/regset.h>
12#include <linux/unistd.h>
13#include <linux/elf.h>
14
15static struct callee_regs *task_callee_regs(struct task_struct *tsk)
16{
17 struct callee_regs *tmp = (struct callee_regs *)tsk->thread.callee_reg;
18 return tmp;
19}
20
21static int genregs_get(struct task_struct *target,
22 const struct user_regset *regset,
23 unsigned int pos, unsigned int count,
24 void *kbuf, void __user *ubuf)
25{
26 const struct pt_regs *ptregs = task_pt_regs(target);
27 const struct callee_regs *cregs = task_callee_regs(target);
28 int ret = 0;
29 unsigned int stop_pc_val;
30
31#define REG_O_CHUNK(START, END, PTR) \
32 if (!ret) \
33 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
34 offsetof(struct user_regs_struct, START), \
35 offsetof(struct user_regs_struct, END));
36
37#define REG_O_ONE(LOC, PTR) \
38 if (!ret) \
39 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
40 offsetof(struct user_regs_struct, LOC), \
41 offsetof(struct user_regs_struct, LOC) + 4);
42
43 REG_O_CHUNK(scratch, callee, ptregs);
44 REG_O_CHUNK(callee, efa, cregs);
45 REG_O_CHUNK(efa, stop_pc, &target->thread.fault_address);
46
47 if (!ret) {
48 if (in_brkpt_trap(ptregs)) {
49 stop_pc_val = target->thread.fault_address;
50 pr_debug("\t\tstop_pc (brk-pt)\n");
51 } else {
52 stop_pc_val = ptregs->ret;
53 pr_debug("\t\tstop_pc (others)\n");
54 }
55
56 REG_O_ONE(stop_pc, &stop_pc_val);
57 }
58
59 return ret;
60}
61
62static int genregs_set(struct task_struct *target,
63 const struct user_regset *regset,
64 unsigned int pos, unsigned int count,
65 const void *kbuf, const void __user *ubuf)
66{
67 const struct pt_regs *ptregs = task_pt_regs(target);
68 const struct callee_regs *cregs = task_callee_regs(target);
69 int ret = 0;
70
71#define REG_IN_CHUNK(FIRST, NEXT, PTR) \
72 if (!ret) \
73 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \
74 (void *)(PTR), \
75 offsetof(struct user_regs_struct, FIRST), \
76 offsetof(struct user_regs_struct, NEXT));
77
78#define REG_IN_ONE(LOC, PTR) \
79 if (!ret) \
80 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \
81 (void *)(PTR), \
82 offsetof(struct user_regs_struct, LOC), \
83 offsetof(struct user_regs_struct, LOC) + 4);
84
85#define REG_IGNORE_ONE(LOC) \
86 if (!ret) \
87 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, \
88 offsetof(struct user_regs_struct, LOC), \
89 offsetof(struct user_regs_struct, LOC) + 4);
90
91 /* TBD: disallow updates to STATUS32, orig_r8 etc*/
92 REG_IN_CHUNK(scratch, callee, ptregs); /* pt_regs[bta..orig_r8] */
93 REG_IN_CHUNK(callee, efa, cregs); /* callee_regs[r25..r13] */
94 REG_IGNORE_ONE(efa); /* efa update invalid */
95 REG_IN_ONE(stop_pc, &ptregs->ret); /* stop_pc: PC update */
96
97 return ret;
98}
99
100enum arc_getset {
101 REGSET_GENERAL,
102};
103
104static const struct user_regset arc_regsets[] = {
105 [REGSET_GENERAL] = {
106 .core_note_type = NT_PRSTATUS,
107 .n = ELF_NGREG,
108 .size = sizeof(unsigned long),
109 .align = sizeof(unsigned long),
110 .get = genregs_get,
111 .set = genregs_set,
112 }
113};
114
115static const struct user_regset_view user_arc_view = {
116 .name = UTS_MACHINE,
117 .e_machine = EM_ARCOMPACT,
118 .regsets = arc_regsets,
119 .n = ARRAY_SIZE(arc_regsets)
120};
121
122const struct user_regset_view *task_user_regset_view(struct task_struct *task)
123{
124 return &user_arc_view;
125}
10 126
11void ptrace_disable(struct task_struct *child) 127void ptrace_disable(struct task_struct *child)
12{ 128{
@@ -16,11 +132,27 @@ long arch_ptrace(struct task_struct *child, long request,
16 unsigned long addr, unsigned long data) 132 unsigned long addr, unsigned long data)
17{ 133{
18 int ret = -EIO; 134 int ret = -EIO;
135
136 pr_debug("REQ=%ld: ADDR =0x%lx, DATA=0x%lx)\n", request, addr, data);
137
138 switch (request) {
139 default:
140 ret = ptrace_request(child, request, addr, data);
141 break;
142 }
143
19 return ret; 144 return ret;
20} 145}
21 146
147asmlinkage int syscall_trace_entry(struct pt_regs *regs)
148{
149 if (tracehook_report_syscall_entry(regs))
150 return ULONG_MAX;
22 151
23const struct user_regset_view *task_user_regset_view(struct task_struct *task) 152 return regs->r8;
153}
154
155asmlinkage void syscall_trace_exit(struct pt_regs *regs)
24{ 156{
25 return (const struct user_regset_view *)NULL; 157 tracehook_report_syscall_exit(regs, 0);
26} 158}