Hexagon: Add ptrace support
Signed-off-by: Richard Kuo <rkuo@codeaurora.org> Signed-off-by: Linas Vepstas <linas@codeaurora.org> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
71e4a47f32
commit
39e89c9fc5
35
arch/hexagon/include/asm/ptrace.h
Normal file
35
arch/hexagon/include/asm/ptrace.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Ptrace definitions for the Hexagon architecture
|
||||
*
|
||||
* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_PTRACE_H
|
||||
#define _ASM_PTRACE_H
|
||||
|
||||
#include <asm/registers.h>
|
||||
|
||||
#define instruction_pointer(regs) pt_elr(regs)
|
||||
#define user_stack_pointer(regs) ((regs)->r29)
|
||||
|
||||
#define profile_pc(regs) instruction_pointer(regs)
|
||||
|
||||
/* kprobe-based event tracer support */
|
||||
extern int regs_query_register_offset(const char *name);
|
||||
extern const char *regs_query_register_name(unsigned int offset);
|
||||
|
||||
#endif
|
180
arch/hexagon/kernel/ptrace.c
Normal file
180
arch/hexagon/kernel/ptrace.c
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Ptrace support for Hexagon
|
||||
*
|
||||
* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <generated/compile.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/regset.h>
|
||||
#include <linux/user.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/user.h>
|
||||
|
||||
static int genregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
int ret;
|
||||
unsigned int dummy;
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
|
||||
|
||||
if (!regs)
|
||||
return -EIO;
|
||||
|
||||
/* The general idea here is that the copyout must happen in
|
||||
* exactly the same order in which the userspace expects these
|
||||
* regs. Now, the sequence in userspace does not match the
|
||||
* sequence in the kernel, so everything past the 32 gprs
|
||||
* happens one at a time.
|
||||
*/
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
®s->r00, 0, 32*sizeof(unsigned long));
|
||||
|
||||
#define ONEXT(KPT_REG, USR_REG) \
|
||||
if (!ret) \
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, \
|
||||
KPT_REG, offsetof(struct user_regs_struct, USR_REG), \
|
||||
offsetof(struct user_regs_struct, USR_REG) + \
|
||||
sizeof(unsigned long));
|
||||
|
||||
/* Must be exactly same sequence as struct user_regs_struct */
|
||||
ONEXT(®s->sa0, sa0);
|
||||
ONEXT(®s->lc0, lc0);
|
||||
ONEXT(®s->sa1, sa1);
|
||||
ONEXT(®s->lc1, lc1);
|
||||
ONEXT(®s->m0, m0);
|
||||
ONEXT(®s->m1, m1);
|
||||
ONEXT(®s->usr, usr);
|
||||
ONEXT(®s->preds, p3_0);
|
||||
ONEXT(®s->gp, gp);
|
||||
ONEXT(®s->ugp, ugp);
|
||||
ONEXT(&pt_elr(regs), pc);
|
||||
dummy = pt_cause(regs);
|
||||
ONEXT(&dummy, cause);
|
||||
ONEXT(&pt_badva(regs), badva);
|
||||
|
||||
/* Pad the rest with zeros, if needed */
|
||||
if (!ret)
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
offsetof(struct user_regs_struct, pad1), -1);
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
unsigned long bucket;
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
|
||||
if (!regs)
|
||||
return -EIO;
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
®s->r00, 0, 32*sizeof(unsigned long));
|
||||
|
||||
#define INEXT(KPT_REG, USR_REG) \
|
||||
if (!ret) \
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \
|
||||
KPT_REG, offsetof(struct user_regs_struct, USR_REG), \
|
||||
offsetof(struct user_regs_struct, USR_REG) + \
|
||||
sizeof(unsigned long));
|
||||
|
||||
/* Must be exactly same sequence as struct user_regs_struct */
|
||||
INEXT(®s->sa0, sa0);
|
||||
INEXT(®s->lc0, lc0);
|
||||
INEXT(®s->sa1, sa1);
|
||||
INEXT(®s->lc1, lc1);
|
||||
INEXT(®s->m0, m0);
|
||||
INEXT(®s->m1, m1);
|
||||
INEXT(®s->usr, usr);
|
||||
INEXT(®s->preds, p3_0);
|
||||
INEXT(®s->gp, gp);
|
||||
INEXT(®s->ugp, ugp);
|
||||
INEXT(&pt_elr(regs), pc);
|
||||
|
||||
/* CAUSE and BADVA aren't writeable. */
|
||||
INEXT(&bucket, cause);
|
||||
INEXT(&bucket, badva);
|
||||
|
||||
/* Ignore the rest, if needed */
|
||||
if (!ret)
|
||||
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
||||
offsetof(struct user_regs_struct, pad1), -1);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* This is special; SP is actually restored by the VM via the
|
||||
* special event record which is set by the special trap.
|
||||
*/
|
||||
regs->hvmer.vmpsp = regs->r29;
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum hexagon_regset {
|
||||
REGSET_GENERAL,
|
||||
};
|
||||
|
||||
static const struct user_regset hexagon_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 hexagon_user_view = {
|
||||
.name = UTS_MACHINE,
|
||||
.e_machine = ELF_ARCH,
|
||||
.ei_osabi = ELF_OSABI,
|
||||
.regsets = hexagon_regsets,
|
||||
.n = ARRAY_SIZE(hexagon_regsets)
|
||||
};
|
||||
|
||||
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
|
||||
{
|
||||
return &hexagon_user_view;
|
||||
}
|
||||
|
||||
void ptrace_disable(struct task_struct *child)
|
||||
{
|
||||
/* Boilerplate - resolves to null inline if no HW single-step */
|
||||
user_disable_single_step(child);
|
||||
}
|
||||
|
||||
long arch_ptrace(struct task_struct *child, long request,
|
||||
unsigned long addr, unsigned long data)
|
||||
{
|
||||
return ptrace_request(child, request, addr, data);
|
||||
}
|
Loading…
Reference in New Issue
Block a user