17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
59acbbeafSnn  * Common Development and Distribution License (the "License").
69acbbeafSnn  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
227230bd30SGerald Jelinek  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include	<stdlib.h>
277c478bd9Sstevel@tonic-gate #include	<stdio.h>
287c478bd9Sstevel@tonic-gate #include	<proc_service.h>
297c478bd9Sstevel@tonic-gate #include	<link.h>
307c478bd9Sstevel@tonic-gate #include	<rtld_db.h>
317c478bd9Sstevel@tonic-gate #include	<rtld.h>
3257ef7aa9SRod Evans #include	<alist.h>
3328bda19cSRod Evans #include	<list.h>
347c478bd9Sstevel@tonic-gate #include	<_rtld_db.h>
357c478bd9Sstevel@tonic-gate #include	<msg.h>
369acbbeafSnn #include	<limits.h>
379acbbeafSnn #include	<string.h>
389acbbeafSnn #include	<sys/param.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * 64-bit builds are going to compile this module twice, the
427c478bd9Sstevel@tonic-gate  * second time with _ELF64 defined.  These defines should make
437c478bd9Sstevel@tonic-gate  * all the necessary adjustments to the code.
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate #ifdef _LP64
467c478bd9Sstevel@tonic-gate #ifdef _ELF64
477c478bd9Sstevel@tonic-gate #define	_rd_event_enable32	_rd_event_enable64
487c478bd9Sstevel@tonic-gate #define	_rd_event_getmsg32	_rd_event_getmsg64
4922872efbSedp #define	_rd_get_dyns32		_rd_get_dyns64
5022872efbSedp #define	_rd_get_ehdr32		_rd_get_ehdr64
517c478bd9Sstevel@tonic-gate #define	_rd_objpad_enable32	_rd_objpad_enable64
527c478bd9Sstevel@tonic-gate #define	_rd_loadobj_iter32	_rd_loadobj_iter64
5322872efbSedp #define	_rd_reset32		_rd_reset64
547c478bd9Sstevel@tonic-gate #define	find_dynamic_ent32	find_dynamic_ent64
5522872efbSedp #define	validate_rdebug32	validate_rdebug64
5657ef7aa9SRod Evans #define	TAPlist			APlist
5757ef7aa9SRod Evans #define	TLm_list		Lm_list
5828bda19cSRod Evans #define	TList			List
5928bda19cSRod Evans #define	TListnode		Listnode
60adbfe822Srie #define	MSG_SYM_BRANDOPS	MSG_SYM_BRANDOPS_64
617c478bd9Sstevel@tonic-gate #else	/* ELF32 */
627c478bd9Sstevel@tonic-gate #define	Rt_map			Rt_map32
637c478bd9Sstevel@tonic-gate #define	Rtld_db_priv		Rtld_db_priv32
6457ef7aa9SRod Evans #define	TAPlist			APlist32
6557ef7aa9SRod Evans #define	TLm_list		Lm_list32
6628bda19cSRod Evans #define	TList			List32
6728bda19cSRod Evans #define	TListnode		Listnode32
6828bda19cSRod Evans #define	Lm_list			Lm_list32
69adbfe822Srie #define	MSG_SYM_BRANDOPS	MSG_SYM_BRANDOPS_32
707c478bd9Sstevel@tonic-gate #endif	/* _ELF64 */
717c478bd9Sstevel@tonic-gate #else	/* _LP64 */
7257ef7aa9SRod Evans #define	TAPlist			APlist
7357ef7aa9SRod Evans #define	TLm_list		Lm_list
7428bda19cSRod Evans #define	TList			List
7528bda19cSRod Evans #define	TListnode		Listnode
76adbfe822Srie #define	MSG_SYM_BRANDOPS	MSG_SYM_BRANDOPS_32
777c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
787c478bd9Sstevel@tonic-gate 
795eae5a6fSedp /*
805eae5a6fSedp  * BrandZ added ps_pbrandname().  Many debuggers that link directly
815eae5a6fSedp  * against librtld_db.so may not implement this interface.  Hence
825eae5a6fSedp  * we won't call the function directly, instead we'll try to look it
835eae5a6fSedp  * up using the linker first and only invoke it if we find it.
845eae5a6fSedp  */
855eae5a6fSedp typedef ps_err_e (*ps_pbrandname_fp_t)(struct ps_prochandle *,
865eae5a6fSedp     char *, size_t);
875eae5a6fSedp 
8822872efbSedp rd_err_e
validate_rdebug32(struct rd_agent * rap)8922872efbSedp validate_rdebug32(struct rd_agent *rap)
907c478bd9Sstevel@tonic-gate {
917c478bd9Sstevel@tonic-gate 	struct ps_prochandle	*php = rap->rd_psp;
927c478bd9Sstevel@tonic-gate 	psaddr_t		db_privp;
937c478bd9Sstevel@tonic-gate 	Rtld_db_priv		db_priv;
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	if (rap->rd_rdebug == 0)
967c478bd9Sstevel@tonic-gate 		return (RD_ERR);
9728bda19cSRod Evans 
987c478bd9Sstevel@tonic-gate 	/*
997c478bd9Sstevel@tonic-gate 	 * The rtld_db_priv structure contains both the traditional (exposed)
1007c478bd9Sstevel@tonic-gate 	 * r_debug structure as well as private data only available to
1017c478bd9Sstevel@tonic-gate 	 * this library.
1027c478bd9Sstevel@tonic-gate 	 */
1037c478bd9Sstevel@tonic-gate 	db_privp = rap->rd_rdebug;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	/*
1067c478bd9Sstevel@tonic-gate 	 * Verify that librtld_db & rtld are at the proper revision
1077c478bd9Sstevel@tonic-gate 	 * levels.
1087c478bd9Sstevel@tonic-gate 	 */
1097c478bd9Sstevel@tonic-gate 	if (ps_pread(php, db_privp, (char *)&db_priv,
1107c478bd9Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK) {
1117c478bd9Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_READPRIVFAIL_1),
1129acbbeafSnn 		    EC_ADDR(db_privp)));
1137c478bd9Sstevel@tonic-gate 		return (RD_DBERR);
1147c478bd9Sstevel@tonic-gate 	}
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	if ((db_priv.rtd_version < R_RTLDDB_VERSION1) ||
1177c478bd9Sstevel@tonic-gate 	    (db_priv.rtd_version > R_RTLDDB_VERSION)) {
1187c478bd9Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_BADPVERS),
1199acbbeafSnn 		    db_priv.rtd_version, R_RTLDDB_VERSION));
1207c478bd9Sstevel@tonic-gate 		return (RD_NOCAPAB);
1217c478bd9Sstevel@tonic-gate 	}
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	/*
1247c478bd9Sstevel@tonic-gate 	 * Is the image being examined from a core file or not.
1257c478bd9Sstevel@tonic-gate 	 * If it is a core file then the following write will fail.
1267c478bd9Sstevel@tonic-gate 	 */
1277c478bd9Sstevel@tonic-gate 	if (ps_pwrite(php, db_privp, (char *)&db_priv,
1287c478bd9Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK)
1297c478bd9Sstevel@tonic-gate 		rap->rd_flags |= RDF_FL_COREFILE;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	rap->rd_rdebugvers = db_priv.rtd_version;
1327c478bd9Sstevel@tonic-gate 	rap->rd_rtlddbpriv = db_privp;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	LOG(ps_plog(MSG_ORIG(MSG_DB_VALIDRDEBUG), EC_ADDR(rap->rd_rdebug),
1359acbbeafSnn 	    R_RTLDDB_VERSION, rap->rd_rdebugvers,
1369acbbeafSnn 	    rap->rd_flags & RDF_FL_COREFILE));
1377c478bd9Sstevel@tonic-gate 	return (RD_OK);
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate rd_err_e
find_dynamic_ent32(struct rd_agent * rap,psaddr_t dynaddr,Xword dyntag,Dyn * dyn)1427c478bd9Sstevel@tonic-gate find_dynamic_ent32(struct rd_agent *rap, psaddr_t dynaddr,
143*22ca2f96SToomas Soome     Xword dyntag, Dyn *dyn)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate 	struct ps_prochandle	*php = rap->rd_psp;
1467c478bd9Sstevel@tonic-gate 	Dyn			d;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	d.d_tag = DT_NULL;
1497c478bd9Sstevel@tonic-gate 	do {
1507c478bd9Sstevel@tonic-gate 		if (ps_pread(php, dynaddr, (void *)(&d), sizeof (d)) !=
1517c478bd9Sstevel@tonic-gate 		    PS_OK) {
1527c478bd9Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_4),
1539acbbeafSnn 			    EC_ADDR(dynaddr)));
1547c478bd9Sstevel@tonic-gate 			return (RD_DBERR);
1557c478bd9Sstevel@tonic-gate 		}
1567c478bd9Sstevel@tonic-gate 		dynaddr += sizeof (d);
1577c478bd9Sstevel@tonic-gate 		if (d.d_tag == dyntag)
1587c478bd9Sstevel@tonic-gate 			break;
1597c478bd9Sstevel@tonic-gate 	} while (d.d_tag != DT_NULL);
1607c478bd9Sstevel@tonic-gate 	if (d.d_tag == dyntag) {
1617c478bd9Sstevel@tonic-gate 		*dyn = d;
1627c478bd9Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_FINDDYNAMIC), EC_ADDR(dyntag),
1637c478bd9Sstevel@tonic-gate 		    EC_ADDR(d.d_un.d_val)));
1647c478bd9Sstevel@tonic-gate 		return (RD_OK);
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 	LOG(ps_plog(MSG_ORIG(MSG_DB_NODYNDEBUG), EC_ADDR(dyntag)));
1677c478bd9Sstevel@tonic-gate 	return (RD_DBERR);
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate 
1709acbbeafSnn extern char rtld_db_helper_path[MAXPATHLEN];
1719acbbeafSnn 
1727c478bd9Sstevel@tonic-gate rd_err_e
_rd_reset32(struct rd_agent * rap)1737c478bd9Sstevel@tonic-gate _rd_reset32(struct rd_agent *rap)
1747c478bd9Sstevel@tonic-gate {
1757c478bd9Sstevel@tonic-gate 	psaddr_t		symaddr;
1767c478bd9Sstevel@tonic-gate 	struct ps_prochandle	*php = rap->rd_psp;
1777c478bd9Sstevel@tonic-gate 	const auxv_t		*auxvp = NULL;
1787c478bd9Sstevel@tonic-gate 	rd_err_e		rc = RD_OK;
1799acbbeafSnn 	char			brandname[MAXPATHLEN];
1809acbbeafSnn 	char			brandlib[MAXPATHLEN];
1815eae5a6fSedp 	ps_pbrandname_fp_t	ps_pbrandname;
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	/*
1847c478bd9Sstevel@tonic-gate 	 * librtld_db attempts three different methods to find
1857c478bd9Sstevel@tonic-gate 	 * the r_debug structure which is required to
1867c478bd9Sstevel@tonic-gate 	 * initialize itself.  The methods are:
1877c478bd9Sstevel@tonic-gate 	 *	method1:
1887c478bd9Sstevel@tonic-gate 	 *		entirely independent of any text segment
1897c478bd9Sstevel@tonic-gate 	 *		and relies on the AT_SUN_LDDATA auxvector
1907c478bd9Sstevel@tonic-gate 	 *		to find the ld.so.1::rdebug structure.
1917c478bd9Sstevel@tonic-gate 	 *	method2:
1927c478bd9Sstevel@tonic-gate 	 *		lookup symbols in ld.so.1's symbol table
1937c478bd9Sstevel@tonic-gate 	 *		to find the r_debug symbol.
1947c478bd9Sstevel@tonic-gate 	 *	method3:
1957c478bd9Sstevel@tonic-gate 	 *		(old dbx method) dependent upon the
1967c478bd9Sstevel@tonic-gate 	 *		text segment/symbol table of the
1977c478bd9Sstevel@tonic-gate 	 *		executable and not ld.so.1.  We lookup the
1987c478bd9Sstevel@tonic-gate 	 *		_DYNAMIC symbol in the executable and look for
1997c478bd9Sstevel@tonic-gate 	 *		the DT_DEBUG entry in the .dynamic table.  This
2007c478bd9Sstevel@tonic-gate 	 *		points to rdebug.
2017c478bd9Sstevel@tonic-gate 	 *
2027c478bd9Sstevel@tonic-gate 	 * If none of that works - we fail.
2037c478bd9Sstevel@tonic-gate 	 */
2047c478bd9Sstevel@tonic-gate 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDRESET), rap->rd_dmodel));
2057c478bd9Sstevel@tonic-gate 	/*
2067c478bd9Sstevel@tonic-gate 	 * Method1
2077c478bd9Sstevel@tonic-gate 	 *
2087c478bd9Sstevel@tonic-gate 	 * Scan the aux vector looking for AT_BASE & AT_SUN_LDDATA
2097c478bd9Sstevel@tonic-gate 	 */
2109acbbeafSnn 
2117c478bd9Sstevel@tonic-gate 	if (ps_pauxv(php, &auxvp) != PS_OK) {
2127c478bd9Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_NOAUXV)));
2137c478bd9Sstevel@tonic-gate 		rc = RD_ERR;
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	rap->rd_rdebug = 0;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	if (auxvp != NULL) {
2197c478bd9Sstevel@tonic-gate 		rc = RD_ERR;
2207c478bd9Sstevel@tonic-gate 		while (auxvp->a_type != AT_NULL) {
2217c478bd9Sstevel@tonic-gate 			if (auxvp->a_type == AT_SUN_LDDATA) {
2227c478bd9Sstevel@tonic-gate 				/* LINTED */
2237c478bd9Sstevel@tonic-gate 				rap->rd_rdebug = (uintptr_t)auxvp->a_un.a_ptr;
2247c478bd9Sstevel@tonic-gate 				LOG(ps_plog(MSG_ORIG(MSG_DB_FLDDATA),
2257c478bd9Sstevel@tonic-gate 				    rap->rd_rdebug));
22622872efbSedp 				rc = validate_rdebug32(rap);
2277c478bd9Sstevel@tonic-gate 				break;
2287c478bd9Sstevel@tonic-gate 			}
2297c478bd9Sstevel@tonic-gate 			auxvp++;
2307c478bd9Sstevel@tonic-gate 		}
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	/*
2347c478bd9Sstevel@tonic-gate 	 * method2 - look for r_rdebug symbol in ld.so.1
2357c478bd9Sstevel@tonic-gate 	 */
2367c478bd9Sstevel@tonic-gate 	if (rc != RD_OK) {
2377c478bd9Sstevel@tonic-gate 		/*
2387c478bd9Sstevel@tonic-gate 		 * If the AT_SUN_LDDATA auxv vector is not present
2397c478bd9Sstevel@tonic-gate 		 * fall back on doing a symlookup of
2407c478bd9Sstevel@tonic-gate 		 * the r_debug symbol.  This is for backward
2417c478bd9Sstevel@tonic-gate 		 * compatiblity with older OS's
2427c478bd9Sstevel@tonic-gate 		 */
2437c478bd9Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_NOLDDATA)));
2447c478bd9Sstevel@tonic-gate 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO, MSG_ORIG(MSG_SYM_DEBUG),
2457c478bd9Sstevel@tonic-gate 		    &symaddr) != PS_OK) {
2467c478bd9Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
2479acbbeafSnn 			    MSG_ORIG(MSG_SYM_DEBUG)));
2487c478bd9Sstevel@tonic-gate 			rc = RD_DBERR;
2497c478bd9Sstevel@tonic-gate 		} else {
2507c478bd9Sstevel@tonic-gate 			rap->rd_rdebug = symaddr;
2517c478bd9Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_SYMRDEBUG),
2529acbbeafSnn 			    EC_ADDR(symaddr)));
25322872efbSedp 			rc = validate_rdebug32(rap);
2547c478bd9Sstevel@tonic-gate 		}
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	/*
2597c478bd9Sstevel@tonic-gate 	 * method3 - find DT_DEBUG in the executables .dynamic section.
2607c478bd9Sstevel@tonic-gate 	 */
2617c478bd9Sstevel@tonic-gate 	if (rc != RD_OK) {
2627c478bd9Sstevel@tonic-gate 		Dyn	dyn;
2637c478bd9Sstevel@tonic-gate 		if (ps_pglobal_lookup(php, PS_OBJ_EXEC,
2647c478bd9Sstevel@tonic-gate 		    MSG_ORIG(MSG_SYM_DYNAMIC), &symaddr) != PS_OK) {
2657c478bd9Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_NODYNAMIC)));
2667c478bd9Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED)));
2677c478bd9Sstevel@tonic-gate 			return (rc);
2687c478bd9Sstevel@tonic-gate 		}
2697c478bd9Sstevel@tonic-gate 		rc = find_dynamic_ent32(rap, symaddr, DT_DEBUG, &dyn);
2707c478bd9Sstevel@tonic-gate 		if (rc != RD_OK) {
2717c478bd9Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED)));
2727c478bd9Sstevel@tonic-gate 			return (rc);
2737c478bd9Sstevel@tonic-gate 		}
2747c478bd9Sstevel@tonic-gate 		rap->rd_rdebug = dyn.d_un.d_ptr;
27522872efbSedp 		rc = validate_rdebug32(rap);
2767c478bd9Sstevel@tonic-gate 		if (rc != RD_OK) {
2777c478bd9Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED)));
2787c478bd9Sstevel@tonic-gate 			return (rc);
2797c478bd9Sstevel@tonic-gate 		}
2807c478bd9Sstevel@tonic-gate 	}
2817c478bd9Sstevel@tonic-gate 
2829acbbeafSnn 	/*
28322872efbSedp 	 * If we are debugging a branded executable, load the appropriate
28422872efbSedp 	 * helper library, and call its initialization routine.  Being unable
28522872efbSedp 	 * to load the helper library is not a critical error.  (Hopefully
28622872efbSedp 	 * we'll still be able to access some objects in the target.)
2879acbbeafSnn 	 */
2885eae5a6fSedp 	ps_pbrandname = (ps_pbrandname_fp_t)dlsym(RTLD_PROBE, "ps_pbrandname");
28922872efbSedp 	while ((ps_pbrandname != NULL) &&
2905eae5a6fSedp 	    (ps_pbrandname(php, brandname, MAXPATHLEN) == PS_OK)) {
2919acbbeafSnn 		const char *isa = "";
2929acbbeafSnn 
29322872efbSedp #ifdef _LP64
2949acbbeafSnn 		isa = MSG_ORIG(MSG_DB_64BIT_PREFIX);
29522872efbSedp #endif /* _LP64 */
2969acbbeafSnn 
2979acbbeafSnn 		if (rtld_db_helper_path[0] != '\0')
2989acbbeafSnn 			(void) snprintf(brandlib, MAXPATHLEN,
2999acbbeafSnn 			    MSG_ORIG(MSG_DB_BRAND_HELPERPATH_PREFIX),
3009acbbeafSnn 			    rtld_db_helper_path,
3019acbbeafSnn 			    MSG_ORIG(MSG_DB_HELPER_PREFIX), brandname, isa,
3029acbbeafSnn 			    brandname);
3039acbbeafSnn 		else
3049acbbeafSnn 			(void) snprintf(brandlib, MAXPATHLEN,
3059acbbeafSnn 			    MSG_ORIG(MSG_DB_BRAND_HELPERPATH),
3069acbbeafSnn 			    MSG_ORIG(MSG_DB_HELPER_PREFIX), brandname, isa,
3079acbbeafSnn 			    brandname);
3089acbbeafSnn 
30922872efbSedp 		rap->rd_helper.rh_dlhandle = dlopen(brandlib,
31022872efbSedp 		    RTLD_LAZY | RTLD_LOCAL);
31122872efbSedp 		if (rap->rd_helper.rh_dlhandle == NULL) {
3129acbbeafSnn 			LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERLOADFAILED),
3139acbbeafSnn 			    brandlib));
31422872efbSedp 			break;
3159acbbeafSnn 		}
3169acbbeafSnn 
31722872efbSedp 		rap->rd_helper.rh_ops = dlsym(rap->rd_helper.rh_dlhandle,
31822872efbSedp 		    MSG_ORIG(MSG_SYM_BRANDOPS));
31922872efbSedp 		if (rap->rd_helper.rh_ops == NULL) {
3209acbbeafSnn 			LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERNOOPS),
3219acbbeafSnn 			    brandlib));
32222872efbSedp 			(void) dlclose(rap->rd_helper.rh_dlhandle);
32322872efbSedp 			rap->rd_helper.rh_dlhandle = NULL;
32422872efbSedp 			break;
3259acbbeafSnn 		}
3269acbbeafSnn 
32722872efbSedp 		rap->rd_helper.rh_data = rap->rd_helper.rh_ops->rho_init(rap,
32822872efbSedp 		    php);
3299acbbeafSnn 		if (rap->rd_helper.rh_data == NULL) {
3309acbbeafSnn 			LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERINITFAILED)));
3319acbbeafSnn 			(void) dlclose(rap->rd_helper.rh_dlhandle);
3329acbbeafSnn 			rap->rd_helper.rh_dlhandle = NULL;
3339acbbeafSnn 			rap->rd_helper.rh_ops = NULL;
33422872efbSedp 			break;
33522872efbSedp 		}
33622872efbSedp 
33722872efbSedp 		LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERLOADED), brandname));
33822872efbSedp 		break;
339adbfe822Srie 
340adbfe822Srie 		/* NOTREACHED */
3419acbbeafSnn 	}
3429acbbeafSnn 
3437c478bd9Sstevel@tonic-gate 	if ((rap->rd_flags & RDF_FL_COREFILE) == 0) {
3447c478bd9Sstevel@tonic-gate 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO,
3457c478bd9Sstevel@tonic-gate 		    MSG_ORIG(MSG_SYM_PREINIT), &symaddr) != PS_OK) {
3467c478bd9Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
3479acbbeafSnn 			    MSG_ORIG(MSG_SYM_PREINIT)));
3487c478bd9Sstevel@tonic-gate 			return (RD_DBERR);
3497c478bd9Sstevel@tonic-gate 		}
3507c478bd9Sstevel@tonic-gate 		rap->rd_preinit = symaddr;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO,
3537c478bd9Sstevel@tonic-gate 		    MSG_ORIG(MSG_SYM_POSTINIT), &symaddr) != PS_OK) {
3547c478bd9Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
3559acbbeafSnn 			    MSG_ORIG(MSG_SYM_POSTINIT)));
3567c478bd9Sstevel@tonic-gate 			return (RD_DBERR);
3577c478bd9Sstevel@tonic-gate 		}
3587c478bd9Sstevel@tonic-gate 		rap->rd_postinit = symaddr;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO,
3617c478bd9Sstevel@tonic-gate 		    MSG_ORIG(MSG_SYM_DLACT), &symaddr) != PS_OK) {
3627c478bd9Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
3639acbbeafSnn 			    MSG_ORIG(MSG_SYM_DLACT)));
3647c478bd9Sstevel@tonic-gate 			return (RD_DBERR);
3657c478bd9Sstevel@tonic-gate 		}
3667c478bd9Sstevel@tonic-gate 		rap->rd_dlact = symaddr;
3677c478bd9Sstevel@tonic-gate 		rap->rd_tbinder = 0;
3687c478bd9Sstevel@tonic-gate 	}
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	return (RD_OK);
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate 
37322872efbSedp rd_err_e
_rd_get_ehdr32(struct rd_agent * rap,psaddr_t addr,Ehdr * ehdr,uint_t * phnum)37422872efbSedp _rd_get_ehdr32(struct rd_agent *rap,
37522872efbSedp     psaddr_t addr, Ehdr *ehdr, uint_t *phnum)
37622872efbSedp {
37722872efbSedp 	struct ps_prochandle	*php = rap->rd_psp;
37822872efbSedp 	Shdr			shdr;
37922872efbSedp 
38022872efbSedp 	if (ps_pread(php, addr, ehdr, sizeof (*ehdr)) != PS_OK) {
38122872efbSedp 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_5), EC_ADDR(addr)));
38222872efbSedp 		return (RD_ERR);
38322872efbSedp 	}
38422872efbSedp 	if (phnum == NULL)
38522872efbSedp 		return (RD_OK);
38622872efbSedp 
38722872efbSedp 	if (ehdr->e_phnum != PN_XNUM) {
38822872efbSedp 		*phnum = ehdr->e_phnum;
38922872efbSedp 		return (RD_OK);
39022872efbSedp 	}
39122872efbSedp 
39222872efbSedp 	/* deal with elf extended program headers */
39322872efbSedp 	if ((ehdr->e_shoff == 0) || (ehdr->e_shentsize < sizeof (shdr)))
39422872efbSedp 		return (RD_ERR);
39522872efbSedp 
39622872efbSedp 	addr += ehdr->e_shoff;
39722872efbSedp 	if (ps_pread(php, addr, &shdr, sizeof (shdr)) != PS_OK) {
39822872efbSedp 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_5), EC_ADDR(addr)));
39922872efbSedp 		return (RD_ERR);
40022872efbSedp 	}
40122872efbSedp 
40222872efbSedp 	if (shdr.sh_info == 0)
40322872efbSedp 		return (RD_ERR);
40422872efbSedp 
40522872efbSedp 	*phnum = shdr.sh_info;
40622872efbSedp 	return (RD_OK);
40722872efbSedp }
40822872efbSedp 
40922872efbSedp rd_err_e
_rd_get_dyns32(rd_agent_t * rap,psaddr_t addr,Dyn ** dynpp,size_t * dynpp_sz)41022872efbSedp _rd_get_dyns32(rd_agent_t *rap, psaddr_t addr, Dyn **dynpp, size_t *dynpp_sz)
41122872efbSedp {
41222872efbSedp 	struct ps_prochandle	*php = rap->rd_psp;
41322872efbSedp 	rd_err_e		err;
41422872efbSedp 	uint_t			phnum;
41522872efbSedp 	Ehdr			ehdr;
41622872efbSedp 	Phdr			phdr;
41722872efbSedp 	Dyn			*dynp;
41822872efbSedp 	int			i;
41922872efbSedp 
42022872efbSedp 	/* We only need to muck with dyn elements for ET_DYN objects */
42122872efbSedp 	if ((err = _rd_get_ehdr32(rap, addr, &ehdr, &phnum)) != RD_OK)
42222872efbSedp 		return (err);
42322872efbSedp 
42422872efbSedp 	for (i = 0; i < phnum; i++) {
42522872efbSedp 		psaddr_t a = addr + ehdr.e_phoff + (i * ehdr.e_phentsize);
42622872efbSedp 		if (ps_pread(php, a, &phdr, sizeof (phdr)) != PS_OK) {
42722872efbSedp 			LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_6), EC_ADDR(a)));
42822872efbSedp 			return (RD_ERR);
42922872efbSedp 		}
43022872efbSedp 		if (phdr.p_type == PT_DYNAMIC)
43122872efbSedp 			break;
43222872efbSedp 	}
43322872efbSedp 	if (i == phnum)
43422872efbSedp 		return (RD_ERR);
43522872efbSedp 
43622872efbSedp 	if ((dynp = malloc(phdr.p_filesz)) == NULL)
43722872efbSedp 		return (RD_ERR);
43822872efbSedp 	if (ehdr.e_type == ET_DYN)
43922872efbSedp 		phdr.p_vaddr += addr;
44022872efbSedp 	if (ps_pread(php, phdr.p_vaddr, dynp, phdr.p_filesz) != PS_OK) {
44122872efbSedp 		free(dynp);
44222872efbSedp 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_6),
44322872efbSedp 		    EC_ADDR(phdr.p_vaddr)));
44422872efbSedp 		return (RD_ERR);
44522872efbSedp 	}
44622872efbSedp 
44722872efbSedp 	*dynpp = dynp;
448544fa60cSedp 	if (dynpp_sz != NULL)
449544fa60cSedp 		*dynpp_sz = phdr.p_filesz;
45022872efbSedp 	return (RD_OK);
45122872efbSedp }
45222872efbSedp 
4537c478bd9Sstevel@tonic-gate rd_err_e
_rd_event_enable32(rd_agent_t * rap,int onoff)4547c478bd9Sstevel@tonic-gate _rd_event_enable32(rd_agent_t *rap, int onoff)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate 	struct ps_prochandle	*php = rap->rd_psp;
4577c478bd9Sstevel@tonic-gate 	Rtld_db_priv		rdb;
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDEVENTENABLE), rap->rd_dmodel, onoff));
4607c478bd9Sstevel@tonic-gate 	/*
4617c478bd9Sstevel@tonic-gate 	 * Tell the debugged process that debugging is occuring
4627c478bd9Sstevel@tonic-gate 	 * This will enable the storing of event messages so that
4637c478bd9Sstevel@tonic-gate 	 * the can be gathered by the debugger.
4647c478bd9Sstevel@tonic-gate 	 */
4657c478bd9Sstevel@tonic-gate 	if (ps_pread(php, rap->rd_rdebug, (char *)&rdb,
4667c478bd9Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK) {
4677c478bd9Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_1),
4687c478bd9Sstevel@tonic-gate 		    EC_ADDR((uintptr_t)&rdb)));
4697c478bd9Sstevel@tonic-gate 		return (RD_DBERR);
4707c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	if (onoff)
4737c478bd9Sstevel@tonic-gate 		rdb.rtd_rdebug.r_flags |= RD_FL_DBG;
4747c478bd9Sstevel@tonic-gate 	else
4757c478bd9Sstevel@tonic-gate 		rdb.rtd_rdebug.r_flags &= ~RD_FL_DBG;
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	if (ps_pwrite(php, rap->rd_rdebug, (char *)&rdb,
4787c478bd9Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK) {
4797c478bd9Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_WRITEFAIL_1),
4807c478bd9Sstevel@tonic-gate 		    EC_ADDR((uintptr_t)&rdb)));
4817c478bd9Sstevel@tonic-gate 		return (RD_DBERR);
4827c478bd9Sstevel@tonic-gate 	}
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	return (RD_OK);
4857c478bd9Sstevel@tonic-gate }
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate rd_err_e
_rd_event_getmsg32(rd_agent_t * rap,rd_event_msg_t * emsg)4897c478bd9Sstevel@tonic-gate _rd_event_getmsg32(rd_agent_t *rap, rd_event_msg_t *emsg)
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 	Rtld_db_priv	rdb;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	if (ps_pread(rap->rd_psp, rap->rd_rdebug, (char *)&rdb,
4947c478bd9Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK) {
4957c478bd9Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_2),
4967c478bd9Sstevel@tonic-gate 		    EC_ADDR(rap->rd_rdebug)));
4977c478bd9Sstevel@tonic-gate 		return (RD_DBERR);
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate 	emsg->type = rdb.rtd_rdebug.r_rdevent;
5007c478bd9Sstevel@tonic-gate 	if (emsg->type == RD_DLACTIVITY) {
5017c478bd9Sstevel@tonic-gate 		switch (rdb.rtd_rdebug.r_state) {
5027c478bd9Sstevel@tonic-gate 			case RT_CONSISTENT:
5037c478bd9Sstevel@tonic-gate 				emsg->u.state = RD_CONSISTENT;
5047c478bd9Sstevel@tonic-gate 				break;
5057c478bd9Sstevel@tonic-gate 			case RT_ADD:
5067c478bd9Sstevel@tonic-gate 				emsg->u.state = RD_ADD;
5077c478bd9Sstevel@tonic-gate 				break;
5087c478bd9Sstevel@tonic-gate 			case RT_DELETE:
5097c478bd9Sstevel@tonic-gate 				emsg->u.state = RD_DELETE;
5107c478bd9Sstevel@tonic-gate 				break;
5117c478bd9Sstevel@tonic-gate 		}
5127c478bd9Sstevel@tonic-gate 	} else
5137c478bd9Sstevel@tonic-gate 		emsg->u.state = RD_NOSTATE;
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDEVENTGETMSG), rap->rd_dmodel,
5169acbbeafSnn 	    emsg->type, emsg->u.state));
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	return (RD_OK);
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate rd_err_e
_rd_objpad_enable32(struct rd_agent * rap,size_t padsize)5237c478bd9Sstevel@tonic-gate _rd_objpad_enable32(struct rd_agent *rap, size_t padsize)
5247c478bd9Sstevel@tonic-gate {
5257c478bd9Sstevel@tonic-gate 	Rtld_db_priv		db_priv;
5267c478bd9Sstevel@tonic-gate 	struct ps_prochandle	*php = rap->rd_psp;
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDOBJPADE), EC_ADDR(padsize)));
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	if (ps_pread(php, rap->rd_rtlddbpriv, (char *)&db_priv,
5317c478bd9Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK) {
5327c478bd9Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_3),
5337c478bd9Sstevel@tonic-gate 		    EC_ADDR(rap->rd_rtlddbpriv)));
5347c478bd9Sstevel@tonic-gate 		return (RD_DBERR);
5357c478bd9Sstevel@tonic-gate 	}
5367c478bd9Sstevel@tonic-gate #if	defined(_LP64) && !defined(_ELF64)
5377c478bd9Sstevel@tonic-gate 	/*LINTED*/
5387c478bd9Sstevel@tonic-gate 	db_priv.rtd_objpad = (uint32_t)padsize;
5397c478bd9Sstevel@tonic-gate #else
5407c478bd9Sstevel@tonic-gate 	db_priv.rtd_objpad = padsize;
5417c478bd9Sstevel@tonic-gate #endif
5427c478bd9Sstevel@tonic-gate 	if (ps_pwrite(php, rap->rd_rtlddbpriv, (char *)&db_priv,
5437c478bd9Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK) {
5447c478bd9Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_WRITEFAIL_2),
5457c478bd9Sstevel@tonic-gate 		    EC_ADDR(rap->rd_rtlddbpriv)));
5467c478bd9Sstevel@tonic-gate 		return (RD_DBERR);
5477c478bd9Sstevel@tonic-gate 	}
5487c478bd9Sstevel@tonic-gate 	return (RD_OK);
5497c478bd9Sstevel@tonic-gate }
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate static rd_err_e
iter_map(rd_agent_t * rap,unsigned long ident,psaddr_t lmaddr,rl_iter_f * cb,void * client_data,uint_t * abort_iterp)5527c478bd9Sstevel@tonic-gate iter_map(rd_agent_t *rap, unsigned long ident, psaddr_t lmaddr,
553*22ca2f96SToomas Soome     rl_iter_f *cb, void *client_data, uint_t *abort_iterp)
5547c478bd9Sstevel@tonic-gate {
5557c478bd9Sstevel@tonic-gate 	while (lmaddr) {
5567c478bd9Sstevel@tonic-gate 		Rt_map		rmap;
5577c478bd9Sstevel@tonic-gate 		rd_loadobj_t	lobj;
5587c478bd9Sstevel@tonic-gate 		int		i;
5597c478bd9Sstevel@tonic-gate 		ulong_t		off;
5607c478bd9Sstevel@tonic-gate 		Ehdr		ehdr;
5617c478bd9Sstevel@tonic-gate 		Phdr		phdr;
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 		if (ps_pread(rap->rd_psp, lmaddr, (char *)&rmap,
5647c478bd9Sstevel@tonic-gate 		    sizeof (Rt_map)) != PS_OK) {
5657c478bd9Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPFAIL)));
5667c478bd9Sstevel@tonic-gate 			return (RD_DBERR);
5677c478bd9Sstevel@tonic-gate 		}
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 		/*
5707c478bd9Sstevel@tonic-gate 		 * As of 'VERSION5' we only report objects
5717c478bd9Sstevel@tonic-gate 		 * which have been fully relocated.  While the maps
5727c478bd9Sstevel@tonic-gate 		 * might be in a consistent state - if a object hasn't
5737c478bd9Sstevel@tonic-gate 		 * been relocated - it's not really ready for the debuggers
5747c478bd9Sstevel@tonic-gate 		 * to examine.  This is mostly due to the fact that we
5757c478bd9Sstevel@tonic-gate 		 * might still be mucking with the text-segment, if
5767c478bd9Sstevel@tonic-gate 		 * we are - we could conflict with any break-points
5777c478bd9Sstevel@tonic-gate 		 * the debuggers might have set.
5787c478bd9Sstevel@tonic-gate 		 */
5797c478bd9Sstevel@tonic-gate 		if (rap->rd_rdebugvers >= R_RTLDDB_VERSION5) {
5807c478bd9Sstevel@tonic-gate 			if ((FLAGS(&rmap) & FLG_RT_RELOCED) == 0) {
5817c478bd9Sstevel@tonic-gate 				lmaddr = (psaddr_t)NEXT(&rmap);
5827c478bd9Sstevel@tonic-gate 				continue;
5837c478bd9Sstevel@tonic-gate 			}
5847c478bd9Sstevel@tonic-gate 		}
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 		lobj.rl_base = (psaddr_t)ADDR(&rmap);
5877c478bd9Sstevel@tonic-gate 		lobj.rl_flags = 0;
5887c478bd9Sstevel@tonic-gate 		lobj.rl_refnameaddr = (psaddr_t)REFNAME(&rmap);
58922872efbSedp 		if ((rap->rd_helper.rh_ops != NULL) &&
59022872efbSedp 		    (rap->rd_helper.rh_ops->rho_lmid != LM_ID_NONE))
59122872efbSedp 			lobj.rl_lmident =
59222872efbSedp 			    rap->rd_helper.rh_ops->rho_lmid;
5939acbbeafSnn 		else
5949acbbeafSnn 			lobj.rl_lmident = ident;
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 		/*
5977c478bd9Sstevel@tonic-gate 		 * refnameaddr is only valid from a core file
5987c478bd9Sstevel@tonic-gate 		 * which is VERSION3 or greater.
5997c478bd9Sstevel@tonic-gate 		 */
6007c478bd9Sstevel@tonic-gate 		if (rap->rd_rdebugvers < R_RTLDDB_VERSION3) {
6017c478bd9Sstevel@tonic-gate 			lobj.rl_nameaddr = (psaddr_t)NAME(&rmap);
6027c478bd9Sstevel@tonic-gate 			lobj.rl_bend = 0;
6037c478bd9Sstevel@tonic-gate 			lobj.rl_padstart = 0;
6047c478bd9Sstevel@tonic-gate 			lobj.rl_padend = 0;
6057c478bd9Sstevel@tonic-gate 		} else {
6067c478bd9Sstevel@tonic-gate 			lobj.rl_nameaddr = (psaddr_t)PATHNAME(&rmap);
6077c478bd9Sstevel@tonic-gate 			lobj.rl_bend = ADDR(&rmap) + MSIZE(&rmap);
6087c478bd9Sstevel@tonic-gate 			lobj.rl_padstart = PADSTART(&rmap);
6097c478bd9Sstevel@tonic-gate 			lobj.rl_padend = PADSTART(&rmap) + PADIMLEN(&rmap);
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 		}
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 		if (rtld_db_version >= RD_VERSION2)
6147c478bd9Sstevel@tonic-gate 			if (FLAGS(&rmap) & FLG_RT_IMGALLOC)
6157c478bd9Sstevel@tonic-gate 				lobj.rl_flags |= RD_FLG_MEM_OBJECT;
6167c478bd9Sstevel@tonic-gate 		if (rtld_db_version >= RD_VERSION2) {
6177c478bd9Sstevel@tonic-gate 			lobj.rl_dynamic = (psaddr_t)DYN(&rmap);
6187c478bd9Sstevel@tonic-gate 		}
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 		if (rtld_db_version >= RD_VERSION4)
6217c478bd9Sstevel@tonic-gate 			lobj.rl_tlsmodid = TLSMODID(&rmap);
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 		/*
6247c478bd9Sstevel@tonic-gate 		 * Look for beginning of data segment.
6257c478bd9Sstevel@tonic-gate 		 *
6267c478bd9Sstevel@tonic-gate 		 * NOTE: the data segment can only be found for full
6277c478bd9Sstevel@tonic-gate 		 *	processes and not from core images.
6287c478bd9Sstevel@tonic-gate 		 */
6297c478bd9Sstevel@tonic-gate 		lobj.rl_data_base = 0;
6307c478bd9Sstevel@tonic-gate 		if (rap->rd_flags & RDF_FL_COREFILE)
6317c478bd9Sstevel@tonic-gate 			lobj.rl_data_base = 0;
6327c478bd9Sstevel@tonic-gate 		else {
6337c478bd9Sstevel@tonic-gate 			off = ADDR(&rmap);
6347c478bd9Sstevel@tonic-gate 			if (ps_pread(rap->rd_psp, off, (char *)&ehdr,
6357c478bd9Sstevel@tonic-gate 			    sizeof (Ehdr)) != PS_OK) {
6367c478bd9Sstevel@tonic-gate 				LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPFAIL)));
6377c478bd9Sstevel@tonic-gate 				return (RD_DBERR);
6387c478bd9Sstevel@tonic-gate 			}
6397c478bd9Sstevel@tonic-gate 			off += sizeof (Ehdr);
6407c478bd9Sstevel@tonic-gate 			for (i = 0; i < ehdr.e_phnum; i++) {
6417c478bd9Sstevel@tonic-gate 				if (ps_pread(rap->rd_psp, off, (char *)&phdr,
6427c478bd9Sstevel@tonic-gate 				    sizeof (Phdr)) != PS_OK) {
6437c478bd9Sstevel@tonic-gate 					LOG(ps_plog(MSG_ORIG(
6447c478bd9Sstevel@tonic-gate 					    MSG_DB_LKMAPFAIL)));
6457c478bd9Sstevel@tonic-gate 					return (RD_DBERR);
6467c478bd9Sstevel@tonic-gate 				}
6477c478bd9Sstevel@tonic-gate 				if ((phdr.p_type == PT_LOAD) &&
6487c478bd9Sstevel@tonic-gate 				    (phdr.p_flags & PF_W)) {
6497c478bd9Sstevel@tonic-gate 					lobj.rl_data_base = phdr.p_vaddr;
6507c478bd9Sstevel@tonic-gate 					if (ehdr.e_type == ET_DYN)
6517c478bd9Sstevel@tonic-gate 						lobj.rl_data_base +=
6529acbbeafSnn 						    ADDR(&rmap);
6537c478bd9Sstevel@tonic-gate 					break;
6547c478bd9Sstevel@tonic-gate 				}
6557c478bd9Sstevel@tonic-gate 				off += ehdr.e_phentsize;
6567c478bd9Sstevel@tonic-gate 			}
6577c478bd9Sstevel@tonic-gate 		}
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 		/*
6607c478bd9Sstevel@tonic-gate 		 * When we transfer control to the client we free the
6617c478bd9Sstevel@tonic-gate 		 * lock and re-atain it after we've returned from the
6627c478bd9Sstevel@tonic-gate 		 * client.  This is to avoid any deadlock situations.
6637c478bd9Sstevel@tonic-gate 		 */
6647c478bd9Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_ITERMAP), cb, client_data,
6659acbbeafSnn 		    EC_ADDR(lobj.rl_base), EC_ADDR(lobj.rl_lmident)));
6667c478bd9Sstevel@tonic-gate 		RDAGUNLOCK(rap);
6677c478bd9Sstevel@tonic-gate 		if ((*cb)(&lobj, client_data) == 0) {
6687c478bd9Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_CALLBACKR0)));
6697c478bd9Sstevel@tonic-gate 			RDAGLOCK(rap);
6700ef25df5SEdward Pilatowicz 			*abort_iterp = 1;
6717c478bd9Sstevel@tonic-gate 			break;
6727c478bd9Sstevel@tonic-gate 		}
6737c478bd9Sstevel@tonic-gate 		RDAGLOCK(rap);
6747c478bd9Sstevel@tonic-gate 		lmaddr = (psaddr_t)NEXT(&rmap);
6757c478bd9Sstevel@tonic-gate 	}
6767c478bd9Sstevel@tonic-gate 	return (RD_OK);
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 
6800ef25df5SEdward Pilatowicz static rd_err_e
_rd_loadobj_iter32_native(rd_agent_t * rap,rl_iter_f * cb,void * client_data,uint_t * abort_iterp)6810ef25df5SEdward Pilatowicz _rd_loadobj_iter32_native(rd_agent_t *rap, rl_iter_f *cb, void *client_data,
6820ef25df5SEdward Pilatowicz     uint_t *abort_iterp)
6837c478bd9Sstevel@tonic-gate {
6847c478bd9Sstevel@tonic-gate 	Rtld_db_priv	db_priv;
68557ef7aa9SRod Evans 	TAPlist		apl;
68657ef7aa9SRod Evans 	uintptr_t	datap, nitems;
68757ef7aa9SRod Evans 	Addr		addr;
6887c478bd9Sstevel@tonic-gate 	rd_err_e	rc;
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	LOG(ps_plog(MSG_ORIG(MSG_DB_LOADOBJITER), rap->rd_dmodel, cb,
6919acbbeafSnn 	    client_data));
6927c478bd9Sstevel@tonic-gate 
693d156cc9dSRod Evans 	/*
694d156cc9dSRod Evans 	 * First, determine whether the link-map information has been
695d156cc9dSRod Evans 	 * established.  Some debuggers have made an initial call to this
696d156cc9dSRod Evans 	 * function with a null call back function (cb), but expect a
697d156cc9dSRod Evans 	 * RD_NOMAPS error return rather than a RD_ERR return when the
698d156cc9dSRod Evans 	 * link-maps aren't available.
699d156cc9dSRod Evans 	 */
7007c478bd9Sstevel@tonic-gate 	if (ps_pread(rap->rd_psp, rap->rd_rtlddbpriv, (char *)&db_priv,
7017c478bd9Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK) {
7027c478bd9Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_1),
7037c478bd9Sstevel@tonic-gate 		    EC_ADDR(rap->rd_rtlddbpriv)));
7047c478bd9Sstevel@tonic-gate 		return (RD_DBERR);
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate 
707*22ca2f96SToomas Soome 	if (db_priv.rtd_dynlmlst == 0) {
7087c478bd9Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPNOINIT),
7099acbbeafSnn 		    EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
7107c478bd9Sstevel@tonic-gate 		return (RD_NOMAPS);
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate 
71357ef7aa9SRod Evans 	if (ps_pread(rap->rd_psp, (psaddr_t)db_priv.rtd_dynlmlst, (char *)&addr,
71457ef7aa9SRod Evans 	    sizeof (Addr)) != PS_OK) {
7157c478bd9Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_3),
7169acbbeafSnn 		    EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
7177c478bd9Sstevel@tonic-gate 		return (RD_DBERR);
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate 
720*22ca2f96SToomas Soome 	if (addr == 0) {
7217c478bd9Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPNOINIT_1),
72257ef7aa9SRod Evans 		    EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
7237c478bd9Sstevel@tonic-gate 		return (RD_NOMAPS);
7247c478bd9Sstevel@tonic-gate 	}
7257c478bd9Sstevel@tonic-gate 
726d156cc9dSRod Evans 	/*
727d156cc9dSRod Evans 	 * Having determined we have link-maps, ensure we have an iterator
728d156cc9dSRod Evans 	 * call back function.
729d156cc9dSRod Evans 	 */
730d156cc9dSRod Evans 	if (cb == NULL) {
731d156cc9dSRod Evans 		LOG(ps_plog(MSG_ORIG(MSG_DB_NULLITER)));
732d156cc9dSRod Evans 		return (RD_ERR);
733d156cc9dSRod Evans 	}
734d156cc9dSRod Evans 
735d156cc9dSRod Evans 	/*
73628bda19cSRod Evans 	 * As of VERSION6, rtd_dynlmlst points to an APlist.  Prior to VERSION6
73728bda19cSRod Evans 	 * rtd_dynlmlst pointed to a List.  But, there was a window where the
73828bda19cSRod Evans 	 * version was not incremented, and this must be worked around by
73928bda19cSRod Evans 	 * interpreting the APlist data.  Read the initial APlist information.
740d156cc9dSRod Evans 	 */
74157ef7aa9SRod Evans 	if (ps_pread(rap->rd_psp, (psaddr_t)addr, (char *)&apl,
74257ef7aa9SRod Evans 	    sizeof (TAPlist)) != PS_OK) {
74357ef7aa9SRod Evans 		LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_4),
74457ef7aa9SRod Evans 		    EC_ADDR((uintptr_t)addr)));
74557ef7aa9SRod Evans 		return (RD_DBERR);
7467c478bd9Sstevel@tonic-gate 	}
7477c478bd9Sstevel@tonic-gate 
74857ef7aa9SRod Evans 	/*
74928bda19cSRod Evans 	 * The rtd_dynlmlst change from a List to an APlist occurred under
75028bda19cSRod Evans 	 * 6801536 in snv_112.  However, this change neglected to preserve
75128bda19cSRod Evans 	 * backward compatibility by maintaining List processing and using a
75228bda19cSRod Evans 	 * version increment to detect the change.  6862967, intergrated in
75328bda19cSRod Evans 	 * snv_121 corrects the version detection.  However, to catch objects
75428bda19cSRod Evans 	 * built between these releases, we look at the first element of the
75528bda19cSRod Evans 	 * APlist.  apl_arritems indicates the number of APlist items that are
75628bda19cSRod Evans 	 * available.  This was originally initialized with a AL_CNT_DYNLIST
75728bda19cSRod Evans 	 * value of 2 (one entry for LM_ID_BASE and one entry for LM_ID_LDSO).
75828bda19cSRod Evans 	 * It is possible that the use of an auditor results in an additional
75928bda19cSRod Evans 	 * link-map list, in which case the original apl_arritems would have
76028bda19cSRod Evans 	 * been doubled.
76128bda19cSRod Evans 	 *
76228bda19cSRod Evans 	 * Therefore, if the debugging verion is VERSION6, or the apl_arritems
76328bda19cSRod Evans 	 * entry has a value less than or equal to 4 and the debugging version
76428bda19cSRod Evans 	 * is VERSION5, then we process APlists.  Otherwise, fall back to List
76528bda19cSRod Evans 	 * processing.
76657ef7aa9SRod Evans 	 */
76728bda19cSRod Evans 	if ((rap->rd_rdebugvers >= R_RTLDDB_VERSION6) ||
76828bda19cSRod Evans 	    ((rap->rd_rdebugvers == R_RTLDDB_VERSION5) &&
76928bda19cSRod Evans 	    (apl.apl_arritems <= 4))) {
7707c478bd9Sstevel@tonic-gate 		/*
77128bda19cSRod Evans 		 * Iterate through each apl.ap_data[] entry.
7727c478bd9Sstevel@tonic-gate 		 */
77328bda19cSRod Evans 		for (datap = (uintptr_t)((char *)(uintptr_t)addr +
77428bda19cSRod Evans 		    ((size_t)(((TAPlist *)0)->apl_data))), nitems = 0;
77528bda19cSRod Evans 		    nitems < apl.apl_nitems; nitems++, datap += sizeof (Addr)) {
77628bda19cSRod Evans 			TLm_list	lm;
77728bda19cSRod Evans 			ulong_t		ident;
77828bda19cSRod Evans 
77928bda19cSRod Evans 			/*
78028bda19cSRod Evans 			 * Obtain the Lm_list address for this apl.ap_data[]
78128bda19cSRod Evans 			 * entry.
78228bda19cSRod Evans 			 */
78328bda19cSRod Evans 			if (ps_pread(rap->rd_psp, (psaddr_t)datap,
78428bda19cSRod Evans 			    (char *)&addr, sizeof (Addr)) != PS_OK) {
78528bda19cSRod Evans 				LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_5),
78628bda19cSRod Evans 				    EC_ADDR(datap)));
78728bda19cSRod Evans 				return (RD_DBERR);
78828bda19cSRod Evans 			}
78928bda19cSRod Evans 
79028bda19cSRod Evans 			/*
79128bda19cSRod Evans 			 * Obtain the Lm_list data for this Lm_list address.
79228bda19cSRod Evans 			 */
79328bda19cSRod Evans 			if (ps_pread(rap->rd_psp, (psaddr_t)addr, (char *)&lm,
79428bda19cSRod Evans 			    sizeof (TLm_list)) != PS_OK) {
79528bda19cSRod Evans 				LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_6),
79628bda19cSRod Evans 				    EC_ADDR((uintptr_t)addr)));
79728bda19cSRod Evans 				return (RD_DBERR);
79828bda19cSRod Evans 			}
79928bda19cSRod Evans 
80028bda19cSRod Evans 			/*
80128bda19cSRod Evans 			 * Determine IDENT of current LM_LIST
80228bda19cSRod Evans 			 */
80328bda19cSRod Evans 			if (lm.lm_flags & LML_FLG_BASELM)
80428bda19cSRod Evans 				ident = LM_ID_BASE;
80528bda19cSRod Evans 			else if (lm.lm_flags & LML_FLG_RTLDLM)
80628bda19cSRod Evans 				ident = LM_ID_LDSO;
80728bda19cSRod Evans 			else
80828bda19cSRod Evans 				ident = (ulong_t)addr;
80928bda19cSRod Evans 
81028bda19cSRod Evans 			if ((rc = iter_map(rap, ident, (psaddr_t)lm.lm_head,
81128bda19cSRod Evans 			    cb, client_data, abort_iterp)) != RD_OK)
81228bda19cSRod Evans 				return (rc);
81328bda19cSRod Evans 
81428bda19cSRod Evans 			if (*abort_iterp != 0)
81528bda19cSRod Evans 				break;
8167c478bd9Sstevel@tonic-gate 		}
81728bda19cSRod Evans 	} else {
81828bda19cSRod Evans 		TList		list;
81928bda19cSRod Evans 		TListnode	lnode;
82028bda19cSRod Evans 		Addr		lnp;
8217c478bd9Sstevel@tonic-gate 
82257ef7aa9SRod Evans 		/*
82328bda19cSRod Evans 		 * Re-read the dynlmlst address to obtain a List structure.
82457ef7aa9SRod Evans 		 */
82528bda19cSRod Evans 		if (ps_pread(rap->rd_psp, (psaddr_t)db_priv.rtd_dynlmlst,
82628bda19cSRod Evans 		    (char *)&list, sizeof (TList)) != PS_OK) {
82728bda19cSRod Evans 			LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_3),
82828bda19cSRod Evans 			    EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
8297c478bd9Sstevel@tonic-gate 			return (RD_DBERR);
8307c478bd9Sstevel@tonic-gate 		}
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 		/*
83328bda19cSRod Evans 		 * Iterate through the link-map list.
8347c478bd9Sstevel@tonic-gate 		 */
83528bda19cSRod Evans 		for (lnp = (Addr)list.head; lnp; lnp = (Addr)lnode.next) {
83628bda19cSRod Evans 			Lm_list	lml;
83728bda19cSRod Evans 			ulong_t	ident;
83828bda19cSRod Evans 
83928bda19cSRod Evans 			/*
84028bda19cSRod Evans 			 * Iterate through the List of Lm_list's.
84128bda19cSRod Evans 			 */
84228bda19cSRod Evans 			if (ps_pread(rap->rd_psp, (psaddr_t)lnp, (char *)&lnode,
84328bda19cSRod Evans 			    sizeof (TListnode)) != PS_OK) {
84428bda19cSRod Evans 				LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_4),
84528bda19cSRod Evans 				    EC_ADDR(lnp)));
84628bda19cSRod Evans 					return (RD_DBERR);
84728bda19cSRod Evans 			}
8487c478bd9Sstevel@tonic-gate 
84928bda19cSRod Evans 			if (ps_pread(rap->rd_psp, (psaddr_t)lnode.data,
85028bda19cSRod Evans 			    (char *)&lml, sizeof (Lm_list)) != PS_OK) {
85128bda19cSRod Evans 				LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_5),
85228bda19cSRod Evans 				    EC_ADDR((uintptr_t)lnode.data)));
85328bda19cSRod Evans 					return (RD_DBERR);
85428bda19cSRod Evans 			}
85528bda19cSRod Evans 
85628bda19cSRod Evans 			/*
85728bda19cSRod Evans 			 * Determine IDENT of current LM_LIST
85828bda19cSRod Evans 			 */
85928bda19cSRod Evans 			if (lml.lm_flags & LML_FLG_BASELM)
86028bda19cSRod Evans 				ident = LM_ID_BASE;
86128bda19cSRod Evans 			else if (lml.lm_flags & LML_FLG_RTLDLM)
86228bda19cSRod Evans 				ident = LM_ID_LDSO;
86328bda19cSRod Evans 			else
86428bda19cSRod Evans 				ident = (unsigned long)lnode.data;
86528bda19cSRod Evans 
86628bda19cSRod Evans 			if ((rc = iter_map(rap, ident, (psaddr_t)lml.lm_head,
86728bda19cSRod Evans 			    cb, client_data, abort_iterp)) != RD_OK)
86828bda19cSRod Evans 				return (rc);
86928bda19cSRod Evans 
87028bda19cSRod Evans 			if (*abort_iterp != 0)
87128bda19cSRod Evans 				break;
8727c478bd9Sstevel@tonic-gate 		}
8737c478bd9Sstevel@tonic-gate 	}
8749acbbeafSnn 
8750ef25df5SEdward Pilatowicz 	return (rc);
8760ef25df5SEdward Pilatowicz }
8770ef25df5SEdward Pilatowicz 
8780ef25df5SEdward Pilatowicz rd_err_e
_rd_loadobj_iter32(rd_agent_t * rap,rl_iter_f * cb,void * client_data)8790ef25df5SEdward Pilatowicz _rd_loadobj_iter32(rd_agent_t *rap, rl_iter_f *cb, void *client_data)
8800ef25df5SEdward Pilatowicz {
8815240bea1SRod Evans 	rd_err_e	rc, rc_brand = RD_OK;
8820ef25df5SEdward Pilatowicz 	uint_t		abort_iter = 0;
8830ef25df5SEdward Pilatowicz 
8840ef25df5SEdward Pilatowicz 	/* First iterate over the native target objects */
8850ef25df5SEdward Pilatowicz 	rc = _rd_loadobj_iter32_native(rap, cb, client_data, &abort_iter);
8860ef25df5SEdward Pilatowicz 	if (abort_iter != 0)
8879acbbeafSnn 		return (rc);
8889acbbeafSnn 
8890ef25df5SEdward Pilatowicz 	/* Then iterate over any branded objects. */
8900ef25df5SEdward Pilatowicz 	if ((rap->rd_helper.rh_ops != NULL) &&
8910ef25df5SEdward Pilatowicz 	    (rap->rd_helper.rh_ops->rho_loadobj_iter != NULL))
8920ef25df5SEdward Pilatowicz 		rc_brand = rap->rd_helper.rh_ops->rho_loadobj_iter(
8930ef25df5SEdward Pilatowicz 		    rap->rd_helper.rh_data, cb, client_data);
8949acbbeafSnn 
8955240bea1SRod Evans 	rc = (rc != RD_OK) ? rc : rc_brand;
8960ef25df5SEdward Pilatowicz 	return (rc);
8977c478bd9Sstevel@tonic-gate }
898