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