xref: /netbsd-src/usr.sbin/lockstat/elf32.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: elf32.c,v 1.6 2007/07/14 13:30:43 ad Exp $	*/
2 
3 /*-
4  * Copyright (c) 2006 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Andrew Doran.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Copyright (c) 1996 Christopher G. Demetriou
41  * All rights reserved.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  * 1. Redistributions of source code must retain the above copyright
47  *    notice, this list of conditions and the following disclaimer.
48  * 2. Redistributions in binary form must reproduce the above copyright
49  *    notice, this list of conditions and the following disclaimer in the
50  *    documentation and/or other materials provided with the distribution.
51  * 3. All advertising materials mentioning features or use of this software
52  *    must display the following acknowledgement:
53  *          This product includes software developed for the
54  *          NetBSD Project.  See http://www.NetBSD.org/ for
55  *          information about NetBSD.
56  * 4. The name of the author may not be used to endorse or promote products
57  *    derived from this software without specific prior written permission.
58  *
59  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
60  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
61  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
62  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
63  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
64  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
65  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
66  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
67  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
68  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
69  *
70  * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
71  */
72 
73 #include <sys/cdefs.h>
74 #if !defined(lint)
75 __RCSID("$NetBSD: elf32.c,v 1.6 2007/07/14 13:30:43 ad Exp $");
76 #endif
77 
78 #ifndef ELFSIZE
79 #define	ELFSIZE		32
80 #endif
81 
82 #include <sys/param.h>
83 #include <sys/exec_elf.h>
84 #include <sys/queue.h>
85 
86 #include <dev/lockstat.h>
87 
88 #include <stdio.h>
89 #include <stdlib.h>
90 #include <string.h>
91 #include <unistd.h>
92 #include <err.h>
93 
94 #include "extern.h"
95 
96 #if (ELFSIZE == 32)
97 #define	NAME(x)	x##32
98 #elif (ELFSIZE == 64)
99 #define	NAME(x)	x##64
100 #endif
101 
102 static int		nsyms;
103 static Elf_Sym		*symp;
104 static char		*strp;
105 
106 int
107 NAME(loadsym)(int fd)
108 {
109 	Elf_Shdr symhdr, strhdr;
110 	Elf_Ehdr ehdr;
111 	size_t sz;
112 	off_t off;
113 	int i;
114 
115 	/*
116 	 * Read the ELF header and make sure it's OK.
117 	 */
118 	if (pread(fd, &ehdr, sizeof(ehdr), 0) != sizeof(ehdr))
119 		return -1;
120 
121 	if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
122 	    ehdr.e_ident[EI_CLASS] != ELFCLASS)
123 		return -1;
124 
125 	switch (ehdr.e_machine) {
126 	ELFDEFNNAME(MACHDEP_ID_CASES)
127 	default:
128 		return -1;
129 	}
130 
131 	/*
132 	 * Find the symbol table header, and make sure the binary isn't
133 	 * stripped.
134 	 */
135 	off = ehdr.e_shoff;
136 	for (i = 0; i < ehdr.e_shnum; i++, off += sizeof(symhdr)) {
137 		sz = pread(fd, &symhdr, sizeof(symhdr), off);
138 		if (sz != sizeof(symhdr))
139 			err(EXIT_FAILURE, "pread (section headers)");
140 		if (symhdr.sh_type == SHT_SYMTAB)
141 			break;
142 	}
143 	if (i == ehdr.e_shnum || symhdr.sh_offset == 0)
144 		err(EXIT_FAILURE, "namelist is stripped");
145 
146 	/*
147 	 * Pull in the string table header, and then read in both the symbol
148 	 * table and string table proper.
149 	 *
150 	 * XXX We can't use mmap(), as /dev/ksyms doesn't support mmap yet.
151 	 */
152 	off = ehdr.e_shoff + symhdr.sh_link * sizeof(symhdr);
153 	if (pread(fd, &strhdr, sizeof(strhdr), off) != sizeof(strhdr))
154 		err(EXIT_FAILURE, "pread");
155 
156 	if ((symp = malloc(symhdr.sh_size)) == NULL)
157 		err(EXIT_FAILURE, "malloc (symbol table)");
158 	sz = pread(fd, symp, symhdr.sh_size, symhdr.sh_offset	);
159 	if (sz != symhdr.sh_size)
160 		err(EXIT_FAILURE, "pread (symbol table)");
161 
162 	if ((strp = malloc(strhdr.sh_size)) == NULL)
163 		err(EXIT_FAILURE, "malloc (string table)");
164 	sz = pread(fd, strp, strhdr.sh_size, strhdr.sh_offset);
165 	if (sz != strhdr.sh_size)
166 		err(EXIT_FAILURE, "pread (string table)");
167 
168 	nsyms = (int)(symhdr.sh_size / sizeof(Elf_Sym));
169 
170 	return 0;
171 }
172 
173 int
174 NAME(findsym)(findsym_t find, char *name, uintptr_t *start, uintptr_t *end)
175 {
176 	static int lastptr[FIND_MAX];
177 	uintptr_t sa, ea;
178 	int i, rv, st, off;
179 
180 	switch (find) {
181 	case LOCK_BYNAME:
182 	case LOCK_BYADDR:
183 		st = STT_OBJECT;
184 		break;
185 	case FUNC_BYNAME:
186 	case FUNC_BYADDR:
187 		st = STT_FUNC;
188 		break;
189 	default:
190 		return -1;
191 	}
192 
193 	rv = -1;
194 
195 #ifdef dump_core
196 	for (i = lastptr[find];;) {
197 #else
198 	for (i = 0; i < nsyms; i++) {
199 #endif
200 		switch (find) {
201 		case LOCK_BYNAME:
202 		case FUNC_BYNAME:
203 			if (ELF_ST_TYPE(symp[i].st_info) != st)
204 				break;
205 			if (strcmp(&strp[symp[i].st_name], name) != 0)
206 				break;
207 			*start = (uintptr_t)symp[i].st_value;
208 			*end = *start + (uintptr_t)symp[i].st_size;
209 			goto found;
210 
211 		case LOCK_BYADDR:
212 		case FUNC_BYADDR:
213 			if (ELF_ST_TYPE(symp[i].st_info) != st)
214 				break;
215 			sa = (uintptr_t)symp[i].st_value;
216 			ea = sa + (uintptr_t)symp[i].st_size - 1;
217 			if (*start < sa || *start > ea)
218 				break;
219 			off = (int)(*start - sa);
220 			*start = sa;
221 			if (end != NULL)
222 				*end = ea;
223 			if (name == NULL)
224 				goto found;
225 			if (off == 0)
226 				strlcpy(name, &strp[symp[i].st_name],
227 				    NAME_SIZE);
228 			else
229 				snprintf(name, NAME_SIZE, "%s+%x",
230 				    &strp[symp[i].st_name], off);
231 			goto found;
232 
233 		default:
234 			break;
235 		}
236 
237 #ifdef dump_core
238 		if (++i >= nsyms)
239 			i = 0;
240 		if (i == lastptr[find])
241 			return -1;
242 #endif
243 	}
244 
245 	return -1;
246 
247  found:
248  	lastptr[find] = i;
249  	return 0;
250 }
251