1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
/*
* 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);
}
|