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 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * Interfaces to sync up with run time linker (rtld) at process start up time
31 * and at dlopen() and dlclose() time
32 * In Solaris 2.6, librtld_db.so should replace this functionality. Issues
33 * to solve before libtnfctl.so can use librtld_db.so:
34 * 1. Should libtnfctl.so be usable before Solaris 2.6 - If so, cannot use
36 * 2. libtnfctl.so will have to provide <proc_service.h> in order to use
37 * librtld_db.so. If libtnfctl.so is now linked into a debugger that
38 * also provides <proc_service.h>, how will the two co-exist - will the
39 * linker get confused, or not ?
46 #include <sys/types.h>
48 #include <sys/fcntl.h>
49 #include <sys/procfs.h>
53 #include "prb_proc_int.h"
57 static prb_status_t
prb_rtld_setup(prb_proc_ctl_t
*proc_p
, boolean_t
*synced
);
58 static prb_status_t
prb_rtld_wait(prb_proc_ctl_t
*proc_p
);
59 static prb_status_t
bpt(prb_proc_ctl_t
*proc_p
, uintptr_t addr
);
60 static prb_status_t
unbpt(prb_proc_ctl_t
*proc_p
, uintptr_t addr
);
63 /* ---------------------------------------------------------------- */
64 /* ----------------------- Public Functions ----------------------- */
65 /* ---------------------------------------------------------------- */
69 * prb_rtld_stalk() - setup for a breakpoint when rtld has opened or closed a
73 prb_rtld_stalk(prb_proc_ctl_t
*proc_p
)
75 prb_status_t prbstat
= PRB_STATUS_OK
;
77 DBG_TNF_PROBE_0(prb_rtld_stalk_1
, "libtnfctl", "sunw%verbosity 2");
79 if (!proc_p
->bptaddr
) {
83 if (proc_p
->dbgaddr
== 0) {
84 DBG((void) fprintf(stderr
,
85 "prb_rtld_stalk: dbgaddr not set\n"));
86 return (PRB_STATUS_BADARG
);
89 prbstat
= prb_proc_read(proc_p
, proc_p
->dbgaddr
,
90 &dentry
, sizeof (dentry
));
91 if (prbstat
|| !dentry
.d_un
.d_ptr
) {
92 DBG((void) fprintf(stderr
,
93 "prb_rtld_stalk: error in d_un.d_ptr\n"));
96 /* read in the debug struct that it points to */
97 prbstat
= prb_proc_read(proc_p
, dentry
.d_un
.d_ptr
,
98 &r_dbg
, sizeof (r_dbg
));
102 proc_p
->bptaddr
= r_dbg
.r_brk
;
104 /* plant a breakpoint trap in the pointed to function */
105 prbstat
= bpt(proc_p
, proc_p
->bptaddr
);
109 /* setup process to stop when breakpoint encountered */
110 prbstat
= prb_proc_tracebpt(proc_p
, B_TRUE
);
118 * prb_rtld_unstalk() - remove rtld breakpoint
121 prb_rtld_unstalk(prb_proc_ctl_t
*proc_p
)
123 prb_status_t prbstat
;
125 DBG_TNF_PROBE_0(prb_rtld_unstalk_1
, "libtnfctl", "sunw%verbosity 2");
127 /* turn off BPT tracing while out of the water ... */
128 prbstat
= prb_proc_tracebpt(proc_p
, B_FALSE
);
130 prbstat
= unbpt(proc_p
, proc_p
->bptaddr
);
137 * prb_rtld_advance() - we've hit a breakpoint, replace the original
138 * instruction, istep, put the breakpoint back ...
141 prb_rtld_advance(prb_proc_ctl_t
*proc_p
)
143 prb_status_t prbstat
;
145 DBG_TNF_PROBE_0(prb_rtld_advance_1
, "libtnfctl", "sunw%verbosity 2");
147 prbstat
= prb_proc_clrbptflt(proc_p
);
150 prbstat
= unbpt(proc_p
, proc_p
->bptaddr
);
154 prbstat
= prb_proc_istepbpt(proc_p
);
158 prbstat
= bpt(proc_p
, proc_p
->bptaddr
);
162 return (PRB_STATUS_OK
);
166 * checks if process has reached rtld_sync point or not i.e. has rltld
167 * loaded in libraries or not ? If not, it lets process run until
168 * rtld has mapped in all libraries (no user code would have been
169 * executed, including .init sections)
172 prb_rtld_sync_if_needed(prb_proc_ctl_t
*proc_p
)
174 prb_status_t prbstat
= PRB_STATUS_OK
;
175 boolean_t synced
= B_FALSE
;
177 prbstat
= prb_rtld_setup(proc_p
, &synced
);
181 if (synced
== B_FALSE
) {
182 /* wait on target to sync up after rtld maps in all .so's */
183 prbstat
= prb_rtld_wait(proc_p
);
191 /* ---------------------------------------------------------------- */
192 /* ----------------------- Private Functions ---------------------- */
193 /* ---------------------------------------------------------------- */
196 * prb_rtld_setup() - turns on the flag in the rtld structure so that rtld
197 * executes a getpid() stystem call after it done mapping all shared objects
198 * but before it executes any init code.
201 prb_rtld_setup(prb_proc_ctl_t
*proc_p
, boolean_t
*synced
)
203 prb_status_t prbstat
= PRB_STATUS_OK
;
206 DBG_TNF_PROBE_0(prb_rtld_setup_1
, "libtnfctl", "sunw%verbosity 2");
208 if (proc_p
->dbgaddr
== 0) {
209 DBG((void) fprintf(stderr
,
210 "prb_rtld_setup: dbgaddr not set\n"));
211 return (PRB_STATUS_BADARG
);
214 prbstat
= prb_proc_read(proc_p
, proc_p
->dbgaddr
, &dentry
,
217 DBG((void) fprintf(stderr
,
218 "prb_rtld_setup: error in d_un.d_ptr\n"));
222 if ((dentry
.d_un
.d_ptr
== 0) || (dentry
.d_un
.d_ptr
== 1)) {
226 return (PRB_STATUS_OK
);
229 /* modify it - i.e. request rtld to do getpid() */
230 dentry
.d_un
.d_ptr
= 1;
231 prbstat
= prb_proc_write(proc_p
, proc_p
->dbgaddr
, &dentry
,
239 * prb_rtld_wait() - waits on target to execute getpid()
242 prb_rtld_wait(prb_proc_ctl_t
*proc_p
)
244 prb_proc_state_t pstate
;
245 prb_status_t prbstat
;
247 DBG_TNF_PROBE_0(prb_rtld_wait_1
, "libtnfctl", "sunw%verbosity 2");
249 /* stop on exit of getpid() */
250 prbstat
= prb_proc_exit(proc_p
, SYS_getpid
, PRB_SYS_ADD
);
252 DBG((void) fprintf(stderr
,
253 "prb_rtld_wait: couldn't set up child to stop on "
254 "exit of getpid(): %s\n", prb_status_str(prbstat
)));
257 /* stop on entry of exit() - i.e. exec failed */
258 prbstat
= prb_proc_entry(proc_p
, SYS_exit
, PRB_SYS_ADD
);
260 DBG((void) fprintf(stderr
,
261 "prb_rtld_wait: couldn't set up child to stop on "
262 "entry of exit(): %s\n", prb_status_str(prbstat
)));
265 /* continue target and wait for it to stop */
266 prbstat
= prb_proc_cont(proc_p
);
268 DBG((void) fprintf(stderr
,
269 "prb_rtld_wait: couldn't continue target process: %s\n",
270 prb_status_str(prbstat
)));
273 /* wait for target to stop */
274 prbstat
= prb_proc_wait(proc_p
, B_FALSE
, NULL
);
276 DBG((void) fprintf(stderr
,
277 "prb_rtld_wait: couldn't wait on target process: %s\n",
278 prb_status_str(prbstat
)));
281 /* make sure it did stop on getpid() */
282 prbstat
= prb_proc_state(proc_p
, &pstate
);
284 DBG((void) fprintf(stderr
,
285 "prb_rtld_wait: couldn't get state of target: %s\n",
286 prb_status_str(prbstat
)));
289 if (pstate
.ps_issysentry
&& (pstate
.ps_syscallnum
== SYS_exit
)) {
290 DBG((void) fprintf(stderr
, "prb_rtld_wait: target exited\n"));
291 return (prb_status_map(EACCES
));
293 /* catch any other errors */
294 if (!(pstate
.ps_issysexit
&& (pstate
.ps_syscallnum
== SYS_getpid
))) {
295 DBG((void) fprintf(stderr
,
296 "prb_rtld_wait: target didn't stop on getpid\n"));
297 return (PRB_STATUS_BADSYNC
);
299 /* clear wait on getpid */
300 prbstat
= prb_proc_exit(proc_p
, SYS_getpid
, PRB_SYS_DEL
);
302 DBG((void) fprintf(stderr
,
303 "prb_rtld_wait: couldn't clear child to stop on "
304 "exit of getpid(): %s\n", prb_status_str(prbstat
)));
307 /* clear wait on exit */
308 prbstat
= prb_proc_entry(proc_p
, SYS_exit
, PRB_SYS_DEL
);
310 DBG((void) fprintf(stderr
,
311 "prb_rtld_wait: couldn't clear child to stop on "
312 "entry of exit(): %s\n", prb_status_str(prbstat
)));
315 /* start-stop the process to clear it out of the system call */
316 prbstat
= prb_proc_prstop(proc_p
);
318 DBG((void) fprintf(stderr
,
319 "prb_rtld_wait: couldn't prstop child: %s\n",
320 prb_status_str(prbstat
)));
323 return (PRB_STATUS_OK
);
328 #define INS_BPT 0x91d02001
329 #elif defined(__i386) || defined(__amd64)
332 #error What is your breakpoint instruction?
336 * plants a breakpoint at the specified location in
337 * the target process, and saves the existing instruction.
340 bpt(prb_proc_ctl_t
*proc_p
, uintptr_t addr
)
342 prb_status_t prbstat
;
345 if (!proc_p
->bpt_inserted
) {
347 DBG_TNF_PROBE_1(bpt_1
, "libtnfctl", "sunw%verbosity 2",
348 tnf_opaque
, bpt_planted_at
, addr
);
350 prbstat
= prb_proc_read(proc_p
, addr
,
351 &(proc_p
->saveinstr
), sizeof (proc_p
->saveinstr
));
355 DBG_TNF_PROBE_1(bpt_2
, "libtnfctl", "sunw%verbosity 2",
356 tnf_opaque
, saved_instr
, (unsigned)proc_p
->saveinstr
);
360 prbstat
= prb_proc_write(proc_p
, addr
,
361 &instr
, sizeof (instr
));
365 proc_p
->bpt_inserted
= B_TRUE
;
367 return (PRB_STATUS_OK
);
371 * removes a breakpoint at the specified location in
372 * the target process, and replaces it with the original instruction.
375 unbpt(prb_proc_ctl_t
*proc_p
, uintptr_t addr
)
377 prb_status_t prbstat
;
379 if (proc_p
->bpt_inserted
) {
381 DBG_TNF_PROBE_2(unbpt_1
, "libtnfctl", "sunw%verbosity 2",
382 tnf_opaque
, unplanting_at
, addr
,
383 tnf_opaque
, saved_instr
, (unsigned)proc_p
->saveinstr
);
385 prbstat
= prb_proc_write(proc_p
, addr
, &(proc_p
->saveinstr
),
386 sizeof (proc_p
->saveinstr
));
390 proc_p
->bpt_inserted
= B_FALSE
;
392 return (PRB_STATUS_OK
);