1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include	<stdlib.h>
29 #include	<stdio.h>
30 #include	<proc_service.h>
31 #include	<link.h>
32 #include	<rtld_db.h>
33 #include	<rtld.h>
34 #include	<_rtld_db.h>
35 #include	<msg.h>
36 #include	<limits.h>
37 #include	<string.h>
38 #include	<sys/param.h>
39 
40 /*
41  * 64-bit builds are going to compile this module twice, the
42  * second time with _ELF64 defined.  These defines should make
43  * all the necessary adjustments to the code.
44  */
45 #ifdef _LP64
46 #ifdef _ELF64
47 #define	_rd_reset32		_rd_reset64
48 #define	_rd_event_enable32	_rd_event_enable64
49 #define	_rd_event_getmsg32	_rd_event_getmsg64
50 #define	_rd_objpad_enable32	_rd_objpad_enable64
51 #define	_rd_loadobj_iter32	_rd_loadobj_iter64
52 #define	find_dynamic_ent32	find_dynamic_ent64
53 #define	TList			List
54 #define	TListnode		Listnode
55 #else	/* ELF32 */
56 #define	Rt_map			Rt_map32
57 #define	Rtld_db_priv		Rtld_db_priv32
58 #define	TList			List32
59 #define	TListnode		Listnode32
60 #define	Lm_list			Lm_list32
61 #endif	/* _ELF64 */
62 #else	/* _LP64 */
63 #define	TList			List
64 #define	TListnode		Listnode
65 #endif	/* _LP64 */
66 
67 /*
68  * BrandZ added ps_pbrandname().  Many debuggers that link directly
69  * against librtld_db.so may not implement this interface.  Hence
70  * we won't call the function directly, instead we'll try to look it
71  * up using the linker first and only invoke it if we find it.
72  */
73 typedef ps_err_e (*ps_pbrandname_fp_t)(struct ps_prochandle *,
74     char *, size_t);
75 
76 static rd_err_e
77 validate_rdebug(struct rd_agent *rap)
78 {
79 	struct ps_prochandle	*php = rap->rd_psp;
80 	psaddr_t		db_privp;
81 	Rtld_db_priv		db_priv;
82 
83 	if (rap->rd_rdebug == 0)
84 		return (RD_ERR);
85 	/*
86 	 * The rtld_db_priv structure contains both the traditional (exposed)
87 	 * r_debug structure as well as private data only available to
88 	 * this library.
89 	 */
90 	db_privp = rap->rd_rdebug;
91 
92 	/*
93 	 * Verify that librtld_db & rtld are at the proper revision
94 	 * levels.
95 	 */
96 	if (ps_pread(php, db_privp, (char *)&db_priv,
97 	    sizeof (Rtld_db_priv)) != PS_OK) {
98 		LOG(ps_plog(MSG_ORIG(MSG_DB_READPRIVFAIL_1),
99 		    EC_ADDR(db_privp)));
100 		return (RD_DBERR);
101 	}
102 
103 	if ((db_priv.rtd_version < R_RTLDDB_VERSION1) ||
104 	    (db_priv.rtd_version > R_RTLDDB_VERSION)) {
105 		LOG(ps_plog(MSG_ORIG(MSG_DB_BADPVERS),
106 		    db_priv.rtd_version, R_RTLDDB_VERSION));
107 		return (RD_NOCAPAB);
108 	}
109 
110 	/*
111 	 * Is the image being examined from a core file or not.
112 	 * If it is a core file then the following write will fail.
113 	 */
114 	if (ps_pwrite(php, db_privp, (char *)&db_priv,
115 	    sizeof (Rtld_db_priv)) != PS_OK)
116 		rap->rd_flags |= RDF_FL_COREFILE;
117 
118 	/*
119 	 * If this *is not* a core file then rtld_db & ld.so.1 are
120 	 * considered tightly coupled.  If the versions of our private
121 	 * data structures don't match - fail!
122 	 */
123 	if (((rap->rd_flags & RDF_FL_COREFILE) == 0) &&
124 	    (db_priv.rtd_version != R_RTLDDB_VERSION)) {
125 		LOG(ps_plog(MSG_ORIG(MSG_DB_BADPVERS),
126 		    db_priv.rtd_version, R_RTLDDB_VERSION));
127 		return (RD_NOCAPAB);
128 	}
129 
130 	rap->rd_rdebugvers = db_priv.rtd_version;
131 	rap->rd_rtlddbpriv = db_privp;
132 
133 	LOG(ps_plog(MSG_ORIG(MSG_DB_VALIDRDEBUG), EC_ADDR(rap->rd_rdebug),
134 	    R_RTLDDB_VERSION, rap->rd_rdebugvers,
135 	    rap->rd_flags & RDF_FL_COREFILE));
136 	return (RD_OK);
137 }
138 
139 
140 rd_err_e
141 find_dynamic_ent32(struct rd_agent *rap, psaddr_t dynaddr,
142 	Xword dyntag, Dyn *dyn)
143 {
144 	struct ps_prochandle	*php = rap->rd_psp;
145 	Dyn			d;
146 
147 	d.d_tag = DT_NULL;
148 	do {
149 		if (ps_pread(php, dynaddr, (void *)(&d), sizeof (d)) !=
150 		    PS_OK) {
151 			LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_4),
152 			    EC_ADDR(dynaddr)));
153 			return (RD_DBERR);
154 		}
155 		dynaddr += sizeof (d);
156 		if (d.d_tag == dyntag)
157 			break;
158 	} while (d.d_tag != DT_NULL);
159 	if (d.d_tag == dyntag) {
160 		*dyn = d;
161 		LOG(ps_plog(MSG_ORIG(MSG_DB_FINDDYNAMIC), EC_ADDR(dyntag),
162 		    EC_ADDR(d.d_un.d_val)));
163 		return (RD_OK);
164 	}
165 	LOG(ps_plog(MSG_ORIG(MSG_DB_NODYNDEBUG), EC_ADDR(dyntag)));
166 	return (RD_DBERR);
167 }
168 
169 extern char rtld_db_helper_path[MAXPATHLEN];
170 
171 #ifndef _ELF64
172 void
173 rd_fix_phdrs(struct rd_agent *rap, Elf32_Dyn *dp, size_t sz, uintptr_t a)
174 {
175 	if (rap->rd_helper.rh_ops != NULL)
176 		rap->rd_helper.rh_ops->rho_fix_phdrs(rap, dp, sz, a);
177 }
178 #endif
179 
180 rd_err_e
181 _rd_reset32(struct rd_agent *rap)
182 {
183 	psaddr_t		symaddr;
184 	struct ps_prochandle	*php = rap->rd_psp;
185 	const auxv_t		*auxvp = NULL;
186 	rd_err_e		rc = RD_OK;
187 	char			brandname[MAXPATHLEN];
188 	char			brandlib[MAXPATHLEN];
189 	ps_pbrandname_fp_t	ps_pbrandname;
190 
191 	/*
192 	 * librtld_db attempts three different methods to find
193 	 * the r_debug structure which is required to
194 	 * initialize itself.  The methods are:
195 	 *	method1:
196 	 *		entirely independent of any text segment
197 	 *		and relies on the AT_SUN_LDDATA auxvector
198 	 *		to find the ld.so.1::rdebug structure.
199 	 *	method2:
200 	 *		lookup symbols in ld.so.1's symbol table
201 	 *		to find the r_debug symbol.
202 	 *	method3:
203 	 *		(old dbx method) dependent upon the
204 	 *		text segment/symbol table of the
205 	 *		executable and not ld.so.1.  We lookup the
206 	 *		_DYNAMIC symbol in the executable and look for
207 	 *		the DT_DEBUG entry in the .dynamic table.  This
208 	 *		points to rdebug.
209 	 *
210 	 * If none of that works - we fail.
211 	 */
212 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDRESET), rap->rd_dmodel));
213 	/*
214 	 * Method1
215 	 *
216 	 * Scan the aux vector looking for AT_BASE & AT_SUN_LDDATA
217 	 */
218 
219 	if (ps_pauxv(php, &auxvp) != PS_OK) {
220 		LOG(ps_plog(MSG_ORIG(MSG_DB_NOAUXV)));
221 		rc = RD_ERR;
222 	}
223 
224 	rap->rd_rdebug = 0;
225 
226 	if (auxvp != NULL) {
227 		rc = RD_ERR;
228 		while (auxvp->a_type != AT_NULL) {
229 			if (auxvp->a_type == AT_SUN_LDDATA) {
230 				/* LINTED */
231 				rap->rd_rdebug = (uintptr_t)auxvp->a_un.a_ptr;
232 				LOG(ps_plog(MSG_ORIG(MSG_DB_FLDDATA),
233 				    rap->rd_rdebug));
234 				rc = validate_rdebug(rap);
235 				break;
236 			}
237 			auxvp++;
238 		}
239 	}
240 
241 	/*
242 	 * method2 - look for r_rdebug symbol in ld.so.1
243 	 */
244 	if (rc != RD_OK) {
245 		/*
246 		 * If the AT_SUN_LDDATA auxv vector is not present
247 		 * fall back on doing a symlookup of
248 		 * the r_debug symbol.  This is for backward
249 		 * compatiblity with older OS's
250 		 */
251 		LOG(ps_plog(MSG_ORIG(MSG_DB_NOLDDATA)));
252 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO, MSG_ORIG(MSG_SYM_DEBUG),
253 		    &symaddr) != PS_OK) {
254 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
255 			    MSG_ORIG(MSG_SYM_DEBUG)));
256 			rc = RD_DBERR;
257 		} else {
258 			rap->rd_rdebug = symaddr;
259 			LOG(ps_plog(MSG_ORIG(MSG_DB_SYMRDEBUG),
260 			    EC_ADDR(symaddr)));
261 			rc = validate_rdebug(rap);
262 		}
263 	}
264 
265 
266 	/*
267 	 * method3 - find DT_DEBUG in the executables .dynamic section.
268 	 */
269 	if (rc != RD_OK) {
270 		Dyn	dyn;
271 		if (ps_pglobal_lookup(php, PS_OBJ_EXEC,
272 		    MSG_ORIG(MSG_SYM_DYNAMIC), &symaddr) != PS_OK) {
273 			LOG(ps_plog(MSG_ORIG(MSG_DB_NODYNAMIC)));
274 			LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED)));
275 			return (rc);
276 		}
277 		rc = find_dynamic_ent32(rap, symaddr, DT_DEBUG, &dyn);
278 		if (rc != RD_OK) {
279 			LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED)));
280 			return (rc);
281 		}
282 		rap->rd_rdebug = dyn.d_un.d_ptr;
283 		rc = validate_rdebug(rap);
284 		if (rc != RD_OK) {
285 			LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED)));
286 			return (rc);
287 		}
288 	}
289 
290 	/*
291 	 * If we are debugging a branded executable, load the appropriate helper
292 	 * library, and call its initialization routine.
293 	 */
294 	ps_pbrandname = (ps_pbrandname_fp_t)dlsym(RTLD_PROBE, "ps_pbrandname");
295 	if ((ps_pbrandname != NULL) &&
296 	    (ps_pbrandname(php, brandname, MAXPATHLEN) == PS_OK)) {
297 		const char *isa = "";
298 
299 #ifdef __amd64
300 		isa = MSG_ORIG(MSG_DB_64BIT_PREFIX);
301 #endif /* __amd64 */
302 
303 		if (rtld_db_helper_path[0] != '\0')
304 			(void) snprintf(brandlib, MAXPATHLEN,
305 			    MSG_ORIG(MSG_DB_BRAND_HELPERPATH_PREFIX),
306 			    rtld_db_helper_path,
307 			    MSG_ORIG(MSG_DB_HELPER_PREFIX), brandname, isa,
308 			    brandname);
309 		else
310 			(void) snprintf(brandlib, MAXPATHLEN,
311 			    MSG_ORIG(MSG_DB_BRAND_HELPERPATH),
312 			    MSG_ORIG(MSG_DB_HELPER_PREFIX), brandname, isa,
313 			    brandname);
314 
315 		if ((rap->rd_helper.rh_dlhandle = dlopen(brandlib,
316 		    RTLD_LAZY | RTLD_LOCAL)) == NULL) {
317 			LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERLOADFAILED),
318 			    brandlib));
319 			return (RD_ERR);
320 		}
321 
322 		if ((rap->rd_helper.rh_ops = dlsym(rap->rd_helper.rh_dlhandle,
323 		    MSG_ORIG(MSG_SYM_BRANDOPS))) == NULL) {
324 			LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERNOOPS),
325 			    brandlib));
326 			return (RD_ERR);
327 		}
328 
329 		rap->rd_helper.rh_data = rap->rd_helper.rh_ops->rho_init(php);
330 		if (rap->rd_helper.rh_data == NULL) {
331 			LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERINITFAILED)));
332 			(void) dlclose(rap->rd_helper.rh_dlhandle);
333 			rap->rd_helper.rh_dlhandle = NULL;
334 			rap->rd_helper.rh_ops = NULL;
335 		} else
336 			LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERLOADED), brandname));
337 	}
338 
339 	if ((rap->rd_flags & RDF_FL_COREFILE) == 0) {
340 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO,
341 		    MSG_ORIG(MSG_SYM_PREINIT), &symaddr) != PS_OK) {
342 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
343 			    MSG_ORIG(MSG_SYM_PREINIT)));
344 			return (RD_DBERR);
345 		}
346 		rap->rd_preinit = symaddr;
347 
348 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO,
349 		    MSG_ORIG(MSG_SYM_POSTINIT), &symaddr) != PS_OK) {
350 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
351 			    MSG_ORIG(MSG_SYM_POSTINIT)));
352 			return (RD_DBERR);
353 		}
354 		rap->rd_postinit = symaddr;
355 
356 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO,
357 		    MSG_ORIG(MSG_SYM_DLACT), &symaddr) != PS_OK) {
358 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
359 			    MSG_ORIG(MSG_SYM_DLACT)));
360 			return (RD_DBERR);
361 		}
362 		rap->rd_dlact = symaddr;
363 		rap->rd_tbinder = 0;
364 	}
365 
366 	return (RD_OK);
367 }
368 
369 rd_err_e
370 _rd_event_enable32(rd_agent_t *rap, int onoff)
371 {
372 	struct ps_prochandle	*php = rap->rd_psp;
373 	Rtld_db_priv		rdb;
374 
375 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDEVENTENABLE), rap->rd_dmodel, onoff));
376 	/*
377 	 * Tell the debugged process that debugging is occuring
378 	 * This will enable the storing of event messages so that
379 	 * the can be gathered by the debugger.
380 	 */
381 	if (ps_pread(php, rap->rd_rdebug, (char *)&rdb,
382 	    sizeof (Rtld_db_priv)) != PS_OK) {
383 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_1),
384 		    EC_ADDR((uintptr_t)&rdb)));
385 		return (RD_DBERR);
386 	}
387 
388 	if (onoff)
389 		rdb.rtd_rdebug.r_flags |= RD_FL_DBG;
390 	else
391 		rdb.rtd_rdebug.r_flags &= ~RD_FL_DBG;
392 
393 	if (ps_pwrite(php, rap->rd_rdebug, (char *)&rdb,
394 	    sizeof (Rtld_db_priv)) != PS_OK) {
395 		LOG(ps_plog(MSG_ORIG(MSG_DB_WRITEFAIL_1),
396 		    EC_ADDR((uintptr_t)&rdb)));
397 		return (RD_DBERR);
398 	}
399 
400 	return (RD_OK);
401 }
402 
403 
404 rd_err_e
405 _rd_event_getmsg32(rd_agent_t *rap, rd_event_msg_t *emsg)
406 {
407 	Rtld_db_priv	rdb;
408 
409 	if (ps_pread(rap->rd_psp, rap->rd_rdebug, (char *)&rdb,
410 	    sizeof (Rtld_db_priv)) != PS_OK) {
411 		LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_2),
412 		    EC_ADDR(rap->rd_rdebug)));
413 		return (RD_DBERR);
414 	}
415 	emsg->type = rdb.rtd_rdebug.r_rdevent;
416 	if (emsg->type == RD_DLACTIVITY) {
417 		switch (rdb.rtd_rdebug.r_state) {
418 			case RT_CONSISTENT:
419 				emsg->u.state = RD_CONSISTENT;
420 				break;
421 			case RT_ADD:
422 				emsg->u.state = RD_ADD;
423 				break;
424 			case RT_DELETE:
425 				emsg->u.state = RD_DELETE;
426 				break;
427 		}
428 	} else
429 		emsg->u.state = RD_NOSTATE;
430 
431 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDEVENTGETMSG), rap->rd_dmodel,
432 	    emsg->type, emsg->u.state));
433 
434 	return (RD_OK);
435 }
436 
437 
438 rd_err_e
439 _rd_objpad_enable32(struct rd_agent *rap, size_t padsize)
440 {
441 	Rtld_db_priv		db_priv;
442 	struct ps_prochandle	*php = rap->rd_psp;
443 
444 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDOBJPADE), EC_ADDR(padsize)));
445 
446 	if (ps_pread(php, rap->rd_rtlddbpriv, (char *)&db_priv,
447 	    sizeof (Rtld_db_priv)) != PS_OK) {
448 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_3),
449 		    EC_ADDR(rap->rd_rtlddbpriv)));
450 		return (RD_DBERR);
451 	}
452 #if	defined(_LP64) && !defined(_ELF64)
453 	/*LINTED*/
454 	db_priv.rtd_objpad = (uint32_t)padsize;
455 #else
456 	db_priv.rtd_objpad = padsize;
457 #endif
458 	if (ps_pwrite(php, rap->rd_rtlddbpriv, (char *)&db_priv,
459 	    sizeof (Rtld_db_priv)) != PS_OK) {
460 		LOG(ps_plog(MSG_ORIG(MSG_DB_WRITEFAIL_2),
461 		    EC_ADDR(rap->rd_rtlddbpriv)));
462 		return (RD_DBERR);
463 	}
464 	return (RD_OK);
465 }
466 
467 static rd_err_e
468 iter_map(rd_agent_t *rap, unsigned long ident, psaddr_t lmaddr,
469 	rl_iter_f *cb, void *client_data, uint_t *abort_iter)
470 {
471 	while (lmaddr) {
472 		Rt_map		rmap;
473 		rd_loadobj_t	lobj;
474 		int		i;
475 		ulong_t		off;
476 		Ehdr		ehdr;
477 		Phdr		phdr;
478 
479 		if (ps_pread(rap->rd_psp, lmaddr, (char *)&rmap,
480 		    sizeof (Rt_map)) != PS_OK) {
481 			LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPFAIL)));
482 			return (RD_DBERR);
483 		}
484 
485 		/*
486 		 * As of 'VERSION5' we only report objects
487 		 * which have been fully relocated.  While the maps
488 		 * might be in a consistent state - if a object hasn't
489 		 * been relocated - it's not really ready for the debuggers
490 		 * to examine.  This is mostly due to the fact that we
491 		 * might still be mucking with the text-segment, if
492 		 * we are - we could conflict with any break-points
493 		 * the debuggers might have set.
494 		 */
495 		if (rap->rd_rdebugvers >= R_RTLDDB_VERSION5) {
496 			if ((FLAGS(&rmap) & FLG_RT_RELOCED) == 0) {
497 				lmaddr = (psaddr_t)NEXT(&rmap);
498 				continue;
499 			}
500 		}
501 
502 		lobj.rl_base = (psaddr_t)ADDR(&rmap);
503 		lobj.rl_flags = 0;
504 		lobj.rl_refnameaddr = (psaddr_t)REFNAME(&rmap);
505 		if (rap->rd_helper.rh_dlhandle != NULL)
506 			lobj.rl_lmident = LM_ID_BRAND;
507 		else
508 			lobj.rl_lmident = ident;
509 
510 		/*
511 		 * refnameaddr is only valid from a core file
512 		 * which is VERSION3 or greater.
513 		 */
514 		if (rap->rd_rdebugvers < R_RTLDDB_VERSION3) {
515 			lobj.rl_nameaddr = (psaddr_t)NAME(&rmap);
516 			lobj.rl_bend = 0;
517 			lobj.rl_padstart = 0;
518 			lobj.rl_padend = 0;
519 		} else {
520 			lobj.rl_nameaddr = (psaddr_t)PATHNAME(&rmap);
521 			lobj.rl_bend = ADDR(&rmap) + MSIZE(&rmap);
522 			lobj.rl_padstart = PADSTART(&rmap);
523 			lobj.rl_padend = PADSTART(&rmap) + PADIMLEN(&rmap);
524 
525 		}
526 
527 		if (rtld_db_version >= RD_VERSION2)
528 			if (FLAGS(&rmap) & FLG_RT_IMGALLOC)
529 				lobj.rl_flags |= RD_FLG_MEM_OBJECT;
530 		if (rtld_db_version >= RD_VERSION2) {
531 			lobj.rl_dynamic = (psaddr_t)DYN(&rmap);
532 		}
533 
534 		if (rtld_db_version >= RD_VERSION4)
535 			lobj.rl_tlsmodid = TLSMODID(&rmap);
536 
537 		/*
538 		 * Look for beginning of data segment.
539 		 *
540 		 * NOTE: the data segment can only be found for full
541 		 *	processes and not from core images.
542 		 */
543 		lobj.rl_data_base = 0;
544 		if (rap->rd_flags & RDF_FL_COREFILE)
545 			lobj.rl_data_base = 0;
546 		else {
547 			off = ADDR(&rmap);
548 			if (ps_pread(rap->rd_psp, off, (char *)&ehdr,
549 			    sizeof (Ehdr)) != PS_OK) {
550 				LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPFAIL)));
551 				return (RD_DBERR);
552 			}
553 			off += sizeof (Ehdr);
554 			for (i = 0; i < ehdr.e_phnum; i++) {
555 				if (ps_pread(rap->rd_psp, off, (char *)&phdr,
556 				    sizeof (Phdr)) != PS_OK) {
557 					LOG(ps_plog(MSG_ORIG(
558 					    MSG_DB_LKMAPFAIL)));
559 					return (RD_DBERR);
560 				}
561 				if ((phdr.p_type == PT_LOAD) &&
562 				    (phdr.p_flags & PF_W)) {
563 					lobj.rl_data_base = phdr.p_vaddr;
564 					if (ehdr.e_type == ET_DYN)
565 						lobj.rl_data_base +=
566 						    ADDR(&rmap);
567 					break;
568 				}
569 				off += ehdr.e_phentsize;
570 			}
571 		}
572 
573 		/*
574 		 * When we transfer control to the client we free the
575 		 * lock and re-atain it after we've returned from the
576 		 * client.  This is to avoid any deadlock situations.
577 		 */
578 		LOG(ps_plog(MSG_ORIG(MSG_DB_ITERMAP), cb, client_data,
579 		    EC_ADDR(lobj.rl_base), EC_ADDR(lobj.rl_lmident)));
580 		RDAGUNLOCK(rap);
581 		if ((*cb)(&lobj, client_data) == 0) {
582 			LOG(ps_plog(MSG_ORIG(MSG_DB_CALLBACKR0)));
583 			RDAGLOCK(rap);
584 			*abort_iter = 1;
585 			break;
586 		}
587 		RDAGLOCK(rap);
588 		lmaddr = (psaddr_t)NEXT(&rmap);
589 	}
590 	return (RD_OK);
591 }
592 
593 
594 rd_err_e
595 _rd_loadobj_iter32(rd_agent_t *rap, rl_iter_f *cb, void *client_data)
596 {
597 	Rtld_db_priv	db_priv;
598 	TList		list;
599 	TListnode	lnode;
600 	Addr		lnp;
601 	unsigned long	ident;
602 	rd_err_e	rc;
603 	uint_t		abort_iter = 0;
604 
605 	LOG(ps_plog(MSG_ORIG(MSG_DB_LOADOBJITER), rap->rd_dmodel, cb,
606 	    client_data));
607 
608 	if (ps_pread(rap->rd_psp, rap->rd_rtlddbpriv, (char *)&db_priv,
609 	    sizeof (Rtld_db_priv)) != PS_OK) {
610 		LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_1),
611 		    EC_ADDR(rap->rd_rtlddbpriv)));
612 		return (RD_DBERR);
613 	}
614 
615 	if (db_priv.rtd_dynlmlst == 0) {
616 		LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPNOINIT),
617 		    EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
618 		return (RD_NOMAPS);
619 	}
620 
621 	if (ps_pread(rap->rd_psp, (psaddr_t)db_priv.rtd_dynlmlst, (char *)&list,
622 	    sizeof (TList)) != PS_OK) {
623 		LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_3),
624 		    EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
625 		return (RD_DBERR);
626 	}
627 
628 	if (list.head == 0) {
629 		LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPNOINIT_1),
630 		    EC_ADDR((uintptr_t)list.head)));
631 		return (RD_NOMAPS);
632 	}
633 
634 
635 	if (cb == 0) {
636 		LOG(ps_plog(MSG_ORIG(MSG_DB_NULLITER)));
637 		return (RD_ERR);
638 	}
639 
640 	for (lnp = (Addr)list.head; lnp; lnp = (Addr)lnode.next) {
641 		Lm_list	lml;
642 
643 		/*
644 		 * Iterate through the List of Lm_list's.
645 		 */
646 		if (ps_pread(rap->rd_psp, (psaddr_t)lnp, (char *)&lnode,
647 		    sizeof (TListnode)) != PS_OK) {
648 			LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_4),
649 			    EC_ADDR(lnp)));
650 			return (RD_DBERR);
651 		}
652 
653 		if (ps_pread(rap->rd_psp, (psaddr_t)lnode.data, (char *)&lml,
654 		    sizeof (Lm_list)) != PS_OK) {
655 			LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_5),
656 			    EC_ADDR((uintptr_t)lnode.data)));
657 			return (RD_DBERR);
658 		}
659 
660 		/*
661 		 * Determine IDENT of current LM_LIST
662 		 */
663 		if (lml.lm_flags & LML_FLG_BASELM)
664 			ident = LM_ID_BASE;
665 		else if (lml.lm_flags & LML_FLG_RTLDLM)
666 			ident = LM_ID_LDSO;
667 		else
668 			ident = (unsigned long)lnode.data;
669 
670 		if ((rc = iter_map(rap, ident, (psaddr_t)lml.lm_head,
671 		    cb, client_data, &abort_iter)) != RD_OK) {
672 			return (rc);
673 		}
674 		if (abort_iter)
675 			break;
676 	}
677 
678 	if (rc != RD_OK)
679 		return (rc);
680 
681 	if (rap->rd_helper.rh_ops != NULL)
682 		return (rap->rd_helper.rh_ops->rho_loadobj_iter(rap->rd_psp, cb,
683 		    client_data, rap->rd_helper.rh_data));
684 
685 	return (RD_OK);
686 }
687