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 <stdlib.h>
   8#include <unistd.h>
   9#include <errno.h>
  10#include <signal.h>
  11#include <fcntl.h>
  12#include <sys/mman.h>
  13#include <sys/ptrace.h>
  14#include <sys/wait.h>
  15#include <asm/unistd.h>
  16#include <init.h>
  17#include <longjmp.h>
  18#include <os.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/* Kill off a ptraced child by all means available.  kill it normally first,
 105 * then PTRACE_KILL it, then PTRACE_CONT it in case it's in a run state from
 106 * which it can't exit directly.
 107 */
 108
 109void os_kill_ptraced_process(int pid, int reap_child)
 110{
 111        kill(pid, SIGKILL);
 112        ptrace(PTRACE_KILL, pid);
 113        ptrace(PTRACE_CONT, pid);
 114        if (reap_child)
 115                CATCH_EINTR(waitpid(pid, NULL, __WALL));
 116}
 117
 118/* Don't use the glibc version, which caches the result in TLS. It misses some
 119 * syscalls, and also breaks with clone(), which does not unshare the TLS.
 120 */
 121
 122int os_getpid(void)
 123{
 124        return syscall(__NR_getpid);
 125}
 126
 127int os_getpgrp(void)
 128{
 129        return getpgrp();
 130}
 131
 132int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len,
 133                  int r, int w, int x)
 134{
 135        void *loc;
 136        int prot;
 137
 138        prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
 139                (x ? PROT_EXEC : 0);
 140
 141        loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED,
 142                     fd, off);
 143        if (loc == MAP_FAILED)
 144                return -errno;
 145        return 0;
 146}
 147
 148int os_protect_memory(void *addr, unsigned long len, int r, int w, int x)
 149{
 150        int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
 151                    (x ? PROT_EXEC : 0));
 152
 153        if (mprotect(addr, len, prot) < 0)
 154                return -errno;
 155
 156        return 0;
 157}
 158
 159int os_unmap_memory(void *addr, int len)
 160{
 161        int err;
 162
 163        err = munmap(addr, len);
 164        if (err < 0)
 165                return -errno;
 166        return 0;
 167}
 168
 169#ifndef MADV_REMOVE
 170#define MADV_REMOVE KERNEL_MADV_REMOVE
 171#endif
 172
 173int os_drop_memory(void *addr, int length)
 174{
 175        int err;
 176
 177        err = madvise(addr, length, MADV_REMOVE);
 178        if (err < 0)
 179                err = -errno;
 180        return err;
 181}
 182
 183int __init can_drop_memory(void)
 184{
 185        void *addr;
 186        int fd, ok = 0;
 187
 188        printk(UM_KERN_INFO "Checking host MADV_REMOVE support...");
 189        fd = create_mem_file(UM_KERN_PAGE_SIZE);
 190        if (fd < 0) {
 191                printk(UM_KERN_ERR "Creating test memory file failed, "
 192                       "err = %d\n", -fd);
 193                goto out;
 194        }
 195
 196        addr = mmap64(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
 197                      MAP_SHARED, fd, 0);
 198        if (addr == MAP_FAILED) {
 199                printk(UM_KERN_ERR "Mapping test memory file failed, "
 200                       "err = %d\n", -errno);
 201                goto out_close;
 202        }
 203
 204        if (madvise(addr, UM_KERN_PAGE_SIZE, MADV_REMOVE) != 0) {
 205                printk(UM_KERN_ERR "MADV_REMOVE failed, err = %d\n", -errno);
 206                goto out_unmap;
 207        }
 208
 209        printk(UM_KERN_CONT "OK\n");
 210        ok = 1;
 211
 212out_unmap:
 213        munmap(addr, UM_KERN_PAGE_SIZE);
 214out_close:
 215        close(fd);
 216out:
 217        return ok;
 218}
 219
 220static int os_page_mincore(void *addr)
 221{
 222        char vec[2];
 223        int ret;
 224
 225        ret = mincore(addr, UM_KERN_PAGE_SIZE, vec);
 226        if (ret < 0) {
 227                if (errno == ENOMEM || errno == EINVAL)
 228                        return 0;
 229                else
 230                        return -errno;
 231        }
 232
 233        return vec[0] & 1;
 234}
 235
 236int os_mincore(void *addr, unsigned long len)
 237{
 238        char *vec;
 239        int ret, i;
 240
 241        if (len <= UM_KERN_PAGE_SIZE)
 242                return os_page_mincore(addr);
 243
 244        vec = calloc(1, (len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE);
 245        if (!vec)
 246                return -ENOMEM;
 247
 248        ret = mincore(addr, UM_KERN_PAGE_SIZE, vec);
 249        if (ret < 0) {
 250                if (errno == ENOMEM || errno == EINVAL)
 251                        ret = 0;
 252                else
 253                        ret = -errno;
 254
 255                goto out;
 256        }
 257
 258        for (i = 0; i < ((len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); i++) {
 259                if (!(vec[i] & 1)) {
 260                        ret = 0;
 261                        goto out;
 262                }
 263        }
 264
 265        ret = 1;
 266out:
 267        free(vec);
 268        return ret;
 269}
 270
 271void init_new_thread_signals(void)
 272{
 273        set_handler(SIGSEGV);
 274        set_handler(SIGTRAP);
 275        set_handler(SIGFPE);
 276        set_handler(SIGILL);
 277        set_handler(SIGBUS);
 278        signal(SIGHUP, SIG_IGN);
 279        set_handler(SIGIO);
 280        signal(SIGWINCH, SIG_IGN);
 281}
 282