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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 29 #include <stdlib.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <proc_service.h> 33 #include <link.h> 34 #include <rtld_db.h> 35 #include <rtld.h> 36 #include <_rtld_db.h> 37 #include <msg.h> 38 #include <sys/param.h> 39 40 /* 41 * Mutex to protect global data 42 */ 43 mutex_t glob_mutex = DEFAULTMUTEX; 44 int rtld_db_version = RD_VERSION1; 45 int rtld_db_logging = 0; 46 char rtld_db_helper_path[MAXPATHLEN]; 47 48 49 void 50 rd_log(const int on_off) 51 { 52 (void) mutex_lock(&glob_mutex); 53 rtld_db_logging = on_off; 54 (void) mutex_unlock(&glob_mutex); 55 LOG(ps_plog(MSG_ORIG(MSG_DB_LOGENABLE))); 56 } 57 58 /* 59 * Versioning Notes. 60 * 61 * The following have been added as the versions of librtld_db 62 * have grown: 63 * 64 * RD_VERSION1: 65 * o baseline version 66 * 67 * RD_VERSION2: 68 * o added support for the use of the AT_SUN_LDBASE auxvector 69 * to find the initialial debugging (r_debug) structures 70 * in ld.so.1 71 * o added the rl_dynamic field to rd_loadobj_t 72 * o added the RD_FLG_MEM_OBJECT to be used with the 73 * rl_dynamic->rl_flags field. 74 * 75 * RD_VERSION3: 76 * o added the following fields/flags to the rd_plt_info_t 77 * type: 78 * pi_baddr - bound address of PLT (if bound) 79 * pi_flags - flag field 80 * RD_FLG_PI_PLTBOUND (flag for pi_flags) 81 * if set - the PLT is bound and pi_baddr 82 * is filled in with the destination of the PLT. 83 * 84 * RD_VERSION4: 85 * o added the following field to the rd_loadobj_t structure: 86 * rl_tlsmodid - module ID for TLS references 87 */ 88 rd_err_e 89 rd_init(int version) 90 { 91 if ((version < RD_VERSION1) || 92 (version > RD_VERSION)) 93 return (RD_NOCAPAB); 94 rtld_db_version = version; 95 LOG(ps_plog(MSG_ORIG(MSG_DB_RDINIT), rtld_db_version)); 96 97 return (RD_OK); 98 } 99 100 rd_err_e 101 rd_ctl(int cmd, void *arg) 102 { 103 if (cmd != RD_CTL_SET_HELPPATH || arg == NULL || 104 strlen((char *)arg) >= MAXPATHLEN) 105 return (RD_ERR); 106 107 (void) strcpy(rtld_db_helper_path, (char *)arg); 108 109 return (RD_OK); 110 } 111 112 rd_err_e 113 rd_reset(struct rd_agent *rap) 114 { 115 rd_err_e err; 116 117 RDAGLOCK(rap); 118 119 rap->rd_flags = 0; 120 121 #ifdef _LP64 122 /* 123 * Determine if client is 32-bit or 64-bit. 124 */ 125 if (ps_pdmodel(rap->rd_psp, &rap->rd_dmodel) != PS_OK) { 126 LOG(ps_plog(MSG_ORIG(MSG_DB_DMLOOKFAIL))); 127 RDAGUNLOCK(rap); 128 return (RD_DBERR); 129 } 130 131 if (rap->rd_dmodel == PR_MODEL_LP64) 132 err = _rd_reset64(rap); 133 else 134 #endif 135 err = _rd_reset32(rap); 136 137 RDAGUNLOCK(rap); 138 return (err); 139 } 140 141 142 rd_agent_t * 143 rd_new(struct ps_prochandle *php) 144 { 145 rd_agent_t *rap; 146 147 LOG(ps_plog(MSG_ORIG(MSG_DB_RDNEW), php)); 148 if ((rap = (rd_agent_t *)calloc(sizeof (rd_agent_t), 1)) == NULL) 149 return (0); 150 151 rap->rd_psp = php; 152 (void) mutex_init(&rap->rd_mutex, USYNC_THREAD, 0); 153 if (rd_reset(rap) != RD_OK) { 154 (void) dlclose(rap->rd_helper.rh_dlhandle); 155 free(rap); 156 LOG(ps_plog(MSG_ORIG(MSG_DB_RESETFAIL))); 157 return ((rd_agent_t *)0); 158 } 159 160 return (rap); 161 } 162 163 164 void 165 rd_delete(rd_agent_t *rap) 166 { 167 LOG(ps_plog(MSG_ORIG(MSG_DB_RDDELETE), rap)); 168 free(rap); 169 } 170 171 172 rd_err_e 173 rd_loadobj_iter(rd_agent_t *rap, rl_iter_f *cb, void *client_data) 174 { 175 rd_err_e err; 176 177 RDAGLOCK(rap); 178 179 #ifdef _LP64 180 if (rap->rd_dmodel == PR_MODEL_LP64) 181 err = _rd_loadobj_iter64(rap, cb, client_data); 182 else 183 #endif 184 err = _rd_loadobj_iter32(rap, cb, client_data); 185 186 RDAGUNLOCK(rap); 187 return (err); 188 } 189 190 191 rd_err_e 192 rd_plt_resolution(rd_agent_t *rap, psaddr_t pc, lwpid_t lwpid, 193 psaddr_t pltbase, rd_plt_info_t *rpi) 194 { 195 rd_err_e err; 196 RDAGLOCK(rap); 197 #ifdef _LP64 198 if (rap->rd_dmodel == PR_MODEL_LP64) 199 err = plt64_resolution(rap, pc, lwpid, pltbase, 200 rpi); 201 else 202 #endif 203 err = plt32_resolution(rap, pc, lwpid, pltbase, 204 rpi); 205 RDAGUNLOCK(rap); 206 return (err); 207 } 208 209 rd_err_e 210 rd_event_addr(rd_agent_t *rap, rd_event_e num, rd_notify_t *np) 211 { 212 rd_err_e rc = RD_OK; 213 214 RDAGLOCK(rap); 215 switch (num) { 216 case RD_NONE: 217 break; 218 case RD_PREINIT: 219 np->type = RD_NOTIFY_BPT; 220 np->u.bptaddr = rap->rd_preinit; 221 break; 222 case RD_POSTINIT: 223 np->type = RD_NOTIFY_BPT; 224 np->u.bptaddr = rap->rd_postinit; 225 break; 226 case RD_DLACTIVITY: 227 np->type = RD_NOTIFY_BPT; 228 np->u.bptaddr = rap->rd_dlact; 229 break; 230 default: 231 LOG(ps_plog(MSG_ORIG(MSG_DB_UNEXPEVENT), num)); 232 rc = RD_ERR; 233 break; 234 } 235 if (rc == RD_OK) { 236 LOG(ps_plog(MSG_ORIG(MSG_DB_RDEVENTADDR), num, 237 EC_ADDR(np->u.bptaddr))); 238 } 239 240 RDAGUNLOCK(rap); 241 return (rc); 242 } 243 244 245 /* ARGSUSED 0 */ 246 rd_err_e 247 rd_event_enable(rd_agent_t *rap, int onoff) 248 { 249 rd_err_e err; 250 251 RDAGLOCK(rap); 252 253 #ifdef _LP64 254 if (rap->rd_dmodel == PR_MODEL_LP64) 255 err = _rd_event_enable64(rap, onoff); 256 else 257 #endif 258 err = _rd_event_enable32(rap, onoff); 259 260 RDAGUNLOCK(rap); 261 return (err); 262 } 263 264 265 rd_err_e 266 rd_event_getmsg(rd_agent_t *rap, rd_event_msg_t *emsg) 267 { 268 rd_err_e err; 269 270 RDAGLOCK(rap); 271 272 #ifdef _LP64 273 if (rap->rd_dmodel == PR_MODEL_LP64) 274 err = _rd_event_getmsg64(rap, emsg); 275 else 276 #endif 277 err = _rd_event_getmsg32(rap, emsg); 278 279 RDAGUNLOCK(rap); 280 return (err); 281 } 282 283 284 rd_err_e 285 rd_binder_exit_addr(struct rd_agent *rap, const char *bname, psaddr_t *beaddr) 286 { 287 ps_sym_t sym; 288 289 if (rap->rd_tbinder) { 290 *beaddr = rap->rd_tbinder; 291 return (RD_OK); 292 } 293 if (ps_pglobal_sym(rap->rd_psp, PS_OBJ_LDSO, bname, &sym) != PS_OK) { 294 LOG(ps_plog(MSG_ORIG(MSG_DB_UNFNDSYM), 295 bname)); 296 return (RD_ERR); 297 } 298 299 rap->rd_tbinder = *beaddr = sym.st_value + sym.st_size - M_BIND_ADJ; 300 301 return (RD_OK); 302 } 303 304 305 rd_err_e 306 rd_objpad_enable(struct rd_agent *rap, size_t padsize) 307 { 308 rd_err_e err; 309 310 RDAGLOCK(rap); 311 312 #ifdef _LP64 313 if (rap->rd_dmodel == PR_MODEL_LP64) 314 err = _rd_objpad_enable64(rap, padsize); 315 else 316 #endif 317 err = _rd_objpad_enable32(rap, padsize); 318 319 RDAGUNLOCK(rap); 320 return (err); 321 } 322 323 324 char * 325 rd_errstr(rd_err_e rderr) 326 { 327 /* 328 * Convert an 'rd_err_e' to a string 329 */ 330 switch (rderr) { 331 case RD_OK: 332 return ((char *)MSG_ORIG(MSG_ER_OK)); 333 case RD_ERR: 334 return ((char *)MSG_ORIG(MSG_ER_ERR)); 335 case RD_DBERR: 336 return ((char *)MSG_ORIG(MSG_ER_DBERR)); 337 case RD_NOCAPAB: 338 return ((char *)MSG_ORIG(MSG_ER_NOCAPAB)); 339 case RD_NODYNAM: 340 return ((char *)MSG_ORIG(MSG_ER_NODYNAM)); 341 case RD_NOBASE: 342 return ((char *)MSG_ORIG(MSG_ER_NOBASE)); 343 case RD_NOMAPS: 344 return ((char *)MSG_ORIG(MSG_ER_NOMAPS)); 345 default: 346 return ((char *)MSG_ORIG(MSG_ER_DEFAULT)); 347 } 348 } 349