Commit e5ad95ce9b8d7efc443d39a7bbc4e55b7a4593f1

Authored by Jonas Bonn
1 parent f8c4a270d9

OpenRISC: PTrace

This patch implements minimal PTrace support.  The pt_regs structure is
not exported to userspace for OpenRISC; rather, the GETREGSET mechanism
is intended to be used and the registers, as such, exported in the core
dump format which is ABI stable.  This is in line with what is intended
for new architectures as of 2.6.34 and has the advantage of permitting
the layout of the registers on the kernel stack (as per pt_regs) to be
freely modified.

Signed-off-by: Jonas Bonn <jonas@southpole.se>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>

Showing 2 changed files with 342 additions and 0 deletions Side-by-side Diff

arch/openrisc/include/asm/ptrace.h
  1 +/*
  2 + * OpenRISC Linux
  3 + *
  4 + * Linux architectural port borrowing liberally from similar works of
  5 + * others. All original copyrights apply as per the original source
  6 + * declaration.
  7 + *
  8 + * OpenRISC implementation:
  9 + * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
  10 + * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
  11 + * et al.
  12 + *
  13 + * This program is free software; you can redistribute it and/or modify
  14 + * it under the terms of the GNU General Public License as published by
  15 + * the Free Software Foundation; either version 2 of the License, or
  16 + * (at your option) any later version.
  17 + */
  18 +
  19 +#ifndef __ASM_OPENRISC_PTRACE_H
  20 +#define __ASM_OPENRISC_PTRACE_H
  21 +
  22 +#include <asm/spr_defs.h>
  23 +
  24 +#ifndef __ASSEMBLY__
  25 +/*
  26 + * This is the layout of the regset returned by the GETREGSET ptrace call
  27 + */
  28 +struct user_regs_struct {
  29 + /* GPR R0-R31... */
  30 + unsigned long gpr[32];
  31 + unsigned long pc;
  32 + unsigned long sr;
  33 + unsigned long pad1;
  34 + unsigned long pad2;
  35 +};
  36 +#endif
  37 +
  38 +#ifdef __KERNEL__
  39 +
  40 +/*
  41 + * Make kernel PTrace/register structures opaque to userspace... userspace can
  42 + * access thread state via the regset mechanism. This allows us a bit of
  43 + * flexibility in how we order the registers on the stack, permitting some
  44 + * optimizations like packing call-clobbered registers together so that
  45 + * they share a cacheline (not done yet, though... future optimization).
  46 + */
  47 +
  48 +#ifndef __ASSEMBLY__
  49 +/*
  50 + * This struct describes how the registers are laid out on the kernel stack
  51 + * during a syscall or other kernel entry.
  52 + *
  53 + * This structure should always be cacheline aligned on the stack.
  54 + * FIXME: I don't think that's the case right now. The alignment is
  55 + * taken care of elsewhere... head.S, process.c, etc.
  56 + */
  57 +
  58 +struct pt_regs {
  59 + union {
  60 + struct {
  61 + /* Named registers */
  62 + long sr; /* Stored in place of r0 */
  63 + long sp; /* r1 */
  64 + };
  65 + struct {
  66 + /* Old style */
  67 + long offset[2];
  68 + long gprs[30];
  69 + };
  70 + struct {
  71 + /* New style */
  72 + long gpr[32];
  73 + };
  74 + };
  75 + long pc;
  76 + long orig_gpr11; /* For restarting system calls */
  77 + long syscallno; /* Syscall number (used by strace) */
  78 + long dummy; /* Cheap alignment fix */
  79 +};
  80 +#endif /* __ASSEMBLY__ */
  81 +
  82 +/* TODO: Rename this to REDZONE because that's what it is */
  83 +#define STACK_FRAME_OVERHEAD 128 /* size of minimum stack frame */
  84 +
  85 +#define instruction_pointer(regs) ((regs)->pc)
  86 +#define user_mode(regs) (((regs)->sr & SPR_SR_SM) == 0)
  87 +#define user_stack_pointer(regs) ((unsigned long)(regs)->sp)
  88 +#define profile_pc(regs) instruction_pointer(regs)
  89 +
  90 +/*
  91 + * Offsets used by 'ptrace' system call interface.
  92 + */
  93 +#define PT_SR 0
  94 +#define PT_SP 4
  95 +#define PT_GPR2 8
  96 +#define PT_GPR3 12
  97 +#define PT_GPR4 16
  98 +#define PT_GPR5 20
  99 +#define PT_GPR6 24
  100 +#define PT_GPR7 28
  101 +#define PT_GPR8 32
  102 +#define PT_GPR9 36
  103 +#define PT_GPR10 40
  104 +#define PT_GPR11 44
  105 +#define PT_GPR12 48
  106 +#define PT_GPR13 52
  107 +#define PT_GPR14 56
  108 +#define PT_GPR15 60
  109 +#define PT_GPR16 64
  110 +#define PT_GPR17 68
  111 +#define PT_GPR18 72
  112 +#define PT_GPR19 76
  113 +#define PT_GPR20 80
  114 +#define PT_GPR21 84
  115 +#define PT_GPR22 88
  116 +#define PT_GPR23 92
  117 +#define PT_GPR24 96
  118 +#define PT_GPR25 100
  119 +#define PT_GPR26 104
  120 +#define PT_GPR27 108
  121 +#define PT_GPR28 112
  122 +#define PT_GPR29 116
  123 +#define PT_GPR30 120
  124 +#define PT_GPR31 124
  125 +#define PT_PC 128
  126 +#define PT_ORIG_GPR11 132
  127 +#define PT_SYSCALLNO 136
  128 +
  129 +#endif /* __KERNEL__ */
  130 +
  131 +#endif /* __ASM_OPENRISC_PTRACE_H */
arch/openrisc/kernel/ptrace.c
  1 +/*
  2 + * OpenRISC ptrace.c
  3 + *
  4 + * Linux architectural port borrowing liberally from similar works of
  5 + * others. All original copyrights apply as per the original source
  6 + * declaration.
  7 + *
  8 + * Modifications for the OpenRISC architecture:
  9 + * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
  10 + * Copyright (C) 2005 Gyorgy Jeney <nog@bsemi.com>
  11 + * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
  12 + *
  13 + * This program is free software; you can redistribute it and/or
  14 + * modify it under the terms of the GNU General Public License
  15 + * as published by the Free Software Foundation; either version
  16 + * 2 of the License, or (at your option) any later version.
  17 + */
  18 +
  19 +#include <stddef.h>
  20 +#include <linux/kernel.h>
  21 +#include <linux/sched.h>
  22 +#include <linux/string.h>
  23 +
  24 +#include <linux/mm.h>
  25 +#include <linux/errno.h>
  26 +#include <linux/ptrace.h>
  27 +#include <linux/audit.h>
  28 +#include <linux/regset.h>
  29 +#include <linux/tracehook.h>
  30 +#include <linux/elf.h>
  31 +
  32 +#include <asm/thread_info.h>
  33 +#include <asm/segment.h>
  34 +#include <asm/page.h>
  35 +#include <asm/pgtable.h>
  36 +#include <asm/system.h>
  37 +
  38 +/*
  39 + * Copy the thread state to a regset that can be interpreted by userspace.
  40 + *
  41 + * It doesn't matter what our internal pt_regs structure looks like. The
  42 + * important thing is that we export a consistent view of the thread state
  43 + * to userspace. As such, we need to make sure that the regset remains
  44 + * ABI compatible as defined by the struct user_regs_struct:
  45 + *
  46 + * (Each item is a 32-bit word)
  47 + * r0 = 0 (exported for clarity)
  48 + * 31 GPRS r1-r31
  49 + * PC (Program counter)
  50 + * SR (Supervision register)
  51 + */
  52 +static int genregs_get(struct task_struct *target,
  53 + const struct user_regset *regset,
  54 + unsigned int pos, unsigned int count,
  55 + void *kbuf, void __user * ubuf)
  56 +{
  57 + const struct pt_regs *regs = task_pt_regs(target);
  58 + int ret;
  59 +
  60 + /* r0 */
  61 + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 0, 4);
  62 +
  63 + if (!ret)
  64 + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  65 + regs->gpr+1, 4, 4*32);
  66 + if (!ret)
  67 + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  68 + &regs->pc, 4*32, 4*33);
  69 + if (!ret)
  70 + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  71 + &regs->sr, 4*33, 4*34);
  72 + if (!ret)
  73 + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
  74 + 4*34, -1);
  75 +
  76 + return ret;
  77 +}
  78 +
  79 +/*
  80 + * Set the thread state from a regset passed in via ptrace
  81 + */
  82 +static int genregs_set(struct task_struct *target,
  83 + const struct user_regset *regset,
  84 + unsigned int pos, unsigned int count,
  85 + const void *kbuf, const void __user * ubuf)
  86 +{
  87 + struct pt_regs *regs = task_pt_regs(target);
  88 + int ret;
  89 +
  90 + /* ignore r0 */
  91 + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, 4);
  92 + /* r1 - r31 */
  93 + if (!ret)
  94 + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  95 + regs->gpr+1, 4, 4*32);
  96 + /* PC */
  97 + if (!ret)
  98 + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  99 + &regs->pc, 4*32, 4*33);
  100 + /*
  101 + * Skip SR and padding... userspace isn't allowed to changes bits in
  102 + * the Supervision register
  103 + */
  104 + if (!ret)
  105 + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
  106 + 4*33, -1);
  107 +
  108 + return ret;
  109 +}
  110 +
  111 +/*
  112 + * Define the register sets available on OpenRISC under Linux
  113 + */
  114 +enum or1k_regset {
  115 + REGSET_GENERAL,
  116 +};
  117 +
  118 +static const struct user_regset or1k_regsets[] = {
  119 + [REGSET_GENERAL] = {
  120 + .core_note_type = NT_PRSTATUS,
  121 + .n = ELF_NGREG,
  122 + .size = sizeof(long),
  123 + .align = sizeof(long),
  124 + .get = genregs_get,
  125 + .set = genregs_set,
  126 + },
  127 +};
  128 +
  129 +static const struct user_regset_view user_or1k_native_view = {
  130 + .name = "or1k",
  131 + .e_machine = EM_OPENRISC,
  132 + .regsets = or1k_regsets,
  133 + .n = ARRAY_SIZE(or1k_regsets),
  134 +};
  135 +
  136 +const struct user_regset_view *task_user_regset_view(struct task_struct *task)
  137 +{
  138 + return &user_or1k_native_view;
  139 +}
  140 +
  141 +/*
  142 + * does not yet catch signals sent when the child dies.
  143 + * in exit.c or in signal.c.
  144 + */
  145 +
  146 +
  147 +/*
  148 + * Called by kernel/ptrace.c when detaching..
  149 + *
  150 + * Make sure the single step bit is not set.
  151 + */
  152 +void ptrace_disable(struct task_struct *child)
  153 +{
  154 + pr_debug("ptrace_disable(): TODO\n");
  155 +
  156 + user_disable_single_step(child);
  157 + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
  158 +}
  159 +
  160 +long arch_ptrace(struct task_struct *child, long request, unsigned long addr,
  161 + unsigned long data)
  162 +{
  163 + int ret;
  164 +
  165 + switch (request) {
  166 + default:
  167 + ret = ptrace_request(child, request, addr, data);
  168 + break;
  169 + }
  170 +
  171 + return ret;
  172 +}
  173 +
  174 +/*
  175 + * Notification of system call entry/exit
  176 + * - triggered by current->work.syscall_trace
  177 + */
  178 +asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
  179 +{
  180 + long ret = 0;
  181 +
  182 + if (test_thread_flag(TIF_SYSCALL_TRACE) &&
  183 + tracehook_report_syscall_entry(regs))
  184 + /*
  185 + * Tracing decided this syscall should not happen.
  186 + * We'll return a bogus call number to get an ENOSYS
  187 + * error, but leave the original number in <something>.
  188 + */
  189 + ret = -1L;
  190 +
  191 + /* Are these regs right??? */
  192 + if (unlikely(current->audit_context))
  193 + audit_syscall_entry(audit_arch(), regs->syscallno,
  194 + regs->gpr[3], regs->gpr[4],
  195 + regs->gpr[5], regs->gpr[6]);
  196 +
  197 + return ret ? : regs->syscallno;
  198 +}
  199 +
  200 +asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
  201 +{
  202 + int step;
  203 +
  204 + if (unlikely(current->audit_context))
  205 + audit_syscall_exit(AUDITSC_RESULT(regs->gpr[11]),
  206 + regs->gpr[11]);
  207 +
  208 + step = test_thread_flag(TIF_SINGLESTEP);
  209 + if (step || test_thread_flag(TIF_SYSCALL_TRACE))
  210 + tracehook_report_syscall_exit(regs, step);
  211 +}