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
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.
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]
23 * Copyright (c) 1994-1999 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This file contains interfaces that are wrappers over the basic
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/fault.h>
44 #include <sys/procfs.h>
46 #include "prb_proc_int.h"
53 #define PROCFORMAT "/proc/%d"
56 prb_proc_open_general(pid_t pid
, prb_proc_ctl_t
**proc_pp
, int oflg
);
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.
67 prb_proc_open_general(pid_t pid
, prb_proc_ctl_t
**proc_pp
, int oflg
)
69 prb_proc_ctl_t
*proc_p
;
70 char path
[MAXPATHLEN
];
73 (void) sprintf(path
, PROCFORMAT
, (int)pid
);
75 DBG_TNF_PROBE_1(prb_proc_open_1
, "libtnfctl", "sunw%verbosity 2",
76 tnf_string
, opening_proc_on
, path
);
78 retval
= open(path
, oflg
);
80 DBG((void) fprintf(stderr
,
81 "proc_open: open of \"%s\" failed: %s\n",
82 path
, strerror(errno
)));
83 return (prb_status_map(errno
));
85 /* allocate proc_p and zero fill */
86 proc_p
= calloc(1, sizeof (*proc_p
));
88 return (PRB_STATUS_ALLOCFAIL
);
89 proc_p
->procfd
= retval
;
92 return (PRB_STATUS_OK
);
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.
103 prb_proc_open(pid_t pid
, prb_proc_ctl_t
**proc_pp
)
106 return (prb_proc_open_general(pid
,
107 proc_pp
, O_RDWR
| O_EXCL
));
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.
118 prb_proc_reopen(pid_t pid
, prb_proc_ctl_t
**proc_pp
)
121 return (prb_proc_open_general(pid
,
127 * prob_proc_close() - close the proc fd and free the memory taken up
131 prb_proc_close(prb_proc_ctl_t
*proc_p
)
133 DBG_TNF_PROBE_0(prb_proc_close_1
, "libtnfctl", "sunw%verbosity 2");
136 return (PRB_STATUS_OK
);
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
));
144 return (PRB_STATUS_OK
);
148 * prb_proc_pid_get() - gets the pid of the proc
151 prb_proc_pid_get(prb_proc_ctl_t
*proc_p
)
153 return (proc_p
->pid
);
157 * prb_proc_stop() - stops the target process
160 prb_proc_stop(prb_proc_ctl_t
*proc_p
)
164 DBG_TNF_PROBE_0(prb_proc_stop_1
, "libtnfctl",
165 "sunw%verbosity 2; sunw%debug 'stopping the target process'");
168 retval
= ioctl(proc_p
->procfd
, PIOCSTOP
, NULL
);
172 DBG((void) fprintf(stderr
,
173 "prb_proc_stop: PIOCSTOP failed: %s\n",
175 return (prb_status_map(errno
));
177 return (PRB_STATUS_OK
);
182 * prb_proc_prstop() - runs and stops the process, used to clear a target
183 * process out of a system call state.
186 prb_proc_prstop(prb_proc_ctl_t
*proc_p
)
193 DBG_TNF_PROBE_0(prb_proc_prstop_1
, "libtnfctl",
194 "sunw%verbosity 2; sunw%debug 'stepping the target process'");
196 procfd
= proc_p
->procfd
;
197 (void) memset((char *)&prrun
, 0, sizeof (prrun
));
198 (void) memset((char *)&prstat
, 0, sizeof (prstat
));
201 prrun
.pr_flags
= PRSTOP
;
202 retval
= ioctl(procfd
, PIOCRUN
, &prrun
);
206 DBG((void) fprintf(stderr
,
207 "prb_proc_prstop: PIOCRUN failed: %s\n",
209 return (prb_status_map(errno
));
212 retval
= ioctl(procfd
, PIOCWSTOP
, &prstat
);
216 DBG((void) fprintf(stderr
,
217 "prb_proc_prstop: PIOCWSTOP failed: %s\n",
219 return (prb_status_map(errno
));
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
225 if (prstat
.pr_why
!= PR_REQUESTED
)
228 return (PRB_STATUS_OK
);
233 * prb_proc_state() - returns the status pf the process
236 prb_proc_state(prb_proc_ctl_t
*proc_p
, prb_proc_state_t
*state_p
)
242 DBG_TNF_PROBE_0(prb_proc_state_1
, "libtnfctl",
243 "sunw%verbosity 2; sunw%debug 'getting the status'");
245 procfd
= proc_p
->procfd
;
247 (void) memset(&prstatus
, 0, sizeof (prstatus
));
250 retval
= ioctl(procfd
, PIOCSTATUS
, &prstatus
);
254 DBG((void) fprintf(stderr
,
255 "prb_proc_status: PIOCSTATUS failed: %s\n",
257 return (prb_status_map(errno
));
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
);
272 * prb_proc_wait() - waits for the target process to stop
275 prb_proc_wait(prb_proc_ctl_t
*proc_p
, boolean_t use_sigmask
, sigset_t
*oldmask
)
282 boolean_t pending_signal
= B_FALSE
;
284 DBG_TNF_PROBE_0(prb_proc_wait_1
, "libtnfctl",
286 "sunw%debug 'waiting for the target process to stop'");
288 procfd
= proc_p
->procfd
;
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 ...
295 (void) memset(&prstat
, 0, sizeof (prstat
));
297 /* if we blocked signals... */
299 if (sigemptyset(&pendmask
) == -1)
300 return (prb_status_map(errno
));
301 if (sigpending(&pendmask
) == -1)
302 return (prb_status_map(errno
));
304 * check if there were any signals pending -
305 * XXXX libc should provide this interface
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
;
313 /* return to original signal mask */
314 if (sigprocmask(SIG_SETMASK
, oldmask
, NULL
) == -1)
315 return (prb_status_map(errno
));
317 /* if there was a pending signal, don't call PIOCWSTOP ioctl */
319 return (prb_status_map(EINTR
));
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)
331 retval
= ioctl(procfd
, PIOCWSTOP
, &prstat
);
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
);
339 if (errno
!= EINTR
&& errno
!= ENOENT
)
340 (void) fprintf(stderr
,
341 "prb_proc_wait: PIOCWSTOP failed: %s\n",
345 return (prb_status_map(errno
));
348 return (PRB_STATUS_OK
);
353 * prb_proc_cont() - continues the target process
356 prb_proc_cont(prb_proc_ctl_t
*proc_p
)
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
;
366 (void) memset((char *)&prrun
, 0, sizeof (prrun
));
369 prrun
.pr_flags
= PRCFAULT
;
370 retval
= ioctl(procfd
, PIOCRUN
, &prrun
);
374 DBG((void) fprintf(stderr
,
375 "prb_proc_cont: PIOCRUN failed: %s\n",
377 return (prb_status_map(errno
));
379 return (PRB_STATUS_OK
);
384 * prb_proc_istepbpt() - step the target process one instruction
386 * CAUTION!!!! - this routine is specialized to only be able to single
387 * step over the breakpoint location.
390 prb_proc_istepbpt(prb_proc_ctl_t
*proc_p
)
398 DBG_TNF_PROBE_0(prb_proc_istepbpt_1
, "libtnfctl",
400 "sunw%debug 'single stepping over breakpoint'");
402 procfd
= proc_p
->procfd
;
404 (void) memset((char *)&run
, 0, sizeof (run
));
406 /* add trace fault to the list of current traced faults */
408 retval
= ioctl(procfd
, PIOCGFAULT
, &faults
);
412 DBG((void) fprintf(stderr
,
413 "prb_proc_istepbpt: PIOCGFAULT failed: %s\n",
415 return (prb_status_map(errno
));
417 praddset(&faults
, FLTTRACE
);
419 /* issue the run command with the single-step option */
420 run
.pr_flags
= PRCFAULT
| PRSFAULT
| PRSTEP
;
421 run
.pr_fault
= faults
;
423 /* load the location of the breakpoint */
424 run
.pr_vaddr
= (caddr_t
)proc_p
->bptaddr
;
425 run
.pr_flags
|= PRSVADDR
;
428 retval
= ioctl(procfd
, PIOCRUN
, &run
);
432 DBG((void) fprintf(stderr
,
433 "prb_proc_istepbpt: PIOCRUN failed: %s\n",
435 return (prb_status_map(errno
));
438 retval
= ioctl(procfd
, PIOCWSTOP
, &prstat
);
442 DBG((void) fprintf(stderr
,
443 "prb_proc_istepbpt: PIOCWSTOP failed: %s\n",
445 return (prb_status_map(errno
));
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
);
453 /* clear any current faults */
455 retval
= ioctl(procfd
, PIOCCFAULT
, NULL
);
459 DBG((void) fprintf(stderr
,
460 "prb_proc_clrbptflt: PIOCCFAULT failed: %s\n",
462 return (prb_status_map(errno
));
464 /* remove the trace fault from the current traced faults */
465 prdelset(&faults
, FLTTRACE
);
467 retval
= ioctl(procfd
, PIOCSFAULT
, &faults
);
471 DBG((void) fprintf(stderr
,
472 "prb_proc_istepbpt: PIOCSFAULT failed: %s\n",
474 return (prb_status_map(errno
));
476 return (PRB_STATUS_OK
);
481 * prb_proc_clrbptflt() - clear an encountered breakpoint fault
484 prb_proc_clrbptflt(prb_proc_ctl_t
*proc_p
)
489 DBG_TNF_PROBE_0(prb_proc_clrbptflt_1
, "libtnfctl", "sunw%verbosity 2");
491 procfd
= proc_p
->procfd
;
493 /* clear any current faults */
495 retval
= ioctl(procfd
, PIOCCFAULT
, NULL
);
499 DBG((void) fprintf(stderr
,
500 "prb_proc_clrbptflt: PIOCCFAULT failed: %s\n",
502 return (prb_status_map(errno
));
504 return (PRB_STATUS_OK
);
509 * prb_proc_tracebpt() - sets the bpt tracing state.
512 prb_proc_tracebpt(prb_proc_ctl_t
*proc_p
, boolean_t bpt
)
518 DBG_TNF_PROBE_1(prb_proc_tracebpt_1
, "libtnfctl", "sunw%verbosity 2;",
519 tnf_string
, bpt_state
, (bpt
) ? "enabled" : "disabled");
521 procfd
= proc_p
->procfd
;
522 /* get the current set of traced faults */
524 retval
= ioctl(procfd
, PIOCGFAULT
, &faults
);
528 DBG((void) fprintf(stderr
,
529 "prb_proc_tracebpt: PIOCGFAULT failed: %s\n",
531 return (prb_status_map(errno
));
533 /* set or clear the breakpoint flag */
535 praddset(&faults
, FLTBPT
);
537 prdelset(&faults
, FLTBPT
);
539 /* write the fault set back */
541 retval
= ioctl(procfd
, PIOCSFAULT
, &faults
);
545 DBG((void) fprintf(stderr
,
546 "prb_proc_tracebpt: PIOCSFAULT failed: %s\n",
548 return (prb_status_map(errno
));
550 return (PRB_STATUS_OK
);
553 /* Note - the following 3 functions should be combined */
556 * prb_proc_setrlc() - sets or clears the run-on-last-close flag.
559 prb_proc_setrlc(prb_proc_ctl_t
*proc_p
, boolean_t rlc
)
565 DBG_TNF_PROBE_1(prb_proc_setrlc_1
, "libtnfctl", "sunw%verbosity 2;",
566 tnf_string
, run_on_last_close
, (rlc
) ? "setting" : "clearing");
568 procfd
= proc_p
->procfd
;
573 retval
= ioctl(procfd
, PIOCSET
, &mode
);
577 DBG((void) fprintf(stderr
,
578 "prb_proc_setrlc: PIOCSET failed: %s\n",
580 return (prb_status_map(errno
));
584 retval
= ioctl(procfd
, PIOCRESET
, &mode
);
588 DBG((void) fprintf(stderr
,
589 "prb_proc_setrlc: PIOCRESET failed: %s\n",
591 return (prb_status_map(errno
));
595 return (PRB_STATUS_OK
);
598 } /* end prb_proc_setrlc */
602 * prb_proc_setklc() - sets or clears the kill-on-last-close flag.
605 prb_proc_setklc(prb_proc_ctl_t
*proc_p
, boolean_t klc
)
611 DBG_TNF_PROBE_1(prb_proc_setklc_1
, "libtnfctl", "sunw%verbosity 2;",
612 tnf_string
, kill_on_last_close
, (klc
) ? "setting" : "clearing");
614 procfd
= proc_p
->procfd
;
619 retval
= ioctl(procfd
, PIOCSET
, &mode
);
623 DBG((void) fprintf(stderr
,
624 "prb_proc_setklc: PIOCSET failed: %s\n",
626 return (prb_status_map(errno
));
630 retval
= ioctl(procfd
, PIOCRESET
, &mode
);
634 DBG((void) fprintf(stderr
,
635 "prb_proc_setklc: PIOCRESET failed: %s\n",
637 return (prb_status_map(errno
));
641 return (PRB_STATUS_OK
);
643 } /* end prb_proc_setklc */
646 * prb_proc_setfork() - sets or clears the inherit-on-fork flag
649 prb_proc_setfork(prb_proc_ctl_t
*proc_p
, boolean_t inhfork
)
655 DBG_TNF_PROBE_1(prb_proc_setfork_1
, "libtnfctl", "sunw%verbosity 2;",
656 tnf_string
, kill_on_last_close
,
657 (inhfork
) ? "setting" : "clearing");
659 procfd
= proc_p
->procfd
;
664 retval
= ioctl(procfd
, PIOCSET
, &mode
);
668 DBG((void) fprintf(stderr
,
669 "prb_proc_setfork: PIOCSET failed: %s\n",
671 return (prb_status_map(errno
));
675 retval
= ioctl(procfd
, PIOCRESET
, &mode
);
679 DBG((void) fprintf(stderr
,
680 "prb_proc_setfork: PIOCRESET failed: %s\n",
682 return (prb_status_map(errno
));
686 return (PRB_STATUS_OK
);
688 } /* end prb_proc_setfork */
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.
699 prb_proc_exit(prb_proc_ctl_t
*proc_p
,
707 DBG_TNF_PROBE_0(prb_proc_exit_1
, "libtnfctl",
709 "sunw%debug 'setting up target to stop on exit of syscall'");
711 procfd
= proc_p
->procfd
;
718 premptyset(&sysmask
);
722 retval
= ioctl(procfd
, PIOCGEXIT
, &sysmask
);
726 DBG((void) fprintf(stderr
,
727 "prb_proc_exit: PIOCGEXIT failed: %s\n",
729 return (prb_status_map(errno
));
731 praddset(&sysmask
, syscall
);
735 retval
= ioctl(procfd
, PIOCGEXIT
, &sysmask
);
739 DBG((void) fprintf(stderr
,
740 "prb_proc_exit: PIOCGEXIT failed: %s\n",
742 return (prb_status_map(errno
));
744 prdelset(&sysmask
, syscall
);
747 DBG((void) fprintf(stderr
, "prb_proc_exit: bad input arg\n"));
748 return (PRB_STATUS_BADARG
);
751 retval
= ioctl(procfd
, PIOCSEXIT
, &sysmask
);
755 DBG((void) fprintf(stderr
,
756 "prb_proc_exit: PIOCSEXIT failed: %s\n",
758 return (prb_status_map(errno
));
760 return (PRB_STATUS_OK
);
762 } /* end prb_proc_exit */
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.
773 prb_proc_entry(prb_proc_ctl_t
*proc_p
,
781 DBG_TNF_PROBE_0(prb_proc_entry_1
, "libtnfctl",
783 "sunw%debug 'setting up target to stop on entry of syscall'");
785 procfd
= proc_p
->procfd
;
792 premptyset(&sysmask
);
796 retval
= ioctl(procfd
, PIOCGENTRY
, &sysmask
);
800 DBG((void) fprintf(stderr
,
801 "prb_proc_entry: PIOCGENTRY failed: %s\n",
803 return (prb_status_map(errno
));
805 praddset(&sysmask
, syscall
);
809 retval
= ioctl(procfd
, PIOCGENTRY
, &sysmask
);
813 DBG((void) fprintf(stderr
,
814 "prb_proc_entry: PIOCGENTRY failed: %s\n",
816 return (prb_status_map(errno
));
818 prdelset(&sysmask
, syscall
);
821 DBG((void) fprintf(stderr
, "prb_proc_entry: bad input arg\n"));
822 return (PRB_STATUS_BADARG
);
825 retval
= ioctl(procfd
, PIOCSENTRY
, &sysmask
);
829 DBG((void) fprintf(stderr
,
830 "prb_proc_entry: PIOCSENTRY failed: %s\n",
832 return (prb_status_map(errno
));
834 return (PRB_STATUS_OK
);
838 * prb_proc_read() - reads a block of memory from a processes address space.
841 prb_proc_read(prb_proc_ctl_t
*proc_p
, uintptr_t addr
, void *buf
, size_t size
)
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
);
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
));
857 sz
= read(procfd
, buf
, size
);
859 DBG(perror("prb_proc_read: read failed"));
860 return (prb_status_map(errno
));
862 return (PRB_STATUS_OK
);
867 * prb_proc_write() - writes a block of memory from a processes address
871 prb_proc_write(prb_proc_ctl_t
*proc_p
, uintptr_t addr
, void *buf
, size_t size
)
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
);
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
));
887 sz
= write(procfd
, buf
, size
);
889 DBG(perror("prb_proc_write: write failed"));
890 return (prb_status_map(errno
));
892 return (PRB_STATUS_OK
);
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.
906 prb_proc_readstr(prb_proc_ctl_t
*proc_p
, uintptr_t addr
, const char **outstr_pp
)
908 prb_status_t prbstat
;
910 char buffer
[BUFSZ
+ 1];
912 char *ptr
, *orig_ptr
;
917 /* allocate an inital return buffer */
918 ptr
= (char *)malloc(BUFSZ
);
920 DBG((void) fprintf(stderr
,
921 "prb_proc_readstr: malloc failed\n"));
922 return (PRB_STATUS_ALLOCFAIL
);
924 /*LINTED constant in conditional context*/
928 /* read a chunk into our buffer */
929 prbstat
= prb_proc_read(proc_p
, addr
+ offset
, buffer
, bufsz
);
933 * if we get into trouble with a large read, try again
934 * with a single byte. Subsequent failure is real ...
941 DBG((void) fprintf(stderr
,
942 "prb_proc_readstr: prb_proc_read failed: %s\n",
943 prb_status_str(prbstat
)));
947 /* copy the chracters into the return buffer */
948 for (i
= 0; i
< bufsz
; i
++) {
953 /* hooray! we saw the end of the string */
955 return (PRB_STATUS_OK
);
959 /* bummer, need to grab another bufsz characters */
962 ptr
= (char *)realloc(ptr
, offset
+ bufsz
);
965 DBG((void) fprintf(stderr
,
966 "prb_proc_readstr: realloc failed\n"));
967 return (PRB_STATUS_ALLOCFAIL
);
972 return (PRB_STATUS_OK
);
977 prb_proc_get_r0_r1(prb_proc_ctl_t
*proc_p
, prgreg_t
*r0
, prgreg_t
*r1
)
983 procfd
= proc_p
->procfd
;
985 retval
= ioctl(procfd
, PIOCSTATUS
, &prstatus
);
989 return (prb_status_map(errno
));
993 * Use R_Rn register definitions for some uniformity
994 * sparc: define R_R0 R_O0
996 * x86: define R_R0 EAX
999 *r0
= prstatus
.pr_reg
[R_R0
];
1000 *r1
= prstatus
.pr_reg
[R_R1
];
1002 (stderr
, "prb_proc_get_r0_r1: R_R0 = %d, R_R1 = %d\n", *r0
, *r1
));
1003 return (PRB_STATUS_OK
);