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