summaryrefslogtreecommitdiff
path: root/usr/src/lib/libtnfctl/sym.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libtnfctl/sym.c
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libtnfctl/sym.c')
-rw-r--r--usr/src/lib/libtnfctl/sym.c372
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);
+}