Home | History | Annotate | Download | only in common
      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