dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / sgs / librtld_db / common / rd_elf.c
blobf9609ab01bfeb692da0c1c561d315973cfa4f6eb
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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 <list.h>
34 #include <_rtld_db.h>
35 #include <msg.h>
36 #include <limits.h>
37 #include <string.h>
38 #include <sys/param.h>
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.
45 #ifdef _LP64
46 #ifdef _ELF64
47 #define _rd_event_enable32 _rd_event_enable64
48 #define _rd_event_getmsg32 _rd_event_getmsg64
49 #define _rd_get_dyns32 _rd_get_dyns64
50 #define _rd_get_ehdr32 _rd_get_ehdr64
51 #define _rd_objpad_enable32 _rd_objpad_enable64
52 #define _rd_loadobj_iter32 _rd_loadobj_iter64
53 #define _rd_reset32 _rd_reset64
54 #define find_dynamic_ent32 find_dynamic_ent64
55 #define validate_rdebug32 validate_rdebug64
56 #define TAPlist APlist
57 #define TLm_list Lm_list
58 #define TList List
59 #define TListnode Listnode
60 #define MSG_SYM_BRANDOPS MSG_SYM_BRANDOPS_64
61 #else /* ELF32 */
62 #define Rt_map Rt_map32
63 #define Rtld_db_priv Rtld_db_priv32
64 #define TAPlist APlist32
65 #define TLm_list Lm_list32
66 #define TList List32
67 #define TListnode Listnode32
68 #define Lm_list Lm_list32
69 #define MSG_SYM_BRANDOPS MSG_SYM_BRANDOPS_32
70 #endif /* _ELF64 */
71 #else /* _LP64 */
72 #define TAPlist APlist
73 #define TLm_list Lm_list
74 #define TList List
75 #define TListnode Listnode
76 #define MSG_SYM_BRANDOPS MSG_SYM_BRANDOPS_32
77 #endif /* _LP64 */
80 * BrandZ added ps_pbrandname(). Many debuggers that link directly
81 * against librtld_db.so may not implement this interface. Hence
82 * we won't call the function directly, instead we'll try to look it
83 * up using the linker first and only invoke it if we find it.
85 typedef ps_err_e (*ps_pbrandname_fp_t)(struct ps_prochandle *,
86 char *, size_t);
88 rd_err_e
89 validate_rdebug32(struct rd_agent *rap)
91 struct ps_prochandle *php = rap->rd_psp;
92 psaddr_t db_privp;
93 Rtld_db_priv db_priv;
95 if (rap->rd_rdebug == 0)
96 return (RD_ERR);
99 * The rtld_db_priv structure contains both the traditional (exposed)
100 * r_debug structure as well as private data only available to
101 * this library.
103 db_privp = rap->rd_rdebug;
106 * Verify that librtld_db & rtld are at the proper revision
107 * levels.
109 if (ps_pread(php, db_privp, (char *)&db_priv,
110 sizeof (Rtld_db_priv)) != PS_OK) {
111 LOG(ps_plog(MSG_ORIG(MSG_DB_READPRIVFAIL_1),
112 EC_ADDR(db_privp)));
113 return (RD_DBERR);
116 if ((db_priv.rtd_version < R_RTLDDB_VERSION1) ||
117 (db_priv.rtd_version > R_RTLDDB_VERSION)) {
118 LOG(ps_plog(MSG_ORIG(MSG_DB_BADPVERS),
119 db_priv.rtd_version, R_RTLDDB_VERSION));
120 return (RD_NOCAPAB);
124 * Is the image being examined from a core file or not.
125 * If it is a core file then the following write will fail.
127 if (ps_pwrite(php, db_privp, (char *)&db_priv,
128 sizeof (Rtld_db_priv)) != PS_OK)
129 rap->rd_flags |= RDF_FL_COREFILE;
131 rap->rd_rdebugvers = db_priv.rtd_version;
132 rap->rd_rtlddbpriv = db_privp;
134 LOG(ps_plog(MSG_ORIG(MSG_DB_VALIDRDEBUG), EC_ADDR(rap->rd_rdebug),
135 R_RTLDDB_VERSION, rap->rd_rdebugvers,
136 rap->rd_flags & RDF_FL_COREFILE));
137 return (RD_OK);
141 rd_err_e
142 find_dynamic_ent32(struct rd_agent *rap, psaddr_t dynaddr,
143 Xword dyntag, Dyn *dyn)
145 struct ps_prochandle *php = rap->rd_psp;
146 Dyn d;
148 d.d_tag = DT_NULL;
149 do {
150 if (ps_pread(php, dynaddr, (void *)(&d), sizeof (d)) !=
151 PS_OK) {
152 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_4),
153 EC_ADDR(dynaddr)));
154 return (RD_DBERR);
156 dynaddr += sizeof (d);
157 if (d.d_tag == dyntag)
158 break;
159 } while (d.d_tag != DT_NULL);
160 if (d.d_tag == dyntag) {
161 *dyn = d;
162 LOG(ps_plog(MSG_ORIG(MSG_DB_FINDDYNAMIC), EC_ADDR(dyntag),
163 EC_ADDR(d.d_un.d_val)));
164 return (RD_OK);
166 LOG(ps_plog(MSG_ORIG(MSG_DB_NODYNDEBUG), EC_ADDR(dyntag)));
167 return (RD_DBERR);
170 extern char rtld_db_helper_path[MAXPATHLEN];
172 rd_err_e
173 _rd_reset32(struct rd_agent *rap)
175 psaddr_t symaddr;
176 struct ps_prochandle *php = rap->rd_psp;
177 const auxv_t *auxvp = NULL;
178 rd_err_e rc = RD_OK;
179 char brandname[MAXPATHLEN];
180 char brandlib[MAXPATHLEN];
181 ps_pbrandname_fp_t ps_pbrandname;
184 * librtld_db attempts three different methods to find
185 * the r_debug structure which is required to
186 * initialize itself. The methods are:
187 * method1:
188 * entirely independent of any text segment
189 * and relies on the AT_SUN_LDDATA auxvector
190 * to find the ld.so.1::rdebug structure.
191 * method2:
192 * lookup symbols in ld.so.1's symbol table
193 * to find the r_debug symbol.
194 * method3:
195 * (old dbx method) dependent upon the
196 * text segment/symbol table of the
197 * executable and not ld.so.1. We lookup the
198 * _DYNAMIC symbol in the executable and look for
199 * the DT_DEBUG entry in the .dynamic table. This
200 * points to rdebug.
202 * If none of that works - we fail.
204 LOG(ps_plog(MSG_ORIG(MSG_DB_RDRESET), rap->rd_dmodel));
206 * Method1
208 * Scan the aux vector looking for AT_BASE & AT_SUN_LDDATA
211 if (ps_pauxv(php, &auxvp) != PS_OK) {
212 LOG(ps_plog(MSG_ORIG(MSG_DB_NOAUXV)));
213 rc = RD_ERR;
216 rap->rd_rdebug = 0;
218 if (auxvp != NULL) {
219 rc = RD_ERR;
220 while (auxvp->a_type != AT_NULL) {
221 if (auxvp->a_type == AT_SUN_LDDATA) {
222 /* LINTED */
223 rap->rd_rdebug = (uintptr_t)auxvp->a_un.a_ptr;
224 LOG(ps_plog(MSG_ORIG(MSG_DB_FLDDATA),
225 rap->rd_rdebug));
226 rc = validate_rdebug32(rap);
227 break;
229 auxvp++;
234 * method2 - look for r_rdebug symbol in ld.so.1
236 if (rc != RD_OK) {
238 * If the AT_SUN_LDDATA auxv vector is not present
239 * fall back on doing a symlookup of
240 * the r_debug symbol. This is for backward
241 * compatiblity with older OS's
243 LOG(ps_plog(MSG_ORIG(MSG_DB_NOLDDATA)));
244 if (ps_pglobal_lookup(php, PS_OBJ_LDSO, MSG_ORIG(MSG_SYM_DEBUG),
245 &symaddr) != PS_OK) {
246 LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
247 MSG_ORIG(MSG_SYM_DEBUG)));
248 rc = RD_DBERR;
249 } else {
250 rap->rd_rdebug = symaddr;
251 LOG(ps_plog(MSG_ORIG(MSG_DB_SYMRDEBUG),
252 EC_ADDR(symaddr)));
253 rc = validate_rdebug32(rap);
259 * method3 - find DT_DEBUG in the executables .dynamic section.
261 if (rc != RD_OK) {
262 Dyn dyn;
263 if (ps_pglobal_lookup(php, PS_OBJ_EXEC,
264 MSG_ORIG(MSG_SYM_DYNAMIC), &symaddr) != PS_OK) {
265 LOG(ps_plog(MSG_ORIG(MSG_DB_NODYNAMIC)));
266 LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED)));
267 return (rc);
269 rc = find_dynamic_ent32(rap, symaddr, DT_DEBUG, &dyn);
270 if (rc != RD_OK) {
271 LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED)));
272 return (rc);
274 rap->rd_rdebug = dyn.d_un.d_ptr;
275 rc = validate_rdebug32(rap);
276 if (rc != RD_OK) {
277 LOG(ps_plog(MSG_ORIG(MSG_DB_INITFAILED)));
278 return (rc);
283 * If we are debugging a branded executable, load the appropriate
284 * helper library, and call its initialization routine. Being unable
285 * to load the helper library is not a critical error. (Hopefully
286 * we'll still be able to access some objects in the target.)
288 ps_pbrandname = (ps_pbrandname_fp_t)dlsym(RTLD_PROBE, "ps_pbrandname");
289 while ((ps_pbrandname != NULL) &&
290 (ps_pbrandname(php, brandname, MAXPATHLEN) == PS_OK)) {
291 const char *isa = "";
293 #ifdef _LP64
294 isa = MSG_ORIG(MSG_DB_64BIT_PREFIX);
295 #endif /* _LP64 */
297 if (rtld_db_helper_path[0] != '\0')
298 (void) snprintf(brandlib, MAXPATHLEN,
299 MSG_ORIG(MSG_DB_BRAND_HELPERPATH_PREFIX),
300 rtld_db_helper_path,
301 MSG_ORIG(MSG_DB_HELPER_PREFIX), brandname, isa,
302 brandname);
303 else
304 (void) snprintf(brandlib, MAXPATHLEN,
305 MSG_ORIG(MSG_DB_BRAND_HELPERPATH),
306 MSG_ORIG(MSG_DB_HELPER_PREFIX), brandname, isa,
307 brandname);
309 rap->rd_helper.rh_dlhandle = dlopen(brandlib,
310 RTLD_LAZY | RTLD_LOCAL);
311 if (rap->rd_helper.rh_dlhandle == NULL) {
312 LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERLOADFAILED),
313 brandlib));
314 break;
317 rap->rd_helper.rh_ops = dlsym(rap->rd_helper.rh_dlhandle,
318 MSG_ORIG(MSG_SYM_BRANDOPS));
319 if (rap->rd_helper.rh_ops == NULL) {
320 LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERNOOPS),
321 brandlib));
322 (void) dlclose(rap->rd_helper.rh_dlhandle);
323 rap->rd_helper.rh_dlhandle = NULL;
324 break;
327 rap->rd_helper.rh_data = rap->rd_helper.rh_ops->rho_init(rap,
328 php);
329 if (rap->rd_helper.rh_data == NULL) {
330 LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERINITFAILED)));
331 (void) dlclose(rap->rd_helper.rh_dlhandle);
332 rap->rd_helper.rh_dlhandle = NULL;
333 rap->rd_helper.rh_ops = NULL;
334 break;
337 LOG(ps_plog(MSG_ORIG(MSG_DB_HELPERLOADED), brandname));
338 break;
340 /* NOTREACHED */
343 if ((rap->rd_flags & RDF_FL_COREFILE) == 0) {
344 if (ps_pglobal_lookup(php, PS_OBJ_LDSO,
345 MSG_ORIG(MSG_SYM_PREINIT), &symaddr) != PS_OK) {
346 LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
347 MSG_ORIG(MSG_SYM_PREINIT)));
348 return (RD_DBERR);
350 rap->rd_preinit = symaddr;
352 if (ps_pglobal_lookup(php, PS_OBJ_LDSO,
353 MSG_ORIG(MSG_SYM_POSTINIT), &symaddr) != PS_OK) {
354 LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
355 MSG_ORIG(MSG_SYM_POSTINIT)));
356 return (RD_DBERR);
358 rap->rd_postinit = symaddr;
360 if (ps_pglobal_lookup(php, PS_OBJ_LDSO,
361 MSG_ORIG(MSG_SYM_DLACT), &symaddr) != PS_OK) {
362 LOG(ps_plog(MSG_ORIG(MSG_DB_LOOKFAIL),
363 MSG_ORIG(MSG_SYM_DLACT)));
364 return (RD_DBERR);
366 rap->rd_dlact = symaddr;
367 rap->rd_tbinder = 0;
370 return (RD_OK);
373 rd_err_e
374 _rd_get_ehdr32(struct rd_agent *rap,
375 psaddr_t addr, Ehdr *ehdr, uint_t *phnum)
377 struct ps_prochandle *php = rap->rd_psp;
378 Shdr shdr;
380 if (ps_pread(php, addr, ehdr, sizeof (*ehdr)) != PS_OK) {
381 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_5), EC_ADDR(addr)));
382 return (RD_ERR);
384 if (phnum == NULL)
385 return (RD_OK);
387 if (ehdr->e_phnum != PN_XNUM) {
388 *phnum = ehdr->e_phnum;
389 return (RD_OK);
392 /* deal with elf extended program headers */
393 if ((ehdr->e_shoff == 0) || (ehdr->e_shentsize < sizeof (shdr)))
394 return (RD_ERR);
396 addr += ehdr->e_shoff;
397 if (ps_pread(php, addr, &shdr, sizeof (shdr)) != PS_OK) {
398 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_5), EC_ADDR(addr)));
399 return (RD_ERR);
402 if (shdr.sh_info == 0)
403 return (RD_ERR);
405 *phnum = shdr.sh_info;
406 return (RD_OK);
409 rd_err_e
410 _rd_get_dyns32(rd_agent_t *rap, psaddr_t addr, Dyn **dynpp, size_t *dynpp_sz)
412 struct ps_prochandle *php = rap->rd_psp;
413 rd_err_e err;
414 uint_t phnum;
415 Ehdr ehdr;
416 Phdr phdr;
417 Dyn *dynp;
418 int i;
420 /* We only need to muck with dyn elements for ET_DYN objects */
421 if ((err = _rd_get_ehdr32(rap, addr, &ehdr, &phnum)) != RD_OK)
422 return (err);
424 for (i = 0; i < phnum; i++) {
425 psaddr_t a = addr + ehdr.e_phoff + (i * ehdr.e_phentsize);
426 if (ps_pread(php, a, &phdr, sizeof (phdr)) != PS_OK) {
427 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_6), EC_ADDR(a)));
428 return (RD_ERR);
430 if (phdr.p_type == PT_DYNAMIC)
431 break;
433 if (i == phnum)
434 return (RD_ERR);
436 if ((dynp = malloc(phdr.p_filesz)) == NULL)
437 return (RD_ERR);
438 if (ehdr.e_type == ET_DYN)
439 phdr.p_vaddr += addr;
440 if (ps_pread(php, phdr.p_vaddr, dynp, phdr.p_filesz) != PS_OK) {
441 free(dynp);
442 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_6),
443 EC_ADDR(phdr.p_vaddr)));
444 return (RD_ERR);
447 *dynpp = dynp;
448 if (dynpp_sz != NULL)
449 *dynpp_sz = phdr.p_filesz;
450 return (RD_OK);
453 rd_err_e
454 _rd_event_enable32(rd_agent_t *rap, int onoff)
456 struct ps_prochandle *php = rap->rd_psp;
457 Rtld_db_priv rdb;
459 LOG(ps_plog(MSG_ORIG(MSG_DB_RDEVENTENABLE), rap->rd_dmodel, onoff));
461 * Tell the debugged process that debugging is occuring
462 * This will enable the storing of event messages so that
463 * the can be gathered by the debugger.
465 if (ps_pread(php, rap->rd_rdebug, (char *)&rdb,
466 sizeof (Rtld_db_priv)) != PS_OK) {
467 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_1),
468 EC_ADDR((uintptr_t)&rdb)));
469 return (RD_DBERR);
472 if (onoff)
473 rdb.rtd_rdebug.r_flags |= RD_FL_DBG;
474 else
475 rdb.rtd_rdebug.r_flags &= ~RD_FL_DBG;
477 if (ps_pwrite(php, rap->rd_rdebug, (char *)&rdb,
478 sizeof (Rtld_db_priv)) != PS_OK) {
479 LOG(ps_plog(MSG_ORIG(MSG_DB_WRITEFAIL_1),
480 EC_ADDR((uintptr_t)&rdb)));
481 return (RD_DBERR);
484 return (RD_OK);
488 rd_err_e
489 _rd_event_getmsg32(rd_agent_t *rap, rd_event_msg_t *emsg)
491 Rtld_db_priv rdb;
493 if (ps_pread(rap->rd_psp, rap->rd_rdebug, (char *)&rdb,
494 sizeof (Rtld_db_priv)) != PS_OK) {
495 LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_2),
496 EC_ADDR(rap->rd_rdebug)));
497 return (RD_DBERR);
499 emsg->type = rdb.rtd_rdebug.r_rdevent;
500 if (emsg->type == RD_DLACTIVITY) {
501 switch (rdb.rtd_rdebug.r_state) {
502 case RT_CONSISTENT:
503 emsg->u.state = RD_CONSISTENT;
504 break;
505 case RT_ADD:
506 emsg->u.state = RD_ADD;
507 break;
508 case RT_DELETE:
509 emsg->u.state = RD_DELETE;
510 break;
512 } else
513 emsg->u.state = RD_NOSTATE;
515 LOG(ps_plog(MSG_ORIG(MSG_DB_RDEVENTGETMSG), rap->rd_dmodel,
516 emsg->type, emsg->u.state));
518 return (RD_OK);
522 rd_err_e
523 _rd_objpad_enable32(struct rd_agent *rap, size_t padsize)
525 Rtld_db_priv db_priv;
526 struct ps_prochandle *php = rap->rd_psp;
528 LOG(ps_plog(MSG_ORIG(MSG_DB_RDOBJPADE), EC_ADDR(padsize)));
530 if (ps_pread(php, rap->rd_rtlddbpriv, (char *)&db_priv,
531 sizeof (Rtld_db_priv)) != PS_OK) {
532 LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_3),
533 EC_ADDR(rap->rd_rtlddbpriv)));
534 return (RD_DBERR);
536 #if defined(_LP64) && !defined(_ELF64)
537 /*LINTED*/
538 db_priv.rtd_objpad = (uint32_t)padsize;
539 #else
540 db_priv.rtd_objpad = padsize;
541 #endif
542 if (ps_pwrite(php, rap->rd_rtlddbpriv, (char *)&db_priv,
543 sizeof (Rtld_db_priv)) != PS_OK) {
544 LOG(ps_plog(MSG_ORIG(MSG_DB_WRITEFAIL_2),
545 EC_ADDR(rap->rd_rtlddbpriv)));
546 return (RD_DBERR);
548 return (RD_OK);
551 static rd_err_e
552 iter_map(rd_agent_t *rap, unsigned long ident, psaddr_t lmaddr,
553 rl_iter_f *cb, void *client_data, uint_t *abort_iterp)
555 while (lmaddr) {
556 Rt_map rmap;
557 rd_loadobj_t lobj;
558 int i;
559 ulong_t off;
560 Ehdr ehdr;
561 Phdr phdr;
563 if (ps_pread(rap->rd_psp, lmaddr, (char *)&rmap,
564 sizeof (Rt_map)) != PS_OK) {
565 LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPFAIL)));
566 return (RD_DBERR);
570 * As of 'VERSION5' we only report objects
571 * which have been fully relocated. While the maps
572 * might be in a consistent state - if a object hasn't
573 * been relocated - it's not really ready for the debuggers
574 * to examine. This is mostly due to the fact that we
575 * might still be mucking with the text-segment, if
576 * we are - we could conflict with any break-points
577 * the debuggers might have set.
579 if (rap->rd_rdebugvers >= R_RTLDDB_VERSION5) {
580 if ((FLAGS(&rmap) & FLG_RT_RELOCED) == 0) {
581 lmaddr = (psaddr_t)NEXT(&rmap);
582 continue;
586 lobj.rl_base = (psaddr_t)ADDR(&rmap);
587 lobj.rl_flags = 0;
588 lobj.rl_refnameaddr = (psaddr_t)REFNAME(&rmap);
589 if ((rap->rd_helper.rh_ops != NULL) &&
590 (rap->rd_helper.rh_ops->rho_lmid != LM_ID_NONE))
591 lobj.rl_lmident =
592 rap->rd_helper.rh_ops->rho_lmid;
593 else
594 lobj.rl_lmident = ident;
597 * refnameaddr is only valid from a core file
598 * which is VERSION3 or greater.
600 if (rap->rd_rdebugvers < R_RTLDDB_VERSION3) {
601 lobj.rl_nameaddr = (psaddr_t)NAME(&rmap);
602 lobj.rl_bend = 0;
603 lobj.rl_padstart = 0;
604 lobj.rl_padend = 0;
605 } else {
606 lobj.rl_nameaddr = (psaddr_t)PATHNAME(&rmap);
607 lobj.rl_bend = ADDR(&rmap) + MSIZE(&rmap);
608 lobj.rl_padstart = PADSTART(&rmap);
609 lobj.rl_padend = PADSTART(&rmap) + PADIMLEN(&rmap);
613 if (rtld_db_version >= RD_VERSION2)
614 if (FLAGS(&rmap) & FLG_RT_IMGALLOC)
615 lobj.rl_flags |= RD_FLG_MEM_OBJECT;
616 if (rtld_db_version >= RD_VERSION2) {
617 lobj.rl_dynamic = (psaddr_t)DYN(&rmap);
620 if (rtld_db_version >= RD_VERSION4)
621 lobj.rl_tlsmodid = TLSMODID(&rmap);
624 * Look for beginning of data segment.
626 * NOTE: the data segment can only be found for full
627 * processes and not from core images.
629 lobj.rl_data_base = 0;
630 if (rap->rd_flags & RDF_FL_COREFILE)
631 lobj.rl_data_base = 0;
632 else {
633 off = ADDR(&rmap);
634 if (ps_pread(rap->rd_psp, off, (char *)&ehdr,
635 sizeof (Ehdr)) != PS_OK) {
636 LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPFAIL)));
637 return (RD_DBERR);
639 off += sizeof (Ehdr);
640 for (i = 0; i < ehdr.e_phnum; i++) {
641 if (ps_pread(rap->rd_psp, off, (char *)&phdr,
642 sizeof (Phdr)) != PS_OK) {
643 LOG(ps_plog(MSG_ORIG(
644 MSG_DB_LKMAPFAIL)));
645 return (RD_DBERR);
647 if ((phdr.p_type == PT_LOAD) &&
648 (phdr.p_flags & PF_W)) {
649 lobj.rl_data_base = phdr.p_vaddr;
650 if (ehdr.e_type == ET_DYN)
651 lobj.rl_data_base +=
652 ADDR(&rmap);
653 break;
655 off += ehdr.e_phentsize;
660 * When we transfer control to the client we free the
661 * lock and re-atain it after we've returned from the
662 * client. This is to avoid any deadlock situations.
664 LOG(ps_plog(MSG_ORIG(MSG_DB_ITERMAP), cb, client_data,
665 EC_ADDR(lobj.rl_base), EC_ADDR(lobj.rl_lmident)));
666 RDAGUNLOCK(rap);
667 if ((*cb)(&lobj, client_data) == 0) {
668 LOG(ps_plog(MSG_ORIG(MSG_DB_CALLBACKR0)));
669 RDAGLOCK(rap);
670 *abort_iterp = 1;
671 break;
673 RDAGLOCK(rap);
674 lmaddr = (psaddr_t)NEXT(&rmap);
676 return (RD_OK);
680 static rd_err_e
681 _rd_loadobj_iter32_native(rd_agent_t *rap, rl_iter_f *cb, void *client_data,
682 uint_t *abort_iterp)
684 Rtld_db_priv db_priv;
685 TAPlist apl;
686 uintptr_t datap, nitems;
687 Addr addr;
688 rd_err_e rc;
690 LOG(ps_plog(MSG_ORIG(MSG_DB_LOADOBJITER), rap->rd_dmodel, cb,
691 client_data));
694 * First, determine whether the link-map information has been
695 * established. Some debuggers have made an initial call to this
696 * function with a null call back function (cb), but expect a
697 * RD_NOMAPS error return rather than a RD_ERR return when the
698 * link-maps aren't available.
700 if (ps_pread(rap->rd_psp, rap->rd_rtlddbpriv, (char *)&db_priv,
701 sizeof (Rtld_db_priv)) != PS_OK) {
702 LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_1),
703 EC_ADDR(rap->rd_rtlddbpriv)));
704 return (RD_DBERR);
707 if (db_priv.rtd_dynlmlst == 0) {
708 LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPNOINIT),
709 EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
710 return (RD_NOMAPS);
713 if (ps_pread(rap->rd_psp, (psaddr_t)db_priv.rtd_dynlmlst, (char *)&addr,
714 sizeof (Addr)) != PS_OK) {
715 LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_3),
716 EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
717 return (RD_DBERR);
720 if (addr == 0) {
721 LOG(ps_plog(MSG_ORIG(MSG_DB_LKMAPNOINIT_1),
722 EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
723 return (RD_NOMAPS);
727 * Having determined we have link-maps, ensure we have an iterator
728 * call back function.
730 if (cb == NULL) {
731 LOG(ps_plog(MSG_ORIG(MSG_DB_NULLITER)));
732 return (RD_ERR);
736 * As of VERSION6, rtd_dynlmlst points to an APlist. Prior to VERSION6
737 * rtd_dynlmlst pointed to a List. But, there was a window where the
738 * version was not incremented, and this must be worked around by
739 * interpreting the APlist data. Read the initial APlist information.
741 if (ps_pread(rap->rd_psp, (psaddr_t)addr, (char *)&apl,
742 sizeof (TAPlist)) != PS_OK) {
743 LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_4),
744 EC_ADDR((uintptr_t)addr)));
745 return (RD_DBERR);
749 * The rtd_dynlmlst change from a List to an APlist occurred under
750 * 6801536 in snv_112. However, this change neglected to preserve
751 * backward compatibility by maintaining List processing and using a
752 * version increment to detect the change. 6862967, intergrated in
753 * snv_121 corrects the version detection. However, to catch objects
754 * built between these releases, we look at the first element of the
755 * APlist. apl_arritems indicates the number of APlist items that are
756 * available. This was originally initialized with a AL_CNT_DYNLIST
757 * value of 2 (one entry for LM_ID_BASE and one entry for LM_ID_LDSO).
758 * It is possible that the use of an auditor results in an additional
759 * link-map list, in which case the original apl_arritems would have
760 * been doubled.
762 * Therefore, if the debugging verion is VERSION6, or the apl_arritems
763 * entry has a value less than or equal to 4 and the debugging version
764 * is VERSION5, then we process APlists. Otherwise, fall back to List
765 * processing.
767 if ((rap->rd_rdebugvers >= R_RTLDDB_VERSION6) ||
768 ((rap->rd_rdebugvers == R_RTLDDB_VERSION5) &&
769 (apl.apl_arritems <= 4))) {
771 * Iterate through each apl.ap_data[] entry.
773 for (datap = (uintptr_t)((char *)(uintptr_t)addr +
774 ((size_t)(((TAPlist *)0)->apl_data))), nitems = 0;
775 nitems < apl.apl_nitems; nitems++, datap += sizeof (Addr)) {
776 TLm_list lm;
777 ulong_t ident;
780 * Obtain the Lm_list address for this apl.ap_data[]
781 * entry.
783 if (ps_pread(rap->rd_psp, (psaddr_t)datap,
784 (char *)&addr, sizeof (Addr)) != PS_OK) {
785 LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_5),
786 EC_ADDR(datap)));
787 return (RD_DBERR);
791 * Obtain the Lm_list data for this Lm_list address.
793 if (ps_pread(rap->rd_psp, (psaddr_t)addr, (char *)&lm,
794 sizeof (TLm_list)) != PS_OK) {
795 LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_6),
796 EC_ADDR((uintptr_t)addr)));
797 return (RD_DBERR);
801 * Determine IDENT of current LM_LIST
803 if (lm.lm_flags & LML_FLG_BASELM)
804 ident = LM_ID_BASE;
805 else if (lm.lm_flags & LML_FLG_RTLDLM)
806 ident = LM_ID_LDSO;
807 else
808 ident = (ulong_t)addr;
810 if ((rc = iter_map(rap, ident, (psaddr_t)lm.lm_head,
811 cb, client_data, abort_iterp)) != RD_OK)
812 return (rc);
814 if (*abort_iterp != 0)
815 break;
817 } else {
818 TList list;
819 TListnode lnode;
820 Addr lnp;
823 * Re-read the dynlmlst address to obtain a List structure.
825 if (ps_pread(rap->rd_psp, (psaddr_t)db_priv.rtd_dynlmlst,
826 (char *)&list, sizeof (TList)) != PS_OK) {
827 LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_3),
828 EC_ADDR((uintptr_t)db_priv.rtd_dynlmlst)));
829 return (RD_DBERR);
833 * Iterate through the link-map list.
835 for (lnp = (Addr)list.head; lnp; lnp = (Addr)lnode.next) {
836 Lm_list lml;
837 ulong_t ident;
840 * Iterate through the List of Lm_list's.
842 if (ps_pread(rap->rd_psp, (psaddr_t)lnp, (char *)&lnode,
843 sizeof (TListnode)) != PS_OK) {
844 LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_4),
845 EC_ADDR(lnp)));
846 return (RD_DBERR);
849 if (ps_pread(rap->rd_psp, (psaddr_t)lnode.data,
850 (char *)&lml, sizeof (Lm_list)) != PS_OK) {
851 LOG(ps_plog(MSG_ORIG(MSG_DB_READDBGFAIL_5),
852 EC_ADDR((uintptr_t)lnode.data)));
853 return (RD_DBERR);
857 * Determine IDENT of current LM_LIST
859 if (lml.lm_flags & LML_FLG_BASELM)
860 ident = LM_ID_BASE;
861 else if (lml.lm_flags & LML_FLG_RTLDLM)
862 ident = LM_ID_LDSO;
863 else
864 ident = (unsigned long)lnode.data;
866 if ((rc = iter_map(rap, ident, (psaddr_t)lml.lm_head,
867 cb, client_data, abort_iterp)) != RD_OK)
868 return (rc);
870 if (*abort_iterp != 0)
871 break;
875 return (rc);
878 rd_err_e
879 _rd_loadobj_iter32(rd_agent_t *rap, rl_iter_f *cb, void *client_data)
881 rd_err_e rc, rc_brand = RD_OK;
882 uint_t abort_iter = 0;
884 /* First iterate over the native target objects */
885 rc = _rd_loadobj_iter32_native(rap, cb, client_data, &abort_iter);
886 if (abort_iter != 0)
887 return (rc);
889 /* Then iterate over any branded objects. */
890 if ((rap->rd_helper.rh_ops != NULL) &&
891 (rap->rd_helper.rh_ops->rho_loadobj_iter != NULL))
892 rc_brand = rap->rd_helper.rh_ops->rho_loadobj_iter(
893 rap->rd_helper.rh_data, cb, client_data);
895 rc = (rc != RD_OK) ? rc : rc_brand;
896 return (rc);