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