xref: /onnv-gate/usr/src/cmd/sgs/librtld_db/common/rd_elf.c (revision 11671:3073ea7cd00e)
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*11671SGerald.Jelinek@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include	<stdlib.h>
270Sstevel@tonic-gate #include	<stdio.h>
280Sstevel@tonic-gate #include	<proc_service.h>
290Sstevel@tonic-gate #include	<link.h>
300Sstevel@tonic-gate #include	<rtld_db.h>
310Sstevel@tonic-gate #include	<rtld.h>
329131SRod.Evans@Sun.COM #include	<alist.h>
3310167SRod.Evans@Sun.COM #include	<list.h>
340Sstevel@tonic-gate #include	<_rtld_db.h>
350Sstevel@tonic-gate #include	<msg.h>
362712Snn35248 #include	<limits.h>
372712Snn35248 #include	<string.h>
382712Snn35248 #include	<sys/param.h>
390Sstevel@tonic-gate 
400Sstevel@tonic-gate /*
410Sstevel@tonic-gate  * 64-bit builds are going to compile this module twice, the
420Sstevel@tonic-gate  * second time with _ELF64 defined.  These defines should make
430Sstevel@tonic-gate  * all the necessary adjustments to the code.
440Sstevel@tonic-gate  */
450Sstevel@tonic-gate #ifdef _LP64
460Sstevel@tonic-gate #ifdef _ELF64
470Sstevel@tonic-gate #define	_rd_event_enable32	_rd_event_enable64
480Sstevel@tonic-gate #define	_rd_event_getmsg32	_rd_event_getmsg64
496830Sedp #define	_rd_get_dyns32		_rd_get_dyns64
506830Sedp #define	_rd_get_ehdr32		_rd_get_ehdr64
510Sstevel@tonic-gate #define	_rd_objpad_enable32	_rd_objpad_enable64
520Sstevel@tonic-gate #define	_rd_loadobj_iter32	_rd_loadobj_iter64
536830Sedp #define	_rd_reset32		_rd_reset64
540Sstevel@tonic-gate #define	find_dynamic_ent32	find_dynamic_ent64
556830Sedp #define	validate_rdebug32	validate_rdebug64
569131SRod.Evans@Sun.COM #define	TAPlist			APlist
579131SRod.Evans@Sun.COM #define	TLm_list		Lm_list
5810167SRod.Evans@Sun.COM #define	TList			List
5910167SRod.Evans@Sun.COM #define	TListnode		Listnode
606874Srie #define	MSG_SYM_BRANDOPS	MSG_SYM_BRANDOPS_64
610Sstevel@tonic-gate #else	/* ELF32 */
620Sstevel@tonic-gate #define	Rt_map			Rt_map32
630Sstevel@tonic-gate #define	Rtld_db_priv		Rtld_db_priv32
649131SRod.Evans@Sun.COM #define	TAPlist			APlist32
659131SRod.Evans@Sun.COM #define	TLm_list		Lm_list32
6610167SRod.Evans@Sun.COM #define	TList			List32
6710167SRod.Evans@Sun.COM #define	TListnode		Listnode32
6810167SRod.Evans@Sun.COM #define	Lm_list			Lm_list32
696874Srie #define	MSG_SYM_BRANDOPS	MSG_SYM_BRANDOPS_32
700Sstevel@tonic-gate #endif	/* _ELF64 */
710Sstevel@tonic-gate #else	/* _LP64 */
729131SRod.Evans@Sun.COM #define	TAPlist			APlist
739131SRod.Evans@Sun.COM #define	TLm_list		Lm_list
7410167SRod.Evans@Sun.COM #define	TList			List
7510167SRod.Evans@Sun.COM #define	TListnode		Listnode
766874Srie #define	MSG_SYM_BRANDOPS	MSG_SYM_BRANDOPS_32
770Sstevel@tonic-gate #endif	/* _LP64 */
780Sstevel@tonic-gate 
795041Sedp /*
805041Sedp  * BrandZ added ps_pbrandname().  Many debuggers that link directly
815041Sedp  * against librtld_db.so may not implement this interface.  Hence
825041Sedp  * we won't call the function directly, instead we'll try to look it
835041Sedp  * up using the linker first and only invoke it if we find it.
845041Sedp  */
855041Sedp typedef ps_err_e (*ps_pbrandname_fp_t)(struct ps_prochandle *,
865041Sedp     char *, size_t);
875041Sedp 
886830Sedp rd_err_e
validate_rdebug32(struct rd_agent * rap)896830Sedp validate_rdebug32(struct rd_agent *rap)
900Sstevel@tonic-gate {
910Sstevel@tonic-gate 	struct ps_prochandle	*php = rap->rd_psp;
920Sstevel@tonic-gate 	psaddr_t		db_privp;
930Sstevel@tonic-gate 	Rtld_db_priv		db_priv;
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	if (rap->rd_rdebug == 0)
960Sstevel@tonic-gate 		return (RD_ERR);
9710167SRod.Evans@Sun.COM 
980Sstevel@tonic-gate 	/*
990Sstevel@tonic-gate 	 * The rtld_db_priv structure contains both the traditional (exposed)
1000Sstevel@tonic-gate 	 * r_debug structure as well as private data only available to
1010Sstevel@tonic-gate 	 * this library.
1020Sstevel@tonic-gate 	 */
1030Sstevel@tonic-gate 	db_privp = rap->rd_rdebug;
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	/*
1060Sstevel@tonic-gate 	 * Verify that librtld_db & rtld are at the proper revision
1070Sstevel@tonic-gate 	 * levels.
1080Sstevel@tonic-gate 	 */
1090Sstevel@tonic-gate 	if (ps_pread(php, db_privp, (char *)&db_priv,
1100Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK) {
1110Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_READPRIVFAIL_1),
1122712Snn35248 		    EC_ADDR(db_privp)));
1130Sstevel@tonic-gate 		return (RD_DBERR);
1140Sstevel@tonic-gate 	}
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	if ((db_priv.rtd_version < R_RTLDDB_VERSION1) ||
1170Sstevel@tonic-gate 	    (db_priv.rtd_version > R_RTLDDB_VERSION)) {
1180Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_BADPVERS),
1192712Snn35248 		    db_priv.rtd_version, R_RTLDDB_VERSION));
1200Sstevel@tonic-gate 		return (RD_NOCAPAB);
1210Sstevel@tonic-gate 	}
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	/*
1240Sstevel@tonic-gate 	 * Is the image being examined from a core file or not.
1250Sstevel@tonic-gate 	 * If it is a core file then the following write will fail.
1260Sstevel@tonic-gate 	 */
1270Sstevel@tonic-gate 	if (ps_pwrite(php, db_privp, (char *)&db_priv,
1280Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK)
1290Sstevel@tonic-gate 		rap->rd_flags |= RDF_FL_COREFILE;
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 	rap->rd_rdebugvers = db_priv.rtd_version;
1320Sstevel@tonic-gate 	rap->rd_rtlddbpriv = db_privp;
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	LOG(ps_plog(MSG_ORIG(MSG_DB_VALIDRDEBUG), EC_ADDR(rap->rd_rdebug),
1352712Snn35248 	    R_RTLDDB_VERSION, rap->rd_rdebugvers,
1362712Snn35248 	    rap->rd_flags & RDF_FL_COREFILE));
1370Sstevel@tonic-gate 	return (RD_OK);
1380Sstevel@tonic-gate }
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate rd_err_e
find_dynamic_ent32(struct rd_agent * rap,psaddr_t dynaddr,Xword dyntag,Dyn * dyn)1420Sstevel@tonic-gate find_dynamic_ent32(struct rd_agent *rap, psaddr_t dynaddr,
1430Sstevel@tonic-gate 	Xword dyntag, Dyn *dyn)
1440Sstevel@tonic-gate {
1450Sstevel@tonic-gate 	struct ps_prochandle	*php = rap->rd_psp;
1460Sstevel@tonic-gate 	Dyn			d;
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	d.d_tag = DT_NULL;
1490Sstevel@tonic-gate 	do {
1500Sstevel@tonic-gate 		if (ps_pread(php, dynaddr, (void *)(&d), sizeof (d)) !=
1510Sstevel@tonic-gate 		    PS_OK) {
1520Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_4),
1532712Snn35248 			    EC_ADDR(dynaddr)));
1540Sstevel@tonic-gate 			return (RD_DBERR);
1550Sstevel@tonic-gate 		}
1560Sstevel@tonic-gate 		dynaddr += sizeof (d);
1570Sstevel@tonic-gate 		if (d.d_tag == dyntag)
1580Sstevel@tonic-gate 			break;
1590Sstevel@tonic-gate 	} while (d.d_tag != DT_NULL);
1600Sstevel@tonic-gate 	if (d.d_tag == dyntag) {
1610Sstevel@tonic-gate 		*dyn = d;
1620Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_FINDDYNAMIC), EC_ADDR(dyntag),
1630Sstevel@tonic-gate 		    EC_ADDR(d.d_un.d_val)));
1640Sstevel@tonic-gate 		return (RD_OK);
1650Sstevel@tonic-gate 	}
1660Sstevel@tonic-gate 	LOG(ps_plog(MSG_ORIG(MSG_DB_NODYNDEBUG), EC_ADDR(dyntag)));
1670Sstevel@tonic-gate 	return (RD_DBERR);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate 
1702712Snn35248 extern char rtld_db_helper_path[MAXPATHLEN];
1712712Snn35248 
1720Sstevel@tonic-gate rd_err_e
_rd_reset32(struct rd_agent * rap)1730Sstevel@tonic-gate _rd_reset32(struct rd_agent *rap)
1740Sstevel@tonic-gate {
1750Sstevel@tonic-gate 	psaddr_t		symaddr;
1760Sstevel@tonic-gate 	struct ps_prochandle	*php = rap->rd_psp;
1770Sstevel@tonic-gate 	const auxv_t		*auxvp = NULL;
1780Sstevel@tonic-gate 	rd_err_e		rc = RD_OK;
1792712Snn35248 	char			brandname[MAXPATHLEN];
1802712Snn35248 	char			brandlib[MAXPATHLEN];
1815041Sedp 	ps_pbrandname_fp_t	ps_pbrandname;
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	/*
1840Sstevel@tonic-gate 	 * librtld_db attempts three different methods to find
1850Sstevel@tonic-gate 	 * the r_debug structure which is required to
1860Sstevel@tonic-gate 	 * initialize itself.  The methods are:
1870Sstevel@tonic-gate 	 *	method1:
1880Sstevel@tonic-gate 	 *		entirely independent of any text segment
1890Sstevel@tonic-gate 	 *		and relies on the AT_SUN_LDDATA auxvector
1900Sstevel@tonic-gate 	 *		to find the ld.so.1::rdebug structure.
1910Sstevel@tonic-gate 	 *	method2:
1920Sstevel@tonic-gate 	 *		lookup symbols in ld.so.1's symbol table
1930Sstevel@tonic-gate 	 *		to find the r_debug symbol.
1940Sstevel@tonic-gate 	 *	method3:
1950Sstevel@tonic-gate 	 *		(old dbx method) dependent upon the
1960Sstevel@tonic-gate 	 *		text segment/symbol table of the
1970Sstevel@tonic-gate 	 *		executable and not ld.so.1.  We lookup the
1980Sstevel@tonic-gate 	 *		_DYNAMIC symbol in the executable and look for
1990Sstevel@tonic-gate 	 *		the DT_DEBUG entry in the .dynamic table.  This
2000Sstevel@tonic-gate 	 *		points to rdebug.
2010Sstevel@tonic-gate 	 *
2020Sstevel@tonic-gate 	 * If none of that works - we fail.
2030Sstevel@tonic-gate 	 */
2040Sstevel@tonic-gate 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDRESET), rap->rd_dmodel));
2050Sstevel@tonic-gate 	/*
2060Sstevel@tonic-gate 	 * Method1
2070Sstevel@tonic-gate 	 *
2080Sstevel@tonic-gate 	 * Scan the aux vector looking for AT_BASE & AT_SUN_LDDATA
2090Sstevel@tonic-gate 	 */
2102712Snn35248 
2110Sstevel@tonic-gate 	if (ps_pauxv(php, &auxvp) != PS_OK) {
2120Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_NOAUXV)));
2130Sstevel@tonic-gate 		rc = RD_ERR;
2140Sstevel@tonic-gate 	}
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	rap->rd_rdebug = 0;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	if (auxvp != NULL) {
2190Sstevel@tonic-gate 		rc = RD_ERR;
2200Sstevel@tonic-gate 		while (auxvp->a_type != AT_NULL) {
2210Sstevel@tonic-gate 			if (auxvp->a_type == AT_SUN_LDDATA) {
2220Sstevel@tonic-gate 				/* LINTED */
2230Sstevel@tonic-gate 				rap->rd_rdebug = (uintptr_t)auxvp->a_un.a_ptr;
2240Sstevel@tonic-gate 				LOG(ps_plog(MSG_ORIG(MSG_DB_FLDDATA),
2250Sstevel@tonic-gate 				    rap->rd_rdebug));
2266830Sedp 				rc = validate_rdebug32(rap);
2270Sstevel@tonic-gate 				break;
2280Sstevel@tonic-gate 			}
2290Sstevel@tonic-gate 			auxvp++;
2300Sstevel@tonic-gate 		}
2310Sstevel@tonic-gate 	}
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	/*
2340Sstevel@tonic-gate 	 * method2 - look for r_rdebug symbol in ld.so.1
2350Sstevel@tonic-gate 	 */
2360Sstevel@tonic-gate 	if (rc != RD_OK) {
2370Sstevel@tonic-gate 		/*
2380Sstevel@tonic-gate 		 * If the AT_SUN_LDDATA auxv vector is not present
2390Sstevel@tonic-gate 		 * fall back on doing a symlookup of
2400Sstevel@tonic-gate 		 * the r_debug symbol.  This is for backward
2410Sstevel@tonic-gate 		 * compatiblity with older OS's
2420Sstevel@tonic-gate 		 */
2430Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_NOLDDATA)));
2440Sstevel@tonic-gate 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO, MSG_ORIG(MSG_SYM_DEBUG),
2450Sstevel@tonic-gate 		    &symaddr) != PS_OK) {
2460Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
2472712Snn35248 			    MSG_ORIG(MSG_SYM_DEBUG)));
2480Sstevel@tonic-gate 			rc = RD_DBERR;
2490Sstevel@tonic-gate 		} else {
2500Sstevel@tonic-gate 			rap->rd_rdebug = symaddr;
2510Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_SYMRDEBUG),
2522712Snn35248 			    EC_ADDR(symaddr)));
2536830Sedp 			rc = validate_rdebug32(rap);
2540Sstevel@tonic-gate 		}
2550Sstevel@tonic-gate 	}
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	/*
2590Sstevel@tonic-gate 	 * method3 - find DT_DEBUG in the executables .dynamic section.
2600Sstevel@tonic-gate 	 */
2610Sstevel@tonic-gate 	if (rc != RD_OK) {
2620Sstevel@tonic-gate 		Dyn	dyn;
2630Sstevel@tonic-gate 		if (ps_pglobal_lookup(php, PS_OBJ_EXEC,
2640Sstevel@tonic-gate 		    MSG_ORIG(MSG_SYM_DYNAMIC), &symaddr) != PS_OK) {
2650Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_NODYNAMIC)));
2660Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED)));
2670Sstevel@tonic-gate 			return (rc);
2680Sstevel@tonic-gate 		}
2690Sstevel@tonic-gate 		rc = find_dynamic_ent32(rap, symaddr, DT_DEBUG, &dyn);
2700Sstevel@tonic-gate 		if (rc != RD_OK) {
2710Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED)));
2720Sstevel@tonic-gate 			return (rc);
2730Sstevel@tonic-gate 		}
2740Sstevel@tonic-gate 		rap->rd_rdebug = dyn.d_un.d_ptr;
2756830Sedp 		rc = validate_rdebug32(rap);
2760Sstevel@tonic-gate 		if (rc != RD_OK) {
2770Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED)));
2780Sstevel@tonic-gate 			return (rc);
2790Sstevel@tonic-gate 		}
2800Sstevel@tonic-gate 	}
2810Sstevel@tonic-gate 
2822712Snn35248 	/*
2836830Sedp 	 * If we are debugging a branded executable, load the appropriate
2846830Sedp 	 * helper library, and call its initialization routine.  Being unable
2856830Sedp 	 * to load the helper library is not a critical error.  (Hopefully
2866830Sedp 	 * we'll still be able to access some objects in the target.)
2872712Snn35248 	 */
2885041Sedp 	ps_pbrandname = (ps_pbrandname_fp_t)dlsym(RTLD_PROBE, "ps_pbrandname");
2896830Sedp 	while ((ps_pbrandname != NULL) &&
2905041Sedp 	    (ps_pbrandname(php, brandname, MAXPATHLEN) == PS_OK)) {
2912712Snn35248 		const char *isa = "";
2922712Snn35248 
2936830Sedp #ifdef _LP64
2942712Snn35248 		isa = MSG_ORIG(MSG_DB_64BIT_PREFIX);
2956830Sedp #endif /* _LP64 */
2962712Snn35248 
2972712Snn35248 		if (rtld_db_helper_path[0] != '\0')
2982712Snn35248 			(void) snprintf(brandlib, MAXPATHLEN,
2992712Snn35248 			    MSG_ORIG(MSG_DB_BRAND_HELPERPATH_PREFIX),
3002712Snn35248 			    rtld_db_helper_path,
3012712Snn35248 			    MSG_ORIG(MSG_DB_HELPER_PREFIX), brandname, isa,
3022712Snn35248 			    brandname);
3032712Snn35248 		else
3042712Snn35248 			(void) snprintf(brandlib, MAXPATHLEN,
3052712Snn35248 			    MSG_ORIG(MSG_DB_BRAND_HELPERPATH),
3062712Snn35248 			    MSG_ORIG(MSG_DB_HELPER_PREFIX), brandname, isa,
3072712Snn35248 			    brandname);
3082712Snn35248 
3096830Sedp 		rap->rd_helper.rh_dlhandle = dlopen(brandlib,
3106830Sedp 		    RTLD_LAZY | RTLD_LOCAL);
3116830Sedp 		if (rap->rd_helper.rh_dlhandle == NULL) {
3122712Snn35248 			LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERLOADFAILED),
3132712Snn35248 			    brandlib));
3146830Sedp 			break;
3152712Snn35248 		}
3162712Snn35248 
3176830Sedp 		rap->rd_helper.rh_ops = dlsym(rap->rd_helper.rh_dlhandle,
3186830Sedp 		    MSG_ORIG(MSG_SYM_BRANDOPS));
3196830Sedp 		if (rap->rd_helper.rh_ops == NULL) {
3202712Snn35248 			LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERNOOPS),
3212712Snn35248 			    brandlib));
3226830Sedp 			(void) dlclose(rap->rd_helper.rh_dlhandle);
3236830Sedp 			rap->rd_helper.rh_dlhandle = NULL;
3246830Sedp 			break;
3252712Snn35248 		}
3262712Snn35248 
3276830Sedp 		rap->rd_helper.rh_data = rap->rd_helper.rh_ops->rho_init(rap,
3286830Sedp 		    php);
3292712Snn35248 		if (rap->rd_helper.rh_data == NULL) {
3302712Snn35248 			LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERINITFAILED)));
3312712Snn35248 			(void) dlclose(rap->rd_helper.rh_dlhandle);
3322712Snn35248 			rap->rd_helper.rh_dlhandle = NULL;
3332712Snn35248 			rap->rd_helper.rh_ops = NULL;
3346830Sedp 			break;
3356830Sedp 		}
3366830Sedp 
3376830Sedp 		LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERLOADED), brandname));
3386830Sedp 		break;
3396874Srie 
3406874Srie 		/* NOTREACHED */
3412712Snn35248 	}
3422712Snn35248 
3430Sstevel@tonic-gate 	if ((rap->rd_flags & RDF_FL_COREFILE) == 0) {
3440Sstevel@tonic-gate 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO,
3450Sstevel@tonic-gate 		    MSG_ORIG(MSG_SYM_PREINIT), &symaddr) != PS_OK) {
3460Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
3472712Snn35248 			    MSG_ORIG(MSG_SYM_PREINIT)));
3480Sstevel@tonic-gate 			return (RD_DBERR);
3490Sstevel@tonic-gate 		}
3500Sstevel@tonic-gate 		rap->rd_preinit = symaddr;
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO,
3530Sstevel@tonic-gate 		    MSG_ORIG(MSG_SYM_POSTINIT), &symaddr) != PS_OK) {
3540Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
3552712Snn35248 			    MSG_ORIG(MSG_SYM_POSTINIT)));
3560Sstevel@tonic-gate 			return (RD_DBERR);
3570Sstevel@tonic-gate 		}
3580Sstevel@tonic-gate 		rap->rd_postinit = symaddr;
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO,
3610Sstevel@tonic-gate 		    MSG_ORIG(MSG_SYM_DLACT), &symaddr) != PS_OK) {
3620Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
3632712Snn35248 			    MSG_ORIG(MSG_SYM_DLACT)));
3640Sstevel@tonic-gate 			return (RD_DBERR);
3650Sstevel@tonic-gate 		}
3660Sstevel@tonic-gate 		rap->rd_dlact = symaddr;
3670Sstevel@tonic-gate 		rap->rd_tbinder = 0;
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	return (RD_OK);
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate rd_err_e
_rd_get_ehdr32(struct rd_agent * rap,psaddr_t addr,Ehdr * ehdr,uint_t * phnum)3746830Sedp _rd_get_ehdr32(struct rd_agent *rap,
3756830Sedp     psaddr_t addr, Ehdr *ehdr, uint_t *phnum)
3766830Sedp {
3776830Sedp 	struct ps_prochandle	*php = rap->rd_psp;
3786830Sedp 	Shdr			shdr;
3796830Sedp 
3806830Sedp 	if (ps_pread(php, addr, ehdr, sizeof (*ehdr)) != PS_OK) {
3816830Sedp 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_5), EC_ADDR(addr)));
3826830Sedp 		return (RD_ERR);
3836830Sedp 	}
3846830Sedp 	if (phnum == NULL)
3856830Sedp 		return (RD_OK);
3866830Sedp 
3876830Sedp 	if (ehdr->e_phnum != PN_XNUM) {
3886830Sedp 		*phnum = ehdr->e_phnum;
3896830Sedp 		return (RD_OK);
3906830Sedp 	}
3916830Sedp 
3926830Sedp 	/* deal with elf extended program headers */
3936830Sedp 	if ((ehdr->e_shoff == 0) || (ehdr->e_shentsize < sizeof (shdr)))
3946830Sedp 		return (RD_ERR);
3956830Sedp 
3966830Sedp 	addr += ehdr->e_shoff;
3976830Sedp 	if (ps_pread(php, addr, &shdr, sizeof (shdr)) != PS_OK) {
3986830Sedp 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_5), EC_ADDR(addr)));
3996830Sedp 		return (RD_ERR);
4006830Sedp 	}
4016830Sedp 
4026830Sedp 	if (shdr.sh_info == 0)
4036830Sedp 		return (RD_ERR);
4046830Sedp 
4056830Sedp 	*phnum = shdr.sh_info;
4066830Sedp 	return (RD_OK);
4076830Sedp }
4086830Sedp 
4096830Sedp rd_err_e
_rd_get_dyns32(rd_agent_t * rap,psaddr_t addr,Dyn ** dynpp,size_t * dynpp_sz)4106830Sedp _rd_get_dyns32(rd_agent_t *rap, psaddr_t addr, Dyn **dynpp, size_t *dynpp_sz)
4116830Sedp {
4126830Sedp 	struct ps_prochandle	*php = rap->rd_psp;
4136830Sedp 	rd_err_e		err;
4146830Sedp 	uint_t			phnum;
4156830Sedp 	Ehdr			ehdr;
4166830Sedp 	Phdr			phdr;
4176830Sedp 	Dyn			*dynp;
4186830Sedp 	int			i;
4196830Sedp 
4206830Sedp 	/* We only need to muck with dyn elements for ET_DYN objects */
4216830Sedp 	if ((err = _rd_get_ehdr32(rap, addr, &ehdr, &phnum)) != RD_OK)
4226830Sedp 		return (err);
4236830Sedp 
4246830Sedp 	for (i = 0; i < phnum; i++) {
4256830Sedp 		psaddr_t a = addr + ehdr.e_phoff + (i * ehdr.e_phentsize);
4266830Sedp 		if (ps_pread(php, a, &phdr, sizeof (phdr)) != PS_OK) {
4276830Sedp 			LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_6), EC_ADDR(a)));
4286830Sedp 			return (RD_ERR);
4296830Sedp 		}
4306830Sedp 		if (phdr.p_type == PT_DYNAMIC)
4316830Sedp 			break;
4326830Sedp 	}
4336830Sedp 	if (i == phnum)
4346830Sedp 		return (RD_ERR);
4356830Sedp 
4366830Sedp 	if ((dynp = malloc(phdr.p_filesz)) == NULL)
4376830Sedp 		return (RD_ERR);
4386830Sedp 	if (ehdr.e_type == ET_DYN)
4396830Sedp 		phdr.p_vaddr += addr;
4406830Sedp 	if (ps_pread(php, phdr.p_vaddr, dynp, phdr.p_filesz) != PS_OK) {
4416830Sedp 		free(dynp);
4426830Sedp 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_6),
4436830Sedp 		    EC_ADDR(phdr.p_vaddr)));
4446830Sedp 		return (RD_ERR);
4456830Sedp 	}
4466830Sedp 
4476830Sedp 	*dynpp = dynp;
4486868Sedp 	if (dynpp_sz != NULL)
4496868Sedp 		*dynpp_sz = phdr.p_filesz;
4506830Sedp 	return (RD_OK);
4516830Sedp }
4526830Sedp 
4536830Sedp rd_err_e
_rd_event_enable32(rd_agent_t * rap,int onoff)4540Sstevel@tonic-gate _rd_event_enable32(rd_agent_t *rap, int onoff)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate 	struct ps_prochandle	*php = rap->rd_psp;
4570Sstevel@tonic-gate 	Rtld_db_priv		rdb;
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDEVENTENABLE), rap->rd_dmodel, onoff));
4600Sstevel@tonic-gate 	/*
4610Sstevel@tonic-gate 	 * Tell the debugged process that debugging is occuring
4620Sstevel@tonic-gate 	 * This will enable the storing of event messages so that
4630Sstevel@tonic-gate 	 * the can be gathered by the debugger.
4640Sstevel@tonic-gate 	 */
4650Sstevel@tonic-gate 	if (ps_pread(php, rap->rd_rdebug, (char *)&rdb,
4660Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK) {
4670Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_1),
4680Sstevel@tonic-gate 		    EC_ADDR((uintptr_t)&rdb)));
4690Sstevel@tonic-gate 		return (RD_DBERR);
4700Sstevel@tonic-gate 	}
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	if (onoff)
4730Sstevel@tonic-gate 		rdb.rtd_rdebug.r_flags |= RD_FL_DBG;
4740Sstevel@tonic-gate 	else
4750Sstevel@tonic-gate 		rdb.rtd_rdebug.r_flags &= ~RD_FL_DBG;
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	if (ps_pwrite(php, rap->rd_rdebug, (char *)&rdb,
4780Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK) {
4790Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_WRITEFAIL_1),
4800Sstevel@tonic-gate 		    EC_ADDR((uintptr_t)&rdb)));
4810Sstevel@tonic-gate 		return (RD_DBERR);
4820Sstevel@tonic-gate 	}
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	return (RD_OK);
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate rd_err_e
_rd_event_getmsg32(rd_agent_t * rap,rd_event_msg_t * emsg)4890Sstevel@tonic-gate _rd_event_getmsg32(rd_agent_t *rap, rd_event_msg_t *emsg)
4900Sstevel@tonic-gate {
4910Sstevel@tonic-gate 	Rtld_db_priv	rdb;
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	if (ps_pread(rap->rd_psp, rap->rd_rdebug, (char *)&rdb,
4940Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK) {
4950Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_2),
4960Sstevel@tonic-gate 		    EC_ADDR(rap->rd_rdebug)));
4970Sstevel@tonic-gate 		return (RD_DBERR);
4980Sstevel@tonic-gate 	}
4990Sstevel@tonic-gate 	emsg->type = rdb.rtd_rdebug.r_rdevent;
5000Sstevel@tonic-gate 	if (emsg->type == RD_DLACTIVITY) {
5010Sstevel@tonic-gate 		switch (rdb.rtd_rdebug.r_state) {
5020Sstevel@tonic-gate 			case RT_CONSISTENT:
5030Sstevel@tonic-gate 				emsg->u.state = RD_CONSISTENT;
5040Sstevel@tonic-gate 				break;
5050Sstevel@tonic-gate 			case RT_ADD:
5060Sstevel@tonic-gate 				emsg->u.state = RD_ADD;
5070Sstevel@tonic-gate 				break;
5080Sstevel@tonic-gate 			case RT_DELETE:
5090Sstevel@tonic-gate 				emsg->u.state = RD_DELETE;
5100Sstevel@tonic-gate 				break;
5110Sstevel@tonic-gate 		}
5120Sstevel@tonic-gate 	} else
5130Sstevel@tonic-gate 		emsg->u.state = RD_NOSTATE;
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDEVENTGETMSG), rap->rd_dmodel,
5162712Snn35248 	    emsg->type, emsg->u.state));
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	return (RD_OK);
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate rd_err_e
_rd_objpad_enable32(struct rd_agent * rap,size_t padsize)5230Sstevel@tonic-gate _rd_objpad_enable32(struct rd_agent *rap, size_t padsize)
5240Sstevel@tonic-gate {
5250Sstevel@tonic-gate 	Rtld_db_priv		db_priv;
5260Sstevel@tonic-gate 	struct ps_prochandle	*php = rap->rd_psp;
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDOBJPADE), EC_ADDR(padsize)));
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	if (ps_pread(php, rap->rd_rtlddbpriv, (char *)&db_priv,
5310Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK) {
5320Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_3),
5330Sstevel@tonic-gate 		    EC_ADDR(rap->rd_rtlddbpriv)));
5340Sstevel@tonic-gate 		return (RD_DBERR);
5350Sstevel@tonic-gate 	}
5360Sstevel@tonic-gate #if	defined(_LP64) && !defined(_ELF64)
5370Sstevel@tonic-gate 	/*LINTED*/
5380Sstevel@tonic-gate 	db_priv.rtd_objpad = (uint32_t)padsize;
5390Sstevel@tonic-gate #else
5400Sstevel@tonic-gate 	db_priv.rtd_objpad = padsize;
5410Sstevel@tonic-gate #endif
5420Sstevel@tonic-gate 	if (ps_pwrite(php, rap->rd_rtlddbpriv, (char *)&db_priv,
5430Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK) {
5440Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_WRITEFAIL_2),
5450Sstevel@tonic-gate 		    EC_ADDR(rap->rd_rtlddbpriv)));
5460Sstevel@tonic-gate 		return (RD_DBERR);
5470Sstevel@tonic-gate 	}
5480Sstevel@tonic-gate 	return (RD_OK);
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate 
5510Sstevel@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)5520Sstevel@tonic-gate iter_map(rd_agent_t *rap, unsigned long ident, psaddr_t lmaddr,
5537924SEdward.Pilatowicz@Sun.COM 	rl_iter_f *cb, void *client_data, uint_t *abort_iterp)
5540Sstevel@tonic-gate {
5550Sstevel@tonic-gate 	while (lmaddr) {
5560Sstevel@tonic-gate 		Rt_map		rmap;
5570Sstevel@tonic-gate 		rd_loadobj_t	lobj;
5580Sstevel@tonic-gate 		int		i;
5590Sstevel@tonic-gate 		ulong_t		off;
5600Sstevel@tonic-gate 		Ehdr		ehdr;
5610Sstevel@tonic-gate 		Phdr		phdr;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 		if (ps_pread(rap->rd_psp, lmaddr, (char *)&rmap,
5640Sstevel@tonic-gate 		    sizeof (Rt_map)) != PS_OK) {
5650Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPFAIL)));
5660Sstevel@tonic-gate 			return (RD_DBERR);
5670Sstevel@tonic-gate 		}
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 		/*
5700Sstevel@tonic-gate 		 * As of 'VERSION5' we only report objects
5710Sstevel@tonic-gate 		 * which have been fully relocated.  While the maps
5720Sstevel@tonic-gate 		 * might be in a consistent state - if a object hasn't
5730Sstevel@tonic-gate 		 * been relocated - it's not really ready for the debuggers
5740Sstevel@tonic-gate 		 * to examine.  This is mostly due to the fact that we
5750Sstevel@tonic-gate 		 * might still be mucking with the text-segment, if
5760Sstevel@tonic-gate 		 * we are - we could conflict with any break-points
5770Sstevel@tonic-gate 		 * the debuggers might have set.
5780Sstevel@tonic-gate 		 */
5790Sstevel@tonic-gate 		if (rap->rd_rdebugvers >= R_RTLDDB_VERSION5) {
5800Sstevel@tonic-gate 			if ((FLAGS(&rmap) & FLG_RT_RELOCED) == 0) {
5810Sstevel@tonic-gate 				lmaddr = (psaddr_t)NEXT(&rmap);
5820Sstevel@tonic-gate 				continue;
5830Sstevel@tonic-gate 			}
5840Sstevel@tonic-gate 		}
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 		lobj.rl_base = (psaddr_t)ADDR(&rmap);
5870Sstevel@tonic-gate 		lobj.rl_flags = 0;
5880Sstevel@tonic-gate 		lobj.rl_refnameaddr = (psaddr_t)REFNAME(&rmap);
5896830Sedp 		if ((rap->rd_helper.rh_ops != NULL) &&
5906830Sedp 		    (rap->rd_helper.rh_ops->rho_lmid != LM_ID_NONE))
5916830Sedp 			lobj.rl_lmident =
5926830Sedp 			    rap->rd_helper.rh_ops->rho_lmid;
5932712Snn35248 		else
5942712Snn35248 			lobj.rl_lmident = ident;
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 		/*
5970Sstevel@tonic-gate 		 * refnameaddr is only valid from a core file
5980Sstevel@tonic-gate 		 * which is VERSION3 or greater.
5990Sstevel@tonic-gate 		 */
6000Sstevel@tonic-gate 		if (rap->rd_rdebugvers < R_RTLDDB_VERSION3) {
6010Sstevel@tonic-gate 			lobj.rl_nameaddr = (psaddr_t)NAME(&rmap);
6020Sstevel@tonic-gate 			lobj.rl_bend = 0;
6030Sstevel@tonic-gate 			lobj.rl_padstart = 0;
6040Sstevel@tonic-gate 			lobj.rl_padend = 0;
6050Sstevel@tonic-gate 		} else {
6060Sstevel@tonic-gate 			lobj.rl_nameaddr = (psaddr_t)PATHNAME(&rmap);
6070Sstevel@tonic-gate 			lobj.rl_bend = ADDR(&rmap) + MSIZE(&rmap);
6080Sstevel@tonic-gate 			lobj.rl_padstart = PADSTART(&rmap);
6090Sstevel@tonic-gate 			lobj.rl_padend = PADSTART(&rmap) + PADIMLEN(&rmap);
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 		}
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 		if (rtld_db_version >= RD_VERSION2)
6140Sstevel@tonic-gate 			if (FLAGS(&rmap) & FLG_RT_IMGALLOC)
6150Sstevel@tonic-gate 				lobj.rl_flags |= RD_FLG_MEM_OBJECT;
6160Sstevel@tonic-gate 		if (rtld_db_version >= RD_VERSION2) {
6170Sstevel@tonic-gate 			lobj.rl_dynamic = (psaddr_t)DYN(&rmap);
6180Sstevel@tonic-gate 		}
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 		if (rtld_db_version >= RD_VERSION4)
6210Sstevel@tonic-gate 			lobj.rl_tlsmodid = TLSMODID(&rmap);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 		/*
6240Sstevel@tonic-gate 		 * Look for beginning of data segment.
6250Sstevel@tonic-gate 		 *
6260Sstevel@tonic-gate 		 * NOTE: the data segment can only be found for full
6270Sstevel@tonic-gate 		 *	processes and not from core images.
6280Sstevel@tonic-gate 		 */
6290Sstevel@tonic-gate 		lobj.rl_data_base = 0;
6300Sstevel@tonic-gate 		if (rap->rd_flags & RDF_FL_COREFILE)
6310Sstevel@tonic-gate 			lobj.rl_data_base = 0;
6320Sstevel@tonic-gate 		else {
6330Sstevel@tonic-gate 			off = ADDR(&rmap);
6340Sstevel@tonic-gate 			if (ps_pread(rap->rd_psp, off, (char *)&ehdr,
6350Sstevel@tonic-gate 			    sizeof (Ehdr)) != PS_OK) {
6360Sstevel@tonic-gate 				LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPFAIL)));
6370Sstevel@tonic-gate 				return (RD_DBERR);
6380Sstevel@tonic-gate 			}
6390Sstevel@tonic-gate 			off += sizeof (Ehdr);
6400Sstevel@tonic-gate 			for (i = 0; i < ehdr.e_phnum; i++) {
6410Sstevel@tonic-gate 				if (ps_pread(rap->rd_psp, off, (char *)&phdr,
6420Sstevel@tonic-gate 				    sizeof (Phdr)) != PS_OK) {
6430Sstevel@tonic-gate 					LOG(ps_plog(MSG_ORIG(
6440Sstevel@tonic-gate 					    MSG_DB_LKMAPFAIL)));
6450Sstevel@tonic-gate 					return (RD_DBERR);
6460Sstevel@tonic-gate 				}
6470Sstevel@tonic-gate 				if ((phdr.p_type == PT_LOAD) &&
6480Sstevel@tonic-gate 				    (phdr.p_flags & PF_W)) {
6490Sstevel@tonic-gate 					lobj.rl_data_base = phdr.p_vaddr;
6500Sstevel@tonic-gate 					if (ehdr.e_type == ET_DYN)
6510Sstevel@tonic-gate 						lobj.rl_data_base +=
6522712Snn35248 						    ADDR(&rmap);
6530Sstevel@tonic-gate 					break;
6540Sstevel@tonic-gate 				}
6550Sstevel@tonic-gate 				off += ehdr.e_phentsize;
6560Sstevel@tonic-gate 			}
6570Sstevel@tonic-gate 		}
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 		/*
6600Sstevel@tonic-gate 		 * When we transfer control to the client we free the
6610Sstevel@tonic-gate 		 * lock and re-atain it after we've returned from the
6620Sstevel@tonic-gate 		 * client.  This is to avoid any deadlock situations.
6630Sstevel@tonic-gate 		 */
6640Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_ITERMAP), cb, client_data,
6652712Snn35248 		    EC_ADDR(lobj.rl_base), EC_ADDR(lobj.rl_lmident)));
6660Sstevel@tonic-gate 		RDAGUNLOCK(rap);
6670Sstevel@tonic-gate 		if ((*cb)(&lobj, client_data) == 0) {
6680Sstevel@tonic-gate 			LOG(ps_plog(MSG_ORIG(MSG_DB_CALLBACKR0)));
6690Sstevel@tonic-gate 			RDAGLOCK(rap);
6707924SEdward.Pilatowicz@Sun.COM 			*abort_iterp = 1;
6710Sstevel@tonic-gate 			break;
6720Sstevel@tonic-gate 		}
6730Sstevel@tonic-gate 		RDAGLOCK(rap);
6740Sstevel@tonic-gate 		lmaddr = (psaddr_t)NEXT(&rmap);
6750Sstevel@tonic-gate 	}
6760Sstevel@tonic-gate 	return (RD_OK);
6770Sstevel@tonic-gate }
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 
6807924SEdward.Pilatowicz@Sun.COM static rd_err_e
_rd_loadobj_iter32_native(rd_agent_t * rap,rl_iter_f * cb,void * client_data,uint_t * abort_iterp)6817924SEdward.Pilatowicz@Sun.COM _rd_loadobj_iter32_native(rd_agent_t *rap, rl_iter_f *cb, void *client_data,
6827924SEdward.Pilatowicz@Sun.COM     uint_t *abort_iterp)
6830Sstevel@tonic-gate {
6840Sstevel@tonic-gate 	Rtld_db_priv	db_priv;
6859131SRod.Evans@Sun.COM 	TAPlist		apl;
6869131SRod.Evans@Sun.COM 	uintptr_t	datap, nitems;
6879131SRod.Evans@Sun.COM 	Addr		addr;
6880Sstevel@tonic-gate 	rd_err_e	rc;
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	LOG(ps_plog(MSG_ORIG(MSG_DB_LOADOBJITER), rap->rd_dmodel, cb,
6912712Snn35248 	    client_data));
6920Sstevel@tonic-gate 
6939218SRod.Evans@Sun.COM 	/*
6949218SRod.Evans@Sun.COM 	 * First, determine whether the link-map information has been
6959218SRod.Evans@Sun.COM 	 * established.  Some debuggers have made an initial call to this
6969218SRod.Evans@Sun.COM 	 * function with a null call back function (cb), but expect a
6979218SRod.Evans@Sun.COM 	 * RD_NOMAPS error return rather than a RD_ERR return when the
6989218SRod.Evans@Sun.COM 	 * link-maps aren't available.
6999218SRod.Evans@Sun.COM 	 */
7000Sstevel@tonic-gate 	if (ps_pread(rap->rd_psp, rap->rd_rtlddbpriv, (char *)&db_priv,
7010Sstevel@tonic-gate 	    sizeof (Rtld_db_priv)) != PS_OK) {
7020Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_1),
7030Sstevel@tonic-gate 		    EC_ADDR(rap->rd_rtlddbpriv)));
7040Sstevel@tonic-gate 		return (RD_DBERR);
7050Sstevel@tonic-gate 	}
7060Sstevel@tonic-gate 
7079131SRod.Evans@Sun.COM 	if (db_priv.rtd_dynlmlst == NULL) {
7080Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPNOINIT),
7092712Snn35248 		    EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
7100Sstevel@tonic-gate 		return (RD_NOMAPS);
7110Sstevel@tonic-gate 	}
7120Sstevel@tonic-gate 
7139131SRod.Evans@Sun.COM 	if (ps_pread(rap->rd_psp, (psaddr_t)db_priv.rtd_dynlmlst, (char *)&addr,
7149131SRod.Evans@Sun.COM 	    sizeof (Addr)) != PS_OK) {
7150Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_3),
7162712Snn35248 		    EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
7170Sstevel@tonic-gate 		return (RD_DBERR);
7180Sstevel@tonic-gate 	}
7190Sstevel@tonic-gate 
7209131SRod.Evans@Sun.COM 	if (addr == NULL) {
7210Sstevel@tonic-gate 		LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPNOINIT_1),
7229131SRod.Evans@Sun.COM 		    EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
7230Sstevel@tonic-gate 		return (RD_NOMAPS);
7240Sstevel@tonic-gate 	}
7250Sstevel@tonic-gate 
7269218SRod.Evans@Sun.COM 	/*
7279218SRod.Evans@Sun.COM 	 * Having determined we have link-maps, ensure we have an iterator
7289218SRod.Evans@Sun.COM 	 * call back function.
7299218SRod.Evans@Sun.COM 	 */
7309218SRod.Evans@Sun.COM 	if (cb == NULL) {
7319218SRod.Evans@Sun.COM 		LOG(ps_plog(MSG_ORIG(MSG_DB_NULLITER)));
7329218SRod.Evans@Sun.COM 		return (RD_ERR);
7339218SRod.Evans@Sun.COM 	}
7349218SRod.Evans@Sun.COM 
7359218SRod.Evans@Sun.COM 	/*
73610167SRod.Evans@Sun.COM 	 * As of VERSION6, rtd_dynlmlst points to an APlist.  Prior to VERSION6
73710167SRod.Evans@Sun.COM 	 * rtd_dynlmlst pointed to a List.  But, there was a window where the
73810167SRod.Evans@Sun.COM 	 * version was not incremented, and this must be worked around by
73910167SRod.Evans@Sun.COM 	 * interpreting the APlist data.  Read the initial APlist information.
7409218SRod.Evans@Sun.COM 	 */
7419131SRod.Evans@Sun.COM 	if (ps_pread(rap->rd_psp, (psaddr_t)addr, (char *)&apl,
7429131SRod.Evans@Sun.COM 	    sizeof (TAPlist)) != PS_OK) {
7439131SRod.Evans@Sun.COM 		LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_4),
7449131SRod.Evans@Sun.COM 		    EC_ADDR((uintptr_t)addr)));
7459131SRod.Evans@Sun.COM 		return (RD_DBERR);
7460Sstevel@tonic-gate 	}
7470Sstevel@tonic-gate 
7489131SRod.Evans@Sun.COM 	/*
74910167SRod.Evans@Sun.COM 	 * The rtd_dynlmlst change from a List to an APlist occurred under
75010167SRod.Evans@Sun.COM 	 * 6801536 in snv_112.  However, this change neglected to preserve
75110167SRod.Evans@Sun.COM 	 * backward compatibility by maintaining List processing and using a
75210167SRod.Evans@Sun.COM 	 * version increment to detect the change.  6862967, intergrated in
75310167SRod.Evans@Sun.COM 	 * snv_121 corrects the version detection.  However, to catch objects
75410167SRod.Evans@Sun.COM 	 * built between these releases, we look at the first element of the
75510167SRod.Evans@Sun.COM 	 * APlist.  apl_arritems indicates the number of APlist items that are
75610167SRod.Evans@Sun.COM 	 * available.  This was originally initialized with a AL_CNT_DYNLIST
75710167SRod.Evans@Sun.COM 	 * value of 2 (one entry for LM_ID_BASE and one entry for LM_ID_LDSO).
75810167SRod.Evans@Sun.COM 	 * It is possible that the use of an auditor results in an additional
75910167SRod.Evans@Sun.COM 	 * link-map list, in which case the original apl_arritems would have
76010167SRod.Evans@Sun.COM 	 * been doubled.
76110167SRod.Evans@Sun.COM 	 *
76210167SRod.Evans@Sun.COM 	 * Therefore, if the debugging verion is VERSION6, or the apl_arritems
76310167SRod.Evans@Sun.COM 	 * entry has a value less than or equal to 4 and the debugging version
76410167SRod.Evans@Sun.COM 	 * is VERSION5, then we process APlists.  Otherwise, fall back to List
76510167SRod.Evans@Sun.COM 	 * processing.
7669131SRod.Evans@Sun.COM 	 */
76710167SRod.Evans@Sun.COM 	if ((rap->rd_rdebugvers >= R_RTLDDB_VERSION6) ||
76810167SRod.Evans@Sun.COM 	    ((rap->rd_rdebugvers == R_RTLDDB_VERSION5) &&
76910167SRod.Evans@Sun.COM 	    (apl.apl_arritems <= 4))) {
77010167SRod.Evans@Sun.COM 		/*
77110167SRod.Evans@Sun.COM 		 * Iterate through each apl.ap_data[] entry.
77210167SRod.Evans@Sun.COM 		 */
77310167SRod.Evans@Sun.COM 		for (datap = (uintptr_t)((char *)(uintptr_t)addr +
77410167SRod.Evans@Sun.COM 		    ((size_t)(((TAPlist *)0)->apl_data))), nitems = 0;
77510167SRod.Evans@Sun.COM 		    nitems < apl.apl_nitems; nitems++, datap += sizeof (Addr)) {
77610167SRod.Evans@Sun.COM 			TLm_list	lm;
77710167SRod.Evans@Sun.COM 			ulong_t		ident;
77810167SRod.Evans@Sun.COM 
77910167SRod.Evans@Sun.COM 			/*
78010167SRod.Evans@Sun.COM 			 * Obtain the Lm_list address for this apl.ap_data[]
78110167SRod.Evans@Sun.COM 			 * entry.
78210167SRod.Evans@Sun.COM 			 */
78310167SRod.Evans@Sun.COM 			if (ps_pread(rap->rd_psp, (psaddr_t)datap,
78410167SRod.Evans@Sun.COM 			    (char *)&addr, sizeof (Addr)) != PS_OK) {
78510167SRod.Evans@Sun.COM 				LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_5),
78610167SRod.Evans@Sun.COM 				    EC_ADDR(datap)));
78710167SRod.Evans@Sun.COM 				return (RD_DBERR);
78810167SRod.Evans@Sun.COM 			}
78910167SRod.Evans@Sun.COM 
79010167SRod.Evans@Sun.COM 			/*
79110167SRod.Evans@Sun.COM 			 * Obtain the Lm_list data for this Lm_list address.
79210167SRod.Evans@Sun.COM 			 */
79310167SRod.Evans@Sun.COM 			if (ps_pread(rap->rd_psp, (psaddr_t)addr, (char *)&lm,
79410167SRod.Evans@Sun.COM 			    sizeof (TLm_list)) != PS_OK) {
79510167SRod.Evans@Sun.COM 				LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_6),
79610167SRod.Evans@Sun.COM 				    EC_ADDR((uintptr_t)addr)));
79710167SRod.Evans@Sun.COM 				return (RD_DBERR);
79810167SRod.Evans@Sun.COM 			}
79910167SRod.Evans@Sun.COM 
80010167SRod.Evans@Sun.COM 			/*
80110167SRod.Evans@Sun.COM 			 * Determine IDENT of current LM_LIST
80210167SRod.Evans@Sun.COM 			 */
80310167SRod.Evans@Sun.COM 			if (lm.lm_flags & LML_FLG_BASELM)
80410167SRod.Evans@Sun.COM 				ident = LM_ID_BASE;
80510167SRod.Evans@Sun.COM 			else if (lm.lm_flags & LML_FLG_RTLDLM)
80610167SRod.Evans@Sun.COM 				ident = LM_ID_LDSO;
80710167SRod.Evans@Sun.COM 			else
80810167SRod.Evans@Sun.COM 				ident = (ulong_t)addr;
80910167SRod.Evans@Sun.COM 
81010167SRod.Evans@Sun.COM 			if ((rc = iter_map(rap, ident, (psaddr_t)lm.lm_head,
81110167SRod.Evans@Sun.COM 			    cb, client_data, abort_iterp)) != RD_OK)
81210167SRod.Evans@Sun.COM 				return (rc);
81310167SRod.Evans@Sun.COM 
81410167SRod.Evans@Sun.COM 			if (*abort_iterp != 0)
81510167SRod.Evans@Sun.COM 				break;
81610167SRod.Evans@Sun.COM 		}
81710167SRod.Evans@Sun.COM 	} else {
81810167SRod.Evans@Sun.COM 		TList		list;
81910167SRod.Evans@Sun.COM 		TListnode	lnode;
82010167SRod.Evans@Sun.COM 		Addr		lnp;
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 		/*
82310167SRod.Evans@Sun.COM 		 * Re-read the dynlmlst address to obtain a List structure.
8240Sstevel@tonic-gate 		 */
82510167SRod.Evans@Sun.COM 		if (ps_pread(rap->rd_psp, (psaddr_t)db_priv.rtd_dynlmlst,
82610167SRod.Evans@Sun.COM 		    (char *)&list, sizeof (TList)) != PS_OK) {
82710167SRod.Evans@Sun.COM 			LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_3),
82810167SRod.Evans@Sun.COM 			    EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
8290Sstevel@tonic-gate 			return (RD_DBERR);
8300Sstevel@tonic-gate 		}
8310Sstevel@tonic-gate 
8329131SRod.Evans@Sun.COM 		/*
83310167SRod.Evans@Sun.COM 		 * Iterate through the link-map list.
8340Sstevel@tonic-gate 		 */
83510167SRod.Evans@Sun.COM 		for (lnp = (Addr)list.head; lnp; lnp = (Addr)lnode.next) {
83610167SRod.Evans@Sun.COM 			Lm_list	lml;
83710167SRod.Evans@Sun.COM 			ulong_t	ident;
83810167SRod.Evans@Sun.COM 
83910167SRod.Evans@Sun.COM 			/*
84010167SRod.Evans@Sun.COM 			 * Iterate through the List of Lm_list's.
84110167SRod.Evans@Sun.COM 			 */
84210167SRod.Evans@Sun.COM 			if (ps_pread(rap->rd_psp, (psaddr_t)lnp, (char *)&lnode,
84310167SRod.Evans@Sun.COM 			    sizeof (TListnode)) != PS_OK) {
84410167SRod.Evans@Sun.COM 				LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_4),
84510167SRod.Evans@Sun.COM 				    EC_ADDR(lnp)));
84610167SRod.Evans@Sun.COM 					return (RD_DBERR);
84710167SRod.Evans@Sun.COM 			}
8480Sstevel@tonic-gate 
84910167SRod.Evans@Sun.COM 			if (ps_pread(rap->rd_psp, (psaddr_t)lnode.data,
85010167SRod.Evans@Sun.COM 			    (char *)&lml, sizeof (Lm_list)) != PS_OK) {
85110167SRod.Evans@Sun.COM 				LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_5),
85210167SRod.Evans@Sun.COM 				    EC_ADDR((uintptr_t)lnode.data)));
85310167SRod.Evans@Sun.COM 					return (RD_DBERR);
85410167SRod.Evans@Sun.COM 			}
85510167SRod.Evans@Sun.COM 
85610167SRod.Evans@Sun.COM 			/*
85710167SRod.Evans@Sun.COM 			 * Determine IDENT of current LM_LIST
85810167SRod.Evans@Sun.COM 			 */
85910167SRod.Evans@Sun.COM 			if (lml.lm_flags & LML_FLG_BASELM)
86010167SRod.Evans@Sun.COM 				ident = LM_ID_BASE;
86110167SRod.Evans@Sun.COM 			else if (lml.lm_flags & LML_FLG_RTLDLM)
86210167SRod.Evans@Sun.COM 				ident = LM_ID_LDSO;
86310167SRod.Evans@Sun.COM 			else
86410167SRod.Evans@Sun.COM 				ident = (unsigned long)lnode.data;
86510167SRod.Evans@Sun.COM 
86610167SRod.Evans@Sun.COM 			if ((rc = iter_map(rap, ident, (psaddr_t)lml.lm_head,
86710167SRod.Evans@Sun.COM 			    cb, client_data, abort_iterp)) != RD_OK)
86810167SRod.Evans@Sun.COM 				return (rc);
86910167SRod.Evans@Sun.COM 
87010167SRod.Evans@Sun.COM 			if (*abort_iterp != 0)
87110167SRod.Evans@Sun.COM 				break;
8720Sstevel@tonic-gate 		}
8730Sstevel@tonic-gate 	}
8742712Snn35248 
8757924SEdward.Pilatowicz@Sun.COM 	return (rc);
8767924SEdward.Pilatowicz@Sun.COM }
8777924SEdward.Pilatowicz@Sun.COM 
8787924SEdward.Pilatowicz@Sun.COM rd_err_e
_rd_loadobj_iter32(rd_agent_t * rap,rl_iter_f * cb,void * client_data)8797924SEdward.Pilatowicz@Sun.COM _rd_loadobj_iter32(rd_agent_t *rap, rl_iter_f *cb, void *client_data)
8807924SEdward.Pilatowicz@Sun.COM {
8818478SRod.Evans@Sun.COM 	rd_err_e	rc, rc_brand = RD_OK;
8827924SEdward.Pilatowicz@Sun.COM 	uint_t		abort_iter = 0;
8837924SEdward.Pilatowicz@Sun.COM 
8847924SEdward.Pilatowicz@Sun.COM 	/* First iterate over the native target objects */
8857924SEdward.Pilatowicz@Sun.COM 	rc = _rd_loadobj_iter32_native(rap, cb, client_data, &abort_iter);
8867924SEdward.Pilatowicz@Sun.COM 	if (abort_iter != 0)
8872712Snn35248 		return (rc);
8882712Snn35248 
8897924SEdward.Pilatowicz@Sun.COM 	/* Then iterate over any branded objects. */
8907924SEdward.Pilatowicz@Sun.COM 	if ((rap->rd_helper.rh_ops != NULL) &&
8917924SEdward.Pilatowicz@Sun.COM 	    (rap->rd_helper.rh_ops->rho_loadobj_iter != NULL))
8927924SEdward.Pilatowicz@Sun.COM 		rc_brand = rap->rd_helper.rh_ops->rho_loadobj_iter(
8937924SEdward.Pilatowicz@Sun.COM 		    rap->rd_helper.rh_data, cb, client_data);
8942712Snn35248 
8958478SRod.Evans@Sun.COM 	rc = (rc != RD_OK) ? rc : rc_brand;
8967924SEdward.Pilatowicz@Sun.COM 	return (rc);
8970Sstevel@tonic-gate }
898