Home | History | Annotate | Download | only in common
      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 2008 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 <stdio.h>
     29 #include <stdlib.h>
     30 #include <string.h>
     31 #include <strings.h>
     32 #include <sys/types.h>
     33 #include <sys/link.h>
     34 #include <libproc.h>
     35 #include <proc_service.h>
     36 #include <rtld_db.h>
     37 #include <synch.h>
     38 
     39 #include <sys/lx_brand.h>
     40 
     41 /*
     42  * ATTENTION:
     43  *	Librtl_db brand plugin libraries should NOT directly invoke any
     44  *	libproc.so interfaces or be linked against libproc.  If a librtl_db
     45  *	brand plugin library uses libproc.so interfaces then it may break
     46  *	any other librtld_db consumers (like mdb) that tries to attach
     47  *	to a branded process.  The only safe interfaces that the a librtld_db
     48  *	brand plugin library can use to access a target process are the
     49  *	proc_service(3PROC) apis.
     50  */
     51 
     52 /*
     53  * M_DATA comes from some streams header file but is also redifined in
     54  * _rtld_db.h, so nuke the old streams definition here.
     55  */
     56 #ifdef M_DATA
     57 #undef M_DATA
     58 #endif /* M_DATA */
     59 
     60 /*
     61  * For 32-bit versions of this library, this file get's compiled once.
     62  * For 64-bit versions of this library, this file get's compiled twice,
     63  * once with _ELF64 defined and once without.  The expectation is that
     64  * the 64-bit version of the library can properly deal with both 32-bit
     65  * and 64-bit elf files, hence in the 64-bit library there are two copies
     66  * of all the interfaces in this file, one set named *32 and one named *64.
     67  *
     68  * This also means that we need to be careful when declaring local pointers
     69  * that point to objects in another processes address space, since these
     70  * pointers may not match the current processes pointer width.  Basically,
     71  * we should avoid using data types that change size between 32 and 64 bit
     72  * modes like: long, void *, uintprt_t, caddr_t, psaddr_t, size_t, etc.
     73  * Instead we should declare all pointers as uint32_t.  Then when we
     74  * are compiled to deal with 64-bit targets we'll re-define uint32_t
     75  * to be a uint64_t.
     76  *
     77  * Finally, one last importante note.  All the 64-bit elf file code
     78  * is never used and can't be tested.  This is because we don't actually
     79  * support 64-bit Linux processes yet.  The reason that we have it here
     80  * is because we want to support debugging 32-bit elf targets with the
     81  * 64-bit version of this library, so we need to have a 64-bit version
     82  * of this library.  But a 64-bit version of this library is expected
     83  * to provide debugging interfaces for both 32 and 64-bit elf targets.
     84  * So we provide the 64-bit elf target interfaces, but they will never
     85  * be invoked and are untested.  If we ever add support for 64-bit elf
     86  * Linux processes, we'll need to verify that this code works correctly
     87  * for those targets.
     88  */
     89 #ifdef _LP64
     90 #ifdef _ELF64
     91 #define	lx_ldb_get_dyns32		lx_ldb_get_dyns64
     92 #define	lx_ldb_init32			lx_ldb_init64
     93 #define	lx_ldb_fini32			lx_ldb_fini64
     94 #define	lx_ldb_loadobj_iter32		lx_ldb_loadobj_iter64
     95 #define	lx_ldb_getauxval32		lx_ldb_getauxval64
     96 #define	lx_elf_props32			lx_elf_props64
     97 #define	_rd_get_dyns32			_rd_get_dyns64
     98 #define	_rd_get_ehdr32			_rd_get_ehdr64
     99 #define	uint32_t			uint64_t
    100 #define	Elf32_Dyn			Elf64_Dyn
    101 #define	Elf32_Ehdr			Elf64_Ehdr
    102 #define	Elf32_Phdr			Elf64_Phdr
    103 #endif /* _ELF64 */
    104 #endif /* _LP64 */
    105 
    106 /* Included from usr/src/cmd/sgs/librtld_db/common */
    107 #include <_rtld_db.h>
    108 
    109 typedef struct lx_rd {
    110 	rd_agent_t		*lr_rap;
    111 	struct ps_prochandle	*lr_php;	/* proc handle pointer */
    112 	uint32_t		lr_rdebug;	/* address of lx r_debug */
    113 	uint32_t		lr_exec;	/* base address of executable */
    114 } lx_rd_t;
    115 
    116 typedef struct lx_link_map {
    117 	uint32_t lxm_addr;	/* Base address shared object is loaded at.  */
    118 	uint32_t lxm_name;	/* Absolute file name object was found in.  */
    119 	uint32_t lxm_ld;	/* Dynamic section of the shared object.  */
    120 	uint32_t lxm_next;	/* Chain of loaded objects.  */
    121 } lx_link_map_t;
    122 
    123 typedef struct lx_r_debug {
    124 	int r_version;		/* Version number for this protocol.  */
    125 	uint32_t	r_map;	/* Head of the chain of loaded objects. */
    126 
    127 	/*
    128 	 * This is the address of a function internal to the run-time linker,
    129 	 * that will always be called when the linker begins to map in a
    130 	 * library or unmap it, and again when the mapping change is complete.
    131 	 * The debugger can set a breakpoint at this address if it wants to
    132 	 * notice shared object mapping changes.
    133 	 */
    134 	uint32_t	r_brk;
    135 	r_state_e	r_state; /* defined the same way between lx/solaris */
    136 	uint32_t	r_ldbase; /* Base address the linker is loaded at. */
    137 } lx_r_debug_t;
    138 
    139 static uint32_t
    140 lx_ldb_getauxval32(struct ps_prochandle *php, int type)
    141 {
    142 	const auxv_t		*auxvp = NULL;
    143 
    144 	if (ps_pauxv(php, &auxvp) != PS_OK)
    145 		return ((uint32_t)-1);
    146 
    147 	while (auxvp->a_type != AT_NULL) {
    148 		if (auxvp->a_type == type)
    149 			return ((uint32_t)(uintptr_t)auxvp->a_un.a_ptr);
    150 		auxvp++;
    151 	}
    152 	return ((uint32_t)-1);
    153 }
    154 
    155 /*
    156  * A key difference between the linux linker and ours' is that the linux
    157  * linker adds the base address of segments to certain values in the
    158  * segments' ELF header. As an example, look at the address of the
    159  * DT_HASH hash table in a Solaris section - it is a relative address
    160  * which locates the start of the hash table, relative to the beginning
    161  * of the ELF file. However, when the linux linker loads a section, it
    162  * modifies the in-memory ELF image by changing address of the hash
    163  * table to be an absolute address. This is only done for libraries - not for
    164  * executables.
    165  *
    166  * Solaris tools expect the relative address to remain relative, so
    167  * here we will modify the in-memory ELF image so that it once again
    168  * contains relative addresses.
    169  *
    170  * To accomplish this, we walk through all sections in the target.
    171  * Linux sections are identified by pointing to the linux linker or libc in the
    172  * DT_NEEDED section. For all matching sections, we subtract the segment
    173  * base address to get back to relative addresses.
    174  */
    175 static rd_err_e
    176 lx_ldb_get_dyns32(rd_helper_data_t rhd,
    177     psaddr_t addr, void **dynpp, size_t *dynpp_sz)
    178 {
    179 	lx_rd_t			*lx_rd = (lx_rd_t *)rhd;
    180 	rd_agent_t		*rap = lx_rd->lr_rap;
    181 	Elf32_Ehdr		ehdr;
    182 	Elf32_Dyn		*dynp = NULL;
    183 	size_t			dynp_sz;
    184 	uint_t			ndyns;
    185 	int			i;
    186 
    187 	ps_plog("lx_ldb_get_dyns: invoked for object at 0x%p", addr);
    188 
    189 	/* Read in a copy of the ehdr */
    190 	if (_rd_get_ehdr32(rap, addr, &ehdr, NULL) != RD_OK) {
    191 		ps_plog("lx_ldb_get_dyns: _rd_get_ehdr() failed");
    192 		return (RD_ERR);
    193 	}
    194 
    195 	/* read out the PT_DYNAMIC elements for this object */
    196 	if (_rd_get_dyns32(rap, addr, &dynp, &dynp_sz) != RD_OK) {
    197 		ps_plog("lx_ldb_get_dyns: _rd_get_dyns() failed");
    198 		return (RD_ERR);
    199 	}
    200 
    201 	/*
    202 	 * From here on out if we encounter an error we'll just return
    203 	 * success and pass back the unmolested dynamic elements that
    204 	 * we've already obtained.
    205 	 */
    206 	*dynpp = dynp;
    207 	*dynpp_sz = dynp_sz;
    208 	ndyns = dynp_sz / sizeof (Elf32_Dyn);
    209 
    210 	/* If this isn't a dynamic object, there's nothing left todo */
    211 	if (ehdr.e_type != ET_DYN) {
    212 		ps_plog("lx_ldb_get_dyns: done: not a shared object");
    213 		return (RD_OK);
    214 	}
    215 
    216 	/*
    217 	 * Before we blindly start changing dynamic section addresses
    218 	 * we need to figure out if the current object that we're looking
    219 	 * at is a linux object or a solaris object.  To do this first
    220 	 * we need to find the string tab dynamic section element.
    221 	 */
    222 	for (i = 0; i < ndyns; i++) {
    223 		if (dynp[i].d_tag == DT_STRTAB)
    224 			break;
    225 	}
    226 	if (i == ndyns) {
    227 		ps_plog("lx_ldb_get_dyns: "
    228 		    "failed to find string tab in the dynamic section");
    229 		return (RD_OK);
    230 	}
    231 
    232 	/*
    233 	 * Check if the strtab value looks like an offset or an address.
    234 	 * It's an offset if the value is less then the base address that
    235 	 * the object is loaded at, or if the value is less than the offset
    236 	 * of the section headers in the same elf object.  This check isn't
    237 	 * perfect, but in practice it's good enough.
    238 	 */
    239 	if ((dynp[i].d_un.d_ptr < addr) ||
    240 	    (dynp[i].d_un.d_ptr < ehdr.e_shoff)) {
    241 		ps_plog("lx_ldb_get_dyns: "
    242 		    "doesn't appear to be an lx object");
    243 		return (RD_OK);
    244 	}
    245 
    246 	/*
    247 	 * This seems to be a a linux object, so we'll patch up the dynamic
    248 	 * section addresses
    249 	 */
    250 	ps_plog("lx_ldb_get_dyns: "
    251 	    "patching up lx object dynamic section addresses");
    252 	for (i = 0; i < ndyns; i++) {
    253 		switch (dynp[i].d_tag) {
    254 		case DT_PLTGOT:
    255 		case DT_HASH:
    256 		case DT_STRTAB:
    257 		case DT_SYMTAB:
    258 		case DT_RELA:
    259 		case DT_REL:
    260 		case DT_DEBUG:
    261 		case DT_JMPREL:
    262 		case DT_VERSYM:
    263 			if (dynp[i].d_un.d_val > addr) {
    264 				dynp[i].d_un.d_ptr -= addr;
    265 			}
    266 			break;
    267 		default:
    268 			break;
    269 		}
    270 	}
    271 	return (RD_OK);
    272 }
    273 
    274 static void
    275 lx_ldb_fini32(rd_helper_data_t rhd)
    276 {
    277 	lx_rd_t *lx_rd = (lx_rd_t *)rhd;
    278 	ps_plog("lx_ldb_fini: cleaning up lx helper");
    279 	free(lx_rd);
    280 }
    281 
    282 /*
    283  * The linux linker has an r_debug structure somewhere in its data section that
    284  * contains the address of the head of the link map list. To find this, we will
    285  * use the DT_DEBUG token in the executable's dynamic section. The linux linker
    286  * wrote the address of its r_debug structure to the DT_DEBUG dynamic entry. We
    287  * get the address of the executable's program headers from the
    288  * AT_SUN_BRAND_LX_PHDR aux vector entry. From there, we calculate the
    289  * address of the Elf header, and from there we can easily get to the DT_DEBUG
    290  * entry.
    291  */
    292 static rd_helper_data_t
    293 lx_ldb_init32(rd_agent_t *rap, struct ps_prochandle *php)
    294 {
    295 	lx_rd_t		*lx_rd;
    296 	uint32_t	addr, phdr_addr, dyn_addr;
    297 	Elf32_Dyn	*dyn;
    298 	Elf32_Phdr	phdr, *ph, *phdrs;
    299 	Elf32_Ehdr	ehdr;
    300 	int		i, dyn_count;
    301 
    302 	lx_rd = calloc(sizeof (lx_rd_t), 1);
    303 	if (lx_rd == NULL) {
    304 		ps_plog("lx_ldb_init: cannot allocate memory");
    305 		return (NULL);
    306 	}
    307 	lx_rd->lr_rap = rap;
    308 	lx_rd->lr_php = php;
    309 
    310 	phdr_addr = lx_ldb_getauxval32(php, AT_SUN_BRAND_LX_PHDR);
    311 	if (phdr_addr == (uint32_t)-1) {
    312 		ps_plog("lx_ldb_init: no LX_PHDR found in aux vector");
    313 		return (NULL);
    314 	}
    315 	ps_plog("lx_ldb_init: found LX_PHDR auxv phdr at: 0x%p",
    316 	    phdr_addr);
    317 
    318 	if (ps_pread(php, phdr_addr, &phdr, sizeof (phdr)) != PS_OK) {
    319 		ps_plog("lx_ldb_init: couldn't read phdr at 0x%p",
    320 		    phdr_addr);
    321 		free(lx_rd);
    322 		return (NULL);
    323 	}
    324 
    325 	/* The ELF headher should be before the program header in memory */
    326 	lx_rd->lr_exec = addr = phdr_addr - phdr.p_offset;
    327 	if (ps_pread(php, addr, &ehdr, sizeof (ehdr)) != PS_OK) {
    328 		ps_plog("lx_ldb_init: couldn't read ehdr at 0x%p",
    329 		    lx_rd->lr_exec);
    330 		free(lx_rd);
    331 		return (NULL);
    332 	}
    333 	ps_plog("lx_ldb_init: read ehdr at: 0x%p", addr);
    334 
    335 	if ((phdrs = malloc(ehdr.e_phnum * ehdr.e_phentsize)) == NULL) {
    336 		ps_plog("lx_ldb_init: couldn't alloc phdrs memory");
    337 		free(lx_rd);
    338 		return (NULL);
    339 	}
    340 
    341 	if (ps_pread(php, phdr_addr, phdrs, ehdr.e_phnum * ehdr.e_phentsize) !=
    342 	    PS_OK) {
    343 		ps_plog("lx_ldb_init: couldn't read phdrs at 0x%p",
    344 		    phdr_addr);
    345 		free(lx_rd);
    346 		free(phdrs);
    347 		return (NULL);
    348 	}
    349 	ps_plog("lx_ldb_init: read %d phdrs at: 0x%p",
    350 	    ehdr.e_phnum, phdr_addr);
    351 
    352 	for (i = 0, ph = phdrs; i < ehdr.e_phnum; i++,
    353 	    /*LINTED */
    354 	    ph = (Elf32_Phdr *)((char *)ph + ehdr.e_phentsize)) {
    355 		if (ph->p_type == PT_DYNAMIC)
    356 			break;
    357 	}
    358 	if (i == ehdr.e_phnum) {
    359 		ps_plog("lx_ldb_init: no PT_DYNAMIC in executable");
    360 		free(lx_rd);
    361 		free(phdrs);
    362 		return (NULL);
    363 	}
    364 	ps_plog("lx_ldb_init: found PT_DYNAMIC phdr[%d] at: 0x%p",
    365 	    i, (phdr_addr + ((char *)ph - (char *)phdrs)));
    366 
    367 	if ((dyn = malloc(ph->p_filesz)) == NULL) {
    368 		ps_plog("lx_ldb_init: couldn't alloc for PT_DYNAMIC");
    369 		free(lx_rd);
    370 		free(phdrs);
    371 		return (NULL);
    372 	}
    373 
    374 	dyn_addr = addr + ph->p_offset;
    375 	dyn_count = ph->p_filesz / sizeof (Elf32_Dyn);
    376 	if (ps_pread(php, dyn_addr, dyn, ph->p_filesz) != PS_OK) {
    377 		ps_plog("lx_ldb_init: couldn't read dynamic at 0x%p",
    378 		    dyn_addr);
    379 		free(lx_rd);
    380 		free(phdrs);
    381 		free(dyn);
    382 		return (NULL);
    383 	}
    384 	ps_plog("lx_ldb_init: read %d dynamic headers at: 0x%p",
    385 	    dyn_count, dyn_addr);
    386 
    387 	for (i = 0; i < dyn_count; i++) {
    388 		if (dyn[i].d_tag == DT_DEBUG) {
    389 			lx_rd->lr_rdebug = dyn[i].d_un.d_ptr;
    390 			break;
    391 		}
    392 	}
    393 	free(phdrs);
    394 	free(dyn);
    395 
    396 	if (lx_rd->lr_rdebug == 0) {
    397 		ps_plog("lx_ldb_init: no DT_DEBUG found in exe");
    398 		free(lx_rd);
    399 		return (NULL);
    400 	}
    401 	ps_plog("lx_ldb_init: found DT_DEBUG: 0x%p", lx_rd->lr_rdebug);
    402 
    403 	return ((rd_helper_data_t)lx_rd);
    404 }
    405 
    406 /*
    407  * Given the address of an ELF object in the target, return its size and
    408  * the proper link map ID.
    409  */
    410 static size_t
    411 lx_elf_props32(struct ps_prochandle *php, uint32_t addr, psaddr_t *data_addr)
    412 {
    413 	Elf32_Ehdr	ehdr;
    414 	Elf32_Phdr	*phdrs, *ph;
    415 	int		i;
    416 	uint32_t	min = (uint32_t)-1;
    417 	uint32_t	max = 0;
    418 	size_t		sz;
    419 
    420 	if (ps_pread(php, addr, &ehdr, sizeof (ehdr)) != PS_OK) {
    421 		ps_plog("lx_elf_props: Couldn't read ELF header at 0x%p",
    422 		    addr);
    423 		return (0);
    424 	}
    425 
    426 	if ((phdrs = malloc(ehdr.e_phnum * ehdr.e_phentsize)) == NULL)
    427 		return (0);
    428 
    429 	if (ps_pread(php, addr + ehdr.e_phoff, phdrs, ehdr.e_phnum *
    430 	    ehdr.e_phentsize) != PS_OK) {
    431 		ps_plog("lx_elf_props: Couldn't read program headers at 0x%p",
    432 		    addr + ehdr.e_phoff);
    433 		return (0);
    434 	}
    435 
    436 	for (i = 0, ph = phdrs; i < ehdr.e_phnum; i++,
    437 	    /*LINTED */
    438 	    ph = (Elf32_Phdr *)((char *)ph + ehdr.e_phentsize)) {
    439 
    440 		if (ph->p_type != PT_LOAD)
    441 			continue;
    442 
    443 		if ((ph->p_flags & (PF_W | PF_R)) == (PF_W | PF_R)) {
    444 			*data_addr = ph->p_vaddr;
    445 			if (ehdr.e_type == ET_DYN)
    446 				*data_addr += addr;
    447 			if (*data_addr & (ph->p_align - 1))
    448 				*data_addr = *data_addr & (~(ph->p_align -1));
    449 		}
    450 
    451 		if (ph->p_vaddr < min)
    452 			min = ph->p_vaddr;
    453 
    454 		if (ph->p_vaddr > max) {
    455 			max = ph->p_vaddr;
    456 			sz = ph->p_memsz + max - min;
    457 			if (sz & (ph->p_align - 1))
    458 				sz = (sz & (~(ph->p_align - 1))) + ph->p_align;
    459 		}
    460 	}
    461 
    462 	free(phdrs);
    463 	return (sz);
    464 }
    465 
    466 static int
    467 lx_ldb_loadobj_iter32(rd_helper_data_t rhd, rl_iter_f *cb, void *client_data)
    468 {
    469 	lx_rd_t			*lx_rd = (lx_rd_t *)rhd;
    470 	struct ps_prochandle	*php = lx_rd->lr_php;
    471 	lx_r_debug_t		r_debug;
    472 	lx_link_map_t		map;
    473 	uint32_t		p = NULL;
    474 	int			rc;
    475 	rd_loadobj_t		exec;
    476 
    477 	if ((rc = ps_pread(php, (psaddr_t)lx_rd->lr_rdebug, &r_debug,
    478 	    sizeof (r_debug))) != PS_OK) {
    479 		ps_plog("lx_ldb_loadobj_iter: "
    480 		    "Couldn't read linux r_debug at 0x%p", lx_rd->lr_rdebug);
    481 		return (rc);
    482 	}
    483 
    484 	p = r_debug.r_map;
    485 
    486 	/*
    487 	 * The first item on the link map list is for the executable, but it
    488 	 * doesn't give us any useful information about it. We need to
    489 	 * synthesize a rd_loadobj_t for the client.
    490 	 *
    491 	 * Linux doesn't give us the executable name, so we'll get it from
    492 	 * the AT_EXECNAME entry instead.
    493 	 */
    494 	if ((rc = ps_pread(php, (psaddr_t)p, &map, sizeof (map))) != PS_OK) {
    495 		ps_plog("lx_ldb_loadobj_iter: "
    496 		    "Couldn't read linux link map at 0x%p", p);
    497 		return (rc);
    498 	}
    499 
    500 	bzero(&exec, sizeof (exec));
    501 	exec.rl_base = lx_rd->lr_exec;
    502 	exec.rl_dynamic = map.lxm_ld;
    503 	exec.rl_nameaddr = lx_ldb_getauxval32(php, AT_SUN_EXECNAME);
    504 	exec.rl_lmident = LM_ID_BASE;
    505 
    506 	exec.rl_bend = exec.rl_base +
    507 	    lx_elf_props32(php, lx_rd->lr_exec, &exec.rl_data_base);
    508 
    509 	if ((*cb)(&exec, client_data) == 0) {
    510 		ps_plog("lx_ldb_loadobj_iter: "
    511 		    "client callb failed for executable");
    512 		return (PS_ERR);
    513 	}
    514 
    515 	for (p = map.lxm_next; p != NULL; p = map.lxm_next) {
    516 		rd_loadobj_t	obj;
    517 
    518 		if ((rc = ps_pread(php, (psaddr_t)p, &map, sizeof (map))) !=
    519 		    PS_OK) {
    520 			ps_plog("lx_ldb_loadobj_iter: "
    521 			    "Couldn't read lk map at %p", p);
    522 			return (rc);
    523 		}
    524 
    525 		/*
    526 		 * The linux link map has less information than the Solaris one.
    527 		 * We need to go fetch the missing information from the ELF
    528 		 * headers.
    529 		 */
    530 
    531 		obj.rl_nameaddr = (psaddr_t)map.lxm_name;
    532 		obj.rl_base = map.lxm_addr;
    533 		obj.rl_refnameaddr = (psaddr_t)map.lxm_name;
    534 		obj.rl_plt_base = NULL;
    535 		obj.rl_plt_size = 0;
    536 		obj.rl_lmident = LM_ID_BASE;
    537 
    538 		/*
    539 		 * Ugh - we have to walk the ELF stuff, find the PT_LOAD
    540 		 * sections, and calculate the end of the file's mappings
    541 		 * ourselves.
    542 		 */
    543 
    544 		obj.rl_bend = map.lxm_addr +
    545 		    lx_elf_props32(php, map.lxm_addr, &obj.rl_data_base);
    546 		obj.rl_padstart = obj.rl_base;
    547 		obj.rl_padend = obj.rl_bend;
    548 		obj.rl_dynamic = map.lxm_ld;
    549 		obj.rl_tlsmodid = 0;
    550 
    551 		ps_plog("lx_ldb_loadobj_iter: 0x%p to 0x%p",
    552 		    obj.rl_base, obj.rl_bend);
    553 
    554 		if ((*cb)(&obj, client_data) == 0) {
    555 			ps_plog("lx_ldb_loadobj_iter: "
    556 			    "Client callback failed on %s", map.lxm_name);
    557 			return (rc);
    558 		}
    559 	}
    560 	return (RD_OK);
    561 }
    562 
    563 /*
    564  * Librtld_db plugin linkage struct.
    565  *
    566  * When we get loaded by librtld_db, it will look for the symbol below
    567  * to find our plugin entry points.
    568  */
    569 rd_helper_ops_t RTLD_DB_BRAND_OPS = {
    570 	LM_ID_BRAND,
    571 	lx_ldb_init32,
    572 	lx_ldb_fini32,
    573 	lx_ldb_loadobj_iter32,
    574 	lx_ldb_get_dyns32
    575 };
    576