xref: /titanic_50/usr/src/lib/libtnfctl/prb_rtld.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * Interfaces to sync up with run time linker (rtld) at process start up time
31*7c478bd9Sstevel@tonic-gate  * and at dlopen() and dlclose() time
32*7c478bd9Sstevel@tonic-gate  * In Solaris 2.6, librtld_db.so should replace this functionality.  Issues
33*7c478bd9Sstevel@tonic-gate  * to solve before libtnfctl.so can use librtld_db.so:
34*7c478bd9Sstevel@tonic-gate  * 1. Should libtnfctl.so be usable before Solaris 2.6 - If so, cannot use
35*7c478bd9Sstevel@tonic-gate  *    librtld_db.so
36*7c478bd9Sstevel@tonic-gate  * 2. libtnfctl.so will have to provide <proc_service.h> in order to use
37*7c478bd9Sstevel@tonic-gate  *    librtld_db.so.  If libtnfctl.so is now linked into a debugger that
38*7c478bd9Sstevel@tonic-gate  *    also provides <proc_service.h>, how will the two co-exist - will the
39*7c478bd9Sstevel@tonic-gate  *    linker get confused, or not ?
40*7c478bd9Sstevel@tonic-gate  */
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate #include <unistd.h>
43*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
44*7c478bd9Sstevel@tonic-gate #include <string.h>
45*7c478bd9Sstevel@tonic-gate #include <errno.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
50*7c478bd9Sstevel@tonic-gate #include <link.h>
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate #include "tnfctl.h"
53*7c478bd9Sstevel@tonic-gate #include "prb_proc_int.h"
54*7c478bd9Sstevel@tonic-gate #include "dbg.h"
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate static prb_status_t prb_rtld_setup(prb_proc_ctl_t *proc_p, boolean_t *synced);
58*7c478bd9Sstevel@tonic-gate static prb_status_t prb_rtld_wait(prb_proc_ctl_t *proc_p);
59*7c478bd9Sstevel@tonic-gate static prb_status_t bpt(prb_proc_ctl_t *proc_p, uintptr_t addr);
60*7c478bd9Sstevel@tonic-gate static prb_status_t unbpt(prb_proc_ctl_t *proc_p, uintptr_t addr);
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
64*7c478bd9Sstevel@tonic-gate /* ----------------------- Public Functions ----------------------- */
65*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate /*
69*7c478bd9Sstevel@tonic-gate  * prb_rtld_stalk() - setup for a breakpoint when rtld has opened or closed a
70*7c478bd9Sstevel@tonic-gate  * shared object.
71*7c478bd9Sstevel@tonic-gate  */
72*7c478bd9Sstevel@tonic-gate prb_status_t
prb_rtld_stalk(prb_proc_ctl_t * proc_p)73*7c478bd9Sstevel@tonic-gate prb_rtld_stalk(prb_proc_ctl_t *proc_p)
74*7c478bd9Sstevel@tonic-gate {
75*7c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat = PRB_STATUS_OK;
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_0(prb_rtld_stalk_1, "libtnfctl", "sunw%verbosity 2");
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate 	if (!proc_p->bptaddr) {
80*7c478bd9Sstevel@tonic-gate 		Elf3264_Dyn	   dentry;
81*7c478bd9Sstevel@tonic-gate 		struct r_debug  r_dbg;
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate 		if (proc_p->dbgaddr == 0) {
84*7c478bd9Sstevel@tonic-gate 			DBG((void) fprintf(stderr,
85*7c478bd9Sstevel@tonic-gate 				"prb_rtld_stalk: dbgaddr not set\n"));
86*7c478bd9Sstevel@tonic-gate 			return (PRB_STATUS_BADARG);
87*7c478bd9Sstevel@tonic-gate 		}
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 		prbstat = prb_proc_read(proc_p, proc_p->dbgaddr,
90*7c478bd9Sstevel@tonic-gate 			&dentry, sizeof (dentry));
91*7c478bd9Sstevel@tonic-gate 		if (prbstat || !dentry.d_un.d_ptr) {
92*7c478bd9Sstevel@tonic-gate 			DBG((void) fprintf(stderr,
93*7c478bd9Sstevel@tonic-gate 				"prb_rtld_stalk: error in d_un.d_ptr\n"));
94*7c478bd9Sstevel@tonic-gate 			return (prbstat);
95*7c478bd9Sstevel@tonic-gate 		}
96*7c478bd9Sstevel@tonic-gate 		/* read in the debug struct that it points to */
97*7c478bd9Sstevel@tonic-gate 		prbstat = prb_proc_read(proc_p, dentry.d_un.d_ptr,
98*7c478bd9Sstevel@tonic-gate 			&r_dbg, sizeof (r_dbg));
99*7c478bd9Sstevel@tonic-gate 		if (prbstat)
100*7c478bd9Sstevel@tonic-gate 			return (prbstat);
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate 		proc_p->bptaddr = r_dbg.r_brk;
103*7c478bd9Sstevel@tonic-gate 	}
104*7c478bd9Sstevel@tonic-gate 	/* plant a breakpoint trap in the pointed to function */
105*7c478bd9Sstevel@tonic-gate 	prbstat = bpt(proc_p, proc_p->bptaddr);
106*7c478bd9Sstevel@tonic-gate 	if (prbstat)
107*7c478bd9Sstevel@tonic-gate 		return (prbstat);
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	/* setup process to stop when breakpoint encountered */
110*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_tracebpt(proc_p, B_TRUE);
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 	return (prbstat);
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate }
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate /*
118*7c478bd9Sstevel@tonic-gate  * prb_rtld_unstalk() - remove rtld breakpoint
119*7c478bd9Sstevel@tonic-gate  */
120*7c478bd9Sstevel@tonic-gate prb_status_t
prb_rtld_unstalk(prb_proc_ctl_t * proc_p)121*7c478bd9Sstevel@tonic-gate prb_rtld_unstalk(prb_proc_ctl_t *proc_p)
122*7c478bd9Sstevel@tonic-gate {
123*7c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat;
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_0(prb_rtld_unstalk_1, "libtnfctl", "sunw%verbosity 2");
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 	/* turn off BPT tracing while out of the water ... */
128*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_tracebpt(proc_p, B_FALSE);
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	prbstat = unbpt(proc_p, proc_p->bptaddr);
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 	return (prbstat);
133*7c478bd9Sstevel@tonic-gate }
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate /*
137*7c478bd9Sstevel@tonic-gate  * prb_rtld_advance() - we've hit a breakpoint, replace the original
138*7c478bd9Sstevel@tonic-gate  * instruction, istep, put the breakpoint back ...
139*7c478bd9Sstevel@tonic-gate  */
140*7c478bd9Sstevel@tonic-gate prb_status_t
prb_rtld_advance(prb_proc_ctl_t * proc_p)141*7c478bd9Sstevel@tonic-gate prb_rtld_advance(prb_proc_ctl_t *proc_p)
142*7c478bd9Sstevel@tonic-gate {
143*7c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat;
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_0(prb_rtld_advance_1, "libtnfctl", "sunw%verbosity 2");
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_clrbptflt(proc_p);
148*7c478bd9Sstevel@tonic-gate 	if (prbstat)
149*7c478bd9Sstevel@tonic-gate 		return (prbstat);
150*7c478bd9Sstevel@tonic-gate 	prbstat = unbpt(proc_p, proc_p->bptaddr);
151*7c478bd9Sstevel@tonic-gate 	if (prbstat)
152*7c478bd9Sstevel@tonic-gate 		return (prbstat);
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_istepbpt(proc_p);
155*7c478bd9Sstevel@tonic-gate 	if (prbstat)
156*7c478bd9Sstevel@tonic-gate 		return (prbstat);
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	prbstat = bpt(proc_p, proc_p->bptaddr);
159*7c478bd9Sstevel@tonic-gate 	if (prbstat)
160*7c478bd9Sstevel@tonic-gate 		return (prbstat);
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	return (PRB_STATUS_OK);
163*7c478bd9Sstevel@tonic-gate }
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate /*
166*7c478bd9Sstevel@tonic-gate  * checks if process has reached rtld_sync point or not i.e. has rltld
167*7c478bd9Sstevel@tonic-gate  * loaded in libraries or not ?  If not, it lets process run until
168*7c478bd9Sstevel@tonic-gate  * rtld has mapped in all libraries (no user code would have been
169*7c478bd9Sstevel@tonic-gate  * executed, including .init sections)
170*7c478bd9Sstevel@tonic-gate  */
171*7c478bd9Sstevel@tonic-gate prb_status_t
prb_rtld_sync_if_needed(prb_proc_ctl_t * proc_p)172*7c478bd9Sstevel@tonic-gate prb_rtld_sync_if_needed(prb_proc_ctl_t *proc_p)
173*7c478bd9Sstevel@tonic-gate {
174*7c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat = PRB_STATUS_OK;
175*7c478bd9Sstevel@tonic-gate 	boolean_t	synced = B_FALSE;
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	prbstat = prb_rtld_setup(proc_p, &synced);
178*7c478bd9Sstevel@tonic-gate 	if (prbstat)
179*7c478bd9Sstevel@tonic-gate 		return (prbstat);
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	if (synced == B_FALSE) {
182*7c478bd9Sstevel@tonic-gate 		/* wait on target to sync up after rtld maps in all .so's */
183*7c478bd9Sstevel@tonic-gate 		prbstat = prb_rtld_wait(proc_p);
184*7c478bd9Sstevel@tonic-gate 		if (prbstat)
185*7c478bd9Sstevel@tonic-gate 			return (prbstat);
186*7c478bd9Sstevel@tonic-gate 	}
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 	return (prbstat);
189*7c478bd9Sstevel@tonic-gate }
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
192*7c478bd9Sstevel@tonic-gate /* ----------------------- Private Functions ---------------------- */
193*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate /*
196*7c478bd9Sstevel@tonic-gate  * prb_rtld_setup() - turns on the flag in the rtld structure so that rtld
197*7c478bd9Sstevel@tonic-gate  * executes a getpid() stystem call after it done mapping all shared objects
198*7c478bd9Sstevel@tonic-gate  * but before it executes any init code.
199*7c478bd9Sstevel@tonic-gate  */
200*7c478bd9Sstevel@tonic-gate static prb_status_t
prb_rtld_setup(prb_proc_ctl_t * proc_p,boolean_t * synced)201*7c478bd9Sstevel@tonic-gate prb_rtld_setup(prb_proc_ctl_t *proc_p, boolean_t *synced)
202*7c478bd9Sstevel@tonic-gate {
203*7c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat = PRB_STATUS_OK;
204*7c478bd9Sstevel@tonic-gate 	Elf3264_Dyn	dentry;
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_0(prb_rtld_setup_1, "libtnfctl", "sunw%verbosity 2");
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	if (proc_p->dbgaddr == 0) {
209*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
210*7c478bd9Sstevel@tonic-gate 			"prb_rtld_setup: dbgaddr not set\n"));
211*7c478bd9Sstevel@tonic-gate 		return (PRB_STATUS_BADARG);
212*7c478bd9Sstevel@tonic-gate 	}
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_read(proc_p, proc_p->dbgaddr, &dentry,
215*7c478bd9Sstevel@tonic-gate 					sizeof (dentry));
216*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
217*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
218*7c478bd9Sstevel@tonic-gate 			"prb_rtld_setup: error in d_un.d_ptr\n"));
219*7c478bd9Sstevel@tonic-gate 		return (prbstat);
220*7c478bd9Sstevel@tonic-gate 	}
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	if ((dentry.d_un.d_ptr == 0) || (dentry.d_un.d_ptr == 1)) {
223*7c478bd9Sstevel@tonic-gate 		*synced = B_FALSE;
224*7c478bd9Sstevel@tonic-gate 	} else {
225*7c478bd9Sstevel@tonic-gate 		*synced = B_TRUE;
226*7c478bd9Sstevel@tonic-gate 		return (PRB_STATUS_OK);
227*7c478bd9Sstevel@tonic-gate 	}
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	/* modify it  - i.e. request rtld to do getpid() */
230*7c478bd9Sstevel@tonic-gate 	dentry.d_un.d_ptr = 1;
231*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_write(proc_p, proc_p->dbgaddr, &dentry,
232*7c478bd9Sstevel@tonic-gate 					sizeof (dentry));
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	return (prbstat);
235*7c478bd9Sstevel@tonic-gate }
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate /*
239*7c478bd9Sstevel@tonic-gate  * prb_rtld_wait() - waits on target to execute getpid()
240*7c478bd9Sstevel@tonic-gate  */
241*7c478bd9Sstevel@tonic-gate static prb_status_t
prb_rtld_wait(prb_proc_ctl_t * proc_p)242*7c478bd9Sstevel@tonic-gate prb_rtld_wait(prb_proc_ctl_t *proc_p)
243*7c478bd9Sstevel@tonic-gate {
244*7c478bd9Sstevel@tonic-gate 	prb_proc_state_t pstate;
245*7c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat;
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_0(prb_rtld_wait_1, "libtnfctl", "sunw%verbosity 2");
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 	/* stop on exit of getpid() */
250*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_exit(proc_p, SYS_getpid, PRB_SYS_ADD);
251*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
252*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
253*7c478bd9Sstevel@tonic-gate 			"prb_rtld_wait: couldn't set up child to stop on "
254*7c478bd9Sstevel@tonic-gate 			"exit of getpid(): %s\n", prb_status_str(prbstat)));
255*7c478bd9Sstevel@tonic-gate 		return (prbstat);
256*7c478bd9Sstevel@tonic-gate 	}
257*7c478bd9Sstevel@tonic-gate 	/* stop on entry of exit() - i.e. exec failed */
258*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_ADD);
259*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
260*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
261*7c478bd9Sstevel@tonic-gate 			"prb_rtld_wait: couldn't set up child to stop on "
262*7c478bd9Sstevel@tonic-gate 			"entry of exit(): %s\n", prb_status_str(prbstat)));
263*7c478bd9Sstevel@tonic-gate 		return (prbstat);
264*7c478bd9Sstevel@tonic-gate 	}
265*7c478bd9Sstevel@tonic-gate 	/* continue target and wait for it to stop */
266*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_cont(proc_p);
267*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
268*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
269*7c478bd9Sstevel@tonic-gate 			"prb_rtld_wait: couldn't continue target process: %s\n",
270*7c478bd9Sstevel@tonic-gate 				prb_status_str(prbstat)));
271*7c478bd9Sstevel@tonic-gate 		return (prbstat);
272*7c478bd9Sstevel@tonic-gate 	}
273*7c478bd9Sstevel@tonic-gate 	/* wait for target to stop */
274*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_wait(proc_p, B_FALSE, NULL);
275*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
276*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
277*7c478bd9Sstevel@tonic-gate 			"prb_rtld_wait: couldn't wait on target process: %s\n",
278*7c478bd9Sstevel@tonic-gate 			prb_status_str(prbstat)));
279*7c478bd9Sstevel@tonic-gate 		return (prbstat);
280*7c478bd9Sstevel@tonic-gate 	}
281*7c478bd9Sstevel@tonic-gate 	/* make sure it did stop on getpid() */
282*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_state(proc_p, &pstate);
283*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
284*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
285*7c478bd9Sstevel@tonic-gate 			"prb_rtld_wait: couldn't get state of target: %s\n",
286*7c478bd9Sstevel@tonic-gate 				prb_status_str(prbstat)));
287*7c478bd9Sstevel@tonic-gate 		return (prbstat);
288*7c478bd9Sstevel@tonic-gate 	}
289*7c478bd9Sstevel@tonic-gate 	if (pstate.ps_issysentry && (pstate.ps_syscallnum == SYS_exit)) {
290*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr, "prb_rtld_wait: target exited\n"));
291*7c478bd9Sstevel@tonic-gate 		return (prb_status_map(EACCES));
292*7c478bd9Sstevel@tonic-gate 	}
293*7c478bd9Sstevel@tonic-gate 	/* catch any other errors */
294*7c478bd9Sstevel@tonic-gate 	if (!(pstate.ps_issysexit && (pstate.ps_syscallnum == SYS_getpid))) {
295*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
296*7c478bd9Sstevel@tonic-gate 			"prb_rtld_wait: target didn't stop on getpid\n"));
297*7c478bd9Sstevel@tonic-gate 		return (PRB_STATUS_BADSYNC);
298*7c478bd9Sstevel@tonic-gate 	}
299*7c478bd9Sstevel@tonic-gate 	/* clear wait on getpid */
300*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_exit(proc_p, SYS_getpid, PRB_SYS_DEL);
301*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
302*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
303*7c478bd9Sstevel@tonic-gate 			"prb_rtld_wait: couldn't clear child to stop on "
304*7c478bd9Sstevel@tonic-gate 			"exit of getpid(): %s\n", prb_status_str(prbstat)));
305*7c478bd9Sstevel@tonic-gate 		return (prbstat);
306*7c478bd9Sstevel@tonic-gate 	}
307*7c478bd9Sstevel@tonic-gate 	/* clear wait on exit */
308*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_DEL);
309*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
310*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
311*7c478bd9Sstevel@tonic-gate 			"prb_rtld_wait: couldn't clear child to stop on "
312*7c478bd9Sstevel@tonic-gate 			"entry of exit(): %s\n", prb_status_str(prbstat)));
313*7c478bd9Sstevel@tonic-gate 		return (prbstat);
314*7c478bd9Sstevel@tonic-gate 	}
315*7c478bd9Sstevel@tonic-gate 	/* start-stop the process to clear it out of the system call */
316*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_prstop(proc_p);
317*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
318*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
319*7c478bd9Sstevel@tonic-gate 			"prb_rtld_wait: couldn't prstop child: %s\n",
320*7c478bd9Sstevel@tonic-gate 			prb_status_str(prbstat)));
321*7c478bd9Sstevel@tonic-gate 		return (prbstat);
322*7c478bd9Sstevel@tonic-gate 	}
323*7c478bd9Sstevel@tonic-gate 	return (PRB_STATUS_OK);
324*7c478bd9Sstevel@tonic-gate }
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate #if defined(__sparc)
328*7c478bd9Sstevel@tonic-gate #define	INS_BPT 0x91d02001
329*7c478bd9Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64)
330*7c478bd9Sstevel@tonic-gate #define	INS_BPT 0xcc
331*7c478bd9Sstevel@tonic-gate #else
332*7c478bd9Sstevel@tonic-gate #error  What is your breakpoint instruction?
333*7c478bd9Sstevel@tonic-gate #endif
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate /*
336*7c478bd9Sstevel@tonic-gate  * plants a breakpoint at the specified location in
337*7c478bd9Sstevel@tonic-gate  * the target process, and saves the existing instruction.
338*7c478bd9Sstevel@tonic-gate  */
339*7c478bd9Sstevel@tonic-gate static prb_status_t
bpt(prb_proc_ctl_t * proc_p,uintptr_t addr)340*7c478bd9Sstevel@tonic-gate bpt(prb_proc_ctl_t *proc_p, uintptr_t addr)
341*7c478bd9Sstevel@tonic-gate {
342*7c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat;
343*7c478bd9Sstevel@tonic-gate 	bptsave_t	instr;
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	if (!proc_p->bpt_inserted) {
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 		DBG_TNF_PROBE_1(bpt_1, "libtnfctl", "sunw%verbosity 2",
348*7c478bd9Sstevel@tonic-gate 			tnf_opaque, bpt_planted_at, addr);
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 		prbstat = prb_proc_read(proc_p, addr,
351*7c478bd9Sstevel@tonic-gate 			&(proc_p->saveinstr), sizeof (proc_p->saveinstr));
352*7c478bd9Sstevel@tonic-gate 		if (prbstat)
353*7c478bd9Sstevel@tonic-gate 			return (prbstat);
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 		DBG_TNF_PROBE_1(bpt_2, "libtnfctl", "sunw%verbosity 2",
356*7c478bd9Sstevel@tonic-gate 			tnf_opaque, saved_instr, (unsigned)proc_p->saveinstr);
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 		instr = INS_BPT;
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 		prbstat = prb_proc_write(proc_p, addr,
361*7c478bd9Sstevel@tonic-gate 			&instr, sizeof (instr));
362*7c478bd9Sstevel@tonic-gate 		if (prbstat)
363*7c478bd9Sstevel@tonic-gate 			return (prbstat);
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 		proc_p->bpt_inserted = B_TRUE;
366*7c478bd9Sstevel@tonic-gate 	}
367*7c478bd9Sstevel@tonic-gate 	return (PRB_STATUS_OK);
368*7c478bd9Sstevel@tonic-gate }
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate /*
371*7c478bd9Sstevel@tonic-gate  * removes  a breakpoint at the specified location in
372*7c478bd9Sstevel@tonic-gate  * the target process, and replaces it with the original instruction.
373*7c478bd9Sstevel@tonic-gate  */
374*7c478bd9Sstevel@tonic-gate prb_status_t
unbpt(prb_proc_ctl_t * proc_p,uintptr_t addr)375*7c478bd9Sstevel@tonic-gate unbpt(prb_proc_ctl_t *proc_p, uintptr_t addr)
376*7c478bd9Sstevel@tonic-gate {
377*7c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat;
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	if (proc_p->bpt_inserted) {
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 		DBG_TNF_PROBE_2(unbpt_1, "libtnfctl", "sunw%verbosity 2",
382*7c478bd9Sstevel@tonic-gate 			tnf_opaque, unplanting_at, addr,
383*7c478bd9Sstevel@tonic-gate 			tnf_opaque, saved_instr, (unsigned)proc_p->saveinstr);
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 		prbstat = prb_proc_write(proc_p, addr, &(proc_p->saveinstr),
386*7c478bd9Sstevel@tonic-gate 			sizeof (proc_p->saveinstr));
387*7c478bd9Sstevel@tonic-gate 		if (prbstat)
388*7c478bd9Sstevel@tonic-gate 			return (prbstat);
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 		proc_p->bpt_inserted = B_FALSE;
391*7c478bd9Sstevel@tonic-gate 	}
392*7c478bd9Sstevel@tonic-gate 	return (PRB_STATUS_OK);
393*7c478bd9Sstevel@tonic-gate }
394