📄 ptrace.c
字号:
/* ptrace.c: FRV specific parts of process tracing * * Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * - Derived from arch/m68k/kernel/ptrace.c * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/errno.h>#include <linux/ptrace.h>#include <linux/user.h>#include <linux/config.h>#include <linux/security.h>#include <linux/signal.h>#include <asm/uaccess.h>#include <asm/page.h>#include <asm/pgtable.h>#include <asm/system.h>#include <asm/processor.h>#include <asm/unistd.h>/* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. *//* * Get contents of register REGNO in task TASK. */static inline long get_reg(struct task_struct *task, int regno){ struct user_context *user = task->thread.user; if (regno < 0 || regno >= PT__END) return 0; return ((unsigned long *) user)[regno];}/* * Write contents of register REGNO in task TASK. */static inline int put_reg(struct task_struct *task, int regno, unsigned long data){ struct user_context *user = task->thread.user; if (regno < 0 || regno >= PT__END) return -EIO; switch (regno) { case PT_GR(0): return 0; case PT_PSR: case PT__STATUS: return -EIO; default: ((unsigned long *) user)[regno] = data; return 0; }}/* * 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_list_struct *vml; for (vml = child->mm->context.vmlist; vml; vml = vml->next) if (start >= vml->vma->vm_start && start + len <= vml->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){ child->thread.frame0->__status &= ~REG__STATUS_STEP;}void ptrace_enable(struct task_struct *child){ child->thread.frame0->__status |= REG__STATUS_STEP;}long arch_ptrace(struct task_struct *child, long request, long addr, long data){ unsigned long tmp; 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: { int copied; ret = -EIO; if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0) break; copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); 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: { tmp = 0; ret = -EIO; if ((addr & 3) || addr < 0) break; ret = 0; switch (addr >> 2) { case 0 ... PT__END - 1: tmp = get_reg(child, addr >> 2); break; case PT__END + 0: tmp = child->mm->end_code - child->mm->start_code; break; case PT__END + 1: tmp = child->mm->end_data - child->mm->start_data; break; case PT__END + 2: tmp = child->mm->start_stack - child->mm->start_brk; break; case PT__END + 3: tmp = child->mm->start_code; break; case PT__END + 4: tmp = child->mm->start_stack; break; default: ret = -EIO; break; } if (ret == 0) 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 = -EIO; if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0) break; if (access_process_vm(child, addr, &data, sizeof(data), 1) != 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 < 0) break; ret = 0; switch (addr >> 2) { case 0 ... PT__END-1: ret = put_reg(child, addr >> 2, data); break; default: ret = -EIO; break; } 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; /* 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_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_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_GETFDPIC: tmp = 0; switch (addr) { case PTRACE_GETFDPIC_EXEC: tmp = child->mm->context.exec_fdpic_loadmap; break; case PTRACE_GETFDPIC_INTERP: tmp = child->mm->context.interp_fdpic_loadmap; break; default: break; } ret = 0; if (put_user(tmp, (unsigned long *) data)) { ret = -EFAULT; break; } break; default: ret = -EIO; 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 },
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -