/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1994, by Sun Microsytems, Inc. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * Interfaces for searching for elf specific information */ #include #include #include #include #include #include #include "tnfctl_int.h" #include "dbg.h" /* * Declarations */ static tnfctl_errcode_t dynsec_num(tnfctl_handle_t *hndl, uintptr_t baseaddr, int objfd, int *num_dyn); static tnfctl_errcode_t elf_dynmatch(Elf *elf, char *strs, Elf_Scn *dyn_scn, GElf_Shdr *dyn_shdr, Elf_Data *dyn_data, uintptr_t baseaddr, tnfctl_elf_search_t * search_info_p); static tnfctl_errcode_t dyn_findtag( Elf3264_Dyn *start, /* start of dynam table read in */ Elf3264_Sword tag, /* tag to search for */ uintptr_t dynam_addr, /* address of _DYNAMIC in target */ int limit, /* number of entries in table */ uintptr_t *dentry_address); /* return value */ /* ---------------------------------------------------------------- */ /* ----------------------- Public Functions ----------------------- */ /* ---------------------------------------------------------------- */ /* * _tnfctl_elf_dbgent() - this function finds the address of the * debug struct (DT_DEBUG) in the target process. _DYNAMIC is a symbol * present in every object. The one in the main executable references * an array that is tagged with the kind of each member. We search * for the tag of DT_DEBUG which is where the run time linker maintains * a structure that references the shared object linked list. * * A side effect of searching for DT_DEBUG ensures that the executable is * a dynamic executable - tracing only works on dynamic executables because * static executables don't have relocation tables. */ tnfctl_errcode_t _tnfctl_elf_dbgent(tnfctl_handle_t *hndl, uintptr_t * entaddr_p) { tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; prb_status_t prbstat = PRB_STATUS_OK; int miscstat; int objfd; int num_dynentries = 0; uintptr_t dynamic_addr; uintptr_t baseaddr; uintptr_t dentry_addr; Elf3264_Dyn *dynam_tab = NULL; long dynam_tab_size; *entaddr_p = NULL; prbstat = prb_mainobj_get(hndl->proc_p, &objfd, &baseaddr); if (prbstat) return (_tnfctl_map_to_errcode(prbstat)); /* find the address of the symbol _DYNAMIC */ prexstat = _tnfctl_sym_find_in_obj(objfd, baseaddr, "_DYNAMIC", &dynamic_addr); if (prexstat) { prexstat = TNFCTL_ERR_NOTDYNAMIC; goto Cleanup; } /* find the number of entries in the .dynamic section */ prexstat = dynsec_num(hndl, baseaddr, objfd, &num_dynentries); if (prexstat) goto Cleanup; DBG_TNF_PROBE_2(_tnfctl_elf_dbgent_1, "libtnfctl", "sunw%verbosity 2", tnf_long, num_of_dynentries, num_dynentries, tnf_opaque, DYNAMIC_address, dynamic_addr); /* read in the dynamic table from the image of the process */ dynam_tab_size = num_dynentries * sizeof (Elf3264_Dyn); dynam_tab = malloc(dynam_tab_size); if (!dynam_tab) { close(objfd); return (TNFCTL_ERR_ALLOCFAIL); } miscstat = hndl->p_read(hndl->proc_p, dynamic_addr, dynam_tab, dynam_tab_size); if (miscstat) { prexstat = TNFCTL_ERR_INTERNAL; goto Cleanup; } prexstat = dyn_findtag(dynam_tab, DT_DEBUG, dynamic_addr, num_dynentries, &dentry_addr); if (prexstat) { goto Cleanup; } *entaddr_p = dentry_addr; Cleanup: close(objfd); if (dynam_tab) free(dynam_tab); return (prexstat); } /* ---------------------------------------------------------------- */ /* ----------------------- Private Functions ---------------------- */ /* ---------------------------------------------------------------- */ /* * dyn_findtag() - searches tags in _DYNAMIC table */ static tnfctl_errcode_t dyn_findtag(Elf3264_Dyn * start, /* start of dynam table read in */ Elf3264_Sword tag, /* tag to search for */ uintptr_t dynam_addr, /* base address of _DYNAMIC in target */ int limit, /* number of entries in table */ uintptr_t * dentry_address) { /* return value */ Elf3264_Dyn *dp; for (dp = start; dp->d_tag != DT_NULL; dp++) { DBG_TNF_PROBE_1(dyn_findtag_1, "libtnfctl", "sunw%verbosity 3; sunw%debug 'in loop'", tnf_long, tag, dp->d_tag); if (dp->d_tag == tag) { *dentry_address = dynam_addr + (dp - start) * sizeof (Elf3264_Dyn); return (TNFCTL_ERR_NONE); } if (--limit <= 0) { DBG((void) fprintf(stderr, "dyn_findtag: exceeded limit of table\n")); return (TNFCTL_ERR_INTERNAL); } } DBG((void) fprintf(stderr, "dyn_findtag: couldn't find tag, last tag=%d\n", (int) dp->d_tag)); return (TNFCTL_ERR_INTERNAL); } /* * dynsec_num() - find the number of entries in the .dynamic section */ /*ARGSUSED*/ static tnfctl_errcode_t dynsec_num(tnfctl_handle_t *hndl, uintptr_t baseaddr, int objfd, int *num_dyn) { int num_ent = 0; tnfctl_errcode_t prexstat; tnfctl_elf_search_t search_info; DBG_TNF_PROBE_0(dynsec_num_1, "libtnfctl", "sunw%verbosity 2;" "sunw%debug 'counting number of entries in .dynamic section'"); search_info.section_func = elf_dynmatch; search_info.section_data = &num_ent; prexstat = _tnfctl_traverse_object(objfd, baseaddr, &search_info); if (prexstat) return (prexstat); if (num_ent == 0) return (TNFCTL_ERR_NOTDYNAMIC); *num_dyn = num_ent; return (TNFCTL_ERR_NONE); } /* * elf_dynmatch() - this function searches for the .dynamic section and * returns the number of entries in it. */ /*ARGSUSED*/ static tnfctl_errcode_t elf_dynmatch(Elf * elf, char *strs, Elf_Scn * dyn_scn, GElf_Shdr * dyn_shdr, Elf_Data * dyn_data, uintptr_t baseaddr, tnfctl_elf_search_t *search_info_p) { char *scn_name; int *ret = (int *) search_info_p->section_data; /* bail if this isn't a .dynamic section */ scn_name = strs + dyn_shdr->sh_name; if (strcmp(scn_name, ".dynamic") != 0) return (TNFCTL_ERR_NONE); if (dyn_shdr->sh_entsize == 0) { /* no dynamic section */ *ret = 0; } else { *ret = (int) (dyn_shdr->sh_size / dyn_shdr->sh_entsize); } return (TNFCTL_ERR_NONE); }