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