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 (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <unistd.h> 29 #include <sys/uio.h> 30 #include <fcntl.h> 31 #include <string.h> 32 #include <errno.h> 33 #include <sys/types.h> 34 #include <sys/signal.h> 35 #include <sys/fault.h> 36 #include <sys/syscall.h> 37 #include <procfs.h> 38 #include <sys/auxv.h> 39 #include <libelf.h> 40 #include <sys/param.h> 41 #include <sys/machelf.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 #define PROCSIZE 20 51 52 static void 53 init_proc() 54 { 55 int pfd; 56 char procname[PROCSIZE]; 57 sigset_t sigset; 58 fltset_t fltset; 59 sysset_t sysset; 60 long oper, pflags; 61 struct iovec piov[2]; 62 63 /* 64 * open our own /proc file and set tracing flags 65 */ 66 (void) snprintf(procname, PROCSIZE, "/proc/%d/ctl", EC_SWORD(getpid())); 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_execve); 121 if (writev(pfd, piov, 2) == -1) 122 perr("PCSEXIT"); 123 124 (void) close(pfd); 125 } 126 127 int 128 main(int argc, char *argv[]) 129 { 130 int pctlfd; 131 int pstatusfd; 132 char procname[PROCSIZE]; 133 char *command; 134 char *rdb_commands = NULL; 135 pid_t cpid; 136 pstatus_t pstatus; 137 sysset_t sysset; 138 int c; 139 int error = 0; 140 long oper; 141 struct iovec piov[2]; 142 extern FILE *yyin; 143 144 command = argv[0]; 145 146 while ((c = getopt(argc, argv, "f:")) != EOF) 147 switch (c) { 148 case 'f': 149 rdb_commands = optarg; 150 break; 151 case '?': 152 break; 153 } 154 155 if (error || (optind == argc)) { 156 (void) printf("usage: %s [-f file] executable " 157 "[executable arguments ...]\n", command); 158 (void) printf("\t-f command file\n"); 159 exit(1); 160 } 161 162 /* 163 * set up for tracing the child. 164 */ 165 init_proc(); 166 167 /* 168 * create a child to fork and exec from. 169 */ 170 if ((cpid = fork()) == 0) { 171 (void) execv(argv[optind], &argv[optind]); 172 perr(argv[1]); 173 } 174 175 if (cpid == -1) /* fork() failure */ 176 perr(command); 177 178 /* 179 * initialize libelf 180 */ 181 if (elf_version(EV_CURRENT) == EV_NONE) { 182 (void) fprintf(stderr, "elf_version() failed: %s\n", 183 elf_errmsg(0)); 184 exit(1); 185 } 186 187 /* 188 * initialize librtld_db 189 */ 190 if (rd_init(RD_VERSION) != RD_OK) { 191 (void) fprintf(stderr, "librtld_db::rd_init() failed: version " 192 "submitted: %d\n", RD_VERSION); 193 exit(1); 194 } 195 196 /* rd_log(1); */ 197 198 /* 199 * Child should now be waiting after the successful 200 * exec. 201 */ 202 (void) snprintf(procname, PROCSIZE, "/proc/%d/ctl", EC_SWORD(cpid)); 203 (void) printf("parent: %d child: %d child procname: %s\n", 204 EC_SWORD(getpid()), EC_SWORD(cpid), procname); 205 if ((pctlfd = open(procname, O_WRONLY)) < 0) { 206 perror(procname); 207 (void) fprintf(stderr, "%s: can't open child %s\n", 208 command, procname); 209 exit(1); 210 } 211 212 /* 213 * wait for child process. 214 */ 215 oper = PCWSTOP; 216 piov[0].iov_base = (caddr_t)&oper; 217 piov[0].iov_len = sizeof (oper); 218 if (writev(pctlfd, piov, 1) == -1) 219 perr("PCWSTOP"); 220 221 /* 222 * open /proc/<cpid>/status 223 */ 224 (void) snprintf(procname, PROCSIZE, "/proc/%d/status", EC_SWORD(cpid)); 225 if ((pstatusfd = open(procname, O_RDONLY)) == -1) 226 perr(procname); 227 228 if (read(pstatusfd, &pstatus, sizeof (pstatus)) == -1) 229 perr("status read failed"); 230 231 /* 232 * Make sure that it stopped where we expected. 233 */ 234 while ((pstatus.pr_lwp.pr_why == PR_SYSEXIT) && 235 (pstatus.pr_lwp.pr_what == SYS_execve)) { 236 long pflags = 0; 237 if (!(pstatus.pr_lwp.pr_reg[R_PS] & ERRBIT)) { 238 /* successfull exec(2) */ 239 break; 240 } 241 242 oper = PCRUN; 243 piov[1].iov_base = (caddr_t)&pflags; 244 piov[1].iov_len = sizeof (pflags); 245 if (writev(pctlfd, piov, 2) == -1) 246 perr("PCRUN1"); 247 248 oper = PCWSTOP; 249 if (writev(pctlfd, piov, 1) == -1) 250 perr("PCWSTOP"); 251 252 if (read(pstatusfd, &pstatus, sizeof (pstatus)) == -1) 253 perr("status read failed"); 254 } 255 256 premptyset(&sysset); 257 oper = PCSEXIT; 258 piov[1].iov_base = (caddr_t)&sysset; 259 piov[1].iov_len = sizeof (sysset); 260 if (writev(pctlfd, piov, 2) == -1) 261 perr("PIOCSEXIT"); 262 263 /* 264 * Did we stop where we expected ? 265 */ 266 if ((pstatus.pr_lwp.pr_why != PR_SYSEXIT) || 267 (pstatus.pr_lwp.pr_what != SYS_execve)) { 268 long pflags = 0; 269 270 (void) fprintf(stderr, "Didn't catch the exec, why: %d " 271 "what: %d\n", pstatus.pr_lwp.pr_why, 272 pstatus.pr_lwp.pr_what); 273 274 oper = PCRUN; 275 piov[1].iov_base = (caddr_t)&pflags; 276 piov[1].iov_len = sizeof (pflags); 277 if (writev(pctlfd, piov, 2) == -1) 278 perr("PCRUN2"); 279 exit(1); 280 } 281 282 (void) ps_init(pctlfd, pstatusfd, cpid, &proch); 283 284 if (rdb_commands) { 285 if ((yyin = fopen(rdb_commands, "r")) == NULL) { 286 (void) printf("unable to open %s for input\n", 287 rdb_commands); 288 perr("fopen"); 289 } 290 } else { 291 proch.pp_flags |= FLG_PP_PROMPT; 292 rdb_prompt(); 293 } 294 (void) yyparse(); 295 296 if (proch.pp_flags & FLG_PP_PACT) { 297 long pflags = PRCFAULT; 298 299 (void) printf("\ncontinuing the hung process...\n"); 300 301 pctlfd = proch.pp_ctlfd; 302 (void) ps_close(&proch); 303 304 oper = PCRUN; 305 piov[1].iov_base = (caddr_t)&pflags; 306 piov[1].iov_len = sizeof (pflags); 307 if (writev(pctlfd, piov, 2) == -1) 308 perr("PCRUN2"); 309 (void) close(pctlfd); 310 } 311 312 return (0); 313 } 314