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