OpenSolaris_b135/lib/libtnfctl/elf.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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"

/*
 * Interfaces for searching for elf specific information
 */

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <link.h>
#include <sys/procfs.h>

#include "tnfctl_int.h"
#include "dbg.h"


/*
 * Declarations
 */

static tnfctl_errcode_t dynsec_num(tnfctl_handle_t *hndl, uintptr_t baseaddr,
					int objfd, int *num_dyn);
static tnfctl_errcode_t elf_dynmatch(Elf *elf, char *strs, Elf_Scn *dyn_scn,
	GElf_Shdr *dyn_shdr, Elf_Data *dyn_data,
	uintptr_t baseaddr, tnfctl_elf_search_t * search_info_p);
static tnfctl_errcode_t dyn_findtag(
	Elf3264_Dyn 	*start,		/* start of dynam table read in */
	Elf3264_Sword 	tag, 		/* tag to search for */
	uintptr_t 	dynam_addr,	/* address of _DYNAMIC in target */
	int 		limit, 		/* number of entries in table */
	uintptr_t 	*dentry_address);	/* return value */


/* ---------------------------------------------------------------- */
/* ----------------------- Public Functions ----------------------- */
/* ---------------------------------------------------------------- */

/*
 * _tnfctl_elf_dbgent() - this function finds the address of the
 * debug struct (DT_DEBUG) in the target process.  _DYNAMIC is a symbol
 * present in every object.  The one in the main executable references
 * an array that is tagged with the kind of each member.  We search
 * for the tag of DT_DEBUG which is where the run time linker maintains
 * a structure that references the shared object linked list.
 *
 * A side effect of searching for DT_DEBUG ensures that the executable is
 * a dynamic executable - tracing only works on dynamic executables because
 * static executables don't have relocation tables.
 */
tnfctl_errcode_t
_tnfctl_elf_dbgent(tnfctl_handle_t *hndl, uintptr_t * entaddr_p)
{
	tnfctl_errcode_t	prexstat = TNFCTL_ERR_NONE;
	prb_status_t	prbstat = PRB_STATUS_OK;
	int		miscstat;
	int		objfd;
	int		num_dynentries = 0;
	uintptr_t	dynamic_addr;
	uintptr_t	baseaddr;
	uintptr_t	dentry_addr;
	Elf3264_Dyn	*dynam_tab = NULL;
	long		dynam_tab_size;

	*entaddr_p = NULL;

	prbstat = prb_mainobj_get(hndl->proc_p, &objfd, &baseaddr);
	if (prbstat)
		return (_tnfctl_map_to_errcode(prbstat));

	/* find the address of the symbol _DYNAMIC */
	prexstat = _tnfctl_sym_find_in_obj(objfd, baseaddr, "_DYNAMIC",
			&dynamic_addr);
	if (prexstat) {
		prexstat = TNFCTL_ERR_NOTDYNAMIC;
		goto Cleanup;
	}

	/* find the number of entries in the .dynamic section */
	prexstat = dynsec_num(hndl, baseaddr, objfd, &num_dynentries);
	if (prexstat)
		goto Cleanup;

	DBG_TNF_PROBE_2(_tnfctl_elf_dbgent_1, "libtnfctl", "sunw%verbosity 2",
		tnf_long, num_of_dynentries, num_dynentries,
		tnf_opaque, DYNAMIC_address, dynamic_addr);

	/* read in the dynamic table from the image of the process */
	dynam_tab_size = num_dynentries * sizeof (Elf3264_Dyn);
	dynam_tab = malloc(dynam_tab_size);
	if (!dynam_tab) {
		close(objfd);
		return (TNFCTL_ERR_ALLOCFAIL);
	}
	miscstat = hndl->p_read(hndl->proc_p, dynamic_addr, dynam_tab,
							dynam_tab_size);
	if (miscstat) {
		prexstat = TNFCTL_ERR_INTERNAL;
		goto Cleanup;
	}

	prexstat = dyn_findtag(dynam_tab, DT_DEBUG, dynamic_addr,
		num_dynentries, &dentry_addr);
	if (prexstat) {
		goto Cleanup;
	}
	*entaddr_p = dentry_addr;

Cleanup:
	close(objfd);
	if (dynam_tab)
		free(dynam_tab);
	return (prexstat);

}


/* ---------------------------------------------------------------- */
/* ----------------------- Private Functions ---------------------- */
/* ---------------------------------------------------------------- */

/*
 * dyn_findtag() - searches tags in _DYNAMIC table
 */
static tnfctl_errcode_t
dyn_findtag(Elf3264_Dyn * start,	/* start of dynam table read in */
		Elf3264_Sword tag,	/* tag to search for */
		uintptr_t dynam_addr,	/* base address of _DYNAMIC in target */
		int limit, /* number of entries in table */
		uintptr_t * dentry_address)
{				/* return value */
	Elf3264_Dyn	  *dp;

	for (dp = start; dp->d_tag != DT_NULL; dp++) {

		DBG_TNF_PROBE_1(dyn_findtag_1, "libtnfctl",
			"sunw%verbosity 3; sunw%debug 'in loop'",
			tnf_long, tag, dp->d_tag);

		if (dp->d_tag == tag) {
			*dentry_address = dynam_addr +
				(dp - start) * sizeof (Elf3264_Dyn);
			return (TNFCTL_ERR_NONE);
		}
		if (--limit <= 0) {
			DBG((void) fprintf(stderr,
				"dyn_findtag: exceeded limit of table\n"));
			return (TNFCTL_ERR_INTERNAL);
		}
	}

	DBG((void) fprintf(stderr,
		"dyn_findtag: couldn't find tag, last tag=%d\n",
		(int) dp->d_tag));
	return (TNFCTL_ERR_INTERNAL);
}


/*
 * dynsec_num() - find the number of entries in the .dynamic section
 */
/*ARGSUSED*/
static tnfctl_errcode_t
dynsec_num(tnfctl_handle_t *hndl, uintptr_t baseaddr,
	int objfd, int *num_dyn)
{
	int		num_ent = 0;
	tnfctl_errcode_t	prexstat;
	tnfctl_elf_search_t search_info;

	DBG_TNF_PROBE_0(dynsec_num_1, "libtnfctl",
		"sunw%verbosity 2;"
		"sunw%debug 'counting number of entries in .dynamic section'");

	search_info.section_func = elf_dynmatch;
	search_info.section_data = &num_ent;

	prexstat = _tnfctl_traverse_object(objfd, baseaddr, &search_info);
	if (prexstat)
		return (prexstat);

	if (num_ent == 0)
		return (TNFCTL_ERR_NOTDYNAMIC);

	*num_dyn = num_ent;

	return (TNFCTL_ERR_NONE);
}


/*
 * elf_dynmatch() - this function searches for the .dynamic section and
 * returns the number of entries in it.
 */
/*ARGSUSED*/
static tnfctl_errcode_t
elf_dynmatch(Elf * elf,
	char *strs,
	Elf_Scn * dyn_scn,
	GElf_Shdr * dyn_shdr,
	Elf_Data * dyn_data,
	uintptr_t baseaddr,
	tnfctl_elf_search_t *search_info_p)
{
	char	*scn_name;
	int	*ret = (int *) search_info_p->section_data;

	/* bail if this isn't a .dynamic section */
	scn_name = strs + dyn_shdr->sh_name;
	if (strcmp(scn_name, ".dynamic") != 0)
		return (TNFCTL_ERR_NONE);

	if (dyn_shdr->sh_entsize == 0) {	/* no dynamic section */
		*ret = 0;
	} else {
		*ret = (int) (dyn_shdr->sh_size / dyn_shdr->sh_entsize);
	}
	return (TNFCTL_ERR_NONE);
}