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 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 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 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 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 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 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 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 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