// SPDX-License-Identifier: GPL-2.0-only /* ptrace.c: Sparc process tracing support. * * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, * and David Mosberger. * * Added Linux support -miguel (weird, eh?, the original code was meant * to emulate SunOS).
*/
/* * Called by kernel/ptrace.c when detaching.. * * Make sure single step bits etc are not set.
*/ void ptrace_disable(struct task_struct *child)
{ /* nothing to do */
}
/* To get the necessary page struct, access_process_vm() first calls * get_user_pages(). This has done a flush_dcache_page() on the * accessed page. Then our caller (copy_{to,from}_user_page()) did * to memcpy to read/write the data from that page. * * Now, the only thing we have to do is: * 1) flush the D-cache if it's possible than an illegal alias * has been created * 2) flush the I-cache if this is pre-cheetah and we did a write
*/ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, unsignedlong uaddr, void *kaddr, unsignedlong len, int write)
{
BUG_ON(len > PAGE_SIZE);
if (tlb_type == hypervisor) return;
preempt_disable();
#ifdef DCACHE_ALIASING_POSSIBLE /* If bit 13 of the kernel address we used to access the * user page is the same as the virtual address that page * is mapped to in the user's address space, we can skip the * D-cache flush.
*/ if ((uaddr ^ (unsignedlong) kaddr) & (1UL << 13)) { unsignedlong start = __pa(kaddr); unsignedlong end = start + len; unsignedlong dcache_line_size;
if (!ret &&
regwindow64_set(target, regs, &window)) return -EFAULT;
}
if (!ret && count > 0) { unsignedlong tstate;
/* TSTATE */
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&tstate,
32 * sizeof(u64),
33 * sizeof(u64)); if (!ret) { /* Only the condition codes and the "in syscall" * state can be modified in the %tstate register.
*/
tstate &= (TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
regs->tstate |= tstate;
}
}
switch (request) { case PTRACE_PEEKUSR:
ret = (addr != 0) ? -EIO : 0; break;
case PTRACE_GETREGS:
ret = copy_regset_to_user(child, &ptrace32_view,
REGSET_GENERAL, 0,
19 * sizeof(u32),
pregs); break;
case PTRACE_SETREGS:
ret = copy_regset_from_user(child, &ptrace32_view,
REGSET_GENERAL, 0,
19 * sizeof(u32),
pregs); break;
case PTRACE_GETFPREGS:
ret = copy_regset_to_user(child, &ptrace32_view,
REGSET_FP, 0,
68 * sizeof(u32),
fps); break;
case PTRACE_SETFPREGS:
ret = copy_regset_from_user(child, &ptrace32_view,
REGSET_FP, 0,
33 * sizeof(u32),
fps); break;
case PTRACE_READTEXT: case PTRACE_READDATA:
ret = ptrace_readdata(child, addr,
(char __user *)addr2, data); if (ret == data)
ret = 0; elseif (ret >= 0)
ret = -EIO; break;
case PTRACE_WRITETEXT: case PTRACE_WRITEDATA:
ret = ptrace_writedata(child, (char __user *) addr2,
addr, data); if (ret == data)
ret = 0; elseif (ret >= 0)
ret = -EIO; break;
default: if (request == PTRACE_SPARC_DETACH)
request = PTRACE_DETACH;
ret = compat_ptrace_request(child, request, addr, data); break;
}
switch (request) { case PTRACE_PEEKUSR:
ret = (addr != 0) ? -EIO : 0; break;
case PTRACE_GETREGS64:
ret = copy_regset_to_user(child, &ptrace64_view,
REGSET_GENERAL, 0,
19 * sizeof(u64),
pregs); break;
case PTRACE_SETREGS64:
ret = copy_regset_from_user(child, &ptrace64_view,
REGSET_GENERAL, 0,
19 * sizeof(u64),
pregs); break;
case PTRACE_GETFPREGS64:
ret = copy_regset_to_user(child, view, REGSET_FP,
0 * sizeof(u64),
33 * sizeof(u64),
fps); break;
case PTRACE_SETFPREGS64:
ret = copy_regset_from_user(child, view, REGSET_FP,
0 * sizeof(u64),
33 * sizeof(u64),
fps); break;
case PTRACE_READTEXT: case PTRACE_READDATA:
ret = ptrace_readdata(child, addr, addr2p, data); if (ret == data)
ret = 0; elseif (ret >= 0)
ret = -EIO; break;
case PTRACE_WRITETEXT: case PTRACE_WRITEDATA:
ret = ptrace_writedata(child, addr2p, addr, data); if (ret == data)
ret = 0; elseif (ret >= 0)
ret = -EIO; break;
default: if (request == PTRACE_SPARC_DETACH)
request = PTRACE_DETACH;
ret = ptrace_request(child, request, addr, data); break;
}
return ret;
}
asmlinkage int syscall_trace_enter(struct pt_regs *regs)
{ int ret = 0;
/* do the secure computing check first */
secure_computing_strict(regs->u_regs[UREG_G1]);
if (test_thread_flag(TIF_NOHZ))
user_exit();
if (test_thread_flag(TIF_SYSCALL_TRACE))
ret = ptrace_report_syscall_entry(regs);
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_enter(regs, regs->u_regs[UREG_G1]);
asmlinkage void syscall_trace_leave(struct pt_regs *regs)
{ if (test_thread_flag(TIF_NOHZ))
user_exit();
audit_syscall_exit(regs);
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_exit(regs, regs->u_regs[UREG_I0]);
if (test_thread_flag(TIF_SYSCALL_TRACE))
ptrace_report_syscall_exit(regs, 0);
if (test_thread_flag(TIF_NOHZ))
user_enter();
}
/** * regs_query_register_offset() - query register offset from its name * @name: the name of a register * * regs_query_register_offset() returns the offset of a register in struct * pt_regs from its name. If the name is invalid, this returns -EINVAL;
*/ int regs_query_register_offset(constchar *name)
{ conststruct pt_regs_offset *roff;
for (roff = regoffset_table; roff->name != NULL; roff++) if (!strcmp(roff->name, name)) return roff->offset; return -EINVAL;
}
/** * regs_within_kernel_stack() - check the address in the stack * @regs: pt_regs which contains kernel stack pointer. * @addr: address which is checked. * * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). * If @addr is within the kernel stack, it returns true. If not, returns false.
*/ staticinlineint regs_within_kernel_stack(struct pt_regs *regs, unsignedlong addr)
{ unsignedlong ksp = kernel_stack_pointer(regs) + STACK_BIAS; return ((addr & ~(THREAD_SIZE - 1)) ==
(ksp & ~(THREAD_SIZE - 1)));
}
/** * regs_get_kernel_stack_nth() - get Nth entry of the stack * @regs: pt_regs which contains kernel stack pointer. * @n: stack entry number. * * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which * is specified by @regs. If the @n th entry is NOT in the kernel stack, * this returns 0.
*/ unsignedlong regs_get_kernel_stack_nth(struct pt_regs *regs, unsignedint n)
{ unsignedlong ksp = kernel_stack_pointer(regs) + STACK_BIAS; unsignedlong *addr = (unsignedlong *)ksp;
addr += n; if (regs_within_kernel_stack(regs, (unsignedlong)addr)) return *addr; else return 0;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.3 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.