1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright (c) 1994, by Sun Microsytems, Inc. 24*7c478bd9Sstevel@tonic-gate */ 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate /* 29*7c478bd9Sstevel@tonic-gate * Interfaces for searching for elf specific information 30*7c478bd9Sstevel@tonic-gate */ 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #include <unistd.h> 33*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 34*7c478bd9Sstevel@tonic-gate #include <string.h> 35*7c478bd9Sstevel@tonic-gate #include <errno.h> 36*7c478bd9Sstevel@tonic-gate #include <link.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/procfs.h> 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate #include "tnfctl_int.h" 40*7c478bd9Sstevel@tonic-gate #include "dbg.h" 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate /* 44*7c478bd9Sstevel@tonic-gate * Declarations 45*7c478bd9Sstevel@tonic-gate */ 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t dynsec_num(tnfctl_handle_t *hndl, uintptr_t baseaddr, 48*7c478bd9Sstevel@tonic-gate int objfd, int *num_dyn); 49*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t elf_dynmatch(Elf *elf, char *strs, Elf_Scn *dyn_scn, 50*7c478bd9Sstevel@tonic-gate GElf_Shdr *dyn_shdr, Elf_Data *dyn_data, 51*7c478bd9Sstevel@tonic-gate uintptr_t baseaddr, tnfctl_elf_search_t * search_info_p); 52*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t dyn_findtag( 53*7c478bd9Sstevel@tonic-gate Elf3264_Dyn *start, /* start of dynam table read in */ 54*7c478bd9Sstevel@tonic-gate Elf3264_Sword tag, /* tag to search for */ 55*7c478bd9Sstevel@tonic-gate uintptr_t dynam_addr, /* address of _DYNAMIC in target */ 56*7c478bd9Sstevel@tonic-gate int limit, /* number of entries in table */ 57*7c478bd9Sstevel@tonic-gate uintptr_t *dentry_address); /* return value */ 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */ 61*7c478bd9Sstevel@tonic-gate /* ----------------------- Public Functions ----------------------- */ 62*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */ 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* 65*7c478bd9Sstevel@tonic-gate * _tnfctl_elf_dbgent() - this function finds the address of the 66*7c478bd9Sstevel@tonic-gate * debug struct (DT_DEBUG) in the target process. _DYNAMIC is a symbol 67*7c478bd9Sstevel@tonic-gate * present in every object. The one in the main executable references 68*7c478bd9Sstevel@tonic-gate * an array that is tagged with the kind of each member. We search 69*7c478bd9Sstevel@tonic-gate * for the tag of DT_DEBUG which is where the run time linker maintains 70*7c478bd9Sstevel@tonic-gate * a structure that references the shared object linked list. 71*7c478bd9Sstevel@tonic-gate * 72*7c478bd9Sstevel@tonic-gate * A side effect of searching for DT_DEBUG ensures that the executable is 73*7c478bd9Sstevel@tonic-gate * a dynamic executable - tracing only works on dynamic executables because 74*7c478bd9Sstevel@tonic-gate * static executables don't have relocation tables. 75*7c478bd9Sstevel@tonic-gate */ 76*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 77*7c478bd9Sstevel@tonic-gate _tnfctl_elf_dbgent(tnfctl_handle_t *hndl, uintptr_t * entaddr_p) 78*7c478bd9Sstevel@tonic-gate { 79*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; 80*7c478bd9Sstevel@tonic-gate prb_status_t prbstat = PRB_STATUS_OK; 81*7c478bd9Sstevel@tonic-gate int miscstat; 82*7c478bd9Sstevel@tonic-gate int objfd; 83*7c478bd9Sstevel@tonic-gate int num_dynentries = 0; 84*7c478bd9Sstevel@tonic-gate uintptr_t dynamic_addr; 85*7c478bd9Sstevel@tonic-gate uintptr_t baseaddr; 86*7c478bd9Sstevel@tonic-gate uintptr_t dentry_addr; 87*7c478bd9Sstevel@tonic-gate Elf3264_Dyn *dynam_tab = NULL; 88*7c478bd9Sstevel@tonic-gate long dynam_tab_size; 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate *entaddr_p = NULL; 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate prbstat = prb_mainobj_get(hndl->proc_p, &objfd, &baseaddr); 93*7c478bd9Sstevel@tonic-gate if (prbstat) 94*7c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat)); 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate /* find the address of the symbol _DYNAMIC */ 97*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find_in_obj(objfd, baseaddr, "_DYNAMIC", 98*7c478bd9Sstevel@tonic-gate &dynamic_addr); 99*7c478bd9Sstevel@tonic-gate if (prexstat) { 100*7c478bd9Sstevel@tonic-gate prexstat = TNFCTL_ERR_NOTDYNAMIC; 101*7c478bd9Sstevel@tonic-gate goto Cleanup; 102*7c478bd9Sstevel@tonic-gate } 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate /* find the number of entries in the .dynamic section */ 105*7c478bd9Sstevel@tonic-gate prexstat = dynsec_num(hndl, baseaddr, objfd, &num_dynentries); 106*7c478bd9Sstevel@tonic-gate if (prexstat) 107*7c478bd9Sstevel@tonic-gate goto Cleanup; 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate DBG_TNF_PROBE_2(_tnfctl_elf_dbgent_1, "libtnfctl", "sunw%verbosity 2", 110*7c478bd9Sstevel@tonic-gate tnf_long, num_of_dynentries, num_dynentries, 111*7c478bd9Sstevel@tonic-gate tnf_opaque, DYNAMIC_address, dynamic_addr); 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate /* read in the dynamic table from the image of the process */ 114*7c478bd9Sstevel@tonic-gate dynam_tab_size = num_dynentries * sizeof (Elf3264_Dyn); 115*7c478bd9Sstevel@tonic-gate dynam_tab = malloc(dynam_tab_size); 116*7c478bd9Sstevel@tonic-gate if (!dynam_tab) { 117*7c478bd9Sstevel@tonic-gate close(objfd); 118*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_ALLOCFAIL); 119*7c478bd9Sstevel@tonic-gate } 120*7c478bd9Sstevel@tonic-gate miscstat = hndl->p_read(hndl->proc_p, dynamic_addr, dynam_tab, 121*7c478bd9Sstevel@tonic-gate dynam_tab_size); 122*7c478bd9Sstevel@tonic-gate if (miscstat) { 123*7c478bd9Sstevel@tonic-gate prexstat = TNFCTL_ERR_INTERNAL; 124*7c478bd9Sstevel@tonic-gate goto Cleanup; 125*7c478bd9Sstevel@tonic-gate } 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate prexstat = dyn_findtag(dynam_tab, DT_DEBUG, dynamic_addr, 128*7c478bd9Sstevel@tonic-gate num_dynentries, &dentry_addr); 129*7c478bd9Sstevel@tonic-gate if (prexstat) { 130*7c478bd9Sstevel@tonic-gate goto Cleanup; 131*7c478bd9Sstevel@tonic-gate } 132*7c478bd9Sstevel@tonic-gate *entaddr_p = dentry_addr; 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate Cleanup: 135*7c478bd9Sstevel@tonic-gate close(objfd); 136*7c478bd9Sstevel@tonic-gate if (dynam_tab) 137*7c478bd9Sstevel@tonic-gate free(dynam_tab); 138*7c478bd9Sstevel@tonic-gate return (prexstat); 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate } 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */ 144*7c478bd9Sstevel@tonic-gate /* ----------------------- Private Functions ---------------------- */ 145*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */ 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate /* 148*7c478bd9Sstevel@tonic-gate * dyn_findtag() - searches tags in _DYNAMIC table 149*7c478bd9Sstevel@tonic-gate */ 150*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t 151*7c478bd9Sstevel@tonic-gate dyn_findtag(Elf3264_Dyn * start, /* start of dynam table read in */ 152*7c478bd9Sstevel@tonic-gate Elf3264_Sword tag, /* tag to search for */ 153*7c478bd9Sstevel@tonic-gate uintptr_t dynam_addr, /* base address of _DYNAMIC in target */ 154*7c478bd9Sstevel@tonic-gate int limit, /* number of entries in table */ 155*7c478bd9Sstevel@tonic-gate uintptr_t * dentry_address) 156*7c478bd9Sstevel@tonic-gate { /* return value */ 157*7c478bd9Sstevel@tonic-gate Elf3264_Dyn *dp; 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate for (dp = start; dp->d_tag != DT_NULL; dp++) { 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate DBG_TNF_PROBE_1(dyn_findtag_1, "libtnfctl", 162*7c478bd9Sstevel@tonic-gate "sunw%verbosity 3; sunw%debug 'in loop'", 163*7c478bd9Sstevel@tonic-gate tnf_long, tag, dp->d_tag); 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate if (dp->d_tag == tag) { 166*7c478bd9Sstevel@tonic-gate *dentry_address = dynam_addr + 167*7c478bd9Sstevel@tonic-gate (dp - start) * sizeof (Elf3264_Dyn); 168*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 169*7c478bd9Sstevel@tonic-gate } 170*7c478bd9Sstevel@tonic-gate if (--limit <= 0) { 171*7c478bd9Sstevel@tonic-gate DBG((void) fprintf(stderr, 172*7c478bd9Sstevel@tonic-gate "dyn_findtag: exceeded limit of table\n")); 173*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_INTERNAL); 174*7c478bd9Sstevel@tonic-gate } 175*7c478bd9Sstevel@tonic-gate } 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate DBG((void) fprintf(stderr, 178*7c478bd9Sstevel@tonic-gate "dyn_findtag: couldn't find tag, last tag=%d\n", 179*7c478bd9Sstevel@tonic-gate (int) dp->d_tag)); 180*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_INTERNAL); 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate /* 185*7c478bd9Sstevel@tonic-gate * dynsec_num() - find the number of entries in the .dynamic section 186*7c478bd9Sstevel@tonic-gate */ 187*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 188*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t 189*7c478bd9Sstevel@tonic-gate dynsec_num(tnfctl_handle_t *hndl, uintptr_t baseaddr, 190*7c478bd9Sstevel@tonic-gate int objfd, int *num_dyn) 191*7c478bd9Sstevel@tonic-gate { 192*7c478bd9Sstevel@tonic-gate int num_ent = 0; 193*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat; 194*7c478bd9Sstevel@tonic-gate tnfctl_elf_search_t search_info; 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate DBG_TNF_PROBE_0(dynsec_num_1, "libtnfctl", 197*7c478bd9Sstevel@tonic-gate "sunw%verbosity 2;" 198*7c478bd9Sstevel@tonic-gate "sunw%debug 'counting number of entries in .dynamic section'"); 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate search_info.section_func = elf_dynmatch; 201*7c478bd9Sstevel@tonic-gate search_info.section_data = &num_ent; 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_traverse_object(objfd, baseaddr, &search_info); 204*7c478bd9Sstevel@tonic-gate if (prexstat) 205*7c478bd9Sstevel@tonic-gate return (prexstat); 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate if (num_ent == 0) 208*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NOTDYNAMIC); 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate *num_dyn = num_ent; 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 213*7c478bd9Sstevel@tonic-gate } 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate /* 217*7c478bd9Sstevel@tonic-gate * elf_dynmatch() - this function searches for the .dynamic section and 218*7c478bd9Sstevel@tonic-gate * returns the number of entries in it. 219*7c478bd9Sstevel@tonic-gate */ 220*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 221*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t 222*7c478bd9Sstevel@tonic-gate elf_dynmatch(Elf * elf, 223*7c478bd9Sstevel@tonic-gate char *strs, 224*7c478bd9Sstevel@tonic-gate Elf_Scn * dyn_scn, 225*7c478bd9Sstevel@tonic-gate GElf_Shdr * dyn_shdr, 226*7c478bd9Sstevel@tonic-gate Elf_Data * dyn_data, 227*7c478bd9Sstevel@tonic-gate uintptr_t baseaddr, 228*7c478bd9Sstevel@tonic-gate tnfctl_elf_search_t *search_info_p) 229*7c478bd9Sstevel@tonic-gate { 230*7c478bd9Sstevel@tonic-gate char *scn_name; 231*7c478bd9Sstevel@tonic-gate int *ret = (int *) search_info_p->section_data; 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate /* bail if this isn't a .dynamic section */ 234*7c478bd9Sstevel@tonic-gate scn_name = strs + dyn_shdr->sh_name; 235*7c478bd9Sstevel@tonic-gate if (strcmp(scn_name, ".dynamic") != 0) 236*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate if (dyn_shdr->sh_entsize == 0) { /* no dynamic section */ 239*7c478bd9Sstevel@tonic-gate *ret = 0; 240*7c478bd9Sstevel@tonic-gate } else { 241*7c478bd9Sstevel@tonic-gate *ret = (int) (dyn_shdr->sh_size / dyn_shdr->sh_entsize); 242*7c478bd9Sstevel@tonic-gate } 243*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 244*7c478bd9Sstevel@tonic-gate } 245