📄 process.c
字号:
/* * Copyright (C) 2002- 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */#include <stdlib.h>#include <unistd.h>#include <sched.h>#include <errno.h>#include <string.h>#include <sys/mman.h>#include <sys/ptrace.h>#include <sys/wait.h>#include <asm/unistd.h>#include "as-layout.h"#include "chan_user.h"#include "kern_constants.h"#include "mem.h"#include "os.h"#include "process.h"#include "proc_mm.h"#include "ptrace_user.h"#include "registers.h"#include "skas.h"#include "skas_ptrace.h"#include "user.h"#include "sysdep/stub.h"int is_skas_winch(int pid, int fd, void *data){ if (pid != getpgrp()) return 0; register_winch_irq(-1, fd, -1, data, 0); return 1;}static int ptrace_dump_regs(int pid){ unsigned long regs[MAX_REG_NR]; int i; if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) return -errno; printk(UM_KERN_ERR "Stub registers -\n"); for (i = 0; i < ARRAY_SIZE(regs); i++) printk(UM_KERN_ERR "\t%d - %lx\n", i, regs[i]); return 0;}/* * Signals that are OK to receive in the stub - we'll just continue it. * SIGWINCH will happen when UML is inside a detached screen. */#define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH))/* Signals that the stub will finish with - anything else is an error */#define STUB_DONE_MASK ((1 << SIGUSR1) | (1 << SIGTRAP))void wait_stub_done(int pid){ int n, status, err; while (1) { CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL)); if ((n < 0) || !WIFSTOPPED(status)) goto bad_wait; if (((1 << WSTOPSIG(status)) & STUB_SIG_MASK) == 0) break; err = ptrace(PTRACE_CONT, pid, 0, 0); if (err) panic("wait_stub_done : continue failed, errno = %d\n", errno); } if (((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0) return;bad_wait: err = ptrace_dump_regs(pid); if (err) printk(UM_KERN_ERR "Failed to get registers from stub, " "errno = %d\n", -err); panic("wait_stub_done : failed to wait for SIGUSR1/SIGTRAP, pid = %d, " "n = %d, errno = %d, status = 0x%x\n", pid, n, errno, status);}extern unsigned long current_stub_stack(void);void get_skas_faultinfo(int pid, struct faultinfo * fi){ int err; if (ptrace_faultinfo) { err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); if (err) panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, " "errno = %d\n", errno); /* Special handling for i386, which has different structs */ if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) memset((char *)fi + sizeof(struct ptrace_faultinfo), 0, sizeof(struct faultinfo) - sizeof(struct ptrace_faultinfo)); } else { err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV); if (err) panic("Failed to continue stub, pid = %d, errno = %d\n", pid, errno); wait_stub_done(pid); /* * faultinfo is prepared by the stub-segv-handler at start of * the stub stack page. We just have to copy it. */ memcpy(fi, (void *)current_stub_stack(), sizeof(*fi)); }}static void handle_segv(int pid, struct uml_pt_regs * regs){ get_skas_faultinfo(pid, ®s->faultinfo); segv(regs->faultinfo, 0, 1, NULL);}/* * To use the same value of using_sysemu as the caller, ask it that value * (in local_using_sysemu */static void handle_trap(int pid, struct uml_pt_regs *regs, int local_using_sysemu){ int err, status; /* Mark this as a syscall */ UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->gp); if (!local_using_sysemu) { err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); if (err < 0) panic("handle_trap - nullifying syscall failed, " "errno = %d\n", errno); err = ptrace(PTRACE_SYSCALL, pid, 0, 0); if (err < 0) panic("handle_trap - continuing to end of syscall " "failed, errno = %d\n", errno); CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL)); if ((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP + 0x80)) { err = ptrace_dump_regs(pid); if (err) printk(UM_KERN_ERR "Failed to get registers " "from process, errno = %d\n", -err); panic("handle_trap - failed to wait at end of syscall, " "errno = %d, status = %d\n", errno, status); } } handle_syscall(regs);}extern int __syscall_stub_start;static int userspace_tramp(void *stack){ void *addr; int err; ptrace(PTRACE_TRACEME, 0, 0, 0); signal(SIGTERM, SIG_DFL); err = set_interval(); if (err) panic("userspace_tramp - setting timer failed, errno = %d\n", err); if (!proc_mm) { /* * This has a pte, but it can't be mapped in with the usual * tlb_flush mechanism because this is part of that mechanism */ int fd; unsigned long long offset; fd = phys_mapping(to_phys(&__syscall_stub_start), &offset); addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE, PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); if (addr == MAP_FAILED) { printk(UM_KERN_ERR "mapping mmap stub at 0x%lx failed, " "errno = %d\n", STUB_CODE, errno); exit(1); } if (stack != NULL) { fd = phys_mapping(to_phys(stack), &offset); addr = mmap((void *) STUB_DATA, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, offset); if (addr == MAP_FAILED) { printk(UM_KERN_ERR "mapping segfault stack " "at 0x%lx failed, errno = %d\n", STUB_DATA, errno); exit(1); } } } if (!ptrace_faultinfo && (stack != NULL)) { struct sigaction sa; unsigned long v = STUB_CODE + (unsigned long) stub_segv_handler - (unsigned long) &__syscall_stub_start; set_sigstack((void *) STUB_DATA, UM_KERN_PAGE_SIZE); sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGIO); sigaddset(&sa.sa_mask, SIGWINCH); sigaddset(&sa.sa_mask, SIGVTALRM); sigaddset(&sa.sa_mask, SIGUSR1); sa.sa_flags = SA_ONSTACK; sa.sa_handler = (void *) v; sa.sa_restorer = NULL; if (sigaction(SIGSEGV, &sa, NULL) < 0) panic("userspace_tramp - setting SIGSEGV handler " "failed - errno = %d\n", errno); } kill(os_getpid(), SIGSTOP); return 0;}/* Each element set once, and only accessed by a single processor anyway */#undef NR_CPUS#define NR_CPUS 1int userspace_pid[NR_CPUS];int start_userspace(unsigned long stub_stack){ void *stack; unsigned long sp; int pid, status, n, flags; stack = mmap(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (stack == MAP_FAILED) panic("start_userspace : mmap failed, errno = %d", errno); sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *); flags = CLONE_FILES; if (proc_mm) flags |= CLONE_VM; else flags |= SIGCHLD; pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack); if (pid < 0) panic("start_userspace : clone failed, errno = %d", errno); do { CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL)); if (n < 0) panic("start_userspace : wait failed, errno = %d", errno); } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) panic("start_userspace : expected SIGSTOP, got status = %d", status); if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, (void *) PTRACE_O_TRACESYSGOOD) < 0) panic("start_userspace : PTRACE_OLDSETOPTIONS failed, " "errno = %d\n", errno); if (munmap(stack, UM_KERN_PAGE_SIZE) < 0) panic("start_userspace : munmap failed, errno = %d\n", errno); return pid;}void userspace(struct uml_pt_regs *regs){ struct itimerval timer; unsigned long long nsecs, now; int err, status, op, pid = userspace_pid[0]; /* To prevent races if using_sysemu changes under us.*/ int local_using_sysemu; if (getitimer(ITIMER_VIRTUAL, &timer)) printk("Failed to get itimer, errno = %d\n", errno); nsecs = timer.it_value.tv_sec * UM_NSEC_PER_SEC + timer.it_value.tv_usec * UM_NSEC_PER_USEC; nsecs += os_nsecs(); while (1) { restore_registers(pid, regs); /* Now we set local_using_sysemu to be used for one loop */ local_using_sysemu = get_using_sysemu(); op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -