10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52712Snn35248 * Common Development and Distribution License (the "License").
62712Snn35248 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*6830Sedp * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include <stdlib.h>
300Sstevel@tonic-gate #include <stdio.h>
312712Snn35248 #include <string.h>
320Sstevel@tonic-gate #include <proc_service.h>
330Sstevel@tonic-gate #include <link.h>
340Sstevel@tonic-gate #include <rtld_db.h>
350Sstevel@tonic-gate #include <rtld.h>
360Sstevel@tonic-gate #include <_rtld_db.h>
370Sstevel@tonic-gate #include <msg.h>
382712Snn35248 #include <sys/param.h>
390Sstevel@tonic-gate
400Sstevel@tonic-gate /*
410Sstevel@tonic-gate * Mutex to protect global data
420Sstevel@tonic-gate */
430Sstevel@tonic-gate mutex_t glob_mutex = DEFAULTMUTEX;
440Sstevel@tonic-gate int rtld_db_version = RD_VERSION1;
450Sstevel@tonic-gate int rtld_db_logging = 0;
462712Snn35248 char rtld_db_helper_path[MAXPATHLEN];
470Sstevel@tonic-gate
480Sstevel@tonic-gate
490Sstevel@tonic-gate void
rd_log(const int on_off)500Sstevel@tonic-gate rd_log(const int on_off)
510Sstevel@tonic-gate {
520Sstevel@tonic-gate (void) mutex_lock(&glob_mutex);
530Sstevel@tonic-gate rtld_db_logging = on_off;
540Sstevel@tonic-gate (void) mutex_unlock(&glob_mutex);
550Sstevel@tonic-gate LOG(ps_plog(MSG_ORIG(MSG_DB_LOGENABLE)));
560Sstevel@tonic-gate }
570Sstevel@tonic-gate
580Sstevel@tonic-gate /*
590Sstevel@tonic-gate * Versioning Notes.
600Sstevel@tonic-gate *
610Sstevel@tonic-gate * The following have been added as the versions of librtld_db
620Sstevel@tonic-gate * have grown:
630Sstevel@tonic-gate *
640Sstevel@tonic-gate * RD_VERSION1:
650Sstevel@tonic-gate * o baseline version
660Sstevel@tonic-gate *
670Sstevel@tonic-gate * RD_VERSION2:
680Sstevel@tonic-gate * o added support for the use of the AT_SUN_LDBASE auxvector
690Sstevel@tonic-gate * to find the initialial debugging (r_debug) structures
700Sstevel@tonic-gate * in ld.so.1
710Sstevel@tonic-gate * o added the rl_dynamic field to rd_loadobj_t
720Sstevel@tonic-gate * o added the RD_FLG_MEM_OBJECT to be used with the
730Sstevel@tonic-gate * rl_dynamic->rl_flags field.
740Sstevel@tonic-gate *
750Sstevel@tonic-gate * RD_VERSION3:
760Sstevel@tonic-gate * o added the following fields/flags to the rd_plt_info_t
770Sstevel@tonic-gate * type:
780Sstevel@tonic-gate * pi_baddr - bound address of PLT (if bound)
790Sstevel@tonic-gate * pi_flags - flag field
800Sstevel@tonic-gate * RD_FLG_PI_PLTBOUND (flag for pi_flags)
810Sstevel@tonic-gate * if set - the PLT is bound and pi_baddr
820Sstevel@tonic-gate * is filled in with the destination of the PLT.
830Sstevel@tonic-gate *
840Sstevel@tonic-gate * RD_VERSION4:
850Sstevel@tonic-gate * o added the following field to the rd_loadobj_t structure:
860Sstevel@tonic-gate * rl_tlsmodid - module ID for TLS references
870Sstevel@tonic-gate */
880Sstevel@tonic-gate rd_err_e
rd_init(int version)890Sstevel@tonic-gate rd_init(int version)
900Sstevel@tonic-gate {
910Sstevel@tonic-gate if ((version < RD_VERSION1) ||
920Sstevel@tonic-gate (version > RD_VERSION))
930Sstevel@tonic-gate return (RD_NOCAPAB);
940Sstevel@tonic-gate rtld_db_version = version;
950Sstevel@tonic-gate LOG(ps_plog(MSG_ORIG(MSG_DB_RDINIT), rtld_db_version));
962712Snn35248
970Sstevel@tonic-gate return (RD_OK);
980Sstevel@tonic-gate }
990Sstevel@tonic-gate
1002712Snn35248 rd_err_e
rd_ctl(int cmd,void * arg)1012712Snn35248 rd_ctl(int cmd, void *arg)
1022712Snn35248 {
1032712Snn35248 if (cmd != RD_CTL_SET_HELPPATH || arg == NULL ||
1042712Snn35248 strlen((char *)arg) >= MAXPATHLEN)
1052712Snn35248 return (RD_ERR);
1062712Snn35248
1072712Snn35248 (void) strcpy(rtld_db_helper_path, (char *)arg);
1082712Snn35248
1092712Snn35248 return (RD_OK);
1102712Snn35248 }
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate rd_err_e
rd_get_dyns(rd_agent_t * rap,psaddr_t addr,void ** dynpp,size_t * dynpp_sz)113*6830Sedp rd_get_dyns(rd_agent_t *rap, psaddr_t addr, void **dynpp, size_t *dynpp_sz)
114*6830Sedp {
115*6830Sedp if (rap->rd_helper.rh_ops != NULL)
116*6830Sedp return (rap->rd_helper.rh_ops->rho_get_dyns(
117*6830Sedp rap->rd_helper.rh_data, addr, dynpp, dynpp_sz));
118*6830Sedp
119*6830Sedp #ifdef _LP64
120*6830Sedp if (rap->rd_dmodel == PR_MODEL_LP64)
121*6830Sedp return (_rd_get_dyns64(rap,
122*6830Sedp addr, (Elf64_Dyn **)dynpp, dynpp_sz));
123*6830Sedp else
124*6830Sedp #endif
125*6830Sedp return (_rd_get_dyns32(rap,
126*6830Sedp addr, (Dyn **)dynpp, dynpp_sz));
127*6830Sedp }
128*6830Sedp
129*6830Sedp rd_err_e
rd_reset(struct rd_agent * rap)1300Sstevel@tonic-gate rd_reset(struct rd_agent *rap)
1310Sstevel@tonic-gate {
1320Sstevel@tonic-gate rd_err_e err;
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate RDAGLOCK(rap);
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate rap->rd_flags = 0;
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate #ifdef _LP64
1390Sstevel@tonic-gate /*
1400Sstevel@tonic-gate * Determine if client is 32-bit or 64-bit.
1410Sstevel@tonic-gate */
1420Sstevel@tonic-gate if (ps_pdmodel(rap->rd_psp, &rap->rd_dmodel) != PS_OK) {
1430Sstevel@tonic-gate LOG(ps_plog(MSG_ORIG(MSG_DB_DMLOOKFAIL)));
1440Sstevel@tonic-gate RDAGUNLOCK(rap);
1450Sstevel@tonic-gate return (RD_DBERR);
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate if (rap->rd_dmodel == PR_MODEL_LP64)
1490Sstevel@tonic-gate err = _rd_reset64(rap);
1500Sstevel@tonic-gate else
1510Sstevel@tonic-gate #endif
1520Sstevel@tonic-gate err = _rd_reset32(rap);
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate RDAGUNLOCK(rap);
1550Sstevel@tonic-gate return (err);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate rd_agent_t *
rd_new(struct ps_prochandle * php)1600Sstevel@tonic-gate rd_new(struct ps_prochandle *php)
1610Sstevel@tonic-gate {
1620Sstevel@tonic-gate rd_agent_t *rap;
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate LOG(ps_plog(MSG_ORIG(MSG_DB_RDNEW), php));
1650Sstevel@tonic-gate if ((rap = (rd_agent_t *)calloc(sizeof (rd_agent_t), 1)) == NULL)
1660Sstevel@tonic-gate return (0);
1670Sstevel@tonic-gate
1680Sstevel@tonic-gate rap->rd_psp = php;
1690Sstevel@tonic-gate (void) mutex_init(&rap->rd_mutex, USYNC_THREAD, 0);
1700Sstevel@tonic-gate if (rd_reset(rap) != RD_OK) {
171*6830Sedp if (rap->rd_helper.rh_dlhandle != NULL) {
172*6830Sedp rap->rd_helper.rh_ops->rho_fini(rap->rd_helper.rh_data);
173*6830Sedp (void) dlclose(rap->rd_helper.rh_dlhandle);
174*6830Sedp }
1750Sstevel@tonic-gate free(rap);
1760Sstevel@tonic-gate LOG(ps_plog(MSG_ORIG(MSG_DB_RESETFAIL)));
1770Sstevel@tonic-gate return ((rd_agent_t *)0);
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate return (rap);
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate
1840Sstevel@tonic-gate void
rd_delete(rd_agent_t * rap)1850Sstevel@tonic-gate rd_delete(rd_agent_t *rap)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate LOG(ps_plog(MSG_ORIG(MSG_DB_RDDELETE), rap));
188*6830Sedp if (rap->rd_helper.rh_dlhandle != NULL) {
189*6830Sedp rap->rd_helper.rh_ops->rho_fini(rap->rd_helper.rh_data);
190*6830Sedp (void) dlclose(rap->rd_helper.rh_dlhandle);
191*6830Sedp }
1920Sstevel@tonic-gate free(rap);
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate rd_err_e
rd_loadobj_iter(rd_agent_t * rap,rl_iter_f * cb,void * client_data)1970Sstevel@tonic-gate rd_loadobj_iter(rd_agent_t *rap, rl_iter_f *cb, void *client_data)
1980Sstevel@tonic-gate {
1990Sstevel@tonic-gate rd_err_e err;
2000Sstevel@tonic-gate
2010Sstevel@tonic-gate RDAGLOCK(rap);
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate #ifdef _LP64
2040Sstevel@tonic-gate if (rap->rd_dmodel == PR_MODEL_LP64)
2050Sstevel@tonic-gate err = _rd_loadobj_iter64(rap, cb, client_data);
2060Sstevel@tonic-gate else
2070Sstevel@tonic-gate #endif
2080Sstevel@tonic-gate err = _rd_loadobj_iter32(rap, cb, client_data);
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate RDAGUNLOCK(rap);
2110Sstevel@tonic-gate return (err);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate rd_err_e
rd_plt_resolution(rd_agent_t * rap,psaddr_t pc,lwpid_t lwpid,psaddr_t pltbase,rd_plt_info_t * rpi)2160Sstevel@tonic-gate rd_plt_resolution(rd_agent_t *rap, psaddr_t pc, lwpid_t lwpid,
2170Sstevel@tonic-gate psaddr_t pltbase, rd_plt_info_t *rpi)
2180Sstevel@tonic-gate {
2190Sstevel@tonic-gate rd_err_e err;
2200Sstevel@tonic-gate RDAGLOCK(rap);
2210Sstevel@tonic-gate #ifdef _LP64
2220Sstevel@tonic-gate if (rap->rd_dmodel == PR_MODEL_LP64)
2230Sstevel@tonic-gate err = plt64_resolution(rap, pc, lwpid, pltbase,
2240Sstevel@tonic-gate rpi);
2250Sstevel@tonic-gate else
2260Sstevel@tonic-gate #endif
2270Sstevel@tonic-gate err = plt32_resolution(rap, pc, lwpid, pltbase,
2280Sstevel@tonic-gate rpi);
2290Sstevel@tonic-gate RDAGUNLOCK(rap);
2300Sstevel@tonic-gate return (err);
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate
2330Sstevel@tonic-gate rd_err_e
rd_event_addr(rd_agent_t * rap,rd_event_e num,rd_notify_t * np)2340Sstevel@tonic-gate rd_event_addr(rd_agent_t *rap, rd_event_e num, rd_notify_t *np)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate rd_err_e rc = RD_OK;
2370Sstevel@tonic-gate
2380Sstevel@tonic-gate RDAGLOCK(rap);
2390Sstevel@tonic-gate switch (num) {
2400Sstevel@tonic-gate case RD_NONE:
2410Sstevel@tonic-gate break;
2420Sstevel@tonic-gate case RD_PREINIT:
2430Sstevel@tonic-gate np->type = RD_NOTIFY_BPT;
2440Sstevel@tonic-gate np->u.bptaddr = rap->rd_preinit;
2450Sstevel@tonic-gate break;
2460Sstevel@tonic-gate case RD_POSTINIT:
2470Sstevel@tonic-gate np->type = RD_NOTIFY_BPT;
2480Sstevel@tonic-gate np->u.bptaddr = rap->rd_postinit;
2490Sstevel@tonic-gate break;
2500Sstevel@tonic-gate case RD_DLACTIVITY:
2510Sstevel@tonic-gate np->type = RD_NOTIFY_BPT;
2520Sstevel@tonic-gate np->u.bptaddr = rap->rd_dlact;
2530Sstevel@tonic-gate break;
2540Sstevel@tonic-gate default:
2550Sstevel@tonic-gate LOG(ps_plog(MSG_ORIG(MSG_DB_UNEXPEVENT), num));
2560Sstevel@tonic-gate rc = RD_ERR;
2570Sstevel@tonic-gate break;
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate if (rc == RD_OK) {
2600Sstevel@tonic-gate LOG(ps_plog(MSG_ORIG(MSG_DB_RDEVENTADDR), num,
2612712Snn35248 EC_ADDR(np->u.bptaddr)));
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate RDAGUNLOCK(rap);
2650Sstevel@tonic-gate return (rc);
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate /* ARGSUSED 0 */
2700Sstevel@tonic-gate rd_err_e
rd_event_enable(rd_agent_t * rap,int onoff)2710Sstevel@tonic-gate rd_event_enable(rd_agent_t *rap, int onoff)
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate rd_err_e err;
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate RDAGLOCK(rap);
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate #ifdef _LP64
2780Sstevel@tonic-gate if (rap->rd_dmodel == PR_MODEL_LP64)
2790Sstevel@tonic-gate err = _rd_event_enable64(rap, onoff);
2800Sstevel@tonic-gate else
2810Sstevel@tonic-gate #endif
2820Sstevel@tonic-gate err = _rd_event_enable32(rap, onoff);
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate RDAGUNLOCK(rap);
2850Sstevel@tonic-gate return (err);
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate rd_err_e
rd_event_getmsg(rd_agent_t * rap,rd_event_msg_t * emsg)2900Sstevel@tonic-gate rd_event_getmsg(rd_agent_t *rap, rd_event_msg_t *emsg)
2910Sstevel@tonic-gate {
2920Sstevel@tonic-gate rd_err_e err;
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate RDAGLOCK(rap);
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate #ifdef _LP64
2970Sstevel@tonic-gate if (rap->rd_dmodel == PR_MODEL_LP64)
2980Sstevel@tonic-gate err = _rd_event_getmsg64(rap, emsg);
2990Sstevel@tonic-gate else
3000Sstevel@tonic-gate #endif
3010Sstevel@tonic-gate err = _rd_event_getmsg32(rap, emsg);
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate RDAGUNLOCK(rap);
3040Sstevel@tonic-gate return (err);
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate
3080Sstevel@tonic-gate rd_err_e
rd_binder_exit_addr(struct rd_agent * rap,const char * bname,psaddr_t * beaddr)3090Sstevel@tonic-gate rd_binder_exit_addr(struct rd_agent *rap, const char *bname, psaddr_t *beaddr)
3100Sstevel@tonic-gate {
3110Sstevel@tonic-gate ps_sym_t sym;
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate if (rap->rd_tbinder) {
3140Sstevel@tonic-gate *beaddr = rap->rd_tbinder;
3150Sstevel@tonic-gate return (RD_OK);
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate if (ps_pglobal_sym(rap->rd_psp, PS_OBJ_LDSO, bname, &sym) != PS_OK) {
3180Sstevel@tonic-gate LOG(ps_plog(MSG_ORIG(MSG_DB_UNFNDSYM),
3190Sstevel@tonic-gate bname));
3200Sstevel@tonic-gate return (RD_ERR);
3210Sstevel@tonic-gate }
3220Sstevel@tonic-gate
3230Sstevel@tonic-gate rap->rd_tbinder = *beaddr = sym.st_value + sym.st_size - M_BIND_ADJ;
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate return (RD_OK);
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate rd_err_e
rd_objpad_enable(struct rd_agent * rap,size_t padsize)3300Sstevel@tonic-gate rd_objpad_enable(struct rd_agent *rap, size_t padsize)
3310Sstevel@tonic-gate {
3320Sstevel@tonic-gate rd_err_e err;
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate RDAGLOCK(rap);
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate #ifdef _LP64
3370Sstevel@tonic-gate if (rap->rd_dmodel == PR_MODEL_LP64)
3380Sstevel@tonic-gate err = _rd_objpad_enable64(rap, padsize);
3390Sstevel@tonic-gate else
3400Sstevel@tonic-gate #endif
3410Sstevel@tonic-gate err = _rd_objpad_enable32(rap, padsize);
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate RDAGUNLOCK(rap);
3440Sstevel@tonic-gate return (err);
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate char *
rd_errstr(rd_err_e rderr)3490Sstevel@tonic-gate rd_errstr(rd_err_e rderr)
3500Sstevel@tonic-gate {
3510Sstevel@tonic-gate /*
3520Sstevel@tonic-gate * Convert an 'rd_err_e' to a string
3530Sstevel@tonic-gate */
3540Sstevel@tonic-gate switch (rderr) {
3550Sstevel@tonic-gate case RD_OK:
3560Sstevel@tonic-gate return ((char *)MSG_ORIG(MSG_ER_OK));
3570Sstevel@tonic-gate case RD_ERR:
3580Sstevel@tonic-gate return ((char *)MSG_ORIG(MSG_ER_ERR));
3590Sstevel@tonic-gate case RD_DBERR:
3600Sstevel@tonic-gate return ((char *)MSG_ORIG(MSG_ER_DBERR));
3610Sstevel@tonic-gate case RD_NOCAPAB:
3620Sstevel@tonic-gate return ((char *)MSG_ORIG(MSG_ER_NOCAPAB));
3630Sstevel@tonic-gate case RD_NODYNAM:
3640Sstevel@tonic-gate return ((char *)MSG_ORIG(MSG_ER_NODYNAM));
3650Sstevel@tonic-gate case RD_NOBASE:
3660Sstevel@tonic-gate return ((char *)MSG_ORIG(MSG_ER_NOBASE));
3670Sstevel@tonic-gate case RD_NOMAPS:
3680Sstevel@tonic-gate return ((char *)MSG_ORIG(MSG_ER_NOMAPS));
3690Sstevel@tonic-gate default:
3700Sstevel@tonic-gate return ((char *)MSG_ORIG(MSG_ER_DEFAULT));
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate }
373