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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1994-1999 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * This file contains interfaces that are wrappers over the basic
31 * /proc ioctls
32 */
33
34 #include <unistd.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <sys/uio.h>
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/fault.h>
44 #include <sys/procfs.h>
45
46 #include "prb_proc_int.h"
47 #include "dbg.h"
48
49 /*
50 * Declarations
51 */
52
53 #define PROCFORMAT "/proc/%d"
54
55 static prb_status_t
56 prb_proc_open_general(pid_t pid, prb_proc_ctl_t **proc_pp, int oflg);
57
58 /*
59 * prb_proc_open_general() - function to open the process file
60 * system entry for the supplied process. Opens with different
61 * options based on the 'oflg'.
62 * Returns a pointer to an opaque structure that contains the fd
63 * needed for /proc control.
64 */
65
66 prb_status_t
prb_proc_open_general(pid_t pid,prb_proc_ctl_t ** proc_pp,int oflg)67 prb_proc_open_general(pid_t pid, prb_proc_ctl_t **proc_pp, int oflg)
68 {
69 prb_proc_ctl_t *proc_p;
70 char path[MAXPATHLEN];
71 int retval;
72
73 (void) sprintf(path, PROCFORMAT, (int)pid);
74
75 DBG_TNF_PROBE_1(prb_proc_open_1, "libtnfctl", "sunw%verbosity 2",
76 tnf_string, opening_proc_on, path);
77
78 retval = open(path, oflg);
79 if (retval == -1) {
80 DBG((void) fprintf(stderr,
81 "proc_open: open of \"%s\" failed: %s\n",
82 path, strerror(errno)));
83 return (prb_status_map(errno));
84 }
85 /* allocate proc_p and zero fill */
86 proc_p = calloc(1, sizeof (*proc_p));
87 if (proc_p == NULL)
88 return (PRB_STATUS_ALLOCFAIL);
89 proc_p->procfd = retval;
90 proc_p->pid = pid;
91 *proc_pp = proc_p;
92 return (PRB_STATUS_OK);
93 }
94
95
96 /*
97 * prb_proc_open() - a wrapper which opens the process file system
98 * entry for the supplied process. Returns a pointer to an opaque
99 * structure that contains the fd needed for /proc control.
100 */
101
102 prb_status_t
prb_proc_open(pid_t pid,prb_proc_ctl_t ** proc_pp)103 prb_proc_open(pid_t pid, prb_proc_ctl_t **proc_pp)
104 {
105
106 return (prb_proc_open_general(pid,
107 proc_pp, O_RDWR | O_EXCL));
108
109 }
110
111 /*
112 * prb_proc_reopen() - re-opens the process, mainly for setuid/setgid files.
113 * Read the last section of /proc man page for details.
114 * re-open should not use O_EXCL flag.
115 */
116
117 prb_status_t
prb_proc_reopen(pid_t pid,prb_proc_ctl_t ** proc_pp)118 prb_proc_reopen(pid_t pid, prb_proc_ctl_t **proc_pp)
119 {
120
121 return (prb_proc_open_general(pid,
122 proc_pp, O_RDWR));
123
124 }
125
126 /*
127 * prob_proc_close() - close the proc fd and free the memory taken up
128 * by proc_p
129 */
130 prb_status_t
prb_proc_close(prb_proc_ctl_t * proc_p)131 prb_proc_close(prb_proc_ctl_t *proc_p)
132 {
133 DBG_TNF_PROBE_0(prb_proc_close_1, "libtnfctl", "sunw%verbosity 2");
134
135 if (proc_p == NULL)
136 return (PRB_STATUS_OK);
137
138 if (close(proc_p->procfd) == -1) {
139 DBG((void) fprintf(stderr,
140 "proc_close: close failed: %s\n", strerror(errno)));
141 return (prb_status_map(errno));
142 }
143 free(proc_p);
144 return (PRB_STATUS_OK);
145 }
146
147 /*
148 * prb_proc_pid_get() - gets the pid of the proc
149 */
150 pid_t
prb_proc_pid_get(prb_proc_ctl_t * proc_p)151 prb_proc_pid_get(prb_proc_ctl_t *proc_p)
152 {
153 return (proc_p->pid);
154 }
155
156 /*
157 * prb_proc_stop() - stops the target process
158 */
159 prb_status_t
prb_proc_stop(prb_proc_ctl_t * proc_p)160 prb_proc_stop(prb_proc_ctl_t *proc_p)
161 {
162 int retval;
163
164 DBG_TNF_PROBE_0(prb_proc_stop_1, "libtnfctl",
165 "sunw%verbosity 2; sunw%debug 'stopping the target process'");
166
167 again:
168 retval = ioctl(proc_p->procfd, PIOCSTOP, NULL);
169 if (retval == -1) {
170 if (errno == EINTR)
171 goto again;
172 DBG((void) fprintf(stderr,
173 "prb_proc_stop: PIOCSTOP failed: %s\n",
174 strerror(errno)));
175 return (prb_status_map(errno));
176 }
177 return (PRB_STATUS_OK);
178 }
179
180
181 /*
182 * prb_proc_prstop() - runs and stops the process, used to clear a target
183 * process out of a system call state.
184 */
185 prb_status_t
prb_proc_prstop(prb_proc_ctl_t * proc_p)186 prb_proc_prstop(prb_proc_ctl_t *proc_p)
187 {
188 int procfd;
189 int retval;
190 prrun_t prrun;
191 prstatus_t prstat;
192
193 DBG_TNF_PROBE_0(prb_proc_prstop_1, "libtnfctl",
194 "sunw%verbosity 2; sunw%debug 'stepping the target process'");
195
196 procfd = proc_p->procfd;
197 (void) memset((char *)&prrun, 0, sizeof (prrun));
198 (void) memset((char *)&prstat, 0, sizeof (prstat));
199
200 again1:
201 prrun.pr_flags = PRSTOP;
202 retval = ioctl(procfd, PIOCRUN, &prrun);
203 if (retval == -1) {
204 if (errno == EINTR)
205 goto again1;
206 DBG((void) fprintf(stderr,
207 "prb_proc_prstop: PIOCRUN failed: %s\n",
208 strerror(errno)));
209 return (prb_status_map(errno));
210 }
211 again2:
212 retval = ioctl(procfd, PIOCWSTOP, &prstat);
213 if (retval == -1) {
214 if (errno == EINTR)
215 goto again2;
216 DBG((void) fprintf(stderr,
217 "prb_proc_prstop: PIOCWSTOP failed: %s\n",
218 strerror(errno)));
219 return (prb_status_map(errno));
220 }
221 /*
222 * if we didn't stop because we requested it (eg. if there was a
223 * signal in the target ?), we might need to try again
224 */
225 if (prstat.pr_why != PR_REQUESTED)
226 goto again1;
227
228 return (PRB_STATUS_OK);
229 }
230
231
232 /*
233 * prb_proc_state() - returns the status pf the process
234 */
235 prb_status_t
prb_proc_state(prb_proc_ctl_t * proc_p,prb_proc_state_t * state_p)236 prb_proc_state(prb_proc_ctl_t *proc_p, prb_proc_state_t *state_p)
237 {
238 int procfd;
239 int retval;
240 prstatus_t prstatus;
241
242 DBG_TNF_PROBE_0(prb_proc_state_1, "libtnfctl",
243 "sunw%verbosity 2; sunw%debug 'getting the status'");
244
245 procfd = proc_p->procfd;
246
247 (void) memset(&prstatus, 0, sizeof (prstatus));
248
249 again:
250 retval = ioctl(procfd, PIOCSTATUS, &prstatus);
251 if (retval == -1) {
252 if (errno == EINTR)
253 goto again;
254 DBG((void) fprintf(stderr,
255 "prb_proc_status: PIOCSTATUS failed: %s\n",
256 strerror(errno)));
257 return (prb_status_map(errno));
258 }
259 state_p->ps_isbptfault = (prstatus.pr_flags & PR_FAULTED &&
260 prstatus.pr_what == FLTBPT);
261 state_p->ps_isstopped = ((prstatus.pr_flags & PR_STOPPED) != 0);
262 state_p->ps_isinsys = ((prstatus.pr_flags & PR_ASLEEP) != 0);
263 state_p->ps_isrequested = ((prstatus.pr_why & PR_REQUESTED) != 0);
264 state_p->ps_issysexit = ((prstatus.pr_why & PR_SYSEXIT) != 0);
265 state_p->ps_issysentry = ((prstatus.pr_why & PR_SYSENTRY) != 0);
266 state_p->ps_syscallnum = prstatus.pr_what;
267 return (PRB_STATUS_OK);
268 }
269
270
271 /*
272 * prb_proc_wait() - waits for the target process to stop
273 */
274 prb_status_t
prb_proc_wait(prb_proc_ctl_t * proc_p,boolean_t use_sigmask,sigset_t * oldmask)275 prb_proc_wait(prb_proc_ctl_t *proc_p, boolean_t use_sigmask, sigset_t *oldmask)
276 {
277 int procfd;
278 int retval;
279 prstatus_t prstat;
280 sigset_t pendmask;
281 int i, mask_size;
282 boolean_t pending_signal = B_FALSE;
283
284 DBG_TNF_PROBE_0(prb_proc_wait_1, "libtnfctl",
285 "sunw%verbosity 2;"
286 "sunw%debug 'waiting for the target process to stop'");
287
288 procfd = proc_p->procfd;
289
290 /*
291 * This one of the places where we do not resubmit the ioctl if
292 * if it is terminated by an EINTR (interrupted system call). In
293 * this case, the caller knows best ...
294 */
295 (void) memset(&prstat, 0, sizeof (prstat));
296
297 /* if we blocked signals... */
298 if (use_sigmask) {
299 if (sigemptyset(&pendmask) == -1)
300 return (prb_status_map(errno));
301 if (sigpending(&pendmask) == -1)
302 return (prb_status_map(errno));
303 /*
304 * check if there were any signals pending -
305 * XXXX libc should provide this interface
306 */
307 mask_size = sizeof (pendmask) / sizeof (pendmask.__sigbits[0]);
308 for (i = 0; i < mask_size; i++) {
309 if (pendmask.__sigbits[i] != 0)
310 pending_signal = B_TRUE;
311 }
312
313 /* return to original signal mask */
314 if (sigprocmask(SIG_SETMASK, oldmask, NULL) == -1)
315 return (prb_status_map(errno));
316
317 /* if there was a pending signal, don't call PIOCWSTOP ioctl */
318 if (pending_signal)
319 return (prb_status_map(EINTR));
320
321 /*
322 * XXXX - there is a a race between now and when we call
323 * the PIOCWSTOP ioctl. One solution, is for the user to
324 * call an interface in libtnfctl from their signal handler.
325 * This interface will do a longjmp such that it never
326 * calls the ioctl (the setjmp would be before we restore
327 * the signal mask above)
328 */
329 }
330
331 retval = ioctl(procfd, PIOCWSTOP, &prstat);
332
333 DBG_TNF_PROBE_2(prb_proc_wait_2, "libtnfctl", "sunw%verbosity 2;",
334 tnf_opaque, pc, prstat.pr_reg[R_PC],
335 tnf_opaque, instr, prstat.pr_instr);
336
337 if (retval == -1) {
338 #ifdef DEBUG
339 if (errno != EINTR && errno != ENOENT)
340 (void) fprintf(stderr,
341 "prb_proc_wait: PIOCWSTOP failed: %s\n",
342 strerror(errno));
343
344 #endif
345 return (prb_status_map(errno));
346 }
347
348 return (PRB_STATUS_OK);
349 }
350
351
352 /*
353 * prb_proc_cont() - continues the target process
354 */
355 prb_status_t
prb_proc_cont(prb_proc_ctl_t * proc_p)356 prb_proc_cont(prb_proc_ctl_t *proc_p)
357 {
358 int procfd;
359 int retval;
360 prrun_t prrun;
361
362 DBG_TNF_PROBE_0(prb_proc_cont_1, "libtnfctl",
363 "sunw%verbosity 2; sunw%debug 'starting the target process'");
364 procfd = proc_p->procfd;
365
366 (void) memset((char *)&prrun, 0, sizeof (prrun));
367
368 again:
369 prrun.pr_flags = PRCFAULT;
370 retval = ioctl(procfd, PIOCRUN, &prrun);
371 if (retval == -1) {
372 if (errno == EINTR)
373 goto again;
374 DBG((void) fprintf(stderr,
375 "prb_proc_cont: PIOCRUN failed: %s\n",
376 strerror(errno)));
377 return (prb_status_map(errno));
378 }
379 return (PRB_STATUS_OK);
380 }
381
382
383 /*
384 * prb_proc_istepbpt() - step the target process one instruction
385 *
386 * CAUTION!!!! - this routine is specialized to only be able to single
387 * step over the breakpoint location.
388 */
389 prb_status_t
prb_proc_istepbpt(prb_proc_ctl_t * proc_p)390 prb_proc_istepbpt(prb_proc_ctl_t *proc_p)
391 {
392 int procfd;
393 int retval;
394 prrun_t run;
395 fltset_t faults;
396 prstatus_t prstat;
397
398 DBG_TNF_PROBE_0(prb_proc_istepbpt_1, "libtnfctl",
399 "sunw%verbosity 2; "
400 "sunw%debug 'single stepping over breakpoint'");
401
402 procfd = proc_p->procfd;
403
404 (void) memset((char *)&run, 0, sizeof (run));
405
406 /* add trace fault to the list of current traced faults */
407 again1:
408 retval = ioctl(procfd, PIOCGFAULT, &faults);
409 if (retval == -1) {
410 if (errno == EINTR)
411 goto again1;
412 DBG((void) fprintf(stderr,
413 "prb_proc_istepbpt: PIOCGFAULT failed: %s\n",
414 strerror(errno)));
415 return (prb_status_map(errno));
416 }
417 praddset(&faults, FLTTRACE);
418
419 /* issue the run command with the single-step option */
420 run.pr_flags = PRCFAULT | PRSFAULT | PRSTEP;
421 run.pr_fault = faults;
422
423 /* load the location of the breakpoint */
424 run.pr_vaddr = (caddr_t)proc_p->bptaddr;
425 run.pr_flags |= PRSVADDR;
426
427 again2:
428 retval = ioctl(procfd, PIOCRUN, &run);
429 if (retval == -1) {
430 if (errno == EINTR)
431 goto again2;
432 DBG((void) fprintf(stderr,
433 "prb_proc_istepbpt: PIOCRUN failed: %s\n",
434 strerror(errno)));
435 return (prb_status_map(errno));
436 }
437 again3:
438 retval = ioctl(procfd, PIOCWSTOP, &prstat);
439 if (retval == -1) {
440 if (errno == EINTR)
441 goto again3;
442 DBG((void) fprintf(stderr,
443 "prb_proc_istepbpt: PIOCWSTOP failed: %s\n",
444 strerror(errno)));
445 return (prb_status_map(errno));
446 }
447
448 DBG_TNF_PROBE_2(prb_proc_istepbpt_2, "libtnfctl", "sunw%verbosity 2;",
449 tnf_opaque, pc, prstat.pr_reg[R_PC],
450 tnf_opaque, instr, prstat.pr_instr);
451
452
453 /* clear any current faults */
454 again4:
455 retval = ioctl(procfd, PIOCCFAULT, NULL);
456 if (retval == -1) {
457 if (errno == EINTR)
458 goto again4;
459 DBG((void) fprintf(stderr,
460 "prb_proc_clrbptflt: PIOCCFAULT failed: %s\n",
461 strerror(errno)));
462 return (prb_status_map(errno));
463 }
464 /* remove the trace fault from the current traced faults */
465 prdelset(&faults, FLTTRACE);
466 again5:
467 retval = ioctl(procfd, PIOCSFAULT, &faults);
468 if (retval == -1) {
469 if (errno == EINTR)
470 goto again5;
471 DBG((void) fprintf(stderr,
472 "prb_proc_istepbpt: PIOCSFAULT failed: %s\n",
473 strerror(errno)));
474 return (prb_status_map(errno));
475 }
476 return (PRB_STATUS_OK);
477 }
478
479
480 /*
481 * prb_proc_clrbptflt() - clear an encountered breakpoint fault
482 */
483 prb_status_t
prb_proc_clrbptflt(prb_proc_ctl_t * proc_p)484 prb_proc_clrbptflt(prb_proc_ctl_t *proc_p)
485 {
486 int retval;
487 int procfd;
488
489 DBG_TNF_PROBE_0(prb_proc_clrbptflt_1, "libtnfctl", "sunw%verbosity 2");
490
491 procfd = proc_p->procfd;
492
493 /* clear any current faults */
494 again:
495 retval = ioctl(procfd, PIOCCFAULT, NULL);
496 if (retval == -1) {
497 if (errno == EINTR)
498 goto again;
499 DBG((void) fprintf(stderr,
500 "prb_proc_clrbptflt: PIOCCFAULT failed: %s\n",
501 strerror(errno)));
502 return (prb_status_map(errno));
503 }
504 return (PRB_STATUS_OK);
505 }
506
507
508 /*
509 * prb_proc_tracebpt() - sets the bpt tracing state.
510 */
511 prb_status_t
prb_proc_tracebpt(prb_proc_ctl_t * proc_p,boolean_t bpt)512 prb_proc_tracebpt(prb_proc_ctl_t *proc_p, boolean_t bpt)
513 {
514 int procfd;
515 int retval;
516 fltset_t faults;
517
518 DBG_TNF_PROBE_1(prb_proc_tracebpt_1, "libtnfctl", "sunw%verbosity 2;",
519 tnf_string, bpt_state, (bpt) ? "enabled" : "disabled");
520
521 procfd = proc_p->procfd;
522 /* get the current set of traced faults */
523 again1:
524 retval = ioctl(procfd, PIOCGFAULT, &faults);
525 if (retval == -1) {
526 if (errno == EINTR)
527 goto again1;
528 DBG((void) fprintf(stderr,
529 "prb_proc_tracebpt: PIOCGFAULT failed: %s\n",
530 strerror(errno)));
531 return (prb_status_map(errno));
532 }
533 /* set or clear the breakpoint flag */
534 if (bpt)
535 praddset(&faults, FLTBPT);
536 else
537 prdelset(&faults, FLTBPT);
538
539 /* write the fault set back */
540 again2:
541 retval = ioctl(procfd, PIOCSFAULT, &faults);
542 if (retval == -1) {
543 if (errno == EINTR)
544 goto again2;
545 DBG((void) fprintf(stderr,
546 "prb_proc_tracebpt: PIOCSFAULT failed: %s\n",
547 strerror(errno)));
548 return (prb_status_map(errno));
549 }
550 return (PRB_STATUS_OK);
551 }
552
553 /* Note - the following 3 functions should be combined */
554
555 /*
556 * prb_proc_setrlc() - sets or clears the run-on-last-close flag.
557 */
558 prb_status_t
prb_proc_setrlc(prb_proc_ctl_t * proc_p,boolean_t rlc)559 prb_proc_setrlc(prb_proc_ctl_t *proc_p, boolean_t rlc)
560 {
561 int procfd;
562 long mode;
563 int retval;
564
565 DBG_TNF_PROBE_1(prb_proc_setrlc_1, "libtnfctl", "sunw%verbosity 2;",
566 tnf_string, run_on_last_close, (rlc) ? "setting" : "clearing");
567
568 procfd = proc_p->procfd;
569 mode = PR_RLC;
570
571 if (rlc) {
572 again1:
573 retval = ioctl(procfd, PIOCSET, &mode);
574 if (retval == -1) {
575 if (errno == EINTR)
576 goto again1;
577 DBG((void) fprintf(stderr,
578 "prb_proc_setrlc: PIOCSET failed: %s\n",
579 strerror(errno)));
580 return (prb_status_map(errno));
581 }
582 } else {
583 again2:
584 retval = ioctl(procfd, PIOCRESET, &mode);
585 if (retval == -1) {
586 if (errno == EINTR)
587 goto again2;
588 DBG((void) fprintf(stderr,
589 "prb_proc_setrlc: PIOCRESET failed: %s\n",
590 strerror(errno)));
591 return (prb_status_map(errno));
592 }
593 }
594
595 return (PRB_STATUS_OK);
596
597
598 } /* end prb_proc_setrlc */
599
600
601 /*
602 * prb_proc_setklc() - sets or clears the kill-on-last-close flag.
603 */
604 prb_status_t
prb_proc_setklc(prb_proc_ctl_t * proc_p,boolean_t klc)605 prb_proc_setklc(prb_proc_ctl_t *proc_p, boolean_t klc)
606 {
607 int procfd;
608 long mode;
609 int retval;
610
611 DBG_TNF_PROBE_1(prb_proc_setklc_1, "libtnfctl", "sunw%verbosity 2;",
612 tnf_string, kill_on_last_close, (klc) ? "setting" : "clearing");
613
614 procfd = proc_p->procfd;
615 mode = PR_KLC;
616
617 if (klc) {
618 again1:
619 retval = ioctl(procfd, PIOCSET, &mode);
620 if (retval == -1) {
621 if (errno == EINTR)
622 goto again1;
623 DBG((void) fprintf(stderr,
624 "prb_proc_setklc: PIOCSET failed: %s\n",
625 strerror(errno)));
626 return (prb_status_map(errno));
627 }
628 } else {
629 again2:
630 retval = ioctl(procfd, PIOCRESET, &mode);
631 if (retval == -1) {
632 if (errno == EINTR)
633 goto again2;
634 DBG((void) fprintf(stderr,
635 "prb_proc_setklc: PIOCRESET failed: %s\n",
636 strerror(errno)));
637 return (prb_status_map(errno));
638 }
639 }
640
641 return (PRB_STATUS_OK);
642
643 } /* end prb_proc_setklc */
644
645 /*
646 * prb_proc_setfork() - sets or clears the inherit-on-fork flag
647 */
648 prb_status_t
prb_proc_setfork(prb_proc_ctl_t * proc_p,boolean_t inhfork)649 prb_proc_setfork(prb_proc_ctl_t *proc_p, boolean_t inhfork)
650 {
651 int procfd;
652 long mode;
653 int retval;
654
655 DBG_TNF_PROBE_1(prb_proc_setfork_1, "libtnfctl", "sunw%verbosity 2;",
656 tnf_string, kill_on_last_close,
657 (inhfork) ? "setting" : "clearing");
658
659 procfd = proc_p->procfd;
660 mode = PR_FORK;
661
662 if (inhfork) {
663 again1:
664 retval = ioctl(procfd, PIOCSET, &mode);
665 if (retval == -1) {
666 if (errno == EINTR)
667 goto again1;
668 DBG((void) fprintf(stderr,
669 "prb_proc_setfork: PIOCSET failed: %s\n",
670 strerror(errno)));
671 return (prb_status_map(errno));
672 }
673 } else {
674 again2:
675 retval = ioctl(procfd, PIOCRESET, &mode);
676 if (retval == -1) {
677 if (errno == EINTR)
678 goto again2;
679 DBG((void) fprintf(stderr,
680 "prb_proc_setfork: PIOCRESET failed: %s\n",
681 strerror(errno)));
682 return (prb_status_map(errno));
683 }
684 }
685
686 return (PRB_STATUS_OK);
687
688 } /* end prb_proc_setfork */
689
690 /*
691 * prb_proc_exit() - if op is PRB_SYS_ALL, sets up the target process to stop
692 * on exit from all system calls. If op is PRB_SYS_NONE, sets up the target
693 * process so that it will not stop on exit from any system call.
694 * PRB_SYS_ADD and PRB_SYS_DEL adds or deletes a particular system call from
695 * the mask of "interested" system calls respectively. This function can be
696 * called multiple times to build up the mask.
697 */
698 prb_status_t
prb_proc_exit(prb_proc_ctl_t * proc_p,uint_t syscall,prb_syscall_op_t op)699 prb_proc_exit(prb_proc_ctl_t *proc_p,
700 uint_t syscall,
701 prb_syscall_op_t op)
702 {
703 int procfd;
704 int retval;
705 sysset_t sysmask;
706
707 DBG_TNF_PROBE_0(prb_proc_exit_1, "libtnfctl",
708 "sunw%verbosity 2; "
709 "sunw%debug 'setting up target to stop on exit of syscall'");
710
711 procfd = proc_p->procfd;
712
713 switch (op) {
714 case PRB_SYS_ALL:
715 prfillset(&sysmask);
716 break;
717 case PRB_SYS_NONE:
718 premptyset(&sysmask);
719 break;
720 case PRB_SYS_ADD:
721 again1:
722 retval = ioctl(procfd, PIOCGEXIT, &sysmask);
723 if (retval == -1) {
724 if (errno == EINTR)
725 goto again1;
726 DBG((void) fprintf(stderr,
727 "prb_proc_exit: PIOCGEXIT failed: %s\n",
728 strerror(errno)));
729 return (prb_status_map(errno));
730 }
731 praddset(&sysmask, syscall);
732 break;
733 case PRB_SYS_DEL:
734 again2:
735 retval = ioctl(procfd, PIOCGEXIT, &sysmask);
736 if (retval == -1) {
737 if (errno == EINTR)
738 goto again2;
739 DBG((void) fprintf(stderr,
740 "prb_proc_exit: PIOCGEXIT failed: %s\n",
741 strerror(errno)));
742 return (prb_status_map(errno));
743 }
744 prdelset(&sysmask, syscall);
745 break;
746 default:
747 DBG((void) fprintf(stderr, "prb_proc_exit: bad input arg\n"));
748 return (PRB_STATUS_BADARG);
749 }
750 again3:
751 retval = ioctl(procfd, PIOCSEXIT, &sysmask);
752 if (retval == -1) {
753 if (errno == EINTR)
754 goto again3;
755 DBG((void) fprintf(stderr,
756 "prb_proc_exit: PIOCSEXIT failed: %s\n",
757 strerror(errno)));
758 return (prb_status_map(errno));
759 }
760 return (PRB_STATUS_OK);
761
762 } /* end prb_proc_exit */
763
764 /*
765 * prb_proc_entry() - if op is PRB_SYS_ALL, sets up the target process to
766 * stop on entry from all system calls. If op is PRB_SYS_NONE, sets up the
767 * target process so that it will not stop on entry from any system call.
768 * PRB_SYS_ADD and PRB_SYS_DEL adds or deletes a particular system call from
769 * the mask of "interested" system calls respectively. This function can be
770 * called multiple times to build up the mask.
771 */
772 prb_status_t
prb_proc_entry(prb_proc_ctl_t * proc_p,uint_t syscall,prb_syscall_op_t op)773 prb_proc_entry(prb_proc_ctl_t *proc_p,
774 uint_t syscall,
775 prb_syscall_op_t op)
776 {
777 int procfd;
778 int retval;
779 sysset_t sysmask;
780
781 DBG_TNF_PROBE_0(prb_proc_entry_1, "libtnfctl",
782 "sunw%verbosity 2; "
783 "sunw%debug 'setting up target to stop on entry of syscall'");
784
785 procfd = proc_p->procfd;
786
787 switch (op) {
788 case PRB_SYS_ALL:
789 prfillset(&sysmask);
790 break;
791 case PRB_SYS_NONE:
792 premptyset(&sysmask);
793 break;
794 case PRB_SYS_ADD:
795 again1:
796 retval = ioctl(procfd, PIOCGENTRY, &sysmask);
797 if (retval == -1) {
798 if (errno == EINTR)
799 goto again1;
800 DBG((void) fprintf(stderr,
801 "prb_proc_entry: PIOCGENTRY failed: %s\n",
802 strerror(errno)));
803 return (prb_status_map(errno));
804 }
805 praddset(&sysmask, syscall);
806 break;
807 case PRB_SYS_DEL:
808 again2:
809 retval = ioctl(procfd, PIOCGENTRY, &sysmask);
810 if (retval == -1) {
811 if (errno == EINTR)
812 goto again2;
813 DBG((void) fprintf(stderr,
814 "prb_proc_entry: PIOCGENTRY failed: %s\n",
815 strerror(errno)));
816 return (prb_status_map(errno));
817 }
818 prdelset(&sysmask, syscall);
819 break;
820 default:
821 DBG((void) fprintf(stderr, "prb_proc_entry: bad input arg\n"));
822 return (PRB_STATUS_BADARG);
823 }
824 again3:
825 retval = ioctl(procfd, PIOCSENTRY, &sysmask);
826 if (retval == -1) {
827 if (errno == EINTR)
828 goto again3;
829 DBG((void) fprintf(stderr,
830 "prb_proc_entry: PIOCSENTRY failed: %s\n",
831 strerror(errno)));
832 return (prb_status_map(errno));
833 }
834 return (PRB_STATUS_OK);
835 }
836
837 /*
838 * prb_proc_read() - reads a block of memory from a processes address space.
839 */
840 prb_status_t
prb_proc_read(prb_proc_ctl_t * proc_p,uintptr_t addr,void * buf,size_t size)841 prb_proc_read(prb_proc_ctl_t *proc_p, uintptr_t addr, void *buf, size_t size)
842 {
843 int procfd;
844 ssize_t sz;
845 off_t offset;
846
847 DBG_TNF_PROBE_2(prb_proc_read_1, "libtnfctl", "sunw%verbosity 3;",
848 tnf_long, num_bytes, size,
849 tnf_opaque, from_address, addr);
850
851 procfd = proc_p->procfd;
852 offset = lseek(procfd, (off_t)addr, SEEK_SET);
853 if (offset != (off_t)addr) {
854 DBG(perror("prb_proc_read: lseek failed"));
855 return (prb_status_map(errno));
856 }
857 sz = read(procfd, buf, size);
858 if (sz != size) {
859 DBG(perror("prb_proc_read: read failed"));
860 return (prb_status_map(errno));
861 }
862 return (PRB_STATUS_OK);
863 }
864
865
866 /*
867 * prb_proc_write() - writes a block of memory from a processes address
868 * space.
869 */
870 prb_status_t
prb_proc_write(prb_proc_ctl_t * proc_p,uintptr_t addr,void * buf,size_t size)871 prb_proc_write(prb_proc_ctl_t *proc_p, uintptr_t addr, void *buf, size_t size)
872 {
873 int procfd;
874 ssize_t sz;
875 off_t offset;
876
877 DBG_TNF_PROBE_2(prb_proc_write_1, "libtnfctl", "sunw%verbosity 3;",
878 tnf_long, num_bytes, size,
879 tnf_opaque, to_address, addr);
880
881 procfd = proc_p->procfd;
882 offset = lseek(procfd, (off_t)addr, SEEK_SET);
883 if (offset != (off_t)addr) {
884 DBG(perror("prb_proc_write: lseek failed"));
885 return (prb_status_map(errno));
886 }
887 sz = write(procfd, buf, size);
888 if (sz != size) {
889 DBG(perror("prb_proc_write: write failed"));
890 return (prb_status_map(errno));
891 }
892 return (PRB_STATUS_OK);
893 }
894
895
896 /*
897 * prb_proc_readstr() - dereferences a string in the target
898 * NOTE: There is a similar routine called _tnfctl_readstr_targ()
899 * used by tnfctl layer. It would be better if there was only
900 * one of these functions defined.
901 */
902
903 #define BUFSZ 256
904
905 prb_status_t
prb_proc_readstr(prb_proc_ctl_t * proc_p,uintptr_t addr,const char ** outstr_pp)906 prb_proc_readstr(prb_proc_ctl_t *proc_p, uintptr_t addr, const char **outstr_pp)
907 {
908 prb_status_t prbstat;
909 int bufsz = BUFSZ;
910 char buffer[BUFSZ + 1];
911 offset_t offset;
912 char *ptr, *orig_ptr;
913
914 *outstr_pp = NULL;
915 offset = 0;
916
917 /* allocate an inital return buffer */
918 ptr = (char *)malloc(BUFSZ);
919 if (!ptr) {
920 DBG((void) fprintf(stderr,
921 "prb_proc_readstr: malloc failed\n"));
922 return (PRB_STATUS_ALLOCFAIL);
923 }
924 /*LINTED constant in conditional context*/
925 while (1) {
926 int i;
927
928 /* read a chunk into our buffer */
929 prbstat = prb_proc_read(proc_p, addr + offset, buffer, bufsz);
930 if (prbstat) {
931
932 /*
933 * if we get into trouble with a large read, try again
934 * with a single byte. Subsequent failure is real ...
935 */
936 if (bufsz > 1) {
937 bufsz = 1;
938 continue;
939 }
940
941 DBG((void) fprintf(stderr,
942 "prb_proc_readstr: prb_proc_read failed: %s\n",
943 prb_status_str(prbstat)));
944 free(ptr);
945 return (prbstat);
946 }
947 /* copy the chracters into the return buffer */
948 for (i = 0; i < bufsz; i++) {
949 char c = buffer[i];
950
951 ptr[offset + i] = c;
952 if (c == '\0') {
953 /* hooray! we saw the end of the string */
954 *outstr_pp = ptr;
955 return (PRB_STATUS_OK);
956 }
957 }
958
959 /* bummer, need to grab another bufsz characters */
960 offset += bufsz;
961 orig_ptr = ptr;
962 ptr = (char *)realloc(ptr, offset + bufsz);
963 if (!ptr) {
964 free(orig_ptr);
965 DBG((void) fprintf(stderr,
966 "prb_proc_readstr: realloc failed\n"));
967 return (PRB_STATUS_ALLOCFAIL);
968 }
969 }
970
971 #if defined(lint)
972 return (PRB_STATUS_OK);
973 #endif
974 }
975
976 prb_status_t
prb_proc_get_r0_r1(prb_proc_ctl_t * proc_p,prgreg_t * r0,prgreg_t * r1)977 prb_proc_get_r0_r1(prb_proc_ctl_t *proc_p, prgreg_t *r0, prgreg_t *r1)
978 {
979 int retval;
980 int procfd;
981 prstatus_t prstatus;
982
983 procfd = proc_p->procfd;
984 again:
985 retval = ioctl(procfd, PIOCSTATUS, &prstatus);
986 if (retval == -1) {
987 if (errno == EINTR)
988 goto again;
989 return (prb_status_map(errno));
990 }
991
992 /*
993 * Use R_Rn register definitions for some uniformity
994 * sparc: define R_R0 R_O0
995 * define R_R1 R_O1
996 * x86: define R_R0 EAX
997 * define R_R1 EDX
998 */
999 *r0 = prstatus.pr_reg[R_R0];
1000 *r1 = prstatus.pr_reg[R_R1];
1001 DBG((void) fprintf
1002 (stderr, "prb_proc_get_r0_r1: R_R0 = %d, R_R1 = %d\n", *r0, *r1));
1003 return (PRB_STATUS_OK);
1004 }
1005