linux/arch/um/os-Linux/process.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   3 * Licensed under the GPL
   4 */
   5
   6#include <stdio.h>
   7#include <unistd.h>
   8#include <errno.h>
   9#include <signal.h>
  10#include <fcntl.h>
  11#include <sys/mman.h>
  12#include <sys/ptrace.h>
  13#include <sys/wait.h>
  14#include <asm/unistd.h>
  15#include "init.h"
  16#include "longjmp.h"
  17#include "os.h"
  18#include "skas_ptrace.h"
  19
  20#define ARBITRARY_ADDR -1
  21#define FAILURE_PID    -1
  22
  23#define STAT_PATH_LEN sizeof("/proc/#######/stat\0")
  24#define COMM_SCANF "%*[^)])"
  25
  26unsigned long os_process_pc(int pid)
  27{
  28        char proc_stat[STAT_PATH_LEN], buf[256];
  29        unsigned long pc = ARBITRARY_ADDR;
  30        int fd, err;
  31
  32        sprintf(proc_stat, "/proc/%d/stat", pid);
  33        fd = open(proc_stat, O_RDONLY, 0);
  34        if (fd < 0) {
  35                printk(UM_KERN_ERR "os_process_pc - couldn't open '%s', "
  36                       "errno = %d\n", proc_stat, errno);
  37                goto out;
  38        }
  39        CATCH_EINTR(err = read(fd, buf, sizeof(buf)));
  40        if (err < 0) {
  41                printk(UM_KERN_ERR "os_process_pc - couldn't read '%s', "
  42                       "err = %d\n", proc_stat, errno);
  43                goto out_close;
  44        }
  45        os_close_file(fd);
  46        pc = ARBITRARY_ADDR;
  47        if (sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d "
  48                   "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
  49                   "%*d %*d %*d %*d %*d %lu", &pc) != 1)
  50                printk(UM_KERN_ERR "os_process_pc - couldn't find pc in '%s'\n",
  51                       buf);
  52 out_close:
  53        close(fd);
  54 out:
  55        return pc;
  56}
  57
  58int os_process_parent(int pid)
  59{
  60        char stat[STAT_PATH_LEN];
  61        char data[256];
  62        int parent = FAILURE_PID, n, fd;
  63
  64        if (pid == -1)
  65                return parent;
  66
  67        snprintf(stat, sizeof(stat), "/proc/%d/stat", pid);
  68        fd = open(stat, O_RDONLY, 0);
  69        if (fd < 0) {
  70                printk(UM_KERN_ERR "Couldn't open '%s', errno = %d\n", stat,
  71                       errno);
  72                return parent;
  73        }
  74
  75        CATCH_EINTR(n = read(fd, data, sizeof(data)));
  76        close(fd);
  77
  78        if (n < 0) {
  79                printk(UM_KERN_ERR "Couldn't read '%s', errno = %d\n", stat,
  80                       errno);
  81                return parent;
  82        }
  83
  84        parent = FAILURE_PID;
  85        n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent);
  86        if (n != 1)
  87                printk(UM_KERN_ERR "Failed to scan '%s'\n", data);
  88
  89        return parent;
  90}
  91
  92void os_stop_process(int pid)
  93{
  94        kill(pid, SIGSTOP);
  95}
  96
  97void os_kill_process(int pid, int reap_child)
  98{
  99        kill(pid, SIGKILL);
 100        if (reap_child)
 101                CATCH_EINTR(waitpid(pid, NULL, __WALL));
 102}
 103
 104/* This is here uniquely to have access to the userspace errno, i.e. the one
 105 * used by ptrace in case of error.
 106 */
 107
 108long os_ptrace_ldt(long pid, long addr, long data)
 109{
 110        int ret;
 111
 112        ret = ptrace(PTRACE_LDT, pid, addr, data);
 113
 114        if (ret < 0)
 115                return -errno;
 116        return ret;
 117}
 118
 119/* Kill off a ptraced child by all means available.  kill it normally first,
 120 * then PTRACE_KILL it, then PTRACE_CONT it in case it's in a run state from
 121 * which it can't exit directly.
 122 */
 123
 124void os_kill_ptraced_process(int pid, int reap_child)
 125{
 126        kill(pid, SIGKILL);
 127        ptrace(PTRACE_KILL, pid);
 128        ptrace(PTRACE_CONT, pid);
 129        if (reap_child)
 130                CATCH_EINTR(waitpid(pid, NULL, __WALL));
 131}
 132
 133/* Don't use the glibc version, which caches the result in TLS. It misses some
 134 * syscalls, and also breaks with clone(), which does not unshare the TLS.
 135 */
 136
 137int os_getpid(void)
 138{
 139        return syscall(__NR_getpid);
 140}
 141
 142int os_getpgrp(void)
 143{
 144        return getpgrp();
 145}
 146
 147int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len,
 148                  int r, int w, int x)
 149{
 150        void *loc;
 151        int prot;
 152
 153        prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
 154                (x ? PROT_EXEC : 0);
 155
 156        loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED,
 157                     fd, off);
 158        if (loc == MAP_FAILED)
 159                return -errno;
 160        return 0;
 161}
 162
 163int os_protect_memory(void *addr, unsigned long len, int r, int w, int x)
 164{
 165        int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
 166                    (x ? PROT_EXEC : 0));
 167
 168        if (mprotect(addr, len, prot) < 0)
 169                return -errno;
 170
 171        return 0;
 172}
 173
 174int os_unmap_memory(void *addr, int len)
 175{
 176        int err;
 177
 178        err = munmap(addr, len);
 179        if (err < 0)
 180                return -errno;
 181        return 0;
 182}
 183
 184#ifndef MADV_REMOVE
 185#define MADV_REMOVE KERNEL_MADV_REMOVE
 186#endif
 187
 188int os_drop_memory(void *addr, int length)
 189{
 190        int err;
 191
 192        err = madvise(addr, length, MADV_REMOVE);
 193        if (err < 0)
 194                err = -errno;
 195        return err;
 196}
 197
 198int __init can_drop_memory(void)
 199{
 200        void *addr;
 201        int fd, ok = 0;
 202
 203        printk(UM_KERN_INFO "Checking host MADV_REMOVE support...");
 204        fd = create_mem_file(UM_KERN_PAGE_SIZE);
 205        if (fd < 0) {
 206                printk(UM_KERN_ERR "Creating test memory file failed, "
 207                       "err = %d\n", -fd);
 208                goto out;
 209        }
 210
 211        addr = mmap64(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
 212                      MAP_SHARED, fd, 0);
 213        if (addr == MAP_FAILED) {
 214                printk(UM_KERN_ERR "Mapping test memory file failed, "
 215                       "err = %d\n", -errno);
 216                goto out_close;
 217        }
 218
 219        if (madvise(addr, UM_KERN_PAGE_SIZE, MADV_REMOVE) != 0) {
 220                printk(UM_KERN_ERR "MADV_REMOVE failed, err = %d\n", -errno);
 221                goto out_unmap;
 222        }
 223
 224        printk(UM_KERN_CONT "OK\n");
 225        ok = 1;
 226
 227out_unmap:
 228        munmap(addr, UM_KERN_PAGE_SIZE);
 229out_close:
 230        close(fd);
 231out:
 232        return ok;
 233}
 234
 235void init_new_thread_signals(void)
 236{
 237        set_handler(SIGSEGV);
 238        set_handler(SIGTRAP);
 239        set_handler(SIGFPE);
 240        set_handler(SIGILL);
 241        set_handler(SIGBUS);
 242        signal(SIGHUP, SIG_IGN);
 243        set_handler(SIGIO);
 244        signal(SIGWINCH, SIG_IGN);
 245        signal(SIGTERM, SIG_DFL);
 246}
 247
 248int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr)
 249{
 250        jmp_buf buf;
 251        int n;
 252
 253        *jmp_ptr = &buf;
 254        n = UML_SETJMP(&buf);
 255        if (n != 0)
 256                return n;
 257        (*fn)(arg);
 258        return 0;
 259}
 260