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 * Routines that 30 * - return an address for a symbol name 31 * - return a symbol name for an address 32 */ 33 34 #ifndef DEBUG 35 #define NDEBUG 1 36 #endif 37 38 #include <stdlib.h> 39 #include <unistd.h> 40 #include <string.h> 41 #include <errno.h> 42 #include <sys/procfs.h> 43 #include <sys/stat.h> 44 #include <assert.h> 45 #include <note.h> 46 47 #include "tnfctl_int.h" 48 #include "dbg.h" 49 50 51 /* 52 * Typedefs 53 */ 54 55 typedef struct sym_args { 56 char *sa_name; 57 uintptr_t sa_addr; 58 } sym_args_t; 59 NOTE(SCHEME_PROTECTS_DATA("always automatic", sym_args)) 60 61 /* 62 * Declarations 63 */ 64 65 static tnfctl_errcode_t sym_findname_in_obj(int objfd, uintptr_t baseaddr, 66 uintptr_t symaddr, char **symname); 67 68 static tnfctl_errcode_t sym_match(char *name, uintptr_t addr, void *sym_entry, 69 tnfctl_elf_search_t *search_info_p); 70 71 static tnfctl_errcode_t sym_matchname(char *name, uintptr_t addr, 72 void *sym_entry, 73 tnfctl_elf_search_t *search_info_p); 74 75 76 /* ---------------------------------------------------------------- */ 77 /* ----------------------- Public Functions ----------------------- */ 78 /* ---------------------------------------------------------------- */ 79 80 /* 81 * _tnfctl_sym_find_in_obj() - determines the virtual address of the supplied 82 * symbol in the object file specified by fd. 83 */ 84 tnfctl_errcode_t 85 _tnfctl_sym_find_in_obj(int objfd, uintptr_t baseaddr, const char *symname, 86 uintptr_t *symaddr) 87 { 88 tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; 89 sym_args_t symargs; 90 tnfctl_elf_search_t search_info; 91 92 DBG_TNF_PROBE_1(_tnfctl_sym_find_in_obj_1, "libtnfctl", 93 "sunw%verbosity 3", 94 tnf_string, searching_for, symname); 95 96 symargs.sa_name = (char *) symname; 97 /* clear output argument in advance */ 98 symargs.sa_addr = 0; 99 100 search_info.section_func = _tnfctl_traverse_dynsym; 101 search_info.record_func = sym_match; 102 search_info.record_data = &symargs; 103 104 prexstat = _tnfctl_traverse_object(objfd, baseaddr, &search_info); 105 if (prexstat) 106 return (prexstat); 107 108 /* check if we found symbol address */ 109 if (symargs.sa_addr == 0) { 110 return (TNFCTL_ERR_BADARG); 111 } 112 113 *symaddr = symargs.sa_addr; 114 return (TNFCTL_ERR_NONE); 115 } 116 117 118 /* 119 * _tnfctl_sym_find() - determines the virtual address of the supplied symbol 120 * in the process. 121 */ 122 tnfctl_errcode_t 123 _tnfctl_sym_find(tnfctl_handle_t *hndl, const char *symname, uintptr_t *symaddr) 124 { 125 boolean_t release_lock; 126 tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; 127 objlist_t *obj; 128 129 DBG_TNF_PROBE_1(_tnfctl_sym_find_start, "libtnfctl", 130 "start _tnfctl_sym_find; sunw%verbosity 3", 131 tnf_string, searching_for, symname); 132 133 /*LINTED statement has no consequent: else*/ 134 LOCK(hndl, prexstat, release_lock); 135 136 /* for every object in list, search for symbol */ 137 for (obj = hndl->objlist; obj; obj = obj->next) { 138 if (obj->old == B_TRUE) 139 continue; /* don't examine dlclose'd libs */ 140 141 /* return value of TNFCTL_ERR_BADARG means symbol not found */ 142 prexstat = _tnfctl_sym_find_in_obj(obj->objfd, 143 obj->baseaddr, symname, symaddr); 144 if (prexstat == TNFCTL_ERR_NONE) 145 /* symbol found */ 146 break; 147 else if (prexstat != TNFCTL_ERR_BADARG) 148 /* error condition */ 149 break; 150 /* continue loop on TNFCTL_ERR_BADARG */ 151 } 152 153 /*LINTED statement has no consequent: else*/ 154 UNLOCK(hndl, release_lock); 155 156 DBG_TNF_PROBE_0(_tnfctl_sym_find_end, "libtnfctl", 157 "end _tnfctl_sym_find; sunw%verbosity 3"); 158 159 return (prexstat); 160 } 161 162 /* 163 * _tnfctl_sym_obj_find() - determines the virtual address of the supplied 164 * symbol in the object specified by base name 165 */ 166 tnfctl_errcode_t 167 _tnfctl_sym_obj_find(tnfctl_handle_t *hndl, const char *lib_base_name, 168 const char *symname, uintptr_t *symaddr) 169 { 170 tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; 171 objlist_t *obj, *found_obj; 172 const char *str_ptr; 173 174 assert((hndl->mode == INTERNAL_MODE) ? 175 (MUTEX_HELD(&_tnfctl_lmap_lock)) : 1); 176 177 DBG_TNF_PROBE_1(_tnfctl_sym_obj_find_start, "libtnfctl", 178 "start _tnfctl_sym_obj_find; sunw%verbosity 3", 179 tnf_string, searching_for, symname); 180 181 found_obj = NULL; 182 /* for every object in list ... */ 183 for (obj = hndl->objlist; obj; obj = obj->next) { 184 if (obj->old == B_TRUE) 185 continue; /* don't examine dlclose'd libs */ 186 187 if (obj->objname == NULL) 188 continue; 189 190 /* find the last occurrence of / in the name */ 191 str_ptr = strrchr(obj->objname, '/'); 192 if (str_ptr == NULL) { 193 str_ptr = obj->objname; 194 } else { 195 str_ptr++; /* bump up past '/' */ 196 } 197 198 /* XXX - use strcoll ? */ 199 if (strcmp(str_ptr, lib_base_name) == 0) { 200 found_obj = obj; 201 break; 202 } 203 } 204 /* return value of TNFCTL_ERR_BADARG means symbol not found */ 205 if (found_obj == NULL) 206 return (TNFCTL_ERR_BADARG); 207 208 prexstat = _tnfctl_sym_find_in_obj(found_obj->objfd, 209 found_obj->baseaddr, symname, symaddr); 210 211 DBG_TNF_PROBE_0(_tnfctl_sym_obj_find_end, "libtnfctl", 212 "end _tnfctl_sym_obj_find; sunw%verbosity 3"); 213 214 return (prexstat); 215 } 216 217 /* 218 * _tnfctl_sym_findname() - determines the name of a function from its address. 219 */ 220 tnfctl_errcode_t 221 _tnfctl_sym_findname(tnfctl_handle_t *hndl, uintptr_t symaddr, 222 char **symname) 223 { 224 boolean_t release_lock; 225 tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; 226 objlist_t *obj; 227 228 DBG_TNF_PROBE_1(_tnfctl_sym_findname_start, "libtnfctl", 229 "start _tnfctl_sym_findname; sunw%verbosity 3", 230 tnf_opaque, searching_for, symaddr); 231 232 /*LINTED statement has no consequent: else*/ 233 LOCK(hndl, prexstat, release_lock); 234 235 /* for every object in list, search for name */ 236 for (obj = hndl->objlist; obj; obj = obj->next) { 237 if (obj->old == B_TRUE) 238 continue; /* don't examine dlclose'd libs */ 239 /* return value of TNFCTL_ERR_BADARG means symbol not found */ 240 prexstat = sym_findname_in_obj(obj->objfd, 241 obj->baseaddr, symaddr, symname); 242 if (prexstat == TNFCTL_ERR_NONE) 243 /* symbol found */ 244 break; 245 else if (prexstat != TNFCTL_ERR_BADARG) 246 /* error condition */ 247 break; 248 /* continue loop on TNFCTL_ERR_BADARG */ 249 } 250 251 /*LINTED statement has no consequent: else*/ 252 UNLOCK(hndl, release_lock); 253 254 DBG_TNF_PROBE_0(_tnfctl_sym_findname_end, "libtnfctl", 255 "end _tnfctl_sym_findname; sunw%verbosity 3"); 256 257 return (prexstat); 258 } 259 260 261 /* ---------------------------------------------------------------- */ 262 /* ----------------------- Private Functions ---------------------- */ 263 /* ---------------------------------------------------------------- */ 264 265 /* 266 * sym_findname_in_obj() - determines the name of the supplied 267 * address in the specified object file. 268 */ 269 static tnfctl_errcode_t 270 sym_findname_in_obj(int objfd, uintptr_t baseaddr, uintptr_t symaddr, 271 char **symname) 272 { 273 tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; 274 sym_args_t symargs; 275 tnfctl_elf_search_t search_info; 276 277 DBG_TNF_PROBE_1(sym_findname_in_obj_1, "libtnfctl", 278 "sunw%verbosity 3", 279 tnf_opaque, searching_for, symaddr); 280 281 /* clear output argument in advance */ 282 symargs.sa_name = NULL; 283 symargs.sa_addr = symaddr; 284 285 search_info.section_func = _tnfctl_traverse_dynsym; 286 search_info.record_func = sym_matchname; 287 search_info.record_data = &symargs; 288 289 prexstat = _tnfctl_traverse_object(objfd, baseaddr, &search_info); 290 if (prexstat) 291 return (prexstat); 292 293 /* check if we found symbol address */ 294 if (symargs.sa_name == NULL) { 295 return (TNFCTL_ERR_BADARG); 296 } 297 298 *symname = symargs.sa_name; 299 return (TNFCTL_ERR_NONE); 300 } 301 302 /* 303 * sym_match() - function to be called on each symbol in a dynsym section. 304 * Used to find the address of a symbol. 305 */ 306 static tnfctl_errcode_t 307 sym_match(char *name, uintptr_t addr, void *sym_entry, 308 tnfctl_elf_search_t *search_info_p) 309 { 310 sym_args_t *symargs_p = (sym_args_t *) search_info_p->record_data; 311 Elf3264_Sym *sym = (Elf3264_Sym *) sym_entry; 312 #if 0 313 printf("enter sym_match: \n"); 314 if (symargs_p->sa_name != 0) 315 printf("(symargs_p->sa_name) = %s\n", symargs_p->sa_name); 316 else 317 printf("symargs_p->sa_name = 0\n"); 318 if (name != 0) 319 printf("(name) = %s\n", name); 320 else 321 printf("name = 0\n"); 322 #endif 323 324 #ifdef VERYVERBOSE 325 (void) fprintf(stderr, "sym_match: checking \"%s\"\n", name); 326 #endif 327 328 if ((sym->st_shndx != SHN_UNDEF) && 329 (strcmp(name, symargs_p->sa_name) == 0)) { 330 331 DBG_TNF_PROBE_2(sym_match_1, "libtnfctl", 332 "sunw%verbosity 2; sunw%debug '\tMatched Symbol'", 333 tnf_string, symbol, name, 334 tnf_opaque, address_found, addr); 335 336 symargs_p->sa_addr = addr; 337 } 338 #if 0 339 printf("leaving sym_match\n"); 340 #endif 341 return (TNFCTL_ERR_NONE); 342 } 343 344 345 /* 346 * sym_matchname() - function to be called on each symbol in a dynsym 347 * section. Used to find the name of a symbol whose address is known. 348 */ 349 static tnfctl_errcode_t 350 sym_matchname(char *name, uintptr_t addr, void *sym_entry, 351 tnfctl_elf_search_t * search_info_p) 352 { 353 sym_args_t *symargs_p = (sym_args_t *) search_info_p->record_data; 354 Elf3264_Sym *sym = (Elf3264_Sym *) sym_entry; 355 356 #ifdef VERYVERBOSE 357 (void) fprintf(stderr, "sym_matchname: checking \"%s\"\n", name); 358 #endif 359 360 if ((sym->st_shndx != SHN_UNDEF) && 361 symargs_p->sa_addr == addr) { 362 363 DBG_TNF_PROBE_2(sym_matchname_1, "libtnfctl", 364 "sunw%verbosity 2; sunw%debug '\tMatched Name'", 365 tnf_string, symbol_found, name, 366 tnf_opaque, address, addr); 367 368 symargs_p->sa_name = strdup(name); 369 } 370 371 return (TNFCTL_ERR_NONE); 372 } 373