/* * 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" /* * Routines that * - return an address for a symbol name * - return a symbol name for an address */ #ifndef DEBUG #define NDEBUG 1 #endif #include #include #include #include #include #include #include #include #include "tnfctl_int.h" #include "dbg.h" /* * Typedefs */ typedef struct sym_args { char *sa_name; uintptr_t sa_addr; } sym_args_t; NOTE(SCHEME_PROTECTS_DATA("always automatic", sym_args)) /* * Declarations */ static tnfctl_errcode_t sym_findname_in_obj(int objfd, uintptr_t baseaddr, uintptr_t symaddr, char **symname); static tnfctl_errcode_t sym_match(char *name, uintptr_t addr, void *sym_entry, tnfctl_elf_search_t *search_info_p); static tnfctl_errcode_t sym_matchname(char *name, uintptr_t addr, void *sym_entry, tnfctl_elf_search_t *search_info_p); /* ---------------------------------------------------------------- */ /* ----------------------- Public Functions ----------------------- */ /* ---------------------------------------------------------------- */ /* * _tnfctl_sym_find_in_obj() - determines the virtual address of the supplied * symbol in the object file specified by fd. */ tnfctl_errcode_t _tnfctl_sym_find_in_obj(int objfd, uintptr_t baseaddr, const char *symname, uintptr_t *symaddr) { tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; sym_args_t symargs; tnfctl_elf_search_t search_info; DBG_TNF_PROBE_1(_tnfctl_sym_find_in_obj_1, "libtnfctl", "sunw%verbosity 3", tnf_string, searching_for, symname); symargs.sa_name = (char *) symname; /* clear output argument in advance */ symargs.sa_addr = 0; search_info.section_func = _tnfctl_traverse_dynsym; search_info.record_func = sym_match; search_info.record_data = &symargs; prexstat = _tnfctl_traverse_object(objfd, baseaddr, &search_info); if (prexstat) return (prexstat); /* check if we found symbol address */ if (symargs.sa_addr == 0) { return (TNFCTL_ERR_BADARG); } *symaddr = symargs.sa_addr; return (TNFCTL_ERR_NONE); } /* * _tnfctl_sym_find() - determines the virtual address of the supplied symbol * in the process. */ tnfctl_errcode_t _tnfctl_sym_find(tnfctl_handle_t *hndl, const char *symname, uintptr_t *symaddr) { boolean_t release_lock; tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; objlist_t *obj; DBG_TNF_PROBE_1(_tnfctl_sym_find_start, "libtnfctl", "start _tnfctl_sym_find; sunw%verbosity 3", tnf_string, searching_for, symname); /*LINTED statement has no consequent: else*/ LOCK(hndl, prexstat, release_lock); /* for every object in list, search for symbol */ for (obj = hndl->objlist; obj; obj = obj->next) { if (obj->old == B_TRUE) continue; /* don't examine dlclose'd libs */ /* return value of TNFCTL_ERR_BADARG means symbol not found */ prexstat = _tnfctl_sym_find_in_obj(obj->objfd, obj->baseaddr, symname, symaddr); if (prexstat == TNFCTL_ERR_NONE) /* symbol found */ break; else if (prexstat != TNFCTL_ERR_BADARG) /* error condition */ break; /* continue loop on TNFCTL_ERR_BADARG */ } /*LINTED statement has no consequent: else*/ UNLOCK(hndl, release_lock); DBG_TNF_PROBE_0(_tnfctl_sym_find_end, "libtnfctl", "end _tnfctl_sym_find; sunw%verbosity 3"); return (prexstat); } /* * _tnfctl_sym_obj_find() - determines the virtual address of the supplied * symbol in the object specified by base name */ tnfctl_errcode_t _tnfctl_sym_obj_find(tnfctl_handle_t *hndl, const char *lib_base_name, const char *symname, uintptr_t *symaddr) { tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; objlist_t *obj, *found_obj; const char *str_ptr; assert((hndl->mode == INTERNAL_MODE) ? (MUTEX_HELD(&_tnfctl_lmap_lock)) : 1); DBG_TNF_PROBE_1(_tnfctl_sym_obj_find_start, "libtnfctl", "start _tnfctl_sym_obj_find; sunw%verbosity 3", tnf_string, searching_for, symname); found_obj = NULL; /* for every object in list ... */ for (obj = hndl->objlist; obj; obj = obj->next) { if (obj->old == B_TRUE) continue; /* don't examine dlclose'd libs */ if (obj->objname == NULL) continue; /* find the last occurrence of / in the name */ str_ptr = strrchr(obj->objname, '/'); if (str_ptr == NULL) { str_ptr = obj->objname; } else { str_ptr++; /* bump up past '/' */ } /* XXX - use strcoll ? */ if (strcmp(str_ptr, lib_base_name) == 0) { found_obj = obj; break; } } /* return value of TNFCTL_ERR_BADARG means symbol not found */ if (found_obj == NULL) return (TNFCTL_ERR_BADARG); prexstat = _tnfctl_sym_find_in_obj(found_obj->objfd, found_obj->baseaddr, symname, symaddr); DBG_TNF_PROBE_0(_tnfctl_sym_obj_find_end, "libtnfctl", "end _tnfctl_sym_obj_find; sunw%verbosity 3"); return (prexstat); } /* * _tnfctl_sym_findname() - determines the name of a function from its address. */ tnfctl_errcode_t _tnfctl_sym_findname(tnfctl_handle_t *hndl, uintptr_t symaddr, char **symname) { boolean_t release_lock; tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; objlist_t *obj; DBG_TNF_PROBE_1(_tnfctl_sym_findname_start, "libtnfctl", "start _tnfctl_sym_findname; sunw%verbosity 3", tnf_opaque, searching_for, symaddr); /*LINTED statement has no consequent: else*/ LOCK(hndl, prexstat, release_lock); /* for every object in list, search for name */ for (obj = hndl->objlist; obj; obj = obj->next) { if (obj->old == B_TRUE) continue; /* don't examine dlclose'd libs */ /* return value of TNFCTL_ERR_BADARG means symbol not found */ prexstat = sym_findname_in_obj(obj->objfd, obj->baseaddr, symaddr, symname); if (prexstat == TNFCTL_ERR_NONE) /* symbol found */ break; else if (prexstat != TNFCTL_ERR_BADARG) /* error condition */ break; /* continue loop on TNFCTL_ERR_BADARG */ } /*LINTED statement has no consequent: else*/ UNLOCK(hndl, release_lock); DBG_TNF_PROBE_0(_tnfctl_sym_findname_end, "libtnfctl", "end _tnfctl_sym_findname; sunw%verbosity 3"); return (prexstat); } /* ---------------------------------------------------------------- */ /* ----------------------- Private Functions ---------------------- */ /* ---------------------------------------------------------------- */ /* * sym_findname_in_obj() - determines the name of the supplied * address in the specified object file. */ static tnfctl_errcode_t sym_findname_in_obj(int objfd, uintptr_t baseaddr, uintptr_t symaddr, char **symname) { tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; sym_args_t symargs; tnfctl_elf_search_t search_info; DBG_TNF_PROBE_1(sym_findname_in_obj_1, "libtnfctl", "sunw%verbosity 3", tnf_opaque, searching_for, symaddr); /* clear output argument in advance */ symargs.sa_name = NULL; symargs.sa_addr = symaddr; search_info.section_func = _tnfctl_traverse_dynsym; search_info.record_func = sym_matchname; search_info.record_data = &symargs; prexstat = _tnfctl_traverse_object(objfd, baseaddr, &search_info); if (prexstat) return (prexstat); /* check if we found symbol address */ if (symargs.sa_name == NULL) { return (TNFCTL_ERR_BADARG); } *symname = symargs.sa_name; return (TNFCTL_ERR_NONE); } /* * sym_match() - function to be called on each symbol in a dynsym section. * Used to find the address of a symbol. */ static tnfctl_errcode_t sym_match(char *name, uintptr_t addr, void *sym_entry, tnfctl_elf_search_t *search_info_p) { sym_args_t *symargs_p = (sym_args_t *) search_info_p->record_data; Elf3264_Sym *sym = (Elf3264_Sym *) sym_entry; #if 0 printf("enter sym_match: \n"); if (symargs_p->sa_name != 0) printf("(symargs_p->sa_name) = %s\n", symargs_p->sa_name); else printf("symargs_p->sa_name = 0\n"); if (name != 0) printf("(name) = %s\n", name); else printf("name = 0\n"); #endif #ifdef VERYVERBOSE (void) fprintf(stderr, "sym_match: checking \"%s\"\n", name); #endif if ((sym->st_shndx != SHN_UNDEF) && (strcmp(name, symargs_p->sa_name) == 0)) { DBG_TNF_PROBE_2(sym_match_1, "libtnfctl", "sunw%verbosity 2; sunw%debug '\tMatched Symbol'", tnf_string, symbol, name, tnf_opaque, address_found, addr); symargs_p->sa_addr = addr; } #if 0 printf("leaving sym_match\n"); #endif return (TNFCTL_ERR_NONE); } /* * sym_matchname() - function to be called on each symbol in a dynsym * section. Used to find the name of a symbol whose address is known. */ static tnfctl_errcode_t sym_matchname(char *name, uintptr_t addr, void *sym_entry, tnfctl_elf_search_t * search_info_p) { sym_args_t *symargs_p = (sym_args_t *) search_info_p->record_data; Elf3264_Sym *sym = (Elf3264_Sym *) sym_entry; #ifdef VERYVERBOSE (void) fprintf(stderr, "sym_matchname: checking \"%s\"\n", name); #endif if ((sym->st_shndx != SHN_UNDEF) && symargs_p->sa_addr == addr) { DBG_TNF_PROBE_2(sym_matchname_1, "libtnfctl", "sunw%verbosity 2; sunw%debug '\tMatched Name'", tnf_string, symbol_found, name, tnf_opaque, address, addr); symargs_p->sa_name = strdup(name); } return (TNFCTL_ERR_NONE); }