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