1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <sys/uio.h> 31 #include <fcntl.h> 32 #include <string.h> 33 #include <errno.h> 34 #include <sys/types.h> 35 #include <sys/signal.h> 36 #include <sys/fault.h> 37 #include <sys/syscall.h> 38 #include <procfs.h> 39 #include <sys/auxv.h> 40 #include <libelf.h> 41 #include <sys/param.h> 42 #include <stdarg.h> 43 44 #include <proc_service.h> 45 46 #include "rdb.h" 47 #include "disasm.h" 48 #include "gram.h" 49 50 static void 51 init_proc() 52 { 53 int pfd; 54 pid_t pid; 55 char procname[MAXPATHLEN]; 56 sigset_t sigset; 57 fltset_t fltset; 58 sysset_t sysset; 59 long oper, pflags; 60 struct iovec piov[2]; 61 62 /* 63 * open our own /proc file and set tracing flags 64 */ 65 pid = getpid(); 66 (void) sprintf(procname, "/proc/%d/ctl", pid); 67 if ((pfd = open(procname, O_WRONLY)) < 0) { 68 (void) fprintf(stderr, "can't open %s\n", procname); 69 exit(1); 70 } 71 72 /* 73 * inherit on fork, and kill-on-last-close 74 */ 75 oper = PCSET; 76 piov[0].iov_base = (caddr_t)(&oper); 77 piov[0].iov_len = sizeof (oper); 78 pflags = PR_FORK; 79 piov[1].iov_base = (caddr_t)&pflags; 80 piov[1].iov_len = sizeof (pflags); 81 82 if (writev(pfd, piov, 2) == -1) 83 perr("init_proc: PCSET"); 84 85 /* 86 * no signal tracing 87 */ 88 oper = PCSTRACE; 89 premptyset(&sigset); 90 piov[1].iov_base = (caddr_t)&sigset; 91 piov[1].iov_len = sizeof (sigset); 92 if (writev(pfd, piov, 2) == -1) 93 perr("PCSTRACE"); 94 95 /* 96 * no fault tracing 97 */ 98 oper = PCSFAULT; 99 premptyset(&fltset); 100 piov[1].iov_base = (caddr_t)&fltset; 101 piov[1].iov_len = sizeof (fltset); 102 if (writev(pfd, piov, 2) == -1) 103 perr("PCSFAULT"); 104 105 /* 106 * no syscall tracing 107 */ 108 oper = PCSENTRY; 109 premptyset(&sysset); 110 piov[1].iov_base = (caddr_t)&sysset; 111 piov[1].iov_len = sizeof (sysset); 112 if (writev(pfd, piov, 2) == -1) 113 perr("PSENTRY"); 114 115 /* 116 * except exit from exec() or execve() 117 */ 118 oper = PCSEXIT; 119 premptyset(&sysset); 120 praddset(&sysset, SYS_exec); 121 praddset(&sysset, SYS_execve); 122 if (writev(pfd, piov, 2) == -1) 123 perr("PCSEXIT"); 124 125 (void) close(pfd); 126 } 127 128 int 129 main(int argc, char *argv[]) 130 { 131 int pctlfd; 132 int pstatusfd; 133 char procname[MAXPATHLEN]; 134 char *command; 135 char *rdb_commands = NULL; 136 pid_t cpid; 137 pstatus_t pstatus; 138 sysset_t sysset; 139 int c; 140 int error = 0; 141 long oper; 142 struct iovec piov[2]; 143 extern FILE *yyin; 144 145 command = argv[0]; 146 147 while ((c = getopt(argc, argv, "f:")) != EOF) 148 switch (c) { 149 case 'f': 150 rdb_commands = optarg; 151 break; 152 case '?': 153 break; 154 } 155 156 if (error || (optind == argc)) { 157 (void) printf("usage: %s [-f file] executable " 158 "[executable arguments ...]\n", command); 159 (void) printf("\t-f command file\n"); 160 exit(1); 161 } 162 163 /* 164 * set up for tracing the child. 165 */ 166 init_proc(); 167 168 /* 169 * create a child to fork and exec from. 170 */ 171 if ((cpid = fork()) == 0) { 172 (void) execv(argv[optind], &argv[optind]); 173 perr(argv[1]); 174 } 175 176 if (cpid == -1) /* fork() failure */ 177 perr(command); 178 179 /* 180 * initialize libelf 181 */ 182 if (elf_version(EV_CURRENT) == EV_NONE) { 183 (void) fprintf(stderr, "elf_version() failed: %s\n", 184 elf_errmsg(0)); 185 exit(1); 186 } 187 188 /* 189 * initialize librtld_db 190 */ 191 if (rd_init(RD_VERSION) != RD_OK) { 192 (void) fprintf(stderr, "librtld_db::rd_init() failed: version " 193 "submitted: %d\n", RD_VERSION); 194 exit(1); 195 } 196 197 /* rd_log(1); */ 198 199 /* 200 * Child should now be waiting after the successful 201 * exec. 202 */ 203 (void) sprintf(procname, "/proc/%d/ctl", cpid); 204 (void) printf("parent: %d child: %d child procname: %s\n", getpid(), 205 cpid, procname); 206 if ((pctlfd = open(procname, O_WRONLY)) < 0) { 207 perror(procname); 208 (void) fprintf(stderr, "%s: can't open child %s\n", 209 command, procname); 210 exit(1); 211 } 212 213 /* 214 * wait for child process. 215 */ 216 oper = PCWSTOP; 217 piov[0].iov_base = (caddr_t)&oper; 218 piov[0].iov_len = sizeof (oper); 219 if (writev(pctlfd, piov, 1) == -1) 220 perr("PCWSTOP"); 221 222 /* 223 * open /proc/<cpid>/status 224 */ 225 (void) sprintf(procname, "/proc/%d/status", cpid); 226 if ((pstatusfd = open(procname, O_RDONLY)) == -1) 227 perr(procname); 228 229 if (read(pstatusfd, &pstatus, sizeof (pstatus)) == -1) 230 perr("status read failed"); 231 232 /* 233 * Make sure that it stopped where we expected. 234 */ 235 while ((pstatus.pr_lwp.pr_why == PR_SYSEXIT) && 236 ((pstatus.pr_lwp.pr_what == SYS_exec) || 237 (pstatus.pr_lwp.pr_what == SYS_execve))) { 238 long pflags = 0; 239 if (!(pstatus.pr_lwp.pr_reg[R_PS] & ERRBIT)) { 240 /* successfull exec(2) */ 241 break; 242 } 243 244 oper = PCRUN; 245 piov[1].iov_base = (caddr_t)&pflags; 246 piov[1].iov_len = sizeof (pflags); 247 if (writev(pctlfd, piov, 2) == -1) 248 perr("PCRUN1"); 249 250 oper = PCWSTOP; 251 if (writev(pctlfd, piov, 1) == -1) 252 perr("PCWSTOP"); 253 254 if (read(pstatusfd, &pstatus, sizeof (pstatus)) == -1) 255 perr("status read failed"); 256 } 257 258 premptyset(&sysset); 259 oper = PCSEXIT; 260 piov[1].iov_base = (caddr_t)&sysset; 261 piov[1].iov_len = sizeof (sysset); 262 if (writev(pctlfd, piov, 2) == -1) 263 perr("PIOCSEXIT"); 264 265 /* 266 * Did we stop where we expected ? 267 */ 268 if ((pstatus.pr_lwp.pr_why != PR_SYSEXIT) || 269 ((pstatus.pr_lwp.pr_what != SYS_exec) && 270 (pstatus.pr_lwp.pr_what != SYS_execve))) { 271 long pflags = 0; 272 273 (void) fprintf(stderr, "Didn't catch the exec, why: %d " 274 "what: %d\n", pstatus.pr_lwp.pr_why, 275 pstatus.pr_lwp.pr_what); 276 277 oper = PCRUN; 278 piov[1].iov_base = (caddr_t)&pflags; 279 piov[1].iov_len = sizeof (pflags); 280 if (writev(pctlfd, piov, 2) == -1) 281 perr("PCRUN2"); 282 exit(1); 283 } 284 285 (void) ps_init(pctlfd, pstatusfd, cpid, &proch); 286 287 if (rdb_commands) { 288 if ((yyin = fopen(rdb_commands, "r")) == NULL) { 289 (void) printf("unable to open %s for input\n", 290 rdb_commands); 291 perr("fopen"); 292 } 293 } else { 294 proch.pp_flags |= FLG_PP_PROMPT; 295 rdb_prompt(); 296 } 297 yyparse(); 298 299 if (proch.pp_flags & FLG_PP_PACT) { 300 long pflags = PRCFAULT; 301 302 (void) printf("\ncontinuing the hung process...\n"); 303 304 pctlfd = proch.pp_ctlfd; 305 (void) ps_close(&proch); 306 307 oper = PCRUN; 308 piov[1].iov_base = (caddr_t)&pflags; 309 piov[1].iov_len = sizeof (pflags); 310 if (writev(pctlfd, piov, 2) == -1) 311 perr("PCRUN2"); 312 (void) close(pctlfd); 313 } 314 315 return (0); 316 } 317