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 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
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
35 * librtld_db.so
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 ?
40 */
41
42 #include <unistd.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <sys/fcntl.h>
49 #include <sys/procfs.h>
50 #include <link.h>
51
52 #include "tnfctl.h"
53 #include "prb_proc_int.h"
54 #include "dbg.h"
55
56
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);
61
62
63 /* ---------------------------------------------------------------- */
64 /* ----------------------- Public Functions ----------------------- */
65 /* ---------------------------------------------------------------- */
66
67
68 /*
69 * prb_rtld_stalk() - setup for a breakpoint when rtld has opened or closed a
70 * shared object.
71 */
72 prb_status_t
prb_rtld_stalk(prb_proc_ctl_t * proc_p)73 prb_rtld_stalk(prb_proc_ctl_t *proc_p)
74 {
75 prb_status_t prbstat = PRB_STATUS_OK;
76
77 DBG_TNF_PROBE_0(prb_rtld_stalk_1, "libtnfctl", "sunw%verbosity 2");
78
79 if (!proc_p->bptaddr) {
80 Elf3264_Dyn dentry;
81 struct r_debug r_dbg;
82
83 if (proc_p->dbgaddr == 0) {
84 DBG((void) fprintf(stderr,
85 "prb_rtld_stalk: dbgaddr not set\n"));
86 return (PRB_STATUS_BADARG);
87 }
88
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"));
94 return (prbstat);
95 }
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));
99 if (prbstat)
100 return (prbstat);
101
102 proc_p->bptaddr = r_dbg.r_brk;
103 }
104 /* plant a breakpoint trap in the pointed to function */
105 prbstat = bpt(proc_p, proc_p->bptaddr);
106 if (prbstat)
107 return (prbstat);
108
109 /* setup process to stop when breakpoint encountered */
110 prbstat = prb_proc_tracebpt(proc_p, B_TRUE);
111
112 return (prbstat);
113
114 }
115
116
117 /*
118 * prb_rtld_unstalk() - remove rtld breakpoint
119 */
120 prb_status_t
prb_rtld_unstalk(prb_proc_ctl_t * proc_p)121 prb_rtld_unstalk(prb_proc_ctl_t *proc_p)
122 {
123 prb_status_t prbstat;
124
125 DBG_TNF_PROBE_0(prb_rtld_unstalk_1, "libtnfctl", "sunw%verbosity 2");
126
127 /* turn off BPT tracing while out of the water ... */
128 prbstat = prb_proc_tracebpt(proc_p, B_FALSE);
129
130 prbstat = unbpt(proc_p, proc_p->bptaddr);
131
132 return (prbstat);
133 }
134
135
136 /*
137 * prb_rtld_advance() - we've hit a breakpoint, replace the original
138 * instruction, istep, put the breakpoint back ...
139 */
140 prb_status_t
prb_rtld_advance(prb_proc_ctl_t * proc_p)141 prb_rtld_advance(prb_proc_ctl_t *proc_p)
142 {
143 prb_status_t prbstat;
144
145 DBG_TNF_PROBE_0(prb_rtld_advance_1, "libtnfctl", "sunw%verbosity 2");
146
147 prbstat = prb_proc_clrbptflt(proc_p);
148 if (prbstat)
149 return (prbstat);
150 prbstat = unbpt(proc_p, proc_p->bptaddr);
151 if (prbstat)
152 return (prbstat);
153
154 prbstat = prb_proc_istepbpt(proc_p);
155 if (prbstat)
156 return (prbstat);
157
158 prbstat = bpt(proc_p, proc_p->bptaddr);
159 if (prbstat)
160 return (prbstat);
161
162 return (PRB_STATUS_OK);
163 }
164
165 /*
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)
170 */
171 prb_status_t
prb_rtld_sync_if_needed(prb_proc_ctl_t * proc_p)172 prb_rtld_sync_if_needed(prb_proc_ctl_t *proc_p)
173 {
174 prb_status_t prbstat = PRB_STATUS_OK;
175 boolean_t synced = B_FALSE;
176
177 prbstat = prb_rtld_setup(proc_p, &synced);
178 if (prbstat)
179 return (prbstat);
180
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);
184 if (prbstat)
185 return (prbstat);
186 }
187
188 return (prbstat);
189 }
190
191 /* ---------------------------------------------------------------- */
192 /* ----------------------- Private Functions ---------------------- */
193 /* ---------------------------------------------------------------- */
194
195 /*
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.
199 */
200 static prb_status_t
prb_rtld_setup(prb_proc_ctl_t * proc_p,boolean_t * synced)201 prb_rtld_setup(prb_proc_ctl_t *proc_p, boolean_t *synced)
202 {
203 prb_status_t prbstat = PRB_STATUS_OK;
204 Elf3264_Dyn dentry;
205
206 DBG_TNF_PROBE_0(prb_rtld_setup_1, "libtnfctl", "sunw%verbosity 2");
207
208 if (proc_p->dbgaddr == 0) {
209 DBG((void) fprintf(stderr,
210 "prb_rtld_setup: dbgaddr not set\n"));
211 return (PRB_STATUS_BADARG);
212 }
213
214 prbstat = prb_proc_read(proc_p, proc_p->dbgaddr, &dentry,
215 sizeof (dentry));
216 if (prbstat) {
217 DBG((void) fprintf(stderr,
218 "prb_rtld_setup: error in d_un.d_ptr\n"));
219 return (prbstat);
220 }
221
222 if ((dentry.d_un.d_ptr == 0) || (dentry.d_un.d_ptr == 1)) {
223 *synced = B_FALSE;
224 } else {
225 *synced = B_TRUE;
226 return (PRB_STATUS_OK);
227 }
228
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,
232 sizeof (dentry));
233
234 return (prbstat);
235 }
236
237
238 /*
239 * prb_rtld_wait() - waits on target to execute getpid()
240 */
241 static prb_status_t
prb_rtld_wait(prb_proc_ctl_t * proc_p)242 prb_rtld_wait(prb_proc_ctl_t *proc_p)
243 {
244 prb_proc_state_t pstate;
245 prb_status_t prbstat;
246
247 DBG_TNF_PROBE_0(prb_rtld_wait_1, "libtnfctl", "sunw%verbosity 2");
248
249 /* stop on exit of getpid() */
250 prbstat = prb_proc_exit(proc_p, SYS_getpid, PRB_SYS_ADD);
251 if (prbstat) {
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)));
255 return (prbstat);
256 }
257 /* stop on entry of exit() - i.e. exec failed */
258 prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_ADD);
259 if (prbstat) {
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)));
263 return (prbstat);
264 }
265 /* continue target and wait for it to stop */
266 prbstat = prb_proc_cont(proc_p);
267 if (prbstat) {
268 DBG((void) fprintf(stderr,
269 "prb_rtld_wait: couldn't continue target process: %s\n",
270 prb_status_str(prbstat)));
271 return (prbstat);
272 }
273 /* wait for target to stop */
274 prbstat = prb_proc_wait(proc_p, B_FALSE, NULL);
275 if (prbstat) {
276 DBG((void) fprintf(stderr,
277 "prb_rtld_wait: couldn't wait on target process: %s\n",
278 prb_status_str(prbstat)));
279 return (prbstat);
280 }
281 /* make sure it did stop on getpid() */
282 prbstat = prb_proc_state(proc_p, &pstate);
283 if (prbstat) {
284 DBG((void) fprintf(stderr,
285 "prb_rtld_wait: couldn't get state of target: %s\n",
286 prb_status_str(prbstat)));
287 return (prbstat);
288 }
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));
292 }
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);
298 }
299 /* clear wait on getpid */
300 prbstat = prb_proc_exit(proc_p, SYS_getpid, PRB_SYS_DEL);
301 if (prbstat) {
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)));
305 return (prbstat);
306 }
307 /* clear wait on exit */
308 prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_DEL);
309 if (prbstat) {
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)));
313 return (prbstat);
314 }
315 /* start-stop the process to clear it out of the system call */
316 prbstat = prb_proc_prstop(proc_p);
317 if (prbstat) {
318 DBG((void) fprintf(stderr,
319 "prb_rtld_wait: couldn't prstop child: %s\n",
320 prb_status_str(prbstat)));
321 return (prbstat);
322 }
323 return (PRB_STATUS_OK);
324 }
325
326
327 #if defined(__sparc)
328 #define INS_BPT 0x91d02001
329 #elif defined(__i386) || defined(__amd64)
330 #define INS_BPT 0xcc
331 #else
332 #error What is your breakpoint instruction?
333 #endif
334
335 /*
336 * plants a breakpoint at the specified location in
337 * the target process, and saves the existing instruction.
338 */
339 static prb_status_t
bpt(prb_proc_ctl_t * proc_p,uintptr_t addr)340 bpt(prb_proc_ctl_t *proc_p, uintptr_t addr)
341 {
342 prb_status_t prbstat;
343 bptsave_t instr;
344
345 if (!proc_p->bpt_inserted) {
346
347 DBG_TNF_PROBE_1(bpt_1, "libtnfctl", "sunw%verbosity 2",
348 tnf_opaque, bpt_planted_at, addr);
349
350 prbstat = prb_proc_read(proc_p, addr,
351 &(proc_p->saveinstr), sizeof (proc_p->saveinstr));
352 if (prbstat)
353 return (prbstat);
354
355 DBG_TNF_PROBE_1(bpt_2, "libtnfctl", "sunw%verbosity 2",
356 tnf_opaque, saved_instr, (unsigned)proc_p->saveinstr);
357
358 instr = INS_BPT;
359
360 prbstat = prb_proc_write(proc_p, addr,
361 &instr, sizeof (instr));
362 if (prbstat)
363 return (prbstat);
364
365 proc_p->bpt_inserted = B_TRUE;
366 }
367 return (PRB_STATUS_OK);
368 }
369
370 /*
371 * removes a breakpoint at the specified location in
372 * the target process, and replaces it with the original instruction.
373 */
374 prb_status_t
unbpt(prb_proc_ctl_t * proc_p,uintptr_t addr)375 unbpt(prb_proc_ctl_t *proc_p, uintptr_t addr)
376 {
377 prb_status_t prbstat;
378
379 if (proc_p->bpt_inserted) {
380
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);
384
385 prbstat = prb_proc_write(proc_p, addr, &(proc_p->saveinstr),
386 sizeof (proc_p->saveinstr));
387 if (prbstat)
388 return (prbstat);
389
390 proc_p->bpt_inserted = B_FALSE;
391 }
392 return (PRB_STATUS_OK);
393 }
394