xref: /titanic_52/usr/src/lib/libtnfctl/elf.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1994, by Sun Microsytems, Inc.
24*7c478bd9Sstevel@tonic-gate  */
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate /*
29*7c478bd9Sstevel@tonic-gate  * Interfaces for searching for elf specific information
30*7c478bd9Sstevel@tonic-gate  */
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #include <unistd.h>
33*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
34*7c478bd9Sstevel@tonic-gate #include <string.h>
35*7c478bd9Sstevel@tonic-gate #include <errno.h>
36*7c478bd9Sstevel@tonic-gate #include <link.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #include "tnfctl_int.h"
40*7c478bd9Sstevel@tonic-gate #include "dbg.h"
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate /*
44*7c478bd9Sstevel@tonic-gate  * Declarations
45*7c478bd9Sstevel@tonic-gate  */
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t dynsec_num(tnfctl_handle_t *hndl, uintptr_t baseaddr,
48*7c478bd9Sstevel@tonic-gate 					int objfd, int *num_dyn);
49*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t elf_dynmatch(Elf *elf, char *strs, Elf_Scn *dyn_scn,
50*7c478bd9Sstevel@tonic-gate 	GElf_Shdr *dyn_shdr, Elf_Data *dyn_data,
51*7c478bd9Sstevel@tonic-gate 	uintptr_t baseaddr, tnfctl_elf_search_t * search_info_p);
52*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t dyn_findtag(
53*7c478bd9Sstevel@tonic-gate 	Elf3264_Dyn 	*start,		/* start of dynam table read in */
54*7c478bd9Sstevel@tonic-gate 	Elf3264_Sword 	tag, 		/* tag to search for */
55*7c478bd9Sstevel@tonic-gate 	uintptr_t 	dynam_addr,	/* address of _DYNAMIC in target */
56*7c478bd9Sstevel@tonic-gate 	int 		limit, 		/* number of entries in table */
57*7c478bd9Sstevel@tonic-gate 	uintptr_t 	*dentry_address);	/* return value */
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
61*7c478bd9Sstevel@tonic-gate /* ----------------------- Public Functions ----------------------- */
62*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate /*
65*7c478bd9Sstevel@tonic-gate  * _tnfctl_elf_dbgent() - this function finds the address of the
66*7c478bd9Sstevel@tonic-gate  * debug struct (DT_DEBUG) in the target process.  _DYNAMIC is a symbol
67*7c478bd9Sstevel@tonic-gate  * present in every object.  The one in the main executable references
68*7c478bd9Sstevel@tonic-gate  * an array that is tagged with the kind of each member.  We search
69*7c478bd9Sstevel@tonic-gate  * for the tag of DT_DEBUG which is where the run time linker maintains
70*7c478bd9Sstevel@tonic-gate  * a structure that references the shared object linked list.
71*7c478bd9Sstevel@tonic-gate  *
72*7c478bd9Sstevel@tonic-gate  * A side effect of searching for DT_DEBUG ensures that the executable is
73*7c478bd9Sstevel@tonic-gate  * a dynamic executable - tracing only works on dynamic executables because
74*7c478bd9Sstevel@tonic-gate  * static executables don't have relocation tables.
75*7c478bd9Sstevel@tonic-gate  */
76*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
77*7c478bd9Sstevel@tonic-gate _tnfctl_elf_dbgent(tnfctl_handle_t *hndl, uintptr_t * entaddr_p)
78*7c478bd9Sstevel@tonic-gate {
79*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat = TNFCTL_ERR_NONE;
80*7c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat = PRB_STATUS_OK;
81*7c478bd9Sstevel@tonic-gate 	int		miscstat;
82*7c478bd9Sstevel@tonic-gate 	int		objfd;
83*7c478bd9Sstevel@tonic-gate 	int		num_dynentries = 0;
84*7c478bd9Sstevel@tonic-gate 	uintptr_t	dynamic_addr;
85*7c478bd9Sstevel@tonic-gate 	uintptr_t	baseaddr;
86*7c478bd9Sstevel@tonic-gate 	uintptr_t	dentry_addr;
87*7c478bd9Sstevel@tonic-gate 	Elf3264_Dyn	*dynam_tab = NULL;
88*7c478bd9Sstevel@tonic-gate 	long		dynam_tab_size;
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate 	*entaddr_p = NULL;
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate 	prbstat = prb_mainobj_get(hndl->proc_p, &objfd, &baseaddr);
93*7c478bd9Sstevel@tonic-gate 	if (prbstat)
94*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	/* find the address of the symbol _DYNAMIC */
97*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_sym_find_in_obj(objfd, baseaddr, "_DYNAMIC",
98*7c478bd9Sstevel@tonic-gate 			&dynamic_addr);
99*7c478bd9Sstevel@tonic-gate 	if (prexstat) {
100*7c478bd9Sstevel@tonic-gate 		prexstat = TNFCTL_ERR_NOTDYNAMIC;
101*7c478bd9Sstevel@tonic-gate 		goto Cleanup;
102*7c478bd9Sstevel@tonic-gate 	}
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 	/* find the number of entries in the .dynamic section */
105*7c478bd9Sstevel@tonic-gate 	prexstat = dynsec_num(hndl, baseaddr, objfd, &num_dynentries);
106*7c478bd9Sstevel@tonic-gate 	if (prexstat)
107*7c478bd9Sstevel@tonic-gate 		goto Cleanup;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_2(_tnfctl_elf_dbgent_1, "libtnfctl", "sunw%verbosity 2",
110*7c478bd9Sstevel@tonic-gate 		tnf_long, num_of_dynentries, num_dynentries,
111*7c478bd9Sstevel@tonic-gate 		tnf_opaque, DYNAMIC_address, dynamic_addr);
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	/* read in the dynamic table from the image of the process */
114*7c478bd9Sstevel@tonic-gate 	dynam_tab_size = num_dynentries * sizeof (Elf3264_Dyn);
115*7c478bd9Sstevel@tonic-gate 	dynam_tab = malloc(dynam_tab_size);
116*7c478bd9Sstevel@tonic-gate 	if (!dynam_tab) {
117*7c478bd9Sstevel@tonic-gate 		close(objfd);
118*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
119*7c478bd9Sstevel@tonic-gate 	}
120*7c478bd9Sstevel@tonic-gate 	miscstat = hndl->p_read(hndl->proc_p, dynamic_addr, dynam_tab,
121*7c478bd9Sstevel@tonic-gate 							dynam_tab_size);
122*7c478bd9Sstevel@tonic-gate 	if (miscstat) {
123*7c478bd9Sstevel@tonic-gate 		prexstat = TNFCTL_ERR_INTERNAL;
124*7c478bd9Sstevel@tonic-gate 		goto Cleanup;
125*7c478bd9Sstevel@tonic-gate 	}
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 	prexstat = dyn_findtag(dynam_tab, DT_DEBUG, dynamic_addr,
128*7c478bd9Sstevel@tonic-gate 		num_dynentries, &dentry_addr);
129*7c478bd9Sstevel@tonic-gate 	if (prexstat) {
130*7c478bd9Sstevel@tonic-gate 		goto Cleanup;
131*7c478bd9Sstevel@tonic-gate 	}
132*7c478bd9Sstevel@tonic-gate 	*entaddr_p = dentry_addr;
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate Cleanup:
135*7c478bd9Sstevel@tonic-gate 	close(objfd);
136*7c478bd9Sstevel@tonic-gate 	if (dynam_tab)
137*7c478bd9Sstevel@tonic-gate 		free(dynam_tab);
138*7c478bd9Sstevel@tonic-gate 	return (prexstat);
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate }
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
144*7c478bd9Sstevel@tonic-gate /* ----------------------- Private Functions ---------------------- */
145*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate /*
148*7c478bd9Sstevel@tonic-gate  * dyn_findtag() - searches tags in _DYNAMIC table
149*7c478bd9Sstevel@tonic-gate  */
150*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
151*7c478bd9Sstevel@tonic-gate dyn_findtag(Elf3264_Dyn * start,	/* start of dynam table read in */
152*7c478bd9Sstevel@tonic-gate 		Elf3264_Sword tag,	/* tag to search for */
153*7c478bd9Sstevel@tonic-gate 		uintptr_t dynam_addr,	/* base address of _DYNAMIC in target */
154*7c478bd9Sstevel@tonic-gate 		int limit, /* number of entries in table */
155*7c478bd9Sstevel@tonic-gate 		uintptr_t * dentry_address)
156*7c478bd9Sstevel@tonic-gate {				/* return value */
157*7c478bd9Sstevel@tonic-gate 	Elf3264_Dyn	  *dp;
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 	for (dp = start; dp->d_tag != DT_NULL; dp++) {
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 		DBG_TNF_PROBE_1(dyn_findtag_1, "libtnfctl",
162*7c478bd9Sstevel@tonic-gate 			"sunw%verbosity 3; sunw%debug 'in loop'",
163*7c478bd9Sstevel@tonic-gate 			tnf_long, tag, dp->d_tag);
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 		if (dp->d_tag == tag) {
166*7c478bd9Sstevel@tonic-gate 			*dentry_address = dynam_addr +
167*7c478bd9Sstevel@tonic-gate 				(dp - start) * sizeof (Elf3264_Dyn);
168*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_NONE);
169*7c478bd9Sstevel@tonic-gate 		}
170*7c478bd9Sstevel@tonic-gate 		if (--limit <= 0) {
171*7c478bd9Sstevel@tonic-gate 			DBG((void) fprintf(stderr,
172*7c478bd9Sstevel@tonic-gate 				"dyn_findtag: exceeded limit of table\n"));
173*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_INTERNAL);
174*7c478bd9Sstevel@tonic-gate 		}
175*7c478bd9Sstevel@tonic-gate 	}
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	DBG((void) fprintf(stderr,
178*7c478bd9Sstevel@tonic-gate 		"dyn_findtag: couldn't find tag, last tag=%d\n",
179*7c478bd9Sstevel@tonic-gate 		(int) dp->d_tag));
180*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_INTERNAL);
181*7c478bd9Sstevel@tonic-gate }
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate /*
185*7c478bd9Sstevel@tonic-gate  * dynsec_num() - find the number of entries in the .dynamic section
186*7c478bd9Sstevel@tonic-gate  */
187*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
188*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
189*7c478bd9Sstevel@tonic-gate dynsec_num(tnfctl_handle_t *hndl, uintptr_t baseaddr,
190*7c478bd9Sstevel@tonic-gate 	int objfd, int *num_dyn)
191*7c478bd9Sstevel@tonic-gate {
192*7c478bd9Sstevel@tonic-gate 	int		num_ent = 0;
193*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
194*7c478bd9Sstevel@tonic-gate 	tnfctl_elf_search_t search_info;
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_0(dynsec_num_1, "libtnfctl",
197*7c478bd9Sstevel@tonic-gate 		"sunw%verbosity 2;"
198*7c478bd9Sstevel@tonic-gate 		"sunw%debug 'counting number of entries in .dynamic section'");
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	search_info.section_func = elf_dynmatch;
201*7c478bd9Sstevel@tonic-gate 	search_info.section_data = &num_ent;
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_traverse_object(objfd, baseaddr, &search_info);
204*7c478bd9Sstevel@tonic-gate 	if (prexstat)
205*7c478bd9Sstevel@tonic-gate 		return (prexstat);
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 	if (num_ent == 0)
208*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NOTDYNAMIC);
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 	*num_dyn = num_ent;
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
213*7c478bd9Sstevel@tonic-gate }
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate /*
217*7c478bd9Sstevel@tonic-gate  * elf_dynmatch() - this function searches for the .dynamic section and
218*7c478bd9Sstevel@tonic-gate  * returns the number of entries in it.
219*7c478bd9Sstevel@tonic-gate  */
220*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
221*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
222*7c478bd9Sstevel@tonic-gate elf_dynmatch(Elf * elf,
223*7c478bd9Sstevel@tonic-gate 	char *strs,
224*7c478bd9Sstevel@tonic-gate 	Elf_Scn * dyn_scn,
225*7c478bd9Sstevel@tonic-gate 	GElf_Shdr * dyn_shdr,
226*7c478bd9Sstevel@tonic-gate 	Elf_Data * dyn_data,
227*7c478bd9Sstevel@tonic-gate 	uintptr_t baseaddr,
228*7c478bd9Sstevel@tonic-gate 	tnfctl_elf_search_t *search_info_p)
229*7c478bd9Sstevel@tonic-gate {
230*7c478bd9Sstevel@tonic-gate 	char	*scn_name;
231*7c478bd9Sstevel@tonic-gate 	int	*ret = (int *) search_info_p->section_data;
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	/* bail if this isn't a .dynamic section */
234*7c478bd9Sstevel@tonic-gate 	scn_name = strs + dyn_shdr->sh_name;
235*7c478bd9Sstevel@tonic-gate 	if (strcmp(scn_name, ".dynamic") != 0)
236*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	if (dyn_shdr->sh_entsize == 0) {	/* no dynamic section */
239*7c478bd9Sstevel@tonic-gate 		*ret = 0;
240*7c478bd9Sstevel@tonic-gate 	} else {
241*7c478bd9Sstevel@tonic-gate 		*ret = (int) (dyn_shdr->sh_size / dyn_shdr->sh_entsize);
242*7c478bd9Sstevel@tonic-gate 	}
243*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
244*7c478bd9Sstevel@tonic-gate }
245