diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libtnfctl/sym.c | |
download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz |
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libtnfctl/sym.c')
-rw-r--r-- | usr/src/lib/libtnfctl/sym.c | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/usr/src/lib/libtnfctl/sym.c b/usr/src/lib/libtnfctl/sym.c new file mode 100644 index 0000000000..350549d5e4 --- /dev/null +++ b/usr/src/lib/libtnfctl/sym.c @@ -0,0 +1,372 @@ +/* + * 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 <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/procfs.h> +#include <sys/stat.h> +#include <assert.h> +#include <note.h> + +#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); +} |