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
55static prb_status_t
56prb_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
66prb_status_t
67prb_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
102prb_status_t
103prb_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
117prb_status_t
118prb_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 */
130prb_status_t
131prb_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 */
150pid_t
151prb_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 */
159prb_status_t
160prb_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
167again:
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 */
185prb_status_t
186prb_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
200again1:
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	}
211again2:
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 */
235prb_status_t
236prb_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
249again:
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 */
274prb_status_t
275prb_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 */
355prb_status_t
356prb_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
368again:
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 */
389prb_status_t
390prb_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 */
407again1:
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
427again2:
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	}
437again3:
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 */
454again4:
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);
466again5:
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 */
483prb_status_t
484prb_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 */
494again:
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 */
511prb_status_t
512prb_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 */
523again1:
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 */
540again2:
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 */
558prb_status_t
559prb_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) {
572again1:
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 {
583again2:
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 */
604prb_status_t
605prb_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) {
618again1:
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 {
629again2:
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 */
648prb_status_t
649prb_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) {
663again1:
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 {
674again2:
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 */
698prb_status_t
699prb_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:
721again1:
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:
734again2:
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	}
750again3:
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 */
772prb_status_t
773prb_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:
795again1:
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:
808again2:
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	}
824again3:
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 */
840prb_status_t
841prb_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 */
870prb_status_t
871prb_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
905prb_status_t
906prb_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
976prb_status_t
977prb_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;
984again:
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