1 /*- 2 * Copyright (c) 2008 John Birrell (jb@freebsd.org) 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/types.h> 31 #include <sys/sysctl.h> 32 #include <sys/user.h> 33 #include <sys/wait.h> 34 35 #include <err.h> 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <limits.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 43 #include <libelf.h> 44 #include <libprocstat.h> 45 46 #include "_libproc.h" 47 48 static int getelfclass(int); 49 static int proc_init(pid_t, int, int, struct proc_handle **); 50 51 static int 52 getelfclass(int fd) 53 { 54 GElf_Ehdr ehdr; 55 Elf *e; 56 int class; 57 58 class = ELFCLASSNONE; 59 60 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) 61 goto out; 62 if (gelf_getehdr(e, &ehdr) == NULL) 63 goto out; 64 class = ehdr.e_ident[EI_CLASS]; 65 out: 66 (void)elf_end(e); 67 return (class); 68 } 69 70 static int 71 proc_init(pid_t pid, int flags, int status, struct proc_handle **pphdl) 72 { 73 struct kinfo_proc *kp; 74 struct proc_handle *phdl; 75 int error, class, count, fd; 76 77 error = ENOMEM; 78 if ((phdl = malloc(sizeof(*phdl))) == NULL) 79 goto out; 80 81 memset(phdl, 0, sizeof(*phdl)); 82 phdl->public.pid = pid; 83 phdl->flags = flags; 84 phdl->status = status; 85 phdl->procstat = procstat_open_sysctl(); 86 if (phdl->procstat == NULL) 87 goto out; 88 89 /* Obtain a path to the executable. */ 90 if ((kp = procstat_getprocs(phdl->procstat, KERN_PROC_PID, pid, 91 &count)) == NULL) 92 goto out; 93 error = procstat_getpathname(phdl->procstat, kp, phdl->execpath, 94 sizeof(phdl->execpath)); 95 procstat_freeprocs(phdl->procstat, kp); 96 if (error != 0) 97 goto out; 98 99 /* Use it to determine the data model for the process. */ 100 if ((fd = open(phdl->execpath, O_RDONLY)) < 0) { 101 error = errno; 102 goto out; 103 } 104 class = getelfclass(fd); 105 switch (class) { 106 case ELFCLASS64: 107 phdl->model = PR_MODEL_LP64; 108 break; 109 case ELFCLASS32: 110 phdl->model = PR_MODEL_ILP32; 111 break; 112 case ELFCLASSNONE: 113 default: 114 error = EINVAL; 115 break; 116 } 117 (void)close(fd); 118 119 out: 120 *pphdl = phdl; 121 return (error); 122 } 123 124 int 125 proc_attach(pid_t pid, int flags, struct proc_handle **pphdl) 126 { 127 struct proc_handle *phdl; 128 int error, status; 129 130 if (pid == 0 || (pid == getpid() && (flags & PATTACH_RDONLY) == 0)) 131 return (EINVAL); 132 if (elf_version(EV_CURRENT) == EV_NONE) 133 return (ENOENT); 134 135 /* 136 * Allocate memory for the process handle, a structure containing 137 * all things related to the process. 138 */ 139 error = proc_init(pid, flags, PS_RUN, &phdl); 140 if (error != 0) 141 goto out; 142 143 if ((flags & PATTACH_RDONLY) == 0) { 144 if (ptrace(PT_ATTACH, proc_getpid(phdl), 0, 0) != 0) { 145 error = errno; 146 DPRINTF("ERROR: cannot ptrace child process %d", pid); 147 goto out; 148 } 149 150 /* Wait for the child process to stop. */ 151 if (waitpid(pid, &status, WUNTRACED) == -1) { 152 error = errno; 153 DPRINTF("ERROR: child process %d didn't stop as expected", pid); 154 goto out; 155 } 156 157 /* Check for an unexpected status. */ 158 if (!WIFSTOPPED(status)) 159 DPRINTFX("ERROR: child process %d status 0x%x", pid, status); 160 else 161 phdl->status = PS_STOP; 162 163 if ((flags & PATTACH_NOSTOP) != 0) 164 proc_continue(phdl); 165 } 166 167 out: 168 if (error != 0 && phdl != NULL) { 169 proc_free(phdl); 170 phdl = NULL; 171 } 172 *pphdl = phdl; 173 return (error); 174 } 175 176 int 177 proc_create(const char *file, char * const *argv, proc_child_func *pcf, 178 void *child_arg, struct proc_handle **pphdl) 179 { 180 struct proc_handle *phdl; 181 int error = 0; 182 int status; 183 pid_t pid; 184 185 if (elf_version(EV_CURRENT) == EV_NONE) 186 return (ENOENT); 187 188 /* Fork a new process. */ 189 if ((pid = vfork()) == -1) 190 error = errno; 191 else if (pid == 0) { 192 /* The child expects to be traced. */ 193 if (ptrace(PT_TRACE_ME, 0, 0, 0) != 0) 194 _exit(1); 195 196 if (pcf != NULL) 197 (*pcf)(child_arg); 198 199 /* Execute the specified file: */ 200 execvp(file, argv); 201 202 /* Couldn't execute the file. */ 203 _exit(2); 204 /* NOTREACHED */ 205 } else { 206 /* The parent owns the process handle. */ 207 error = proc_init(pid, 0, PS_IDLE, &phdl); 208 if (error != 0) 209 goto bad; 210 211 /* Wait for the child process to stop. */ 212 if (waitpid(pid, &status, WUNTRACED) == -1) { 213 error = errno; 214 DPRINTF("ERROR: child process %d didn't stop as expected", pid); 215 goto bad; 216 } 217 218 /* Check for an unexpected status. */ 219 if (!WIFSTOPPED(status)) { 220 error = errno; 221 DPRINTFX("ERROR: child process %d status 0x%x", pid, status); 222 goto bad; 223 } else 224 phdl->status = PS_STOP; 225 } 226 bad: 227 if (error && phdl != NULL) { 228 proc_free(phdl); 229 phdl = NULL; 230 } 231 *pphdl = phdl; 232 return (error); 233 } 234 235 void 236 proc_free(struct proc_handle *phdl) 237 { 238 struct file_info *file; 239 size_t i; 240 241 for (i = 0; i < phdl->nmappings; i++) { 242 file = phdl->mappings[i].file; 243 if (file != NULL && --file->refs == 0) { 244 if (file->elf != NULL) { 245 (void)elf_end(file->elf); 246 (void)close(file->fd); 247 if (file->symtab.nsyms > 0) 248 free(file->symtab.index); 249 if (file->dynsymtab.nsyms > 0) 250 free(file->dynsymtab.index); 251 } 252 free(file); 253 } 254 } 255 if (phdl->maparrsz > 0) 256 free(phdl->mappings); 257 if (phdl->procstat != NULL) 258 procstat_close(phdl->procstat); 259 if (phdl->rdap != NULL) 260 rd_delete(phdl->rdap); 261 free(phdl); 262 } 263