void user_enable_single_step(struct task_struct *task)
{
clear_tsk_thread_flag(task, TIF_BLOCKSTEP);
set_tsk_thread_flag(task, TIF_SINGLESTEP);
if (pa_psw(task)->n) {
struct siginfo si;
/* Nullified, just crank over the queue. */
task_regs(task)->iaoq[0] = task_regs(task)->iaoq[1];
task_regs(task)->iasq[0] = task_regs(task)->iasq[1];
task_regs(task)->iaoq[1] = task_regs(task)->iaoq[0] + 4;
pa_psw(task)->n = 0;
pa_psw(task)->x = 0;
pa_psw(task)->y = 0;
pa_psw(task)->z = 0;
pa_psw(task)->b = 0;
ptrace_disable(task);
/* Don't wake up the task, but let the
parent know something happened. */
si.si_code = TRAP_TRACE;
si.si_addr = (void __user *) (task_regs(task)->iaoq[0] & ~3);
si.si_signo = SIGTRAP;
si.si_errno = 0;
force_sig_info(SIGTRAP, &si, task);
/* notify_parent(task, SIGCHLD); */
return;
}
/* Enable recovery counter traps. The recovery counter
* itself will be set to zero on a task switch. If the
* task is suspended on a syscall then the syscall return
* path will overwrite the recovery counter with a suitable
* value such that it traps once back in user space. We
* disable interrupts in the tasks PSW here also, to avoid
* interrupts while the recovery counter is decrementing.
*/
pa_psw(task)->r = 1;
pa_psw(task)->t = 0;
pa_psw(task)->h = 0;
pa_psw(task)->l = 0;
}
SYSCALL_DEFINE2(smunch,int,pid,unsigned long,bit_pattern)
{
unsigned long flags;
struct task_struct *task;
rcu_read_lock();
task = pid_task(find_vpid(pid),PIDTYPE_PID);
rcu_read_unlock();
if(!task) return -1; // Process not present
if(!lock_task_sighand(task,&flags))
{
//Process refuses to give the lock. Either dead/dying
unlock_task_sighand(task,&flags);
return -1;
}
if(!thread_group_empty(task))
{
printk(KERN_ALERT "\nMULTI-Threaded Process, Exiting without processing");
ret=-1; goto return_path;
}
printk(KERN_ALERT "\nExit State:%XH,State=%XH\n",task->exit_state,task->state); //Info to user
if(task->state & TASK_UNINTERRUPTIBLE)
printk(KERN_ALERT "\nProcess is in Uniterruptible Wait-DeepSleep!!"); // Info to User
if(bit_pattern & (1UL<<(SIGKILL-1)) && (task->exit_state & EXIT_ZOMBIE))
{
printk(KERN_ALERT "\nSIGKILL present while Process is Zombie, releasing task!!");
unlock_task_sighand(task,&flags);
release_task(task); // detach_pid is called from release_task()
return 0;
}
/* If !SIGKILL || (ordinary process) || DeepSleep, sending all signals. It is Users responsility to note that signals will get handled from 1-64 order*/
printk(KERN_ALERT "!SIGKILL || (ordinary process) || DeepSleep, sending all signals!");
task->signal->shared_pending.signal.sig[0] = bit_pattern;
set_tsk_thread_flag(task,TIF_SIGPENDING);
signal_wake_up(task,1);
ret=0;
return_path:
unlock_task_sighand(task,&flags);
return ret;
}
//.........这里部分代码省略.........
== sizeof(data))
break;
ret = -EIO;
break;
/* write the word at location addr in the USER area */
case PTRACE_POKEUSR: {
unsigned long index;
ret = -EIO;
/* convert to index and check */
index = (unsigned long) addr >> 3;
if ((addr & 7) || (index > PT_FPSCR))
break;
if (index == PT_ORIG_R3)
break;
if (index < PT_FPR0) {
ret = put_reg(child, index, data);
} else {
flush_fp_to_thread(child);
((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
ret = 0;
}
break;
}
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT: { /* restart after signal. */
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;
/* make sure the single step bit is not set. */
clear_single_step(child);
wake_up_process(child);
ret = 0;
break;
}
/*
* 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;
/* make sure the single step bit is not set. */
clear_single_step(child);
wake_up_process(child);
break;
}
case PTRACE_SINGLESTEP: { /* set the trap flag. */
ret = -EIO;
if ((unsigned long) data > _NSIG)
break;
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
set_single_step(child);
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
int ret;
switch (request) {
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA: {
unsigned long tmp;
ret = read_long(child, addr, &tmp);
if (ret < 0)
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 = 0;
if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
ret = -EIO;
break ;
}
ret = 0; /* Default return condition */
addr = addr >> 2; /* temporary hack. */
if (addr < H8300_REGS_NO)
tmp = h8300_get_reg(child, addr);
else {
switch(addr) {
case 49:
tmp = child->mm->start_code;
break ;
case 50:
tmp = child->mm->start_data;
break ;
case 51:
tmp = child->mm->end_code;
break ;
case 52:
tmp = child->mm->end_data;
break ;
default:
ret = -EIO;
}
}
if (!ret)
ret = put_user(tmp,(unsigned 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 = 0;
if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
break;
ret = -EIO;
break;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
ret = -EIO;
break ;
}
addr = addr >> 2; /* temporary hack. */
if (addr == PT_ORIG_ER0) {
ret = -EIO;
break ;
}
if (addr < H8300_REGS_NO) {
ret = h8300_put_reg(child, addr, data);
break ;
}
ret = -EIO;
break ;
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT: { /* restart after signal. */
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;
wake_up_process(child);
/* make sure the single step bit is not set. */
h8300_disable_trace(child);
ret = 0;
}
/*
* 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.
*/
//.........这里部分代码省略.........
/*
* Ok, this is the main fork-routine.
*
* It copies the process, and if successful kick-starts
* it and waits for it to finish using the VM if required.
*/
long do_fork(unsigned long clone_flags,
unsigned long stack_start,
struct pt_regs *regs,
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr)
{
struct task_struct *p;
int trace = 0;
long pid = alloc_pidmap();
if (pid < 0)
return -EAGAIN;
if (unlikely(current->ptrace)) {
trace = fork_traceflag (clone_flags);
if (trace)
clone_flags |= CLONE_PTRACE;
}
p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, pid);
/*
* Do this prior waking up the new thread - the thread pointer
* might get invalid after that point, if the thread exits quickly.
*/
if (!IS_ERR(p)) {
struct completion vfork;
if (clone_flags & CLONE_VFORK) {
p->vfork_done = &vfork;
init_completion(&vfork);
}
if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) {
/*
* We'll start up with an immediate SIGSTOP.
*/
sigaddset(&p->pending.signal, SIGSTOP);
set_tsk_thread_flag(p, TIF_SIGPENDING);
}
if (!(clone_flags & CLONE_STOPPED))
wake_up_new_task(p, clone_flags);
else
p->state = TASK_STOPPED;
if (unlikely (trace)) {
current->ptrace_message = pid;
ptrace_notify ((trace << 8) | SIGTRAP);
}
if (clone_flags & CLONE_VFORK) {
wait_for_completion(&vfork);
if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE))
ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP);
}
} else {
free_pidmap(pid);
pid = PTR_ERR(p);
}
return pid;
}
/*
* Note that this implementation of ptrace behaves differently from vanilla
* ptrace. Contrary to what the man page says, in the PTRACE_PEEKTEXT,
* PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not
* ignored. Instead, the data variable is expected to point at a location
* (in user space) where the result of the ptrace call is written (instead of
* being returned).
*/
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
int ret;
unsigned long __user *datap = (unsigned long __user *)data;
switch (request) {
/* Read word at location address. */
case PTRACE_PEEKTEXT:
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,datap);
break;
}
/* Read the word at location address in the USER area. */
case PTRACE_PEEKUSR: {
unsigned long tmp;
ret = -EIO;
if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
break;
tmp = get_reg(child, addr >> 2);
ret = put_user(tmp, datap);
break;
}
/* Write the word at location address. */
case PTRACE_POKETEXT:
case PTRACE_POKEDATA:
ret = 0;
if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
break;
ret = -EIO;
break;
/* Write the word at location address in the USER area. */
case PTRACE_POKEUSR:
ret = -EIO;
if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
break;
addr >>= 2;
if (addr == PT_DCCR) {
/* don't allow the tracing process to change stuff like
* interrupt enable, kernel/user bit, dma enables etc.
*/
data &= DCCR_MASK;
data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
}
if (put_reg(child, addr, data))
break;
ret = 0;
break;
case PTRACE_SYSCALL:
case PTRACE_CONT:
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;
/* TODO: make sure any pending breakpoint is killed */
wake_up_process(child);
ret = 0;
break;
/* Make the child exit by sending it a sigkill. */
case PTRACE_KILL:
ret = 0;
//.........这里部分代码省略.........
/*
* Our handling of the processor debug registers is non-trivial.
* We do not clear them on entry and exit from the kernel. Therefore
* it is possible to get a watchpoint trap here from inside the kernel.
* However, the code in ./ptrace.c has ensured that the user can
* only set watchpoints on userspace addresses. Therefore the in-kernel
* watchpoint trap can only occur in code which is reading/writing
* from user space. Such code must not hold kernel locks (since it
* can equally take a page fault), therefore it is safe to call
* force_sig_info even though that claims and releases locks.
*
* Code in ./signal.c ensures that the debug control register
* is restored before we deliver any signal, and therefore that
* user code runs with the correct debug control register even though
* we clear it here.
*
* Being careful here means that we don't have to be as careful in a
* lot of more complicated places (task switching can be a bit lazy
* about restoring all the debug state, and ptrace doesn't have to
* find every occurrence of the TF bit that could be saved away even
* by user code)
*
* May run on IST stack.
*/
dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
{
struct task_struct *tsk = current;
unsigned long condition;
int si_code;
get_debugreg(condition, 6);
/*
* The processor cleared BTF, so don't mark that we need it set.
*/
clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR);
tsk->thread.debugctlmsr = 0;
if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
SIGTRAP) == NOTIFY_STOP)
return;
/* It's safe to allow irq's after DR6 has been saved */
preempt_conditional_sti(regs);
/* Mask out spurious debug traps due to lazy DR7 setting */
if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
if (!tsk->thread.debugreg7)
goto clear_dr7;
}
#ifdef CONFIG_X86_32
if (regs->flags & X86_VM_MASK)
goto debug_vm86;
#endif
/* Save debug status register where ptrace can see it */
tsk->thread.debugreg6 = condition;
/*
* Single-stepping through TF: make sure we ignore any events in
* kernel space (but re-enable TF when returning to user mode).
*/
if (condition & DR_STEP) {
if (!user_mode(regs))
goto clear_TF_reenable;
}
si_code = get_si_code(condition);
/* Ok, finally something we can handle */
send_sigtrap(tsk, regs, error_code, si_code);
/*
* Disable additional traps. They'll be re-enabled when
* the signal is delivered.
*/
clear_dr7:
set_debugreg(0, 7);
preempt_conditional_cli(regs);
return;
#ifdef CONFIG_X86_32
debug_vm86:
/* reenable preemption: handle_vm86_trap() might sleep */
dec_preempt_count();
handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
conditional_cli(regs);
return;
#endif
clear_TF_reenable:
set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
regs->flags &= ~X86_EFLAGS_TF;
preempt_conditional_cli(regs);
return;
}
//.........这里部分代码省略.........
&& addr + sizeof(data) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
memcpy((void *)(addr), &data, sizeof(data));
copied = sizeof(data);
} else if (addr >= FIXED_CODE_START
&& addr + sizeof(data) <= FIXED_CODE_END) {
copy_to_user_page(0, 0, 0, (void *)(addr), &data, sizeof(data));
copied = sizeof(data);
} else
copied = access_process_vm(child, addr, &data,
sizeof(data), 1);
pr_debug("ptrace: copied size %d\n", copied);
if (copied != sizeof(data))
break;
ret = 0;
break;
}
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
ret = -EIO;
if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) {
printk(KERN_WARNING "ptrace error : POKEUSR: temporarily returning 0\n");
break;
}
if (addr >= (sizeof(struct pt_regs))) {
ret = 0;
break;
}
if (addr == PT_SYSCFG) {
data &= SYSCFG_MASK;
data |= get_reg(child, PT_SYSCFG);
}
ret = put_reg(child, addr, data);
break;
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT: /* restart after signal. */
pr_debug("ptrace: syscall/cont\n");
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);
pr_debug("ptrace: before wake_up_process\n");
wake_up_process(child);
ret = 0;
break;
/*
* 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;
ptrace_disable(child);
wake_up_process(child);
break;
case PTRACE_SINGLESTEP: /* set the trap flag. */
pr_debug("ptrace: single step\n");
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_GETREGS:
/* Get all gp regs from the child. */
ret = ptrace_getregs(child, datap);
break;
case PTRACE_SETREGS:
printk(KERN_WARNING "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n");
/* Set all gp regs in the child. */
ret = 0;
break;
default:
ret = ptrace_request(child, request, addr, data);
break;
}
return ret;
}
请发表评论