xref: /titanic_52/usr/src/lib/libtnfctl/sym.c (revision 1cb6af97c6f66f456d4f726ef056e1ebc0f73305)
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
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
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
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
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
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
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
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