1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1994, by Sun Microsytems, Inc.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 /*
29 * Routines that
30 * - return an address for a symbol name
31 * - return a symbol name for an address
32 */
33
34 #ifndef DEBUG
35 #define NDEBUG 1
36 #endif
37
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <errno.h>
42 #include <sys/procfs.h>
43 #include <sys/stat.h>
44 #include <assert.h>
45 #include <note.h>
46
47 #include "tnfctl_int.h"
48 #include "dbg.h"
49
50
51 /*
52 * Typedefs
53 */
54
55 typedef struct sym_args {
56 char *sa_name;
57 uintptr_t sa_addr;
58 } sym_args_t;
59 NOTE(SCHEME_PROTECTS_DATA("always automatic", sym_args))
60
61 /*
62 * Declarations
63 */
64
65 static tnfctl_errcode_t sym_findname_in_obj(int objfd, uintptr_t baseaddr,
66 uintptr_t symaddr, char **symname);
67
68 static tnfctl_errcode_t sym_match(char *name, uintptr_t addr, void *sym_entry,
69 tnfctl_elf_search_t *search_info_p);
70
71 static tnfctl_errcode_t sym_matchname(char *name, uintptr_t addr,
72 void *sym_entry,
73 tnfctl_elf_search_t *search_info_p);
74
75
76 /* ---------------------------------------------------------------- */
77 /* ----------------------- Public Functions ----------------------- */
78 /* ---------------------------------------------------------------- */
79
80 /*
81 * _tnfctl_sym_find_in_obj() - determines the virtual address of the supplied
82 * symbol in the object file specified by fd.
83 */
84 tnfctl_errcode_t
_tnfctl_sym_find_in_obj(int objfd,uintptr_t baseaddr,const char * symname,uintptr_t * symaddr)85 _tnfctl_sym_find_in_obj(int objfd, uintptr_t baseaddr, const char *symname,
86 uintptr_t *symaddr)
87 {
88 tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE;
89 sym_args_t symargs;
90 tnfctl_elf_search_t search_info;
91
92 DBG_TNF_PROBE_1(_tnfctl_sym_find_in_obj_1, "libtnfctl",
93 "sunw%verbosity 3",
94 tnf_string, searching_for, symname);
95
96 symargs.sa_name = (char *) symname;
97 /* clear output argument in advance */
98 symargs.sa_addr = 0;
99
100 search_info.section_func = _tnfctl_traverse_dynsym;
101 search_info.record_func = sym_match;
102 search_info.record_data = &symargs;
103
104 prexstat = _tnfctl_traverse_object(objfd, baseaddr, &search_info);
105 if (prexstat)
106 return (prexstat);
107
108 /* check if we found symbol address */
109 if (symargs.sa_addr == 0) {
110 return (TNFCTL_ERR_BADARG);
111 }
112
113 *symaddr = symargs.sa_addr;
114 return (TNFCTL_ERR_NONE);
115 }
116
117
118 /*
119 * _tnfctl_sym_find() - determines the virtual address of the supplied symbol
120 * in the process.
121 */
122 tnfctl_errcode_t
_tnfctl_sym_find(tnfctl_handle_t * hndl,const char * symname,uintptr_t * symaddr)123 _tnfctl_sym_find(tnfctl_handle_t *hndl, const char *symname, uintptr_t *symaddr)
124 {
125 boolean_t release_lock;
126 tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE;
127 objlist_t *obj;
128
129 DBG_TNF_PROBE_1(_tnfctl_sym_find_start, "libtnfctl",
130 "start _tnfctl_sym_find; sunw%verbosity 3",
131 tnf_string, searching_for, symname);
132
133 /*LINTED statement has no consequent: else*/
134 LOCK(hndl, prexstat, release_lock);
135
136 /* for every object in list, search for symbol */
137 for (obj = hndl->objlist; obj; obj = obj->next) {
138 if (obj->old == B_TRUE)
139 continue; /* don't examine dlclose'd libs */
140
141 /* return value of TNFCTL_ERR_BADARG means symbol not found */
142 prexstat = _tnfctl_sym_find_in_obj(obj->objfd,
143 obj->baseaddr, symname, symaddr);
144 if (prexstat == TNFCTL_ERR_NONE)
145 /* symbol found */
146 break;
147 else if (prexstat != TNFCTL_ERR_BADARG)
148 /* error condition */
149 break;
150 /* continue loop on TNFCTL_ERR_BADARG */
151 }
152
153 /*LINTED statement has no consequent: else*/
154 UNLOCK(hndl, release_lock);
155
156 DBG_TNF_PROBE_0(_tnfctl_sym_find_end, "libtnfctl",
157 "end _tnfctl_sym_find; sunw%verbosity 3");
158
159 return (prexstat);
160 }
161
162 /*
163 * _tnfctl_sym_obj_find() - determines the virtual address of the supplied
164 * symbol in the object specified by base name
165 */
166 tnfctl_errcode_t
_tnfctl_sym_obj_find(tnfctl_handle_t * hndl,const char * lib_base_name,const char * symname,uintptr_t * symaddr)167 _tnfctl_sym_obj_find(tnfctl_handle_t *hndl, const char *lib_base_name,
168 const char *symname, uintptr_t *symaddr)
169 {
170 tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE;
171 objlist_t *obj, *found_obj;
172 const char *str_ptr;
173
174 assert((hndl->mode == INTERNAL_MODE) ?
175 (MUTEX_HELD(&_tnfctl_lmap_lock)) : 1);
176
177 DBG_TNF_PROBE_1(_tnfctl_sym_obj_find_start, "libtnfctl",
178 "start _tnfctl_sym_obj_find; sunw%verbosity 3",
179 tnf_string, searching_for, symname);
180
181 found_obj = NULL;
182 /* for every object in list ... */
183 for (obj = hndl->objlist; obj; obj = obj->next) {
184 if (obj->old == B_TRUE)
185 continue; /* don't examine dlclose'd libs */
186
187 if (obj->objname == NULL)
188 continue;
189
190 /* find the last occurrence of / in the name */
191 str_ptr = strrchr(obj->objname, '/');
192 if (str_ptr == NULL) {
193 str_ptr = obj->objname;
194 } else {
195 str_ptr++; /* bump up past '/' */
196 }
197
198 /* XXX - use strcoll ? */
199 if (strcmp(str_ptr, lib_base_name) == 0) {
200 found_obj = obj;
201 break;
202 }
203 }
204 /* return value of TNFCTL_ERR_BADARG means symbol not found */
205 if (found_obj == NULL)
206 return (TNFCTL_ERR_BADARG);
207
208 prexstat = _tnfctl_sym_find_in_obj(found_obj->objfd,
209 found_obj->baseaddr, symname, symaddr);
210
211 DBG_TNF_PROBE_0(_tnfctl_sym_obj_find_end, "libtnfctl",
212 "end _tnfctl_sym_obj_find; sunw%verbosity 3");
213
214 return (prexstat);
215 }
216
217 /*
218 * _tnfctl_sym_findname() - determines the name of a function from its address.
219 */
220 tnfctl_errcode_t
_tnfctl_sym_findname(tnfctl_handle_t * hndl,uintptr_t symaddr,char ** symname)221 _tnfctl_sym_findname(tnfctl_handle_t *hndl, uintptr_t symaddr,
222 char **symname)
223 {
224 boolean_t release_lock;
225 tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE;
226 objlist_t *obj;
227
228 DBG_TNF_PROBE_1(_tnfctl_sym_findname_start, "libtnfctl",
229 "start _tnfctl_sym_findname; sunw%verbosity 3",
230 tnf_opaque, searching_for, symaddr);
231
232 /*LINTED statement has no consequent: else*/
233 LOCK(hndl, prexstat, release_lock);
234
235 /* for every object in list, search for name */
236 for (obj = hndl->objlist; obj; obj = obj->next) {
237 if (obj->old == B_TRUE)
238 continue; /* don't examine dlclose'd libs */
239 /* return value of TNFCTL_ERR_BADARG means symbol not found */
240 prexstat = sym_findname_in_obj(obj->objfd,
241 obj->baseaddr, symaddr, symname);
242 if (prexstat == TNFCTL_ERR_NONE)
243 /* symbol found */
244 break;
245 else if (prexstat != TNFCTL_ERR_BADARG)
246 /* error condition */
247 break;
248 /* continue loop on TNFCTL_ERR_BADARG */
249 }
250
251 /*LINTED statement has no consequent: else*/
252 UNLOCK(hndl, release_lock);
253
254 DBG_TNF_PROBE_0(_tnfctl_sym_findname_end, "libtnfctl",
255 "end _tnfctl_sym_findname; sunw%verbosity 3");
256
257 return (prexstat);
258 }
259
260
261 /* ---------------------------------------------------------------- */
262 /* ----------------------- Private Functions ---------------------- */
263 /* ---------------------------------------------------------------- */
264
265 /*
266 * sym_findname_in_obj() - determines the name of the supplied
267 * address in the specified object file.
268 */
269 static tnfctl_errcode_t
sym_findname_in_obj(int objfd,uintptr_t baseaddr,uintptr_t symaddr,char ** symname)270 sym_findname_in_obj(int objfd, uintptr_t baseaddr, uintptr_t symaddr,
271 char **symname)
272 {
273 tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE;
274 sym_args_t symargs;
275 tnfctl_elf_search_t search_info;
276
277 DBG_TNF_PROBE_1(sym_findname_in_obj_1, "libtnfctl",
278 "sunw%verbosity 3",
279 tnf_opaque, searching_for, symaddr);
280
281 /* clear output argument in advance */
282 symargs.sa_name = NULL;
283 symargs.sa_addr = symaddr;
284
285 search_info.section_func = _tnfctl_traverse_dynsym;
286 search_info.record_func = sym_matchname;
287 search_info.record_data = &symargs;
288
289 prexstat = _tnfctl_traverse_object(objfd, baseaddr, &search_info);
290 if (prexstat)
291 return (prexstat);
292
293 /* check if we found symbol address */
294 if (symargs.sa_name == NULL) {
295 return (TNFCTL_ERR_BADARG);
296 }
297
298 *symname = symargs.sa_name;
299 return (TNFCTL_ERR_NONE);
300 }
301
302 /*
303 * sym_match() - function to be called on each symbol in a dynsym section.
304 * Used to find the address of a symbol.
305 */
306 static tnfctl_errcode_t
sym_match(char * name,uintptr_t addr,void * sym_entry,tnfctl_elf_search_t * search_info_p)307 sym_match(char *name, uintptr_t addr, void *sym_entry,
308 tnfctl_elf_search_t *search_info_p)
309 {
310 sym_args_t *symargs_p = (sym_args_t *) search_info_p->record_data;
311 Elf3264_Sym *sym = (Elf3264_Sym *) sym_entry;
312 #if 0
313 printf("enter sym_match: \n");
314 if (symargs_p->sa_name != 0)
315 printf("(symargs_p->sa_name) = %s\n", symargs_p->sa_name);
316 else
317 printf("symargs_p->sa_name = 0\n");
318 if (name != 0)
319 printf("(name) = %s\n", name);
320 else
321 printf("name = 0\n");
322 #endif
323
324 #ifdef VERYVERBOSE
325 (void) fprintf(stderr, "sym_match: checking \"%s\"\n", name);
326 #endif
327
328 if ((sym->st_shndx != SHN_UNDEF) &&
329 (strcmp(name, symargs_p->sa_name) == 0)) {
330
331 DBG_TNF_PROBE_2(sym_match_1, "libtnfctl",
332 "sunw%verbosity 2; sunw%debug '\tMatched Symbol'",
333 tnf_string, symbol, name,
334 tnf_opaque, address_found, addr);
335
336 symargs_p->sa_addr = addr;
337 }
338 #if 0
339 printf("leaving sym_match\n");
340 #endif
341 return (TNFCTL_ERR_NONE);
342 }
343
344
345 /*
346 * sym_matchname() - function to be called on each symbol in a dynsym
347 * section. Used to find the name of a symbol whose address is known.
348 */
349 static tnfctl_errcode_t
sym_matchname(char * name,uintptr_t addr,void * sym_entry,tnfctl_elf_search_t * search_info_p)350 sym_matchname(char *name, uintptr_t addr, void *sym_entry,
351 tnfctl_elf_search_t * search_info_p)
352 {
353 sym_args_t *symargs_p = (sym_args_t *) search_info_p->record_data;
354 Elf3264_Sym *sym = (Elf3264_Sym *) sym_entry;
355
356 #ifdef VERYVERBOSE
357 (void) fprintf(stderr, "sym_matchname: checking \"%s\"\n", name);
358 #endif
359
360 if ((sym->st_shndx != SHN_UNDEF) &&
361 symargs_p->sa_addr == addr) {
362
363 DBG_TNF_PROBE_2(sym_matchname_1, "libtnfctl",
364 "sunw%verbosity 2; sunw%debug '\tMatched Name'",
365 tnf_string, symbol_found, name,
366 tnf_opaque, address, addr);
367
368 symargs_p->sa_name = strdup(name);
369 }
370
371 return (TNFCTL_ERR_NONE);
372 }
373