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
init_proc()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
main(int argc,char * argv[])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