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