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