Merge branches 'frv' and 'mn10300'
* frv: FRV: Implement new-style ptrace FRV: Don't turn on TIF_SYSCALL_TRACE unconditionally in syscall prologue FRV: Implement TIF_NOTIFY_RESUME FRV: Remove in-kernel strace code FRV: BUG to BUG_ON changes FRV: bitops: Change the bitmap index from int to unsigned long * mn10300: MN10300: Add utrace/tracehooks support MN10300: Don't set the dirty bit in the DTLB entries in the TLB-miss handler
This commit is contained in:
Коммит
59c288ffb6
|
@ -6,6 +6,7 @@ config FRV
|
|||
bool
|
||||
default y
|
||||
select HAVE_IDE
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
|
||||
config ZONE_DMA
|
||||
bool
|
||||
|
|
|
@ -112,7 +112,7 @@ extern unsigned long atomic_test_and_XOR_mask(unsigned long mask, volatile unsig
|
|||
#define atomic_clear_mask(mask, v) atomic_test_and_ANDNOT_mask((mask), (v))
|
||||
#define atomic_set_mask(mask, v) atomic_test_and_OR_mask((mask), (v))
|
||||
|
||||
static inline int test_and_clear_bit(int nr, volatile void *addr)
|
||||
static inline int test_and_clear_bit(unsigned long nr, volatile void *addr)
|
||||
{
|
||||
volatile unsigned long *ptr = addr;
|
||||
unsigned long mask = 1UL << (nr & 31);
|
||||
|
@ -120,7 +120,7 @@ static inline int test_and_clear_bit(int nr, volatile void *addr)
|
|||
return (atomic_test_and_ANDNOT_mask(mask, ptr) & mask) != 0;
|
||||
}
|
||||
|
||||
static inline int test_and_set_bit(int nr, volatile void *addr)
|
||||
static inline int test_and_set_bit(unsigned long nr, volatile void *addr)
|
||||
{
|
||||
volatile unsigned long *ptr = addr;
|
||||
unsigned long mask = 1UL << (nr & 31);
|
||||
|
@ -128,7 +128,7 @@ static inline int test_and_set_bit(int nr, volatile void *addr)
|
|||
return (atomic_test_and_OR_mask(mask, ptr) & mask) != 0;
|
||||
}
|
||||
|
||||
static inline int test_and_change_bit(int nr, volatile void *addr)
|
||||
static inline int test_and_change_bit(unsigned long nr, volatile void *addr)
|
||||
{
|
||||
volatile unsigned long *ptr = addr;
|
||||
unsigned long mask = 1UL << (nr & 31);
|
||||
|
@ -136,22 +136,22 @@ static inline int test_and_change_bit(int nr, volatile void *addr)
|
|||
return (atomic_test_and_XOR_mask(mask, ptr) & mask) != 0;
|
||||
}
|
||||
|
||||
static inline void clear_bit(int nr, volatile void *addr)
|
||||
static inline void clear_bit(unsigned long nr, volatile void *addr)
|
||||
{
|
||||
test_and_clear_bit(nr, addr);
|
||||
}
|
||||
|
||||
static inline void set_bit(int nr, volatile void *addr)
|
||||
static inline void set_bit(unsigned long nr, volatile void *addr)
|
||||
{
|
||||
test_and_set_bit(nr, addr);
|
||||
}
|
||||
|
||||
static inline void change_bit(int nr, volatile void * addr)
|
||||
static inline void change_bit(unsigned long nr, volatile void *addr)
|
||||
{
|
||||
test_and_change_bit(nr, addr);
|
||||
}
|
||||
|
||||
static inline void __clear_bit(int nr, volatile void * addr)
|
||||
static inline void __clear_bit(unsigned long nr, volatile void *addr)
|
||||
{
|
||||
volatile unsigned long *a = addr;
|
||||
int mask;
|
||||
|
@ -161,7 +161,7 @@ static inline void __clear_bit(int nr, volatile void * addr)
|
|||
*a &= ~mask;
|
||||
}
|
||||
|
||||
static inline void __set_bit(int nr, volatile void * addr)
|
||||
static inline void __set_bit(unsigned long nr, volatile void *addr)
|
||||
{
|
||||
volatile unsigned long *a = addr;
|
||||
int mask;
|
||||
|
@ -171,7 +171,7 @@ static inline void __set_bit(int nr, volatile void * addr)
|
|||
*a |= mask;
|
||||
}
|
||||
|
||||
static inline void __change_bit(int nr, volatile void *addr)
|
||||
static inline void __change_bit(unsigned long nr, volatile void *addr)
|
||||
{
|
||||
volatile unsigned long *a = addr;
|
||||
int mask;
|
||||
|
@ -181,7 +181,7 @@ static inline void __change_bit(int nr, volatile void *addr)
|
|||
*a ^= mask;
|
||||
}
|
||||
|
||||
static inline int __test_and_clear_bit(int nr, volatile void * addr)
|
||||
static inline int __test_and_clear_bit(unsigned long nr, volatile void *addr)
|
||||
{
|
||||
volatile unsigned long *a = addr;
|
||||
int mask, retval;
|
||||
|
@ -193,7 +193,7 @@ static inline int __test_and_clear_bit(int nr, volatile void * addr)
|
|||
return retval;
|
||||
}
|
||||
|
||||
static inline int __test_and_set_bit(int nr, volatile void * addr)
|
||||
static inline int __test_and_set_bit(unsigned long nr, volatile void *addr)
|
||||
{
|
||||
volatile unsigned long *a = addr;
|
||||
int mask, retval;
|
||||
|
@ -205,7 +205,7 @@ static inline int __test_and_set_bit(int nr, volatile void * addr)
|
|||
return retval;
|
||||
}
|
||||
|
||||
static inline int __test_and_change_bit(int nr, volatile void * addr)
|
||||
static inline int __test_and_change_bit(unsigned long nr, volatile void *addr)
|
||||
{
|
||||
volatile unsigned long *a = addr;
|
||||
int mask, retval;
|
||||
|
@ -220,12 +220,13 @@ static inline int __test_and_change_bit(int nr, volatile void * addr)
|
|||
/*
|
||||
* This routine doesn't need to be atomic.
|
||||
*/
|
||||
static inline int __constant_test_bit(int nr, const volatile void * addr)
|
||||
static inline int
|
||||
__constant_test_bit(unsigned long nr, const volatile void *addr)
|
||||
{
|
||||
return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
|
||||
}
|
||||
|
||||
static inline int __test_bit(int nr, const volatile void * addr)
|
||||
static inline int __test_bit(unsigned long nr, const volatile void *addr)
|
||||
{
|
||||
int * a = (int *) addr;
|
||||
int mask;
|
||||
|
|
|
@ -116,6 +116,7 @@ do { \
|
|||
} while(0)
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
#define CORE_DUMP_USE_REGSET
|
||||
#define ELF_FDPIC_CORE_EFLAGS EF_FRV_FDPIC
|
||||
#define ELF_EXEC_PAGESIZE 16384
|
||||
|
||||
|
|
|
@ -87,8 +87,7 @@ static inline void pci_dma_sync_single(struct pci_dev *hwdev,
|
|||
dma_addr_t dma_handle,
|
||||
size_t size, int direction)
|
||||
{
|
||||
if (direction == PCI_DMA_NONE)
|
||||
BUG();
|
||||
BUG_ON(direction == PCI_DMA_NONE);
|
||||
|
||||
frv_cache_wback_inv((unsigned long)bus_to_virt(dma_handle),
|
||||
(unsigned long)bus_to_virt(dma_handle) + size);
|
||||
|
@ -105,9 +104,7 @@ static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
|
|||
int nelems, int direction)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (direction == PCI_DMA_NONE)
|
||||
BUG();
|
||||
BUG_ON(direction == PCI_DMA_NONE);
|
||||
|
||||
for (i = 0; i < nelems; i++)
|
||||
frv_cache_wback_inv(sg_dma_address(&sg[i]),
|
||||
|
|
|
@ -65,6 +65,8 @@
|
|||
#ifdef __KERNEL__
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
struct task_struct;
|
||||
|
||||
/*
|
||||
* we dedicate GR28 to keeping a pointer to the current exception frame
|
||||
* - gr28 is destroyed on entry to the kernel from userspace
|
||||
|
@ -73,11 +75,18 @@ register struct pt_regs *__frame asm("gr28");
|
|||
|
||||
#define user_mode(regs) (!((regs)->psr & PSR_S))
|
||||
#define instruction_pointer(regs) ((regs)->pc)
|
||||
#define user_stack_pointer(regs) ((regs)->sp)
|
||||
|
||||
extern unsigned long user_stack(const struct pt_regs *);
|
||||
extern void show_regs(struct pt_regs *);
|
||||
#define profile_pc(regs) ((regs)->pc)
|
||||
#endif
|
||||
|
||||
#define task_pt_regs(task) ((task)->thread.frame0)
|
||||
|
||||
#define arch_has_single_step() (1)
|
||||
extern void user_enable_single_step(struct task_struct *);
|
||||
extern void user_disable_single_step(struct task_struct *);
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _ASM_PTRACE_H */
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/* syscall parameter access functions
|
||||
*
|
||||
* Copyright (C) 2009 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public Licence
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the Licence, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_SYSCALL_H
|
||||
#define _ASM_SYSCALL_H
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
/*
|
||||
* Get the system call number or -1
|
||||
*/
|
||||
static inline long syscall_get_nr(struct task_struct *task,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
return regs->syscallno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore the clobbered GR8 register
|
||||
* (1st syscall arg was overwritten with syscall return or error)
|
||||
*/
|
||||
static inline void syscall_rollback(struct task_struct *task,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
regs->gr8 = regs->orig_gr8;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the syscall return value is an error, returning it if it is and 0 if
|
||||
* not
|
||||
*/
|
||||
static inline long syscall_get_error(struct task_struct *task,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
return IS_ERR_VALUE(regs->gr8) ? regs->gr8 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the syscall return value
|
||||
*/
|
||||
static inline long syscall_get_return_value(struct task_struct *task,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
return regs->gr8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the syscall return value
|
||||
*/
|
||||
static inline void syscall_set_return_value(struct task_struct *task,
|
||||
struct pt_regs *regs,
|
||||
int error, long val)
|
||||
{
|
||||
if (error)
|
||||
regs->gr8 = -error;
|
||||
else
|
||||
regs->gr8 = val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the system call arguments
|
||||
*/
|
||||
static inline void syscall_get_arguments(struct task_struct *task,
|
||||
struct pt_regs *regs,
|
||||
unsigned int i, unsigned int n,
|
||||
unsigned long *args)
|
||||
{
|
||||
/*
|
||||
* Do this simply for now. If we need to start supporting
|
||||
* fetching arguments from arbitrary indices, this will need some
|
||||
* extra logic. Presently there are no in-tree users that depend
|
||||
* on this behaviour.
|
||||
*/
|
||||
BUG_ON(i);
|
||||
|
||||
/* Argument pattern is: GR8, GR9, GR10, GR11, GR12, GR13 */
|
||||
switch (n) {
|
||||
case 6: args[5] = regs->gr13;
|
||||
case 5: args[4] = regs->gr12;
|
||||
case 4: args[3] = regs->gr11;
|
||||
case 3: args[2] = regs->gr10;
|
||||
case 2: args[1] = regs->gr9;
|
||||
case 1: args[0] = regs->gr8;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Alter the system call arguments
|
||||
*/
|
||||
static inline void syscall_set_arguments(struct task_struct *task,
|
||||
struct pt_regs *regs,
|
||||
unsigned int i, unsigned int n,
|
||||
const unsigned long *args)
|
||||
{
|
||||
/* Same note as above applies */
|
||||
BUG_ON(i);
|
||||
|
||||
switch (n) {
|
||||
case 6: regs->gr13 = args[5];
|
||||
case 5: regs->gr12 = args[4];
|
||||
case 4: regs->gr11 = args[3];
|
||||
case 3: regs->gr10 = args[2];
|
||||
case 2: regs->gr9 = args[1];
|
||||
case 1: regs->gr8 = args[0];
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _ASM_SYSCALL_H */
|
|
@ -109,20 +109,20 @@ register struct thread_info *__current_thread_info asm("gr15");
|
|||
* - other flags in MSW
|
||||
*/
|
||||
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
|
||||
#define TIF_SIGPENDING 1 /* signal pending */
|
||||
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
|
||||
#define TIF_SINGLESTEP 3 /* restore singlestep on return to user mode */
|
||||
#define TIF_IRET 4 /* return with iret */
|
||||
#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */
|
||||
#define TIF_SIGPENDING 2 /* signal pending */
|
||||
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
|
||||
#define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */
|
||||
#define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */
|
||||
#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
|
||||
#define TIF_MEMDIE 17 /* OOM killer killed process */
|
||||
#define TIF_FREEZE 18 /* freezing for suspend */
|
||||
|
||||
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
|
||||
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
|
||||
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
|
||||
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
|
||||
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
|
||||
#define _TIF_IRET (1 << TIF_IRET)
|
||||
#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
|
||||
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
|
||||
#define _TIF_FREEZE (1 << TIF_FREEZE)
|
||||
|
|
|
@ -886,7 +886,6 @@ system_call:
|
|||
bnc icc0,#0,__syscall_badsys
|
||||
|
||||
ldi @(gr15,#TI_FLAGS),gr4
|
||||
ori gr4,#_TIF_SYSCALL_TRACE,gr4
|
||||
andicc gr4,#_TIF_SYSCALL_TRACE,gr0,icc0
|
||||
bne icc0,#0,__syscall_trace_entry
|
||||
|
||||
|
@ -1150,11 +1149,10 @@ __entry_work_notifysig:
|
|||
# perform syscall entry tracing
|
||||
__syscall_trace_entry:
|
||||
LEDS 0x6320
|
||||
setlos.p #0,gr8
|
||||
call do_syscall_trace
|
||||
call syscall_trace_entry
|
||||
|
||||
ldi @(gr28,#REG_SYSCALLNO),gr7
|
||||
lddi @(gr28,#REG_GR(8)) ,gr8
|
||||
lddi.p @(gr28,#REG_GR(8)) ,gr8
|
||||
ori gr8,#0,gr7 ; syscall_trace_entry() returned new syscallno
|
||||
lddi @(gr28,#REG_GR(10)),gr10
|
||||
lddi.p @(gr28,#REG_GR(12)),gr12
|
||||
|
||||
|
@ -1169,11 +1167,10 @@ __syscall_exit_work:
|
|||
beq icc0,#1,__entry_work_pending
|
||||
|
||||
movsg psr,gr23
|
||||
andi gr23,#~PSR_PIL,gr23 ; could let do_syscall_trace() call schedule()
|
||||
andi gr23,#~PSR_PIL,gr23 ; could let syscall_trace_exit() call schedule()
|
||||
movgs gr23,psr
|
||||
|
||||
setlos.p #1,gr8
|
||||
call do_syscall_trace
|
||||
call syscall_trace_exit
|
||||
bra __entry_resume_userspace
|
||||
|
||||
__syscall_badsys:
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
#include <linux/user.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/regset.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/tracehook.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/page.h>
|
||||
|
@ -32,6 +35,169 @@
|
|||
* in exit.c or in signal.c.
|
||||
*/
|
||||
|
||||
/*
|
||||
* retrieve the contents of FRV userspace general registers
|
||||
*/
|
||||
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 user_int_regs *iregs = &target->thread.user->i;
|
||||
int ret;
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
iregs, 0, sizeof(*iregs));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
sizeof(*iregs), -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* update the contents of the FRV userspace general registers
|
||||
*/
|
||||
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)
|
||||
{
|
||||
struct user_int_regs *iregs = &target->thread.user->i;
|
||||
unsigned int offs_gr0, offs_gr1;
|
||||
int ret;
|
||||
|
||||
/* not allowed to set PSR or __status */
|
||||
if (pos < offsetof(struct user_int_regs, psr) + sizeof(long) &&
|
||||
pos + count > offsetof(struct user_int_regs, psr))
|
||||
return -EIO;
|
||||
|
||||
if (pos < offsetof(struct user_int_regs, __status) + sizeof(long) &&
|
||||
pos + count > offsetof(struct user_int_regs, __status))
|
||||
return -EIO;
|
||||
|
||||
/* set the control regs */
|
||||
offs_gr0 = offsetof(struct user_int_regs, gr[0]);
|
||||
offs_gr1 = offsetof(struct user_int_regs, gr[1]);
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
iregs, 0, offs_gr0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* skip GR0/TBR */
|
||||
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
||||
offs_gr0, offs_gr1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* set the general regs */
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&iregs->gr[1], offs_gr1, sizeof(*iregs));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
||||
sizeof(*iregs), -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* retrieve the contents of FRV userspace FP/Media registers
|
||||
*/
|
||||
static int fpmregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
const struct user_fpmedia_regs *fpregs = &target->thread.user->f;
|
||||
int ret;
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
fpregs, 0, sizeof(*fpregs));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
sizeof(*fpregs), -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* update the contents of the FRV userspace FP/Media registers
|
||||
*/
|
||||
static int fpmregs_set(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
struct user_fpmedia_regs *fpregs = &target->thread.user->f;
|
||||
int ret;
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
fpregs, 0, sizeof(*fpregs));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
||||
sizeof(*fpregs), -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* determine if the FP/Media registers have actually been used
|
||||
*/
|
||||
static int fpmregs_active(struct task_struct *target,
|
||||
const struct user_regset *regset)
|
||||
{
|
||||
return tsk_used_math(target) ? regset->n : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Define the register sets available on the FRV under Linux
|
||||
*/
|
||||
enum frv_regset {
|
||||
REGSET_GENERAL,
|
||||
REGSET_FPMEDIA,
|
||||
};
|
||||
|
||||
static const struct user_regset frv_regsets[] = {
|
||||
/*
|
||||
* General register format is:
|
||||
* PSR, ISR, CCR, CCCR, LR, LCR, PC, (STATUS), SYSCALLNO, ORIG_G8
|
||||
* GNER0-1, IACC0, TBR, GR1-63
|
||||
*/
|
||||
[REGSET_GENERAL] = {
|
||||
.core_note_type = NT_PRSTATUS,
|
||||
.n = ELF_NGREG,
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.get = genregs_get,
|
||||
.set = genregs_set,
|
||||
},
|
||||
/*
|
||||
* FPU/Media register format is:
|
||||
* FR0-63, FNER0-1, MSR0-1, ACC0-7, ACCG0-8, FSR
|
||||
*/
|
||||
[REGSET_FPMEDIA] = {
|
||||
.core_note_type = NT_PRFPREG,
|
||||
.n = sizeof(struct user_fpmedia_regs) / sizeof(long),
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.get = fpmregs_get,
|
||||
.set = fpmregs_set,
|
||||
.active = fpmregs_active,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct user_regset_view user_frv_native_view = {
|
||||
.name = "frv",
|
||||
.e_machine = EM_FRV,
|
||||
.regsets = frv_regsets,
|
||||
.n = ARRAY_SIZE(frv_regsets),
|
||||
};
|
||||
|
||||
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
|
||||
{
|
||||
return &user_frv_native_view;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get contents of register REGNO in task TASK.
|
||||
*/
|
||||
|
@ -68,41 +234,24 @@ static inline int put_reg(struct task_struct *task, int regno,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* check that an address falls within the bounds of the target process's memory
|
||||
* mappings
|
||||
*/
|
||||
static inline int is_user_addr_valid(struct task_struct *child,
|
||||
unsigned long start, unsigned long len)
|
||||
{
|
||||
#ifdef CONFIG_MMU
|
||||
if (start >= PAGE_OFFSET || len > PAGE_OFFSET - start)
|
||||
return -EIO;
|
||||
return 0;
|
||||
#else
|
||||
struct vm_area_struct *vma;
|
||||
|
||||
vma = find_vma(child->mm, start);
|
||||
if (vma && start >= vma->vm_start && start + len <= vma->vm_end)
|
||||
return 0;
|
||||
|
||||
return -EIO;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by kernel/ptrace.c when detaching..
|
||||
*
|
||||
* Control h/w single stepping
|
||||
*/
|
||||
void ptrace_disable(struct task_struct *child)
|
||||
void user_enable_single_step(struct task_struct *child)
|
||||
{
|
||||
child->thread.frame0->__status |= REG__STATUS_STEP;
|
||||
}
|
||||
|
||||
void user_disable_single_step(struct task_struct *child)
|
||||
{
|
||||
child->thread.frame0->__status &= ~REG__STATUS_STEP;
|
||||
}
|
||||
|
||||
void ptrace_enable(struct task_struct *child)
|
||||
void ptrace_disable(struct task_struct *child)
|
||||
{
|
||||
child->thread.frame0->__status |= REG__STATUS_STEP;
|
||||
user_disable_single_step(child);
|
||||
}
|
||||
|
||||
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||
|
@ -111,15 +260,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||
int ret;
|
||||
|
||||
switch (request) {
|
||||
/* when I and D space are separate, these will need to be fixed. */
|
||||
case PTRACE_PEEKTEXT: /* read word at location addr. */
|
||||
case PTRACE_PEEKDATA:
|
||||
ret = -EIO;
|
||||
if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
|
||||
break;
|
||||
ret = generic_ptrace_peekdata(child, addr, data);
|
||||
break;
|
||||
|
||||
/* read the word at location addr in the USER area. */
|
||||
case PTRACE_PEEKUSR: {
|
||||
tmp = 0;
|
||||
|
@ -163,15 +303,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||
break;
|
||||
}
|
||||
|
||||
/* when I and D space are separate, this will have to be fixed. */
|
||||
case PTRACE_POKETEXT: /* write the word at location addr. */
|
||||
case PTRACE_POKEDATA:
|
||||
ret = -EIO;
|
||||
if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
|
||||
break;
|
||||
ret = generic_ptrace_pokedata(child, addr, data);
|
||||
break;
|
||||
|
||||
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
|
||||
ret = -EIO;
|
||||
if ((addr & 3) || addr < 0)
|
||||
|
@ -179,7 +310,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||
|
||||
ret = 0;
|
||||
switch (addr >> 2) {
|
||||
case 0 ... PT__END-1:
|
||||
case 0 ... PT__END - 1:
|
||||
ret = put_reg(child, addr >> 2, data);
|
||||
break;
|
||||
|
||||
|
@ -189,95 +320,29 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||
}
|
||||
break;
|
||||
|
||||
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
|
||||
case PTRACE_CONT: /* restart after signal. */
|
||||
ret = -EIO;
|
||||
if (!valid_signal(data))
|
||||
break;
|
||||
if (request == PTRACE_SYSCALL)
|
||||
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
else
|
||||
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
child->exit_code = data;
|
||||
ptrace_disable(child);
|
||||
wake_up_process(child);
|
||||
ret = 0;
|
||||
break;
|
||||
case PTRACE_GETREGS: /* Get all integer regs from the child. */
|
||||
return copy_regset_to_user(child, &user_frv_native_view,
|
||||
REGSET_GENERAL,
|
||||
0, sizeof(child->thread.user->i),
|
||||
(void __user *)data);
|
||||
|
||||
/* make the child exit. Best I can do is send it a sigkill.
|
||||
* perhaps it should be put in the status that it wants to
|
||||
* exit.
|
||||
*/
|
||||
case PTRACE_KILL:
|
||||
ret = 0;
|
||||
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
|
||||
break;
|
||||
child->exit_code = SIGKILL;
|
||||
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
|
||||
ptrace_disable(child);
|
||||
wake_up_process(child);
|
||||
break;
|
||||
case PTRACE_SETREGS: /* Set all integer regs in the child. */
|
||||
return copy_regset_from_user(child, &user_frv_native_view,
|
||||
REGSET_GENERAL,
|
||||
0, sizeof(child->thread.user->i),
|
||||
(const void __user *)data);
|
||||
|
||||
case PTRACE_SINGLESTEP: /* set the trap flag. */
|
||||
ret = -EIO;
|
||||
if (!valid_signal(data))
|
||||
break;
|
||||
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
ptrace_enable(child);
|
||||
child->exit_code = data;
|
||||
wake_up_process(child);
|
||||
ret = 0;
|
||||
break;
|
||||
case PTRACE_GETFPREGS: /* Get the child FP/Media state. */
|
||||
return copy_regset_to_user(child, &user_frv_native_view,
|
||||
REGSET_FPMEDIA,
|
||||
0, sizeof(child->thread.user->f),
|
||||
(void __user *)data);
|
||||
|
||||
case PTRACE_DETACH: /* detach a process that was attached. */
|
||||
ret = ptrace_detach(child, data);
|
||||
break;
|
||||
|
||||
case PTRACE_GETREGS: { /* Get all integer regs from the child. */
|
||||
int i;
|
||||
for (i = 0; i < PT__GPEND; i++) {
|
||||
tmp = get_reg(child, i);
|
||||
if (put_user(tmp, (unsigned long *) data)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
data += sizeof(long);
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SETREGS: { /* Set all integer regs in the child. */
|
||||
int i;
|
||||
for (i = 0; i < PT__GPEND; i++) {
|
||||
if (get_user(tmp, (unsigned long *) data)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
put_reg(child, i, tmp);
|
||||
data += sizeof(long);
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_GETFPREGS: { /* Get the child FP/Media state. */
|
||||
ret = 0;
|
||||
if (copy_to_user((void *) data,
|
||||
&child->thread.user->f,
|
||||
sizeof(child->thread.user->f)))
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SETFPREGS: { /* Set the child FP/Media state. */
|
||||
ret = 0;
|
||||
if (copy_from_user(&child->thread.user->f,
|
||||
(void *) data,
|
||||
sizeof(child->thread.user->f)))
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
case PTRACE_SETFPREGS: /* Set the child FP/Media state. */
|
||||
return copy_regset_from_user(child, &user_frv_native_view,
|
||||
REGSET_FPMEDIA,
|
||||
0, sizeof(child->thread.user->f),
|
||||
(const void __user *)data);
|
||||
|
||||
case PTRACE_GETFDPIC:
|
||||
tmp = 0;
|
||||
|
@ -300,414 +365,36 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||
break;
|
||||
|
||||
default:
|
||||
ret = -EIO;
|
||||
ret = ptrace_request(child, request, addr, data);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __nongprelbss kstrace;
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
unsigned argmask;
|
||||
} __syscall_name_table[NR_syscalls] = {
|
||||
[0] = { "restart_syscall" },
|
||||
[1] = { "exit", 0x000001 },
|
||||
[2] = { "fork", 0xffffff },
|
||||
[3] = { "read", 0x000141 },
|
||||
[4] = { "write", 0x000141 },
|
||||
[5] = { "open", 0x000235 },
|
||||
[6] = { "close", 0x000001 },
|
||||
[7] = { "waitpid", 0x000141 },
|
||||
[8] = { "creat", 0x000025 },
|
||||
[9] = { "link", 0x000055 },
|
||||
[10] = { "unlink", 0x000005 },
|
||||
[11] = { "execve", 0x000445 },
|
||||
[12] = { "chdir", 0x000005 },
|
||||
[13] = { "time", 0x000004 },
|
||||
[14] = { "mknod", 0x000325 },
|
||||
[15] = { "chmod", 0x000025 },
|
||||
[16] = { "lchown", 0x000025 },
|
||||
[17] = { "break" },
|
||||
[18] = { "oldstat", 0x000045 },
|
||||
[19] = { "lseek", 0x000131 },
|
||||
[20] = { "getpid", 0xffffff },
|
||||
[21] = { "mount", 0x043555 },
|
||||
[22] = { "umount", 0x000005 },
|
||||
[23] = { "setuid", 0x000001 },
|
||||
[24] = { "getuid", 0xffffff },
|
||||
[25] = { "stime", 0x000004 },
|
||||
[26] = { "ptrace", 0x004413 },
|
||||
[27] = { "alarm", 0x000001 },
|
||||
[28] = { "oldfstat", 0x000041 },
|
||||
[29] = { "pause", 0xffffff },
|
||||
[30] = { "utime", 0x000045 },
|
||||
[31] = { "stty" },
|
||||
[32] = { "gtty" },
|
||||
[33] = { "access", 0x000025 },
|
||||
[34] = { "nice", 0x000001 },
|
||||
[35] = { "ftime" },
|
||||
[36] = { "sync", 0xffffff },
|
||||
[37] = { "kill", 0x000011 },
|
||||
[38] = { "rename", 0x000055 },
|
||||
[39] = { "mkdir", 0x000025 },
|
||||
[40] = { "rmdir", 0x000005 },
|
||||
[41] = { "dup", 0x000001 },
|
||||
[42] = { "pipe", 0x000004 },
|
||||
[43] = { "times", 0x000004 },
|
||||
[44] = { "prof" },
|
||||
[45] = { "brk", 0x000004 },
|
||||
[46] = { "setgid", 0x000001 },
|
||||
[47] = { "getgid", 0xffffff },
|
||||
[48] = { "signal", 0x000041 },
|
||||
[49] = { "geteuid", 0xffffff },
|
||||
[50] = { "getegid", 0xffffff },
|
||||
[51] = { "acct", 0x000005 },
|
||||
[52] = { "umount2", 0x000035 },
|
||||
[53] = { "lock" },
|
||||
[54] = { "ioctl", 0x000331 },
|
||||
[55] = { "fcntl", 0x000331 },
|
||||
[56] = { "mpx" },
|
||||
[57] = { "setpgid", 0x000011 },
|
||||
[58] = { "ulimit" },
|
||||
[60] = { "umask", 0x000002 },
|
||||
[61] = { "chroot", 0x000005 },
|
||||
[62] = { "ustat", 0x000043 },
|
||||
[63] = { "dup2", 0x000011 },
|
||||
[64] = { "getppid", 0xffffff },
|
||||
[65] = { "getpgrp", 0xffffff },
|
||||
[66] = { "setsid", 0xffffff },
|
||||
[67] = { "sigaction" },
|
||||
[68] = { "sgetmask" },
|
||||
[69] = { "ssetmask" },
|
||||
[70] = { "setreuid" },
|
||||
[71] = { "setregid" },
|
||||
[72] = { "sigsuspend" },
|
||||
[73] = { "sigpending" },
|
||||
[74] = { "sethostname" },
|
||||
[75] = { "setrlimit" },
|
||||
[76] = { "getrlimit" },
|
||||
[77] = { "getrusage" },
|
||||
[78] = { "gettimeofday" },
|
||||
[79] = { "settimeofday" },
|
||||
[80] = { "getgroups" },
|
||||
[81] = { "setgroups" },
|
||||
[82] = { "select" },
|
||||
[83] = { "symlink" },
|
||||
[84] = { "oldlstat" },
|
||||
[85] = { "readlink" },
|
||||
[86] = { "uselib" },
|
||||
[87] = { "swapon" },
|
||||
[88] = { "reboot" },
|
||||
[89] = { "readdir" },
|
||||
[91] = { "munmap", 0x000034 },
|
||||
[92] = { "truncate" },
|
||||
[93] = { "ftruncate" },
|
||||
[94] = { "fchmod" },
|
||||
[95] = { "fchown" },
|
||||
[96] = { "getpriority" },
|
||||
[97] = { "setpriority" },
|
||||
[99] = { "statfs" },
|
||||
[100] = { "fstatfs" },
|
||||
[102] = { "socketcall" },
|
||||
[103] = { "syslog" },
|
||||
[104] = { "setitimer" },
|
||||
[105] = { "getitimer" },
|
||||
[106] = { "stat" },
|
||||
[107] = { "lstat" },
|
||||
[108] = { "fstat" },
|
||||
[111] = { "vhangup" },
|
||||
[114] = { "wait4" },
|
||||
[115] = { "swapoff" },
|
||||
[116] = { "sysinfo" },
|
||||
[117] = { "ipc" },
|
||||
[118] = { "fsync" },
|
||||
[119] = { "sigreturn" },
|
||||
[120] = { "clone" },
|
||||
[121] = { "setdomainname" },
|
||||
[122] = { "uname" },
|
||||
[123] = { "modify_ldt" },
|
||||
[123] = { "cacheflush" },
|
||||
[124] = { "adjtimex" },
|
||||
[125] = { "mprotect" },
|
||||
[126] = { "sigprocmask" },
|
||||
[127] = { "create_module" },
|
||||
[128] = { "init_module" },
|
||||
[129] = { "delete_module" },
|
||||
[130] = { "get_kernel_syms" },
|
||||
[131] = { "quotactl" },
|
||||
[132] = { "getpgid" },
|
||||
[133] = { "fchdir" },
|
||||
[134] = { "bdflush" },
|
||||
[135] = { "sysfs" },
|
||||
[136] = { "personality" },
|
||||
[137] = { "afs_syscall" },
|
||||
[138] = { "setfsuid" },
|
||||
[139] = { "setfsgid" },
|
||||
[140] = { "_llseek", 0x014331 },
|
||||
[141] = { "getdents" },
|
||||
[142] = { "_newselect", 0x000141 },
|
||||
[143] = { "flock" },
|
||||
[144] = { "msync" },
|
||||
[145] = { "readv" },
|
||||
[146] = { "writev" },
|
||||
[147] = { "getsid", 0x000001 },
|
||||
[148] = { "fdatasync", 0x000001 },
|
||||
[149] = { "_sysctl", 0x000004 },
|
||||
[150] = { "mlock" },
|
||||
[151] = { "munlock" },
|
||||
[152] = { "mlockall" },
|
||||
[153] = { "munlockall" },
|
||||
[154] = { "sched_setparam" },
|
||||
[155] = { "sched_getparam" },
|
||||
[156] = { "sched_setscheduler" },
|
||||
[157] = { "sched_getscheduler" },
|
||||
[158] = { "sched_yield" },
|
||||
[159] = { "sched_get_priority_max" },
|
||||
[160] = { "sched_get_priority_min" },
|
||||
[161] = { "sched_rr_get_interval" },
|
||||
[162] = { "nanosleep", 0x000044 },
|
||||
[163] = { "mremap" },
|
||||
[164] = { "setresuid" },
|
||||
[165] = { "getresuid" },
|
||||
[166] = { "vm86" },
|
||||
[167] = { "query_module" },
|
||||
[168] = { "poll" },
|
||||
[169] = { "nfsservctl" },
|
||||
[170] = { "setresgid" },
|
||||
[171] = { "getresgid" },
|
||||
[172] = { "prctl", 0x333331 },
|
||||
[173] = { "rt_sigreturn", 0xffffff },
|
||||
[174] = { "rt_sigaction", 0x001441 },
|
||||
[175] = { "rt_sigprocmask", 0x001441 },
|
||||
[176] = { "rt_sigpending", 0x000014 },
|
||||
[177] = { "rt_sigtimedwait", 0x001444 },
|
||||
[178] = { "rt_sigqueueinfo", 0x000411 },
|
||||
[179] = { "rt_sigsuspend", 0x000014 },
|
||||
[180] = { "pread", 0x003341 },
|
||||
[181] = { "pwrite", 0x003341 },
|
||||
[182] = { "chown", 0x000115 },
|
||||
[183] = { "getcwd" },
|
||||
[184] = { "capget" },
|
||||
[185] = { "capset" },
|
||||
[186] = { "sigaltstack" },
|
||||
[187] = { "sendfile" },
|
||||
[188] = { "getpmsg" },
|
||||
[189] = { "putpmsg" },
|
||||
[190] = { "vfork", 0xffffff },
|
||||
[191] = { "ugetrlimit" },
|
||||
[192] = { "mmap2", 0x313314 },
|
||||
[193] = { "truncate64" },
|
||||
[194] = { "ftruncate64" },
|
||||
[195] = { "stat64", 0x000045 },
|
||||
[196] = { "lstat64", 0x000045 },
|
||||
[197] = { "fstat64", 0x000041 },
|
||||
[198] = { "lchown32" },
|
||||
[199] = { "getuid32", 0xffffff },
|
||||
[200] = { "getgid32", 0xffffff },
|
||||
[201] = { "geteuid32", 0xffffff },
|
||||
[202] = { "getegid32", 0xffffff },
|
||||
[203] = { "setreuid32" },
|
||||
[204] = { "setregid32" },
|
||||
[205] = { "getgroups32" },
|
||||
[206] = { "setgroups32" },
|
||||
[207] = { "fchown32" },
|
||||
[208] = { "setresuid32" },
|
||||
[209] = { "getresuid32" },
|
||||
[210] = { "setresgid32" },
|
||||
[211] = { "getresgid32" },
|
||||
[212] = { "chown32" },
|
||||
[213] = { "setuid32" },
|
||||
[214] = { "setgid32" },
|
||||
[215] = { "setfsuid32" },
|
||||
[216] = { "setfsgid32" },
|
||||
[217] = { "pivot_root" },
|
||||
[218] = { "mincore" },
|
||||
[219] = { "madvise" },
|
||||
[220] = { "getdents64" },
|
||||
[221] = { "fcntl64" },
|
||||
[223] = { "security" },
|
||||
[224] = { "gettid" },
|
||||
[225] = { "readahead" },
|
||||
[226] = { "setxattr" },
|
||||
[227] = { "lsetxattr" },
|
||||
[228] = { "fsetxattr" },
|
||||
[229] = { "getxattr" },
|
||||
[230] = { "lgetxattr" },
|
||||
[231] = { "fgetxattr" },
|
||||
[232] = { "listxattr" },
|
||||
[233] = { "llistxattr" },
|
||||
[234] = { "flistxattr" },
|
||||
[235] = { "removexattr" },
|
||||
[236] = { "lremovexattr" },
|
||||
[237] = { "fremovexattr" },
|
||||
[238] = { "tkill" },
|
||||
[239] = { "sendfile64" },
|
||||
[240] = { "futex" },
|
||||
[241] = { "sched_setaffinity" },
|
||||
[242] = { "sched_getaffinity" },
|
||||
[243] = { "set_thread_area" },
|
||||
[244] = { "get_thread_area" },
|
||||
[245] = { "io_setup" },
|
||||
[246] = { "io_destroy" },
|
||||
[247] = { "io_getevents" },
|
||||
[248] = { "io_submit" },
|
||||
[249] = { "io_cancel" },
|
||||
[250] = { "fadvise64" },
|
||||
[252] = { "exit_group", 0x000001 },
|
||||
[253] = { "lookup_dcookie" },
|
||||
[254] = { "epoll_create" },
|
||||
[255] = { "epoll_ctl" },
|
||||
[256] = { "epoll_wait" },
|
||||
[257] = { "remap_file_pages" },
|
||||
[258] = { "set_tid_address" },
|
||||
[259] = { "timer_create" },
|
||||
[260] = { "timer_settime" },
|
||||
[261] = { "timer_gettime" },
|
||||
[262] = { "timer_getoverrun" },
|
||||
[263] = { "timer_delete" },
|
||||
[264] = { "clock_settime" },
|
||||
[265] = { "clock_gettime" },
|
||||
[266] = { "clock_getres" },
|
||||
[267] = { "clock_nanosleep" },
|
||||
[268] = { "statfs64" },
|
||||
[269] = { "fstatfs64" },
|
||||
[270] = { "tgkill" },
|
||||
[271] = { "utimes" },
|
||||
[272] = { "fadvise64_64" },
|
||||
[273] = { "vserver" },
|
||||
[274] = { "mbind" },
|
||||
[275] = { "get_mempolicy" },
|
||||
[276] = { "set_mempolicy" },
|
||||
[277] = { "mq_open" },
|
||||
[278] = { "mq_unlink" },
|
||||
[279] = { "mq_timedsend" },
|
||||
[280] = { "mq_timedreceive" },
|
||||
[281] = { "mq_notify" },
|
||||
[282] = { "mq_getsetattr" },
|
||||
[283] = { "sys_kexec_load" },
|
||||
};
|
||||
|
||||
asmlinkage void do_syscall_trace(int leaving)
|
||||
/*
|
||||
* handle tracing of system call entry
|
||||
* - return the revised system call number or ULONG_MAX to cause ENOSYS
|
||||
*/
|
||||
asmlinkage unsigned long syscall_trace_entry(void)
|
||||
{
|
||||
#if 0
|
||||
unsigned long *argp;
|
||||
const char *name;
|
||||
unsigned argmask;
|
||||
char buffer[16];
|
||||
|
||||
if (!kstrace)
|
||||
return;
|
||||
|
||||
if (!current->mm)
|
||||
return;
|
||||
|
||||
if (__frame->gr7 == __NR_close)
|
||||
return;
|
||||
|
||||
#if 0
|
||||
if (__frame->gr7 != __NR_mmap2 &&
|
||||
__frame->gr7 != __NR_vfork &&
|
||||
__frame->gr7 != __NR_execve &&
|
||||
__frame->gr7 != __NR_exit)
|
||||
return;
|
||||
#endif
|
||||
|
||||
argmask = 0;
|
||||
name = NULL;
|
||||
if (__frame->gr7 < NR_syscalls) {
|
||||
name = __syscall_name_table[__frame->gr7].name;
|
||||
argmask = __syscall_name_table[__frame->gr7].argmask;
|
||||
}
|
||||
if (!name) {
|
||||
sprintf(buffer, "sys_%lx", __frame->gr7);
|
||||
name = buffer;
|
||||
__frame->__status |= REG__STATUS_SYSC_ENTRY;
|
||||
if (tracehook_report_syscall_entry(__frame)) {
|
||||
/* tracing decided this syscall should not happen, so
|
||||
* We'll return a bogus call number to get an ENOSYS
|
||||
* error, but leave the original number in
|
||||
* __frame->syscallno
|
||||
*/
|
||||
return ULONG_MAX;
|
||||
}
|
||||
|
||||
if (!leaving) {
|
||||
if (!argmask) {
|
||||
printk(KERN_CRIT "[%d] %s(%lx,%lx,%lx,%lx,%lx,%lx)\n",
|
||||
current->pid,
|
||||
name,
|
||||
__frame->gr8,
|
||||
__frame->gr9,
|
||||
__frame->gr10,
|
||||
__frame->gr11,
|
||||
__frame->gr12,
|
||||
__frame->gr13);
|
||||
}
|
||||
else if (argmask == 0xffffff) {
|
||||
printk(KERN_CRIT "[%d] %s()\n",
|
||||
current->pid,
|
||||
name);
|
||||
}
|
||||
else {
|
||||
printk(KERN_CRIT "[%d] %s(",
|
||||
current->pid,
|
||||
name);
|
||||
|
||||
argp = &__frame->gr8;
|
||||
|
||||
do {
|
||||
switch (argmask & 0xf) {
|
||||
case 1:
|
||||
printk("%ld", (long) *argp);
|
||||
break;
|
||||
case 2:
|
||||
printk("%lo", *argp);
|
||||
break;
|
||||
case 3:
|
||||
printk("%lx", *argp);
|
||||
break;
|
||||
case 4:
|
||||
printk("%p", (void *) *argp);
|
||||
break;
|
||||
case 5:
|
||||
printk("\"%s\"", (char *) *argp);
|
||||
break;
|
||||
}
|
||||
|
||||
argp++;
|
||||
argmask >>= 4;
|
||||
if (argmask)
|
||||
printk(",");
|
||||
|
||||
} while (argmask);
|
||||
|
||||
printk(")\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((int)__frame->gr8 > -4096 && (int)__frame->gr8 < 4096)
|
||||
printk(KERN_CRIT "[%d] %s() = %ld\n", current->pid, name, __frame->gr8);
|
||||
else
|
||||
printk(KERN_CRIT "[%d] %s() = %lx\n", current->pid, name, __frame->gr8);
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!test_thread_flag(TIF_SYSCALL_TRACE))
|
||||
return;
|
||||
|
||||
if (!(current->ptrace & PT_PTRACED))
|
||||
return;
|
||||
|
||||
/* we need to indicate entry or exit to strace */
|
||||
if (leaving)
|
||||
__frame->__status |= REG__STATUS_SYSC_EXIT;
|
||||
else
|
||||
__frame->__status |= REG__STATUS_SYSC_ENTRY;
|
||||
|
||||
ptrace_notify(SIGTRAP);
|
||||
|
||||
/*
|
||||
* this isn't the same as continuing with a signal, but it will do
|
||||
* for normal use. strace only continues with a signal if the
|
||||
* stopping signal is not SIGTRAP. -brl
|
||||
*/
|
||||
if (current->exit_code) {
|
||||
send_sig(current->exit_code, current, 1);
|
||||
current->exit_code = 0;
|
||||
}
|
||||
return __frame->syscallno;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle tracing of system call exit
|
||||
*/
|
||||
asmlinkage void syscall_trace_exit(void)
|
||||
{
|
||||
__frame->__status |= REG__STATUS_SYSC_EXIT;
|
||||
tracehook_report_syscall_exit(__frame, 0);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/unistd.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/tracehook.h>
|
||||
#include <asm/ucontext.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
@ -516,6 +517,9 @@ static void do_signal(void)
|
|||
* clear the TIF_RESTORE_SIGMASK flag */
|
||||
if (test_thread_flag(TIF_RESTORE_SIGMASK))
|
||||
clear_thread_flag(TIF_RESTORE_SIGMASK);
|
||||
|
||||
tracehook_signal_handler(signr, &info, &ka, __frame,
|
||||
test_thread_flag(TIF_SINGLESTEP));
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -564,4 +568,10 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags)
|
|||
if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
|
||||
do_signal();
|
||||
|
||||
/* deal with notification on about to resume userspace execution */
|
||||
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
|
||||
clear_thread_flag(TIF_NOTIFY_RESUME);
|
||||
tracehook_notify_resume(__frame);
|
||||
}
|
||||
|
||||
} /* end do_notify_resume() */
|
||||
|
|
|
@ -23,8 +23,7 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
|
|||
char *p, ch;
|
||||
long err = -EFAULT;
|
||||
|
||||
if (count < 0)
|
||||
BUG();
|
||||
BUG_ON(count < 0);
|
||||
|
||||
p = dst;
|
||||
|
||||
|
@ -76,8 +75,7 @@ long strnlen_user(const char __user *src, long count)
|
|||
long err = 0;
|
||||
char ch;
|
||||
|
||||
if (count < 0)
|
||||
BUG();
|
||||
BUG_ON(count < 0);
|
||||
|
||||
#ifndef CONFIG_MMU
|
||||
if ((unsigned long) src < memory_start)
|
||||
|
|
|
@ -116,8 +116,7 @@ EXPORT_SYMBOL(dma_free_coherent);
|
|||
dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
if (direction == DMA_NONE)
|
||||
BUG();
|
||||
BUG_ON(direction == DMA_NONE);
|
||||
|
||||
frv_cache_wback_inv((unsigned long) ptr, (unsigned long) ptr + size);
|
||||
|
||||
|
@ -151,8 +150,7 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
|
|||
frv_cache_wback_inv(sg_dma_address(&sg[i]),
|
||||
sg_dma_address(&sg[i]) + sg_dma_len(&sg[i]));
|
||||
|
||||
if (direction == DMA_NONE)
|
||||
BUG();
|
||||
BUG_ON(direction == DMA_NONE);
|
||||
|
||||
return nents;
|
||||
}
|
||||
|
|
|
@ -48,8 +48,7 @@ EXPORT_SYMBOL(dma_free_coherent);
|
|||
dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
if (direction == DMA_NONE)
|
||||
BUG();
|
||||
BUG_ON(direction == DMA_NONE);
|
||||
|
||||
frv_cache_wback_inv((unsigned long) ptr, (unsigned long) ptr + size);
|
||||
|
||||
|
@ -81,8 +80,7 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
|
|||
void *vaddr;
|
||||
int i;
|
||||
|
||||
if (direction == DMA_NONE)
|
||||
BUG();
|
||||
BUG_ON(direction == DMA_NONE);
|
||||
|
||||
dampr2 = __get_DAMPR(2);
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ mainmenu "Linux Kernel Configuration"
|
|||
config MN10300
|
||||
def_bool y
|
||||
select HAVE_OPROFILE
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
|
||||
config AM33
|
||||
def_bool y
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
*/
|
||||
typedef unsigned long elf_greg_t;
|
||||
|
||||
#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
|
||||
#define ELF_NGREG ((sizeof(struct pt_regs) / sizeof(elf_greg_t)) - 1)
|
||||
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
|
||||
|
||||
#define ELF_NFPREG 32
|
||||
|
@ -76,6 +76,7 @@ do { \
|
|||
} while (0)
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
#define CORE_DUMP_USE_REGSET
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
/*
|
||||
|
|
|
@ -143,13 +143,7 @@ extern unsigned long thread_saved_pc(struct task_struct *tsk);
|
|||
|
||||
unsigned long get_wchan(struct task_struct *p);
|
||||
|
||||
#define task_pt_regs(task) \
|
||||
({ \
|
||||
struct pt_regs *__regs__; \
|
||||
__regs__ = (struct pt_regs *) (KSTK_TOP(task_stack_page(task)) - 8); \
|
||||
__regs__ - 1; \
|
||||
})
|
||||
|
||||
#define task_pt_regs(task) ((task)->thread.uregs)
|
||||
#define KSTK_EIP(task) (task_pt_regs(task)->pc)
|
||||
#define KSTK_ESP(task) (task_pt_regs(task)->sp)
|
||||
|
||||
|
|
|
@ -91,9 +91,17 @@ extern struct pt_regs *__frame; /* current frame pointer */
|
|||
#if defined(__KERNEL__)
|
||||
|
||||
#if !defined(__ASSEMBLY__)
|
||||
struct task_struct;
|
||||
|
||||
#define user_mode(regs) (((regs)->epsw & EPSW_nSL) == EPSW_nSL)
|
||||
#define instruction_pointer(regs) ((regs)->pc)
|
||||
#define user_stack_pointer(regs) ((regs)->sp)
|
||||
extern void show_regs(struct pt_regs *);
|
||||
|
||||
#define arch_has_single_step() (1)
|
||||
extern void user_enable_single_step(struct task_struct *);
|
||||
extern void user_disable_single_step(struct task_struct *);
|
||||
|
||||
#endif /* !__ASSEMBLY */
|
||||
|
||||
#define profile_pc(regs) ((regs)->pc)
|
||||
|
|
|
@ -76,7 +76,7 @@ ENTRY(system_call)
|
|||
cmp nr_syscalls,d0
|
||||
bcc syscall_badsys
|
||||
btst _TIF_SYSCALL_TRACE,(TI_flags,a2)
|
||||
bne syscall_trace_entry
|
||||
bne syscall_entry_trace
|
||||
syscall_call:
|
||||
add d0,d0,a1
|
||||
add a1,a1
|
||||
|
@ -104,11 +104,10 @@ restore_all:
|
|||
syscall_exit_work:
|
||||
btst _TIF_SYSCALL_TRACE,d2
|
||||
beq work_pending
|
||||
__sti # could let do_syscall_trace() call
|
||||
__sti # could let syscall_trace_exit() call
|
||||
# schedule() instead
|
||||
mov fp,d0
|
||||
mov 1,d1
|
||||
call do_syscall_trace[],0 # do_syscall_trace(regs,entryexit)
|
||||
call syscall_trace_exit[],0 # do_syscall_trace(regs)
|
||||
jmp resume_userspace
|
||||
|
||||
ALIGN
|
||||
|
@ -138,13 +137,11 @@ work_notifysig:
|
|||
jmp resume_userspace
|
||||
|
||||
# perform syscall entry tracing
|
||||
syscall_trace_entry:
|
||||
syscall_entry_trace:
|
||||
mov -ENOSYS,d0
|
||||
mov d0,(REG_D0,fp)
|
||||
mov fp,d0
|
||||
clr d1
|
||||
call do_syscall_trace[],0
|
||||
mov (REG_ORIG_D0,fp),d0
|
||||
call syscall_trace_entry[],0 # returns the syscall number to actually use
|
||||
mov (REG_D1,fp),d1
|
||||
cmp nr_syscalls,d0
|
||||
bcs syscall_call
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/regset.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/tracehook.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/system.h>
|
||||
|
@ -64,12 +67,6 @@ static inline int get_stack_long(struct task_struct *task, int offset)
|
|||
((unsigned long) task->thread.uregs + offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* this routine will put a word on the processes privileged stack.
|
||||
* the offset is how far from the base addr as stored in the TSS.
|
||||
* this routine assumes that all the privileged stacks are in our
|
||||
* data space.
|
||||
*/
|
||||
static inline
|
||||
int put_stack_long(struct task_struct *task, int offset, unsigned long data)
|
||||
{
|
||||
|
@ -80,44 +77,191 @@ int put_stack_long(struct task_struct *task, int offset, unsigned long data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned long get_fpregs(struct fpu_state_struct *buf,
|
||||
struct task_struct *tsk)
|
||||
/*
|
||||
* retrieve the contents of MN10300 userspace general registers
|
||||
*/
|
||||
static int genregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
return __copy_to_user(buf, &tsk->thread.fpu_state,
|
||||
sizeof(struct fpu_state_struct));
|
||||
}
|
||||
const struct pt_regs *regs = task_pt_regs(target);
|
||||
int ret;
|
||||
|
||||
static inline unsigned long set_fpregs(struct task_struct *tsk,
|
||||
struct fpu_state_struct *buf)
|
||||
{
|
||||
return __copy_from_user(&tsk->thread.fpu_state, buf,
|
||||
sizeof(struct fpu_state_struct));
|
||||
}
|
||||
/* we need to skip regs->next */
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
regs, 0, PT_ORIG_D0 * sizeof(long));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
static inline void fpsave_init(struct task_struct *task)
|
||||
{
|
||||
memset(&task->thread.fpu_state, 0, sizeof(struct fpu_state_struct));
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
®s->orig_d0, PT_ORIG_D0 * sizeof(long),
|
||||
NR_PTREGS * sizeof(long));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
NR_PTREGS * sizeof(long), -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* make sure the single step bit is not set
|
||||
* update the contents of the MN10300 userspace general registers
|
||||
*/
|
||||
void ptrace_disable(struct task_struct *child)
|
||||
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)
|
||||
{
|
||||
#ifndef CONFIG_MN10300_USING_JTAG
|
||||
struct user *dummy = NULL;
|
||||
long tmp;
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
unsigned long tmp;
|
||||
int ret;
|
||||
|
||||
tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
|
||||
tmp &= ~EPSW_T;
|
||||
put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
|
||||
#endif
|
||||
/* we need to skip regs->next */
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
regs, 0, PT_ORIG_D0 * sizeof(long));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
®s->orig_d0, PT_ORIG_D0 * sizeof(long),
|
||||
PT_EPSW * sizeof(long));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* we need to mask off changes to EPSW */
|
||||
tmp = regs->epsw;
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&tmp, PT_EPSW * sizeof(long),
|
||||
PT_PC * sizeof(long));
|
||||
tmp &= EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N | EPSW_FLAG_Z;
|
||||
tmp |= regs->epsw & ~(EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N |
|
||||
EPSW_FLAG_Z);
|
||||
regs->epsw = tmp;
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* and finally load the PC */
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
®s->pc, PT_PC * sizeof(long),
|
||||
NR_PTREGS * sizeof(long));
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
||||
NR_PTREGS * sizeof(long), -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* set the single step bit
|
||||
* retrieve the contents of MN10300 userspace FPU registers
|
||||
*/
|
||||
void ptrace_enable(struct task_struct *child)
|
||||
static int fpuregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
const struct fpu_state_struct *fpregs = &target->thread.fpu_state;
|
||||
int ret;
|
||||
|
||||
unlazy_fpu(target);
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
fpregs, 0, sizeof(*fpregs));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
sizeof(*fpregs), -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* update the contents of the MN10300 userspace FPU registers
|
||||
*/
|
||||
static int fpuregs_set(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
struct fpu_state_struct fpu_state = target->thread.fpu_state;
|
||||
int ret;
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&fpu_state, 0, sizeof(fpu_state));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
fpu_kill_state(target);
|
||||
target->thread.fpu_state = fpu_state;
|
||||
set_using_fpu(target);
|
||||
|
||||
return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
||||
sizeof(fpu_state), -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* determine if the FPU registers have actually been used
|
||||
*/
|
||||
static int fpuregs_active(struct task_struct *target,
|
||||
const struct user_regset *regset)
|
||||
{
|
||||
return is_using_fpu(target) ? regset->n : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Define the register sets available on the MN10300 under Linux
|
||||
*/
|
||||
enum mn10300_regset {
|
||||
REGSET_GENERAL,
|
||||
REGSET_FPU,
|
||||
};
|
||||
|
||||
static const struct user_regset mn10300_regsets[] = {
|
||||
/*
|
||||
* General register format is:
|
||||
* A3, A2, D3, D2, MCVF, MCRL, MCRH, MDRQ
|
||||
* E1, E0, E7...E2, SP, LAR, LIR, MDR
|
||||
* A1, A0, D1, D0, ORIG_D0, EPSW, PC
|
||||
*/
|
||||
[REGSET_GENERAL] = {
|
||||
.core_note_type = NT_PRSTATUS,
|
||||
.n = ELF_NGREG,
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.get = genregs_get,
|
||||
.set = genregs_set,
|
||||
},
|
||||
/*
|
||||
* FPU register format is:
|
||||
* FS0-31, FPCR
|
||||
*/
|
||||
[REGSET_FPU] = {
|
||||
.core_note_type = NT_PRFPREG,
|
||||
.n = sizeof(struct fpu_state_struct) / sizeof(long),
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.get = fpuregs_get,
|
||||
.set = fpuregs_set,
|
||||
.active = fpuregs_active,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct user_regset_view user_mn10300_native_view = {
|
||||
.name = "mn10300",
|
||||
.e_machine = EM_MN10300,
|
||||
.regsets = mn10300_regsets,
|
||||
.n = ARRAY_SIZE(mn10300_regsets),
|
||||
};
|
||||
|
||||
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
|
||||
{
|
||||
return &user_mn10300_native_view;
|
||||
}
|
||||
|
||||
/*
|
||||
* set the single-step bit
|
||||
*/
|
||||
void user_enable_single_step(struct task_struct *child)
|
||||
{
|
||||
#ifndef CONFIG_MN10300_USING_JTAG
|
||||
struct user *dummy = NULL;
|
||||
|
@ -129,45 +273,37 @@ void ptrace_enable(struct task_struct *child)
|
|||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* make sure the single-step bit is not set
|
||||
*/
|
||||
void user_disable_single_step(struct task_struct *child)
|
||||
{
|
||||
#ifndef CONFIG_MN10300_USING_JTAG
|
||||
struct user *dummy = NULL;
|
||||
long tmp;
|
||||
|
||||
tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
|
||||
tmp &= ~EPSW_T;
|
||||
put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ptrace_disable(struct task_struct *child)
|
||||
{
|
||||
user_disable_single_step(child);
|
||||
}
|
||||
|
||||
/*
|
||||
* handle the arch-specific side of process tracing
|
||||
*/
|
||||
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||
{
|
||||
struct fpu_state_struct fpu_state;
|
||||
int i, ret;
|
||||
unsigned long tmp;
|
||||
int ret;
|
||||
|
||||
switch (request) {
|
||||
/* read the word at location addr. */
|
||||
case PTRACE_PEEKTEXT: {
|
||||
unsigned long tmp;
|
||||
int copied;
|
||||
|
||||
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
|
||||
ret = -EIO;
|
||||
if (copied != sizeof(tmp))
|
||||
break;
|
||||
ret = put_user(tmp, (unsigned long *) data);
|
||||
break;
|
||||
}
|
||||
|
||||
/* read the word at location addr. */
|
||||
case PTRACE_PEEKDATA: {
|
||||
unsigned long tmp;
|
||||
int copied;
|
||||
|
||||
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
|
||||
ret = -EIO;
|
||||
if (copied != sizeof(tmp))
|
||||
break;
|
||||
ret = put_user(tmp, (unsigned long *) data);
|
||||
break;
|
||||
}
|
||||
|
||||
/* read the word at location addr in the USER area. */
|
||||
case PTRACE_PEEKUSR: {
|
||||
unsigned long tmp;
|
||||
|
||||
case PTRACE_PEEKUSR:
|
||||
ret = -EIO;
|
||||
if ((addr & 3) || addr < 0 ||
|
||||
addr > sizeof(struct user) - 3)
|
||||
|
@ -179,17 +315,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||
ptrace_regid_to_frame[addr]);
|
||||
ret = put_user(tmp, (unsigned long *) data);
|
||||
break;
|
||||
}
|
||||
|
||||
/* write the word at location addr. */
|
||||
case PTRACE_POKETEXT:
|
||||
case PTRACE_POKEDATA:
|
||||
if (access_process_vm(child, addr, &data, sizeof(data), 1) ==
|
||||
sizeof(data))
|
||||
ret = 0;
|
||||
else
|
||||
ret = -EIO;
|
||||
break;
|
||||
|
||||
/* write the word at location addr in the USER area */
|
||||
case PTRACE_POKEUSR:
|
||||
|
@ -204,132 +329,32 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||
data);
|
||||
break;
|
||||
|
||||
/* continue and stop at next (return from) syscall */
|
||||
case PTRACE_SYSCALL:
|
||||
/* restart after signal. */
|
||||
case PTRACE_CONT:
|
||||
ret = -EIO;
|
||||
if ((unsigned long) data > _NSIG)
|
||||
break;
|
||||
if (request == PTRACE_SYSCALL)
|
||||
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
else
|
||||
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
child->exit_code = data;
|
||||
ptrace_disable(child);
|
||||
wake_up_process(child);
|
||||
ret = 0;
|
||||
break;
|
||||
case PTRACE_GETREGS: /* Get all integer regs from the child. */
|
||||
return copy_regset_to_user(child, &user_mn10300_native_view,
|
||||
REGSET_GENERAL,
|
||||
0, NR_PTREGS * sizeof(long),
|
||||
(void __user *)data);
|
||||
|
||||
/*
|
||||
* make the child exit
|
||||
* - the best I can do is send it a sigkill
|
||||
* - perhaps it should be put in the status that it wants to
|
||||
* exit
|
||||
*/
|
||||
case PTRACE_KILL:
|
||||
ret = 0;
|
||||
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
|
||||
break;
|
||||
child->exit_code = SIGKILL;
|
||||
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
|
||||
ptrace_disable(child);
|
||||
wake_up_process(child);
|
||||
break;
|
||||
case PTRACE_SETREGS: /* Set all integer regs in the child. */
|
||||
return copy_regset_from_user(child, &user_mn10300_native_view,
|
||||
REGSET_GENERAL,
|
||||
0, NR_PTREGS * sizeof(long),
|
||||
(const void __user *)data);
|
||||
|
||||
case PTRACE_SINGLESTEP: /* set the trap flag. */
|
||||
#ifndef CONFIG_MN10300_USING_JTAG
|
||||
ret = -EIO;
|
||||
if ((unsigned long) data > _NSIG)
|
||||
break;
|
||||
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
ptrace_enable(child);
|
||||
child->exit_code = data;
|
||||
wake_up_process(child);
|
||||
ret = 0;
|
||||
#else
|
||||
ret = -EINVAL;
|
||||
#endif
|
||||
break;
|
||||
case PTRACE_GETFPREGS: /* Get the child FPU state. */
|
||||
return copy_regset_to_user(child, &user_mn10300_native_view,
|
||||
REGSET_FPU,
|
||||
0, sizeof(struct fpu_state_struct),
|
||||
(void __user *)data);
|
||||
|
||||
case PTRACE_DETACH: /* detach a process that was attached. */
|
||||
ret = ptrace_detach(child, data);
|
||||
break;
|
||||
|
||||
/* Get all gp regs from the child. */
|
||||
case PTRACE_GETREGS: {
|
||||
unsigned long tmp;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, (unsigned *) data, NR_PTREGS << 2)) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < NR_PTREGS << 2; i += 4) {
|
||||
tmp = get_stack_long(child, ptrace_regid_to_frame[i]);
|
||||
__put_user(tmp, (unsigned long *) data);
|
||||
data += sizeof(tmp);
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SETREGS: { /* Set all gp regs in the child. */
|
||||
unsigned long tmp;
|
||||
|
||||
if (!access_ok(VERIFY_READ, (unsigned long *)data,
|
||||
sizeof(struct pt_regs))) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < NR_PTREGS << 2; i += 4) {
|
||||
__get_user(tmp, (unsigned long *) data);
|
||||
put_stack_long(child, ptrace_regid_to_frame[i], tmp);
|
||||
data += sizeof(tmp);
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_GETFPREGS: { /* Get the child FPU state. */
|
||||
if (is_using_fpu(child)) {
|
||||
unlazy_fpu(child);
|
||||
fpu_state = child->thread.fpu_state;
|
||||
} else {
|
||||
memset(&fpu_state, 0, sizeof(fpu_state));
|
||||
}
|
||||
|
||||
ret = -EIO;
|
||||
if (copy_to_user((void *) data, &fpu_state,
|
||||
sizeof(fpu_state)) == 0)
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SETFPREGS: { /* Set the child FPU state. */
|
||||
ret = -EFAULT;
|
||||
if (copy_from_user(&fpu_state, (const void *) data,
|
||||
sizeof(fpu_state)) == 0) {
|
||||
fpu_kill_state(child);
|
||||
child->thread.fpu_state = fpu_state;
|
||||
set_using_fpu(child);
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SETOPTIONS: {
|
||||
if (data & PTRACE_O_TRACESYSGOOD)
|
||||
child->ptrace |= PT_TRACESYSGOOD;
|
||||
else
|
||||
child->ptrace &= ~PT_TRACESYSGOOD;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
case PTRACE_SETFPREGS: /* Set the child FPU state. */
|
||||
return copy_regset_from_user(child, &user_mn10300_native_view,
|
||||
REGSET_FPU,
|
||||
0, sizeof(struct fpu_state_struct),
|
||||
(const void __user *)data);
|
||||
|
||||
default:
|
||||
ret = -EIO;
|
||||
ret = ptrace_request(child, request, addr, data);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -337,43 +362,26 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||
}
|
||||
|
||||
/*
|
||||
* notification of system call entry/exit
|
||||
* - triggered by current->work.syscall_trace
|
||||
* handle tracing of system call entry
|
||||
* - return the revised system call number or ULONG_MAX to cause ENOSYS
|
||||
*/
|
||||
asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
|
||||
asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs)
|
||||
{
|
||||
#if 0
|
||||
/* just in case... */
|
||||
printk(KERN_DEBUG "[%d] syscall_%lu(%lx,%lx,%lx,%lx) = %lx\n",
|
||||
current->pid,
|
||||
regs->orig_d0,
|
||||
regs->a0,
|
||||
regs->d1,
|
||||
regs->a3,
|
||||
regs->a2,
|
||||
regs->d0);
|
||||
return;
|
||||
#endif
|
||||
if (tracehook_report_syscall_entry(regs))
|
||||
/* tracing decided this syscall should not happen, so
|
||||
* We'll return a bogus call number to get an ENOSYS
|
||||
* error, but leave the original number in
|
||||
* regs->orig_d0
|
||||
*/
|
||||
return ULONG_MAX;
|
||||
|
||||
if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
|
||||
!test_thread_flag(TIF_SINGLESTEP))
|
||||
return;
|
||||
if (!(current->ptrace & PT_PTRACED))
|
||||
return;
|
||||
|
||||
/* the 0x80 provides a way for the tracing parent to distinguish
|
||||
between a syscall stop and SIGTRAP delivery */
|
||||
ptrace_notify(SIGTRAP |
|
||||
((current->ptrace & PT_TRACESYSGOOD) &&
|
||||
!test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
|
||||
|
||||
/*
|
||||
* this isn't the same as continuing with a signal, but it will do
|
||||
* for normal use. strace only continues with a signal if the
|
||||
* stopping signal is not SIGTRAP. -brl
|
||||
*/
|
||||
if (current->exit_code) {
|
||||
send_sig(current->exit_code, current, 1);
|
||||
current->exit_code = 0;
|
||||
}
|
||||
return regs->orig_d0;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle tracing of system call exit
|
||||
*/
|
||||
asmlinkage void syscall_trace_exit(struct pt_regs *regs)
|
||||
{
|
||||
tracehook_report_syscall_exit(regs, 0);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/tty.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/tracehook.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/ucontext.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
@ -511,6 +512,9 @@ static void do_signal(struct pt_regs *regs)
|
|||
* clear the TIF_RESTORE_SIGMASK flag */
|
||||
if (test_thread_flag(TIF_RESTORE_SIGMASK))
|
||||
clear_thread_flag(TIF_RESTORE_SIGMASK);
|
||||
|
||||
tracehook_signal_handler(signr, &info, &ka, regs,
|
||||
test_thread_flag(TIF_SINGLESTEP));
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -561,4 +565,9 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
|
|||
/* deal with pending signal delivery */
|
||||
if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
|
||||
do_signal(regs);
|
||||
|
||||
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
|
||||
clear_thread_flag(TIF_NOTIFY_RESUME);
|
||||
tracehook_notify_resume(__frame);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -165,24 +165,6 @@ ENTRY(itlb_aerror)
|
|||
ENTRY(dtlb_aerror)
|
||||
and ~EPSW_NMID,epsw
|
||||
add -4,sp
|
||||
mov d1,(sp)
|
||||
|
||||
movhu (MMUFCR_DFC),d1 # is it the initial valid write
|
||||
# to this page?
|
||||
and MMUFCR_xFC_INITWR,d1
|
||||
beq dtlb_pagefault # jump if not
|
||||
|
||||
mov (DPTEL),d1 # set the dirty bit
|
||||
# (don't replace with BSET!)
|
||||
or _PAGE_DIRTY,d1
|
||||
mov d1,(DPTEL)
|
||||
mov (sp),d1
|
||||
add 4,sp
|
||||
rti
|
||||
|
||||
ALIGN
|
||||
dtlb_pagefault:
|
||||
mov (sp),d1
|
||||
SAVE_ALL
|
||||
add -4,sp # need to pass three params
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче