xref: /illumos-gate/usr/src/cmd/sgs/librtld_db/common/rd_elf.c (revision ef2504f26d1ea5859db9838255bb63f488f1b050)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include	<stdlib.h>
27 #include	<stdio.h>
28 #include	<proc_service.h>
29 #include	<link.h>
30 #include	<rtld_db.h>
31 #include	<rtld.h>
32 #include	<alist.h>
33 #include	<_rtld_db.h>
34 #include	<msg.h>
35 #include	<limits.h>
36 #include	<string.h>
37 #include	<sys/param.h>
38 
39 /*
40  * 64-bit builds are going to compile this module twice, the
41  * second time with _ELF64 defined.  These defines should make
42  * all the necessary adjustments to the code.
43  */
44 #ifdef _LP64
45 #ifdef _ELF64
46 #define	_rd_event_enable32	_rd_event_enable64
47 #define	_rd_event_getmsg32	_rd_event_getmsg64
48 #define	_rd_get_dyns32		_rd_get_dyns64
49 #define	_rd_get_ehdr32		_rd_get_ehdr64
50 #define	_rd_objpad_enable32	_rd_objpad_enable64
51 #define	_rd_loadobj_iter32	_rd_loadobj_iter64
52 #define	_rd_reset32		_rd_reset64
53 #define	find_dynamic_ent32	find_dynamic_ent64
54 #define	validate_rdebug32	validate_rdebug64
55 #define	TAPlist			APlist
56 #define	TLm_list		Lm_list
57 #define	MSG_SYM_BRANDOPS	MSG_SYM_BRANDOPS_64
58 #else	/* ELF32 */
59 #define	Rt_map			Rt_map32
60 #define	Rtld_db_priv		Rtld_db_priv32
61 #define	TAPlist			APlist32
62 #define	TLm_list		Lm_list32
63 #define	MSG_SYM_BRANDOPS	MSG_SYM_BRANDOPS_32
64 #endif	/* _ELF64 */
65 #else	/* _LP64 */
66 #define	TAPlist			APlist
67 #define	TLm_list		Lm_list
68 #define	MSG_SYM_BRANDOPS	MSG_SYM_BRANDOPS_32
69 #endif	/* _LP64 */
70 
71 /*
72  * BrandZ added ps_pbrandname().  Many debuggers that link directly
73  * against librtld_db.so may not implement this interface.  Hence
74  * we won't call the function directly, instead we'll try to look it
75  * up using the linker first and only invoke it if we find it.
76  */
77 typedef ps_err_e (*ps_pbrandname_fp_t)(struct ps_prochandle *,
78     char *, size_t);
79 
80 rd_err_e
81 validate_rdebug32(struct rd_agent *rap)
82 {
83 	struct ps_prochandle	*php = rap->rd_psp;
84 	psaddr_t		db_privp;
85 	Rtld_db_priv		db_priv;
86 
87 	if (rap->rd_rdebug == 0)
88 		return (RD_ERR);
89 	/*
90 	 * The rtld_db_priv structure contains both the traditional (exposed)
91 	 * r_debug structure as well as private data only available to
92 	 * this library.
93 	 */
94 	db_privp = rap->rd_rdebug;
95 
96 	/*
97 	 * Verify that librtld_db & rtld are at the proper revision
98 	 * levels.
99 	 */
100 	if (ps_pread(php, db_privp, (char *)&db_priv,
101 	    sizeof (Rtld_db_priv)) != PS_OK) {
102 		LOG(ps_plog(MSG_ORIG(MSG_DB_READPRIVFAIL_1),
103 		    EC_ADDR(db_privp)));
104 		return (RD_DBERR);
105 	}
106 
107 	if ((db_priv.rtd_version < R_RTLDDB_VERSION1) ||
108 	    (db_priv.rtd_version > R_RTLDDB_VERSION)) {
109 		LOG(ps_plog(MSG_ORIG(MSG_DB_BADPVERS),
110 		    db_priv.rtd_version, R_RTLDDB_VERSION));
111 		return (RD_NOCAPAB);
112 	}
113 
114 	/*
115 	 * Is the image being examined from a core file or not.
116 	 * If it is a core file then the following write will fail.
117 	 */
118 	if (ps_pwrite(php, db_privp, (char *)&db_priv,
119 	    sizeof (Rtld_db_priv)) != PS_OK)
120 		rap->rd_flags |= RDF_FL_COREFILE;
121 
122 	/*
123 	 * If this *is not* a core file then rtld_db & ld.so.1 are
124 	 * considered tightly coupled.  If the versions of our private
125 	 * data structures don't match - fail!
126 	 */
127 	if (((rap->rd_flags & RDF_FL_COREFILE) == 0) &&
128 	    (db_priv.rtd_version != R_RTLDDB_VERSION)) {
129 		LOG(ps_plog(MSG_ORIG(MSG_DB_BADPVERS),
130 		    db_priv.rtd_version, R_RTLDDB_VERSION));
131 		return (RD_NOCAPAB);
132 	}
133 
134 	rap->rd_rdebugvers = db_priv.rtd_version;
135 	rap->rd_rtlddbpriv = db_privp;
136 
137 	LOG(ps_plog(MSG_ORIG(MSG_DB_VALIDRDEBUG), EC_ADDR(rap->rd_rdebug),
138 	    R_RTLDDB_VERSION, rap->rd_rdebugvers,
139 	    rap->rd_flags & RDF_FL_COREFILE));
140 	return (RD_OK);
141 }
142 
143 
144 rd_err_e
145 find_dynamic_ent32(struct rd_agent *rap, psaddr_t dynaddr,
146 	Xword dyntag, Dyn *dyn)
147 {
148 	struct ps_prochandle	*php = rap->rd_psp;
149 	Dyn			d;
150 
151 	d.d_tag = DT_NULL;
152 	do {
153 		if (ps_pread(php, dynaddr, (void *)(&d), sizeof (d)) !=
154 		    PS_OK) {
155 			LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_4),
156 			    EC_ADDR(dynaddr)));
157 			return (RD_DBERR);
158 		}
159 		dynaddr += sizeof (d);
160 		if (d.d_tag == dyntag)
161 			break;
162 	} while (d.d_tag != DT_NULL);
163 	if (d.d_tag == dyntag) {
164 		*dyn = d;
165 		LOG(ps_plog(MSG_ORIG(MSG_DB_FINDDYNAMIC), EC_ADDR(dyntag),
166 		    EC_ADDR(d.d_un.d_val)));
167 		return (RD_OK);
168 	}
169 	LOG(ps_plog(MSG_ORIG(MSG_DB_NODYNDEBUG), EC_ADDR(dyntag)));
170 	return (RD_DBERR);
171 }
172 
173 extern char rtld_db_helper_path[MAXPATHLEN];
174 
175 rd_err_e
176 _rd_reset32(struct rd_agent *rap)
177 {
178 	psaddr_t		symaddr;
179 	struct ps_prochandle	*php = rap->rd_psp;
180 	const auxv_t		*auxvp = NULL;
181 	rd_err_e		rc = RD_OK;
182 	char			brandname[MAXPATHLEN];
183 	char			brandlib[MAXPATHLEN];
184 	ps_pbrandname_fp_t	ps_pbrandname;
185 
186 	/*
187 	 * librtld_db attempts three different methods to find
188 	 * the r_debug structure which is required to
189 	 * initialize itself.  The methods are:
190 	 *	method1:
191 	 *		entirely independent of any text segment
192 	 *		and relies on the AT_SUN_LDDATA auxvector
193 	 *		to find the ld.so.1::rdebug structure.
194 	 *	method2:
195 	 *		lookup symbols in ld.so.1's symbol table
196 	 *		to find the r_debug symbol.
197 	 *	method3:
198 	 *		(old dbx method) dependent upon the
199 	 *		text segment/symbol table of the
200 	 *		executable and not ld.so.1.  We lookup the
201 	 *		_DYNAMIC symbol in the executable and look for
202 	 *		the DT_DEBUG entry in the .dynamic table.  This
203 	 *		points to rdebug.
204 	 *
205 	 * If none of that works - we fail.
206 	 */
207 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDRESET), rap->rd_dmodel));
208 	/*
209 	 * Method1
210 	 *
211 	 * Scan the aux vector looking for AT_BASE & AT_SUN_LDDATA
212 	 */
213 
214 	if (ps_pauxv(php, &auxvp) != PS_OK) {
215 		LOG(ps_plog(MSG_ORIG(MSG_DB_NOAUXV)));
216 		rc = RD_ERR;
217 	}
218 
219 	rap->rd_rdebug = 0;
220 
221 	if (auxvp != NULL) {
222 		rc = RD_ERR;
223 		while (auxvp->a_type != AT_NULL) {
224 			if (auxvp->a_type == AT_SUN_LDDATA) {
225 				/* LINTED */
226 				rap->rd_rdebug = (uintptr_t)auxvp->a_un.a_ptr;
227 				LOG(ps_plog(MSG_ORIG(MSG_DB_FLDDATA),
228 				    rap->rd_rdebug));
229 				rc = validate_rdebug32(rap);
230 				break;
231 			}
232 			auxvp++;
233 		}
234 	}
235 
236 	/*
237 	 * method2 - look for r_rdebug symbol in ld.so.1
238 	 */
239 	if (rc != RD_OK) {
240 		/*
241 		 * If the AT_SUN_LDDATA auxv vector is not present
242 		 * fall back on doing a symlookup of
243 		 * the r_debug symbol.  This is for backward
244 		 * compatiblity with older OS's
245 		 */
246 		LOG(ps_plog(MSG_ORIG(MSG_DB_NOLDDATA)));
247 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO, MSG_ORIG(MSG_SYM_DEBUG),
248 		    &symaddr) != PS_OK) {
249 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
250 			    MSG_ORIG(MSG_SYM_DEBUG)));
251 			rc = RD_DBERR;
252 		} else {
253 			rap->rd_rdebug = symaddr;
254 			LOG(ps_plog(MSG_ORIG(MSG_DB_SYMRDEBUG),
255 			    EC_ADDR(symaddr)));
256 			rc = validate_rdebug32(rap);
257 		}
258 	}
259 
260 
261 	/*
262 	 * method3 - find DT_DEBUG in the executables .dynamic section.
263 	 */
264 	if (rc != RD_OK) {
265 		Dyn	dyn;
266 		if (ps_pglobal_lookup(php, PS_OBJ_EXEC,
267 		    MSG_ORIG(MSG_SYM_DYNAMIC), &symaddr) != PS_OK) {
268 			LOG(ps_plog(MSG_ORIG(MSG_DB_NODYNAMIC)));
269 			LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED)));
270 			return (rc);
271 		}
272 		rc = find_dynamic_ent32(rap, symaddr, DT_DEBUG, &dyn);
273 		if (rc != RD_OK) {
274 			LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED)));
275 			return (rc);
276 		}
277 		rap->rd_rdebug = dyn.d_un.d_ptr;
278 		rc = validate_rdebug32(rap);
279 		if (rc != RD_OK) {
280 			LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED)));
281 			return (rc);
282 		}
283 	}
284 
285 	/*
286 	 * If we are debugging a branded executable, load the appropriate
287 	 * helper library, and call its initialization routine.  Being unable
288 	 * to load the helper library is not a critical error.  (Hopefully
289 	 * we'll still be able to access some objects in the target.)
290 	 */
291 	ps_pbrandname = (ps_pbrandname_fp_t)dlsym(RTLD_PROBE, "ps_pbrandname");
292 	while ((ps_pbrandname != NULL) &&
293 	    (ps_pbrandname(php, brandname, MAXPATHLEN) == PS_OK)) {
294 		const char *isa = "";
295 
296 #ifdef _LP64
297 		isa = MSG_ORIG(MSG_DB_64BIT_PREFIX);
298 #endif /* _LP64 */
299 
300 		if (rtld_db_helper_path[0] != '\0')
301 			(void) snprintf(brandlib, MAXPATHLEN,
302 			    MSG_ORIG(MSG_DB_BRAND_HELPERPATH_PREFIX),
303 			    rtld_db_helper_path,
304 			    MSG_ORIG(MSG_DB_HELPER_PREFIX), brandname, isa,
305 			    brandname);
306 		else
307 			(void) snprintf(brandlib, MAXPATHLEN,
308 			    MSG_ORIG(MSG_DB_BRAND_HELPERPATH),
309 			    MSG_ORIG(MSG_DB_HELPER_PREFIX), brandname, isa,
310 			    brandname);
311 
312 		rap->rd_helper.rh_dlhandle = dlopen(brandlib,
313 		    RTLD_LAZY | RTLD_LOCAL);
314 		if (rap->rd_helper.rh_dlhandle == NULL) {
315 			LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERLOADFAILED),
316 			    brandlib));
317 			break;
318 		}
319 
320 		rap->rd_helper.rh_ops = dlsym(rap->rd_helper.rh_dlhandle,
321 		    MSG_ORIG(MSG_SYM_BRANDOPS));
322 		if (rap->rd_helper.rh_ops == NULL) {
323 			LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERNOOPS),
324 			    brandlib));
325 			(void) dlclose(rap->rd_helper.rh_dlhandle);
326 			rap->rd_helper.rh_dlhandle = NULL;
327 			break;
328 		}
329 
330 		rap->rd_helper.rh_data = rap->rd_helper.rh_ops->rho_init(rap,
331 		    php);
332 		if (rap->rd_helper.rh_data == NULL) {
333 			LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERINITFAILED)));
334 			(void) dlclose(rap->rd_helper.rh_dlhandle);
335 			rap->rd_helper.rh_dlhandle = NULL;
336 			rap->rd_helper.rh_ops = NULL;
337 			break;
338 		}
339 
340 		LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERLOADED), brandname));
341 		break;
342 
343 		/* NOTREACHED */
344 	}
345 
346 	if ((rap->rd_flags & RDF_FL_COREFILE) == 0) {
347 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO,
348 		    MSG_ORIG(MSG_SYM_PREINIT), &symaddr) != PS_OK) {
349 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
350 			    MSG_ORIG(MSG_SYM_PREINIT)));
351 			return (RD_DBERR);
352 		}
353 		rap->rd_preinit = symaddr;
354 
355 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO,
356 		    MSG_ORIG(MSG_SYM_POSTINIT), &symaddr) != PS_OK) {
357 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
358 			    MSG_ORIG(MSG_SYM_POSTINIT)));
359 			return (RD_DBERR);
360 		}
361 		rap->rd_postinit = symaddr;
362 
363 		if (ps_pglobal_lookup(php, PS_OBJ_LDSO,
364 		    MSG_ORIG(MSG_SYM_DLACT), &symaddr) != PS_OK) {
365 			LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
366 			    MSG_ORIG(MSG_SYM_DLACT)));
367 			return (RD_DBERR);
368 		}
369 		rap->rd_dlact = symaddr;
370 		rap->rd_tbinder = 0;
371 	}
372 
373 	return (RD_OK);
374 }
375 
376 rd_err_e
377 _rd_get_ehdr32(struct rd_agent *rap,
378     psaddr_t addr, Ehdr *ehdr, uint_t *phnum)
379 {
380 	struct ps_prochandle	*php = rap->rd_psp;
381 	Shdr			shdr;
382 
383 	if (ps_pread(php, addr, ehdr, sizeof (*ehdr)) != PS_OK) {
384 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_5), EC_ADDR(addr)));
385 		return (RD_ERR);
386 	}
387 	if (phnum == NULL)
388 		return (RD_OK);
389 
390 	if (ehdr->e_phnum != PN_XNUM) {
391 		*phnum = ehdr->e_phnum;
392 		return (RD_OK);
393 	}
394 
395 	/* deal with elf extended program headers */
396 	if ((ehdr->e_shoff == 0) || (ehdr->e_shentsize < sizeof (shdr)))
397 		return (RD_ERR);
398 
399 	addr += ehdr->e_shoff;
400 	if (ps_pread(php, addr, &shdr, sizeof (shdr)) != PS_OK) {
401 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_5), EC_ADDR(addr)));
402 		return (RD_ERR);
403 	}
404 
405 	if (shdr.sh_info == 0)
406 		return (RD_ERR);
407 
408 	*phnum = shdr.sh_info;
409 	return (RD_OK);
410 }
411 
412 rd_err_e
413 _rd_get_dyns32(rd_agent_t *rap, psaddr_t addr, Dyn **dynpp, size_t *dynpp_sz)
414 {
415 	struct ps_prochandle	*php = rap->rd_psp;
416 	rd_err_e		err;
417 	uint_t			phnum;
418 	Ehdr			ehdr;
419 	Phdr			phdr;
420 	Dyn			*dynp;
421 	int			i;
422 
423 	/* We only need to muck with dyn elements for ET_DYN objects */
424 	if ((err = _rd_get_ehdr32(rap, addr, &ehdr, &phnum)) != RD_OK)
425 		return (err);
426 
427 	for (i = 0; i < phnum; i++) {
428 		psaddr_t a = addr + ehdr.e_phoff + (i * ehdr.e_phentsize);
429 		if (ps_pread(php, a, &phdr, sizeof (phdr)) != PS_OK) {
430 			LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_6), EC_ADDR(a)));
431 			return (RD_ERR);
432 		}
433 		if (phdr.p_type == PT_DYNAMIC)
434 			break;
435 	}
436 	if (i == phnum)
437 		return (RD_ERR);
438 
439 	if ((dynp = malloc(phdr.p_filesz)) == NULL)
440 		return (RD_ERR);
441 	if (ehdr.e_type == ET_DYN)
442 		phdr.p_vaddr += addr;
443 	if (ps_pread(php, phdr.p_vaddr, dynp, phdr.p_filesz) != PS_OK) {
444 		free(dynp);
445 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_6),
446 		    EC_ADDR(phdr.p_vaddr)));
447 		return (RD_ERR);
448 	}
449 
450 	*dynpp = dynp;
451 	if (dynpp_sz != NULL)
452 		*dynpp_sz = phdr.p_filesz;
453 	return (RD_OK);
454 }
455 
456 rd_err_e
457 _rd_event_enable32(rd_agent_t *rap, int onoff)
458 {
459 	struct ps_prochandle	*php = rap->rd_psp;
460 	Rtld_db_priv		rdb;
461 
462 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDEVENTENABLE), rap->rd_dmodel, onoff));
463 	/*
464 	 * Tell the debugged process that debugging is occuring
465 	 * This will enable the storing of event messages so that
466 	 * the can be gathered by the debugger.
467 	 */
468 	if (ps_pread(php, rap->rd_rdebug, (char *)&rdb,
469 	    sizeof (Rtld_db_priv)) != PS_OK) {
470 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_1),
471 		    EC_ADDR((uintptr_t)&rdb)));
472 		return (RD_DBERR);
473 	}
474 
475 	if (onoff)
476 		rdb.rtd_rdebug.r_flags |= RD_FL_DBG;
477 	else
478 		rdb.rtd_rdebug.r_flags &= ~RD_FL_DBG;
479 
480 	if (ps_pwrite(php, rap->rd_rdebug, (char *)&rdb,
481 	    sizeof (Rtld_db_priv)) != PS_OK) {
482 		LOG(ps_plog(MSG_ORIG(MSG_DB_WRITEFAIL_1),
483 		    EC_ADDR((uintptr_t)&rdb)));
484 		return (RD_DBERR);
485 	}
486 
487 	return (RD_OK);
488 }
489 
490 
491 rd_err_e
492 _rd_event_getmsg32(rd_agent_t *rap, rd_event_msg_t *emsg)
493 {
494 	Rtld_db_priv	rdb;
495 
496 	if (ps_pread(rap->rd_psp, rap->rd_rdebug, (char *)&rdb,
497 	    sizeof (Rtld_db_priv)) != PS_OK) {
498 		LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_2),
499 		    EC_ADDR(rap->rd_rdebug)));
500 		return (RD_DBERR);
501 	}
502 	emsg->type = rdb.rtd_rdebug.r_rdevent;
503 	if (emsg->type == RD_DLACTIVITY) {
504 		switch (rdb.rtd_rdebug.r_state) {
505 			case RT_CONSISTENT:
506 				emsg->u.state = RD_CONSISTENT;
507 				break;
508 			case RT_ADD:
509 				emsg->u.state = RD_ADD;
510 				break;
511 			case RT_DELETE:
512 				emsg->u.state = RD_DELETE;
513 				break;
514 		}
515 	} else
516 		emsg->u.state = RD_NOSTATE;
517 
518 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDEVENTGETMSG), rap->rd_dmodel,
519 	    emsg->type, emsg->u.state));
520 
521 	return (RD_OK);
522 }
523 
524 
525 rd_err_e
526 _rd_objpad_enable32(struct rd_agent *rap, size_t padsize)
527 {
528 	Rtld_db_priv		db_priv;
529 	struct ps_prochandle	*php = rap->rd_psp;
530 
531 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDOBJPADE), EC_ADDR(padsize)));
532 
533 	if (ps_pread(php, rap->rd_rtlddbpriv, (char *)&db_priv,
534 	    sizeof (Rtld_db_priv)) != PS_OK) {
535 		LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_3),
536 		    EC_ADDR(rap->rd_rtlddbpriv)));
537 		return (RD_DBERR);
538 	}
539 #if	defined(_LP64) && !defined(_ELF64)
540 	/*LINTED*/
541 	db_priv.rtd_objpad = (uint32_t)padsize;
542 #else
543 	db_priv.rtd_objpad = padsize;
544 #endif
545 	if (ps_pwrite(php, rap->rd_rtlddbpriv, (char *)&db_priv,
546 	    sizeof (Rtld_db_priv)) != PS_OK) {
547 		LOG(ps_plog(MSG_ORIG(MSG_DB_WRITEFAIL_2),
548 		    EC_ADDR(rap->rd_rtlddbpriv)));
549 		return (RD_DBERR);
550 	}
551 	return (RD_OK);
552 }
553 
554 static rd_err_e
555 iter_map(rd_agent_t *rap, unsigned long ident, psaddr_t lmaddr,
556 	rl_iter_f *cb, void *client_data, uint_t *abort_iterp)
557 {
558 	while (lmaddr) {
559 		Rt_map		rmap;
560 		rd_loadobj_t	lobj;
561 		int		i;
562 		ulong_t		off;
563 		Ehdr		ehdr;
564 		Phdr		phdr;
565 
566 		if (ps_pread(rap->rd_psp, lmaddr, (char *)&rmap,
567 		    sizeof (Rt_map)) != PS_OK) {
568 			LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPFAIL)));
569 			return (RD_DBERR);
570 		}
571 
572 		/*
573 		 * As of 'VERSION5' we only report objects
574 		 * which have been fully relocated.  While the maps
575 		 * might be in a consistent state - if a object hasn't
576 		 * been relocated - it's not really ready for the debuggers
577 		 * to examine.  This is mostly due to the fact that we
578 		 * might still be mucking with the text-segment, if
579 		 * we are - we could conflict with any break-points
580 		 * the debuggers might have set.
581 		 */
582 		if (rap->rd_rdebugvers >= R_RTLDDB_VERSION5) {
583 			if ((FLAGS(&rmap) & FLG_RT_RELOCED) == 0) {
584 				lmaddr = (psaddr_t)NEXT(&rmap);
585 				continue;
586 			}
587 		}
588 
589 		lobj.rl_base = (psaddr_t)ADDR(&rmap);
590 		lobj.rl_flags = 0;
591 		lobj.rl_refnameaddr = (psaddr_t)REFNAME(&rmap);
592 		if ((rap->rd_helper.rh_ops != NULL) &&
593 		    (rap->rd_helper.rh_ops->rho_lmid != LM_ID_NONE))
594 			lobj.rl_lmident =
595 			    rap->rd_helper.rh_ops->rho_lmid;
596 		else
597 			lobj.rl_lmident = ident;
598 
599 		/*
600 		 * refnameaddr is only valid from a core file
601 		 * which is VERSION3 or greater.
602 		 */
603 		if (rap->rd_rdebugvers < R_RTLDDB_VERSION3) {
604 			lobj.rl_nameaddr = (psaddr_t)NAME(&rmap);
605 			lobj.rl_bend = 0;
606 			lobj.rl_padstart = 0;
607 			lobj.rl_padend = 0;
608 		} else {
609 			lobj.rl_nameaddr = (psaddr_t)PATHNAME(&rmap);
610 			lobj.rl_bend = ADDR(&rmap) + MSIZE(&rmap);
611 			lobj.rl_padstart = PADSTART(&rmap);
612 			lobj.rl_padend = PADSTART(&rmap) + PADIMLEN(&rmap);
613 
614 		}
615 
616 		if (rtld_db_version >= RD_VERSION2)
617 			if (FLAGS(&rmap) & FLG_RT_IMGALLOC)
618 				lobj.rl_flags |= RD_FLG_MEM_OBJECT;
619 		if (rtld_db_version >= RD_VERSION2) {
620 			lobj.rl_dynamic = (psaddr_t)DYN(&rmap);
621 		}
622 
623 		if (rtld_db_version >= RD_VERSION4)
624 			lobj.rl_tlsmodid = TLSMODID(&rmap);
625 
626 		/*
627 		 * Look for beginning of data segment.
628 		 *
629 		 * NOTE: the data segment can only be found for full
630 		 *	processes and not from core images.
631 		 */
632 		lobj.rl_data_base = 0;
633 		if (rap->rd_flags & RDF_FL_COREFILE)
634 			lobj.rl_data_base = 0;
635 		else {
636 			off = ADDR(&rmap);
637 			if (ps_pread(rap->rd_psp, off, (char *)&ehdr,
638 			    sizeof (Ehdr)) != PS_OK) {
639 				LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPFAIL)));
640 				return (RD_DBERR);
641 			}
642 			off += sizeof (Ehdr);
643 			for (i = 0; i < ehdr.e_phnum; i++) {
644 				if (ps_pread(rap->rd_psp, off, (char *)&phdr,
645 				    sizeof (Phdr)) != PS_OK) {
646 					LOG(ps_plog(MSG_ORIG(
647 					    MSG_DB_LKMAPFAIL)));
648 					return (RD_DBERR);
649 				}
650 				if ((phdr.p_type == PT_LOAD) &&
651 				    (phdr.p_flags & PF_W)) {
652 					lobj.rl_data_base = phdr.p_vaddr;
653 					if (ehdr.e_type == ET_DYN)
654 						lobj.rl_data_base +=
655 						    ADDR(&rmap);
656 					break;
657 				}
658 				off += ehdr.e_phentsize;
659 			}
660 		}
661 
662 		/*
663 		 * When we transfer control to the client we free the
664 		 * lock and re-atain it after we've returned from the
665 		 * client.  This is to avoid any deadlock situations.
666 		 */
667 		LOG(ps_plog(MSG_ORIG(MSG_DB_ITERMAP), cb, client_data,
668 		    EC_ADDR(lobj.rl_base), EC_ADDR(lobj.rl_lmident)));
669 		RDAGUNLOCK(rap);
670 		if ((*cb)(&lobj, client_data) == 0) {
671 			LOG(ps_plog(MSG_ORIG(MSG_DB_CALLBACKR0)));
672 			RDAGLOCK(rap);
673 			*abort_iterp = 1;
674 			break;
675 		}
676 		RDAGLOCK(rap);
677 		lmaddr = (psaddr_t)NEXT(&rmap);
678 	}
679 	return (RD_OK);
680 }
681 
682 
683 static rd_err_e
684 _rd_loadobj_iter32_native(rd_agent_t *rap, rl_iter_f *cb, void *client_data,
685     uint_t *abort_iterp)
686 {
687 	Rtld_db_priv	db_priv;
688 	TAPlist		apl;
689 	uintptr_t	datap, nitems;
690 	Addr		addr;
691 	rd_err_e	rc;
692 
693 	LOG(ps_plog(MSG_ORIG(MSG_DB_LOADOBJITER), rap->rd_dmodel, cb,
694 	    client_data));
695 
696 	/*
697 	 * First, determine whether the link-map information has been
698 	 * established.  Some debuggers have made an initial call to this
699 	 * function with a null call back function (cb), but expect a
700 	 * RD_NOMAPS error return rather than a RD_ERR return when the
701 	 * link-maps aren't available.
702 	 */
703 	if (ps_pread(rap->rd_psp, rap->rd_rtlddbpriv, (char *)&db_priv,
704 	    sizeof (Rtld_db_priv)) != PS_OK) {
705 		LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_1),
706 		    EC_ADDR(rap->rd_rtlddbpriv)));
707 		return (RD_DBERR);
708 	}
709 
710 	if (db_priv.rtd_dynlmlst == NULL) {
711 		LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPNOINIT),
712 		    EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
713 		return (RD_NOMAPS);
714 	}
715 
716 	if (ps_pread(rap->rd_psp, (psaddr_t)db_priv.rtd_dynlmlst, (char *)&addr,
717 	    sizeof (Addr)) != PS_OK) {
718 		LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_3),
719 		    EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
720 		return (RD_DBERR);
721 	}
722 
723 	if (addr == NULL) {
724 		LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPNOINIT_1),
725 		    EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
726 		return (RD_NOMAPS);
727 	}
728 
729 	/*
730 	 * Having determined we have link-maps, ensure we have an iterator
731 	 * call back function.
732 	 */
733 	if (cb == NULL) {
734 		LOG(ps_plog(MSG_ORIG(MSG_DB_NULLITER)));
735 		return (RD_ERR);
736 	}
737 
738 	/*
739 	 * Read the initial APlist information that contains the link-map list
740 	 * entries.
741 	 */
742 	if (ps_pread(rap->rd_psp, (psaddr_t)addr, (char *)&apl,
743 	    sizeof (TAPlist)) != PS_OK) {
744 		LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_4),
745 		    EC_ADDR((uintptr_t)addr)));
746 		return (RD_DBERR);
747 	}
748 
749 	/*
750 	 * Iterate through each apl.ap_data[] entry.
751 	 */
752 	for (datap = (uintptr_t)((char *)(uintptr_t)addr +
753 	    ((size_t)(((TAPlist *)0)->apl_data))), nitems = 0;
754 	    nitems < apl.apl_nitems; nitems++, datap += sizeof (Addr)) {
755 		TLm_list	lm;
756 		ulong_t		ident;
757 
758 		/*
759 		 * Obtain the Lm_list address for this apl.ap_data[] entry.
760 		 */
761 		if (ps_pread(rap->rd_psp, (psaddr_t)datap, (char *)&addr,
762 		    sizeof (Addr)) != PS_OK) {
763 			LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_5),
764 			    EC_ADDR(datap)));
765 			return (RD_DBERR);
766 		}
767 
768 		/*
769 		 * Obtain the Lm_list data for this Lm_list address.
770 		 */
771 		if (ps_pread(rap->rd_psp, (psaddr_t)addr, (char *)&lm,
772 		    sizeof (TLm_list)) != PS_OK) {
773 			LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_6),
774 			    EC_ADDR((uintptr_t)addr)));
775 			return (RD_DBERR);
776 		}
777 
778 		/*
779 		 * Determine IDENT of current LM_LIST
780 		 */
781 		if (lm.lm_flags & LML_FLG_BASELM)
782 			ident = LM_ID_BASE;
783 		else if (lm.lm_flags & LML_FLG_RTLDLM)
784 			ident = LM_ID_LDSO;
785 		else
786 			ident = (ulong_t)addr;
787 
788 		if ((rc = iter_map(rap, ident, (psaddr_t)lm.lm_head,
789 		    cb, client_data, abort_iterp)) != RD_OK) {
790 			return (rc);
791 		}
792 		if (*abort_iterp != 0)
793 			break;
794 	}
795 
796 	return (rc);
797 }
798 
799 rd_err_e
800 _rd_loadobj_iter32(rd_agent_t *rap, rl_iter_f *cb, void *client_data)
801 {
802 	rd_err_e	rc, rc_brand = RD_OK;
803 	uint_t		abort_iter = 0;
804 
805 	/* First iterate over the native target objects */
806 	rc = _rd_loadobj_iter32_native(rap, cb, client_data, &abort_iter);
807 	if (abort_iter != 0)
808 		return (rc);
809 
810 	/* Then iterate over any branded objects. */
811 	if ((rap->rd_helper.rh_ops != NULL) &&
812 	    (rap->rd_helper.rh_ops->rho_loadobj_iter != NULL))
813 		rc_brand = rap->rd_helper.rh_ops->rho_loadobj_iter(
814 		    rap->rd_helper.rh_data, cb, client_data);
815 
816 	rc = (rc != RD_OK) ? rc : rc_brand;
817 	return (rc);
818 }
819