main.c revision 12927:a27c46eb192b
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
52static void
53init_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
127int
128main(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