xref: /illumos-gate/usr/src/cmd/sgs/demo_rdb/common/main.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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[optind]);
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