/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rdb.h" #include "disasm.h" #include "gram.h" #define PROCSIZE 20 static void init_proc() { int pfd; char procname[PROCSIZE]; sigset_t sigset; fltset_t fltset; sysset_t sysset; long oper, pflags; struct iovec piov[2]; /* * open our own /proc file and set tracing flags */ (void) snprintf(procname, PROCSIZE, "/proc/%d/ctl", EC_SWORD(getpid())); if ((pfd = open(procname, O_WRONLY)) < 0) { (void) fprintf(stderr, "can't open %s\n", procname); exit(1); } /* * inherit on fork, and kill-on-last-close */ oper = PCSET; piov[0].iov_base = (caddr_t)(&oper); piov[0].iov_len = sizeof (oper); pflags = PR_FORK; piov[1].iov_base = (caddr_t)&pflags; piov[1].iov_len = sizeof (pflags); if (writev(pfd, piov, 2) == -1) perr("init_proc: PCSET"); /* * no signal tracing */ oper = PCSTRACE; premptyset(&sigset); piov[1].iov_base = (caddr_t)&sigset; piov[1].iov_len = sizeof (sigset); if (writev(pfd, piov, 2) == -1) perr("PCSTRACE"); /* * no fault tracing */ oper = PCSFAULT; premptyset(&fltset); piov[1].iov_base = (caddr_t)&fltset; piov[1].iov_len = sizeof (fltset); if (writev(pfd, piov, 2) == -1) perr("PCSFAULT"); /* * no syscall tracing */ oper = PCSENTRY; premptyset(&sysset); piov[1].iov_base = (caddr_t)&sysset; piov[1].iov_len = sizeof (sysset); if (writev(pfd, piov, 2) == -1) perr("PSENTRY"); /* * except exit from exec() or execve() */ oper = PCSEXIT; premptyset(&sysset); praddset(&sysset, SYS_execve); if (writev(pfd, piov, 2) == -1) perr("PCSEXIT"); (void) close(pfd); } int main(int argc, char *argv[]) { int pctlfd; int pstatusfd; char procname[PROCSIZE]; char *command; char *rdb_commands = NULL; pid_t cpid; pstatus_t pstatus; sysset_t sysset; int c; int error = 0; long oper; struct iovec piov[2]; extern FILE *yyin; command = argv[0]; while ((c = getopt(argc, argv, "f:")) != EOF) switch (c) { case 'f': rdb_commands = optarg; break; case '?': break; } if (error || (optind == argc)) { (void) printf("usage: %s [-f file] executable " "[executable arguments ...]\n", command); (void) printf("\t-f command file\n"); exit(1); } /* * set up for tracing the child. */ init_proc(); /* * create a child to fork and exec from. */ if ((cpid = fork()) == 0) { (void) execv(argv[optind], &argv[optind]); perr(argv[1]); } if (cpid == -1) /* fork() failure */ perr(command); /* * initialize libelf */ if (elf_version(EV_CURRENT) == EV_NONE) { (void) fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); exit(1); } /* * initialize librtld_db */ if (rd_init(RD_VERSION) != RD_OK) { (void) fprintf(stderr, "librtld_db::rd_init() failed: version " "submitted: %d\n", RD_VERSION); exit(1); } /* rd_log(1); */ /* * Child should now be waiting after the successful * exec. */ (void) snprintf(procname, PROCSIZE, "/proc/%d/ctl", EC_SWORD(cpid)); (void) printf("parent: %d child: %d child procname: %s\n", EC_SWORD(getpid()), EC_SWORD(cpid), procname); if ((pctlfd = open(procname, O_WRONLY)) < 0) { perror(procname); (void) fprintf(stderr, "%s: can't open child %s\n", command, procname); exit(1); } /* * wait for child process. */ oper = PCWSTOP; piov[0].iov_base = (caddr_t)&oper; piov[0].iov_len = sizeof (oper); if (writev(pctlfd, piov, 1) == -1) perr("PCWSTOP"); /* * open /proc//status */ (void) snprintf(procname, PROCSIZE, "/proc/%d/status", EC_SWORD(cpid)); if ((pstatusfd = open(procname, O_RDONLY)) == -1) perr(procname); if (read(pstatusfd, &pstatus, sizeof (pstatus)) == -1) perr("status read failed"); /* * Make sure that it stopped where we expected. */ while ((pstatus.pr_lwp.pr_why == PR_SYSEXIT) && (pstatus.pr_lwp.pr_what == SYS_execve)) { long pflags = 0; if (!(pstatus.pr_lwp.pr_reg[R_PS] & ERRBIT)) { /* successfull exec(2) */ break; } oper = PCRUN; piov[1].iov_base = (caddr_t)&pflags; piov[1].iov_len = sizeof (pflags); if (writev(pctlfd, piov, 2) == -1) perr("PCRUN1"); oper = PCWSTOP; if (writev(pctlfd, piov, 1) == -1) perr("PCWSTOP"); if (read(pstatusfd, &pstatus, sizeof (pstatus)) == -1) perr("status read failed"); } premptyset(&sysset); oper = PCSEXIT; piov[1].iov_base = (caddr_t)&sysset; piov[1].iov_len = sizeof (sysset); if (writev(pctlfd, piov, 2) == -1) perr("PIOCSEXIT"); /* * Did we stop where we expected ? */ if ((pstatus.pr_lwp.pr_why != PR_SYSEXIT) || (pstatus.pr_lwp.pr_what != SYS_execve)) { long pflags = 0; (void) fprintf(stderr, "Didn't catch the exec, why: %d " "what: %d\n", pstatus.pr_lwp.pr_why, pstatus.pr_lwp.pr_what); oper = PCRUN; piov[1].iov_base = (caddr_t)&pflags; piov[1].iov_len = sizeof (pflags); if (writev(pctlfd, piov, 2) == -1) perr("PCRUN2"); exit(1); } (void) ps_init(pctlfd, pstatusfd, cpid, &proch); if (rdb_commands) { if ((yyin = fopen(rdb_commands, "r")) == NULL) { (void) printf("unable to open %s for input\n", rdb_commands); perr("fopen"); } } else { proch.pp_flags |= FLG_PP_PROMPT; rdb_prompt(); } (void) yyparse(); if (proch.pp_flags & FLG_PP_PACT) { long pflags = PRCFAULT; (void) printf("\ncontinuing the hung process...\n"); pctlfd = proch.pp_ctlfd; (void) ps_close(&proch); oper = PCRUN; piov[1].iov_base = (caddr_t)&pflags; piov[1].iov_len = sizeof (pflags); if (writev(pctlfd, piov, 2) == -1) perr("PCRUN2"); (void) close(pctlfd); } return (0); }