123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- /*
- * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
- #include <linux/ptrace.h>
- #include <linux/tracehook.h>
- #include <linux/regset.h>
- #include <linux/unistd.h>
- #include <linux/elf.h>
- static struct callee_regs *task_callee_regs(struct task_struct *tsk)
- {
- struct callee_regs *tmp = (struct callee_regs *)tsk->thread.callee_reg;
- return tmp;
- }
- static int genregs_get(struct task_struct *target,
- const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- void *kbuf, void __user *ubuf)
- {
- const struct pt_regs *ptregs = task_pt_regs(target);
- const struct callee_regs *cregs = task_callee_regs(target);
- int ret = 0;
- unsigned int stop_pc_val;
- #define REG_O_CHUNK(START, END, PTR) \
- if (!ret) \
- ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
- offsetof(struct user_regs_struct, START), \
- offsetof(struct user_regs_struct, END));
- #define REG_O_ONE(LOC, PTR) \
- if (!ret) \
- ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
- offsetof(struct user_regs_struct, LOC), \
- offsetof(struct user_regs_struct, LOC) + 4);
- #define REG_O_ZERO(LOC) \
- if (!ret) \
- ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \
- offsetof(struct user_regs_struct, LOC), \
- offsetof(struct user_regs_struct, LOC) + 4);
- REG_O_ZERO(pad);
- REG_O_ONE(scratch.bta, &ptregs->bta);
- REG_O_ONE(scratch.lp_start, &ptregs->lp_start);
- REG_O_ONE(scratch.lp_end, &ptregs->lp_end);
- REG_O_ONE(scratch.lp_count, &ptregs->lp_count);
- REG_O_ONE(scratch.status32, &ptregs->status32);
- REG_O_ONE(scratch.ret, &ptregs->ret);
- REG_O_ONE(scratch.blink, &ptregs->blink);
- REG_O_ONE(scratch.fp, &ptregs->fp);
- REG_O_ONE(scratch.gp, &ptregs->r26);
- REG_O_ONE(scratch.r12, &ptregs->r12);
- REG_O_ONE(scratch.r11, &ptregs->r11);
- REG_O_ONE(scratch.r10, &ptregs->r10);
- REG_O_ONE(scratch.r9, &ptregs->r9);
- REG_O_ONE(scratch.r8, &ptregs->r8);
- REG_O_ONE(scratch.r7, &ptregs->r7);
- REG_O_ONE(scratch.r6, &ptregs->r6);
- REG_O_ONE(scratch.r5, &ptregs->r5);
- REG_O_ONE(scratch.r4, &ptregs->r4);
- REG_O_ONE(scratch.r3, &ptregs->r3);
- REG_O_ONE(scratch.r2, &ptregs->r2);
- REG_O_ONE(scratch.r1, &ptregs->r1);
- REG_O_ONE(scratch.r0, &ptregs->r0);
- REG_O_ONE(scratch.sp, &ptregs->sp);
- REG_O_ZERO(pad2);
- REG_O_ONE(callee.r25, &cregs->r25);
- REG_O_ONE(callee.r24, &cregs->r24);
- REG_O_ONE(callee.r23, &cregs->r23);
- REG_O_ONE(callee.r22, &cregs->r22);
- REG_O_ONE(callee.r21, &cregs->r21);
- REG_O_ONE(callee.r20, &cregs->r20);
- REG_O_ONE(callee.r19, &cregs->r19);
- REG_O_ONE(callee.r18, &cregs->r18);
- REG_O_ONE(callee.r17, &cregs->r17);
- REG_O_ONE(callee.r16, &cregs->r16);
- REG_O_ONE(callee.r15, &cregs->r15);
- REG_O_ONE(callee.r14, &cregs->r14);
- REG_O_ONE(callee.r13, &cregs->r13);
- REG_O_ONE(efa, &target->thread.fault_address);
- if (!ret) {
- if (in_brkpt_trap(ptregs)) {
- stop_pc_val = target->thread.fault_address;
- pr_debug("\t\tstop_pc (brk-pt)\n");
- } else {
- stop_pc_val = ptregs->ret;
- pr_debug("\t\tstop_pc (others)\n");
- }
- REG_O_ONE(stop_pc, &stop_pc_val);
- }
- return ret;
- }
- static int genregs_set(struct task_struct *target,
- const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- const void *kbuf, const void __user *ubuf)
- {
- const struct pt_regs *ptregs = task_pt_regs(target);
- const struct callee_regs *cregs = task_callee_regs(target);
- int ret = 0;
- #define REG_IN_CHUNK(FIRST, NEXT, PTR) \
- if (!ret) \
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \
- (void *)(PTR), \
- offsetof(struct user_regs_struct, FIRST), \
- offsetof(struct user_regs_struct, NEXT));
- #define REG_IN_ONE(LOC, PTR) \
- if (!ret) \
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \
- (void *)(PTR), \
- offsetof(struct user_regs_struct, LOC), \
- offsetof(struct user_regs_struct, LOC) + 4);
- #define REG_IGNORE_ONE(LOC) \
- if (!ret) \
- ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, \
- offsetof(struct user_regs_struct, LOC), \
- offsetof(struct user_regs_struct, LOC) + 4);
- REG_IGNORE_ONE(pad);
- REG_IN_ONE(scratch.bta, &ptregs->bta);
- REG_IN_ONE(scratch.lp_start, &ptregs->lp_start);
- REG_IN_ONE(scratch.lp_end, &ptregs->lp_end);
- REG_IN_ONE(scratch.lp_count, &ptregs->lp_count);
- REG_IGNORE_ONE(scratch.status32);
- REG_IN_ONE(scratch.ret, &ptregs->ret);
- REG_IN_ONE(scratch.blink, &ptregs->blink);
- REG_IN_ONE(scratch.fp, &ptregs->fp);
- REG_IN_ONE(scratch.gp, &ptregs->r26);
- REG_IN_ONE(scratch.r12, &ptregs->r12);
- REG_IN_ONE(scratch.r11, &ptregs->r11);
- REG_IN_ONE(scratch.r10, &ptregs->r10);
- REG_IN_ONE(scratch.r9, &ptregs->r9);
- REG_IN_ONE(scratch.r8, &ptregs->r8);
- REG_IN_ONE(scratch.r7, &ptregs->r7);
- REG_IN_ONE(scratch.r6, &ptregs->r6);
- REG_IN_ONE(scratch.r5, &ptregs->r5);
- REG_IN_ONE(scratch.r4, &ptregs->r4);
- REG_IN_ONE(scratch.r3, &ptregs->r3);
- REG_IN_ONE(scratch.r2, &ptregs->r2);
- REG_IN_ONE(scratch.r1, &ptregs->r1);
- REG_IN_ONE(scratch.r0, &ptregs->r0);
- REG_IN_ONE(scratch.sp, &ptregs->sp);
- REG_IGNORE_ONE(pad2);
- REG_IN_ONE(callee.r25, &cregs->r25);
- REG_IN_ONE(callee.r24, &cregs->r24);
- REG_IN_ONE(callee.r23, &cregs->r23);
- REG_IN_ONE(callee.r22, &cregs->r22);
- REG_IN_ONE(callee.r21, &cregs->r21);
- REG_IN_ONE(callee.r20, &cregs->r20);
- REG_IN_ONE(callee.r19, &cregs->r19);
- REG_IN_ONE(callee.r18, &cregs->r18);
- REG_IN_ONE(callee.r17, &cregs->r17);
- REG_IN_ONE(callee.r16, &cregs->r16);
- REG_IN_ONE(callee.r15, &cregs->r15);
- REG_IN_ONE(callee.r14, &cregs->r14);
- REG_IN_ONE(callee.r13, &cregs->r13);
- REG_IGNORE_ONE(efa); /* efa update invalid */
- REG_IGNORE_ONE(stop_pc); /* PC updated via @ret */
- return ret;
- }
- enum arc_getset {
- REGSET_GENERAL,
- };
- static const struct user_regset arc_regsets[] = {
- [REGSET_GENERAL] = {
- .core_note_type = NT_PRSTATUS,
- .n = ELF_NGREG,
- .size = sizeof(unsigned long),
- .align = sizeof(unsigned long),
- .get = genregs_get,
- .set = genregs_set,
- }
- };
- static const struct user_regset_view user_arc_view = {
- .name = UTS_MACHINE,
- .e_machine = EM_ARC_INUSE,
- .regsets = arc_regsets,
- .n = ARRAY_SIZE(arc_regsets)
- };
- const struct user_regset_view *task_user_regset_view(struct task_struct *task)
- {
- return &user_arc_view;
- }
- void ptrace_disable(struct task_struct *child)
- {
- }
- long arch_ptrace(struct task_struct *child, long request,
- unsigned long addr, unsigned long data)
- {
- int ret = -EIO;
- pr_debug("REQ=%ld: ADDR =0x%lx, DATA=0x%lx)\n", request, addr, data);
- switch (request) {
- case PTRACE_GET_THREAD_AREA:
- ret = put_user(task_thread_info(child)->thr_ptr,
- (unsigned long __user *)data);
- break;
- default:
- ret = ptrace_request(child, request, addr, data);
- break;
- }
- return ret;
- }
- asmlinkage int syscall_trace_entry(struct pt_regs *regs)
- {
- if (tracehook_report_syscall_entry(regs))
- return ULONG_MAX;
- return regs->r8;
- }
- asmlinkage void syscall_trace_exit(struct pt_regs *regs)
- {
- tracehook_report_syscall_exit(regs, 0);
- }
|