xref: /netbsd-src/external/gpl3/binutils/usr.sbin/dbsym/dbsym.c (revision a536ee5124e62c9a0051a252f7833dc8f50f44c9)
1 /* $NetBSD: dbsym.c,v 1.3 2012/03/19 09:14:15 wiz Exp $ */
2 
3 /*
4  * Copyright (c) 2001 Simon Burge (for Wasabi Systems)
5  * Copyright (c) 1996 Christopher G. Demetriou
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
31  */
32 
33 #if HAVE_NBTOOL_CONFIG_H
34 #include "nbtool_config.h"
35 #endif
36 
37 #include <sys/cdefs.h>
38 #if !defined(lint)
39 __COPYRIGHT("@(#) Copyright (c) 1996 Christopher G. Demetriou.\
40   Copyright 2001 Simon Burge.\
41   All rights reserved.");
42 __RCSID("$NetBSD: dbsym.c,v 1.3 2012/03/19 09:14:15 wiz Exp $");
43 #endif /* not lint */
44 
45 #include <sys/param.h>
46 #include <sys/mman.h>
47 #include <sys/stat.h>
48 
49 #include <bfd.h>
50 #include <err.h>
51 #include <fcntl.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 
57 /* BFD ELF headers */
58 #include <elf/common.h>
59 #include <elf/external.h>
60 
61 struct symbols {
62 	char *name;
63 	size_t offset;
64 } db_symtab_symbols[] = {
65 #define	X_DB_SYMTAB	0
66 	{ "_db_symtab", 0 },
67 #define	X_DB_SYMTABSIZE	1
68 	{ "_db_symtabsize", 0 },
69 	{ NULL, 0 }
70 };
71 
72 int	main(int, char **);
73 void	usage(void) __attribute__((noreturn));
74 int	find_symtab(bfd *, struct symbols *);
75 int	load_symtab(bfd *, int fd, char **, u_int32_t *);
76 
77 int	verbose;
78 int	printsize;
79 
80 int
81 main(int argc, char **argv)
82 {
83 	int ch, kfd;
84 	struct stat ksb;
85 	size_t symtab_offset;
86 	u_int32_t symtab_space, symtabsize;
87 	const char *kfile;
88 	char *bfdname, *mappedkfile, *symtab;
89 	bfd *abfd;
90 
91 	setprogname(argv[0]);
92 
93 	bfdname = NULL;
94 	while ((ch = getopt(argc, argv, "b:pv")) != -1)
95 		switch (ch) {
96 		case 'b':
97 			bfdname = optarg;
98 			break;
99 		case 'v':
100 			verbose = 1;
101 			break;
102 		case 'p':
103 			printsize = 1;
104 			break;
105 		case '?':
106 		default:
107 			usage();
108 	}
109 	argc -= optind;
110 	argv += optind;
111 
112 	if (argc != 1)
113 		usage();
114 	kfile = argv[0];
115 
116 	if ((kfd = open(kfile, O_RDWR, 0))  == -1)
117 		err(1, "open %s", kfile);
118 
119 	bfd_init();
120 	if ((abfd = bfd_fdopenr(kfile, bfdname, kfd)) == NULL) {
121 		bfd_perror("open");
122 		exit(1);
123 	}
124 	if (!bfd_check_format(abfd, bfd_object)) {
125 		bfd_perror("check format");
126 		exit(1);
127 	}
128 
129 	if (!(bfd_get_file_flags(abfd) & HAS_SYMS))
130 		errx(1, "no symbol table in %s", kfile);
131 
132 	if (find_symtab(abfd, db_symtab_symbols) != 0)
133 		errx(1, "could not find SYMTAB_SPACE in %s", kfile);
134 	if (verbose)
135 		fprintf(stderr, "got SYMTAB_SPACE symbols from %s\n", kfile);
136 
137 	if (load_symtab(abfd, kfd, &symtab, &symtabsize) != 0)
138 		errx(1, "could not load symbol table from %s", kfile);
139 	if (verbose)
140 		fprintf(stderr, "loaded symbol table from %s\n", kfile);
141 
142 	if (fstat(kfd, &ksb) == -1)
143 		err(1, "fstat %s", kfile);
144 	if (ksb.st_size != (size_t)ksb.st_size)
145 		errx(1, "%s too big to map", kfile);
146 
147 	if ((mappedkfile = mmap(NULL, ksb.st_size, PROT_READ | PROT_WRITE,
148 	    MAP_FILE | MAP_SHARED, kfd, 0)) == (caddr_t)-1)
149 		err(1, "mmap %s", kfile);
150 	if (verbose)
151 		fprintf(stderr, "mapped %s\n", kfile);
152 
153 	symtab_offset = db_symtab_symbols[X_DB_SYMTAB].offset;
154 	symtab_space = bfd_get_32(abfd,
155 	    &mappedkfile[db_symtab_symbols[X_DB_SYMTABSIZE].offset]);
156 
157 	if (printsize) {
158 		printf("%d %d\n", symtabsize, symtab_space);
159 		goto done;
160 	}
161 
162 	if (symtabsize > symtab_space)
163 		errx(1, "symbol table (%u bytes) too big for buffer (%u bytes)\n"
164 		    "Increase options SYMTAB_SPACE in your kernel config",
165 		    symtabsize, symtab_space);
166 
167 	if (verbose)
168 		fprintf(stderr, "symtab size %d, space available %d\n",
169 		    symtabsize, symtab_space);
170 
171 	memcpy(mappedkfile + symtab_offset, symtab, symtabsize);
172 
173 	if (verbose)
174 		fprintf(stderr, "done copying image to file offset %#lx\n",
175 		    (long)db_symtab_symbols[X_DB_SYMTAB].offset);
176 
177 	bfd_put_32(abfd, symtabsize,
178 	    &mappedkfile[db_symtab_symbols[X_DB_SYMTABSIZE].offset]);
179 
180 done:
181 	munmap(mappedkfile, ksb.st_size);
182 	close(kfd);
183 
184 	if (verbose)
185 		fprintf(stderr, "exiting\n");
186 
187 	bfd_close_all_done(abfd);
188 	exit(0);
189 }
190 
191 void
192 usage(void)
193 {
194 	const char **list;
195 
196 	fprintf(stderr,
197 	    "usage: %s [-pv] [-b bfdname] kernel\n",
198 	    getprogname());
199 	fprintf(stderr, "supported targets:");
200 	for (list = bfd_target_list(); *list != NULL; list++)
201 		fprintf(stderr, " %s", *list);
202 	fprintf(stderr, "\n");
203 	exit(1);
204 }
205 
206 int
207 find_symtab(bfd *abfd, struct symbols *symbols)
208 {
209 	long i;
210 	long storage_needed;
211 	long number_of_symbols;
212 	asymbol **symbol_table = NULL;
213 	struct symbols *s;
214 
215 	storage_needed = bfd_get_symtab_upper_bound(abfd);
216 	if (storage_needed <= 0)
217 		return (1);
218 
219 	if ((symbol_table = (asymbol **)malloc(storage_needed)) == NULL)
220 		return (1);
221 
222 	number_of_symbols = bfd_canonicalize_symtab(abfd, symbol_table);
223 	if (number_of_symbols <= 0) {
224 		free(symbol_table);
225 		return (1);
226 	}
227 
228 	for (i = 0; i < number_of_symbols; i++) {
229 		for (s = symbols; s->name != NULL; s++) {
230 		  const char *sym = symbol_table[i]->name;
231 
232 			/*
233 			 * match symbol prefix '_' or ''.
234 			 * XXX: use bfd_get_symbol_leading_char() here?
235 			 */
236 			if (!strcmp(s->name, sym) ||
237 			    !strcmp(s->name + 1, sym)) {
238 				s->offset = (size_t)
239 				    (symbol_table[i]->section->filepos
240                                     + symbol_table[i]->value);
241 
242 			}
243 		}
244 	}
245 
246 	free(symbol_table);
247 
248 	for (s = symbols; s->name != NULL; s++) {
249 		if (s->offset == 0)
250 			return (1);
251 	}
252 
253 	return (0);
254 }
255 
256 /* --------------------------- ELF gunk follows --------------------------- */
257 
258 /*
259  * The format of the symbols loaded by the boot program is:
260  *
261  *      Elf exec header
262  *      first section header
263  *      . . .
264  *      . . .
265  *      last section header
266  *      first symbol or string table section
267  *      . . .
268  *      . . .
269  *      last symbol or string table section
270  */
271 
272 
273 /* Note elftype is local to load_symtab()... */
274 #define	ELF_TYPE_64	0x01
275 #define	ISELF64		(elftype & ELF_TYPE_64)
276 
277 /*
278  * Field sizes for the Elf exec header:
279  *
280  *    ELF32    ELF64
281  *
282  *    unsigned char      e_ident[ELF_NIDENT];    # Id bytes
283  *     16       16       e_type;                 # file type
284  *     16       16       e_machine;              # machine type
285  *     32       32       e_version;              # version number
286  *     32       64       e_entry;                # entry point
287  *     32       64       e_phoff;                # Program hdr offset
288  *     32       64       e_shoff;                # Section hdr offset
289  *     32       32       e_flags;                # Processor flags
290  *     16       16       e_ehsize;               # sizeof ehdr
291  *     16       16       e_phentsize;            # Program header entry size
292  *     16       16       e_phnum;                # Number of program headers
293  *     16       16       e_shentsize;            # Section header entry size
294  *     16       16       e_shnum;                # Number of section headers
295  *     16       16       e_shstrndx;             # String table index
296  */
297 
298 typedef union {
299 	Elf32_External_Ehdr e32hdr;
300 	Elf64_External_Ehdr e64hdr;
301 	char e_ident[16];		/* XXX MAGIC NUMBER */
302 } elf_ehdr;
303 
304 #define	e32_hdr	ehdr.e32hdr
305 #define	e64_hdr	ehdr.e64hdr
306 
307 /*
308  * Field sizes for Elf section headers
309  *
310  *    ELF32    ELF64
311  *
312  *     32       32       sh_name;        # section name (.shstrtab index)
313  *     32       32       sh_type;        # section type
314  *     32       64       sh_flags;       # section flags
315  *     32       64       sh_addr;        # virtual address
316  *     32       64       sh_offset;      # file offset
317  *     32       64       sh_size;        # section size
318  *     32       32       sh_link;        # link to another
319  *     32       32       sh_info;        # misc info
320  *     32       64       sh_addralign;   # memory alignment
321  *     32       64       sh_entsize;     # table entry size
322  */
323 
324 /* Extract a 32 bit field from Elf32_Shdr */
325 #define	SH_E32_32(x, n)		bfd_get_32(abfd, s32hdr[(x)].n)
326 
327 /* Extract a 32 bit field from Elf64_Shdr */
328 #define	SH_E64_32(x, n)		bfd_get_32(abfd, s64hdr[(x)].n)
329 
330 /* Extract a 64 bit field from Elf64_Shdr */
331 #define	SH_E64_64(x, n)		bfd_get_64(abfd, s64hdr[(x)].n)
332 
333 /* Extract a 32 bit field from either size Shdr */
334 #define	SH_E32E32(x, n)	(ISELF64 ? SH_E64_32(x, n) : SH_E32_32(x, n))
335 
336 /* Extract a 32 bit field from Elf32_Shdr or 64 bit field from Elf64_Shdr */
337 #define	SH_E32E64(x, n)	(ISELF64 ? SH_E64_64(x, n) : SH_E32_32(x, n))
338 
339 #define	SH_NAME(x)	SH_E32E32(x, sh_name)
340 #define	SH_TYPE(x)	SH_E32E32(x, sh_type)
341 #define	SH_FLAGS(x)	SH_E32E64(x, sh_flags)
342 #define	SH_ADDR(x)	SH_E32E64(x, sh_addr)
343 #define	SH_OFFSET(x)	SH_E32E64(x, sh_offset)
344 #define	SH_SIZE(x)	SH_E32E64(x, sh_size)
345 #define	SH_LINK(x)	SH_E32E32(x, sh_link)
346 #define	SH_INFO(x)	SH_E32E32(x, sh_info)
347 #define	SH_ADDRALIGN(x)	SH_E32E64(x, sh_addralign)
348 #define	SH_ENTSIZE(x)	SH_E32E64(x, sh_entsize)
349 
350 int
351 load_symtab(bfd *abfd, int fd, char **symtab, u_int32_t *symtabsize)
352 {
353 	elf_ehdr ehdr;
354 	Elf32_External_Shdr *s32hdr = NULL;
355 	Elf64_External_Shdr *s64hdr = NULL;
356 	void *shdr;
357 	u_int32_t osymtabsize, sh_offset;
358 	int elftype, e_shnum, i, sh_size;
359 	off_t e_shoff;
360 
361 	if (lseek(fd, 0, SEEK_SET) < 0)
362 		return (1);
363 	if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
364 		return (1);
365 
366 	/*
367 	 * Check that we are targetting an Elf binary.
368 	 */
369 	if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
370 	    ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
371 	    ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
372 	    ehdr.e_ident[EI_MAG3] != ELFMAG3)
373 		return (1);
374 
375 	/*
376 	 * Determine Elf size and endianness.
377 	 */
378 	elftype = 0;
379 	if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
380 		elftype |= ELF_TYPE_64;
381 
382 	/*
383 	 * Elf exec header.  Only need to allocate space for now,
384 	 * the header is copied into place at the end.
385 	 */
386 	*symtabsize = ISELF64 ? sizeof(Elf64_External_Ehdr)
387 			      : sizeof(Elf32_External_Ehdr);
388 	*symtab = NULL;
389 
390 	/*
391 	 * Section headers.  Allocate a temporary copy that will
392 	 * be copied into place at the end.
393 	 */
394 	sh_offset = osymtabsize = *symtabsize;
395 	e_shnum = (ISELF64
396 	    ? bfd_get_16(abfd, e64_hdr.e_shnum)
397 	    : bfd_get_16(abfd, e32_hdr.e_shnum));
398 	sh_size = e_shnum * (ISELF64 ? sizeof(Elf64_External_Shdr)
399 				     : sizeof(Elf32_External_Shdr));
400 	if ((shdr = malloc(sh_size)) == NULL)
401 		return (1);
402 	if (ISELF64)
403 		s64hdr = shdr;
404 	else
405 		s32hdr = shdr;
406 
407 	*symtabsize += roundup(sh_size, ISELF64 ? 8 : 4);
408 
409 	e_shoff = (ISELF64
410 	   ? bfd_get_64(abfd, e64_hdr.e_shoff)
411 	   : bfd_get_32(abfd, e32_hdr.e_shoff));
412 	if (lseek(fd, e_shoff, SEEK_SET) < 0)
413 		goto out;
414 	if (read(fd, shdr, sh_size) != sh_size)
415 		goto out;
416 
417 	for (i = 0; i < e_shnum; i++) {
418 		if (SH_TYPE(i) == SHT_SYMTAB || SH_TYPE(i) == SHT_STRTAB) {
419 			osymtabsize = *symtabsize;
420 			*symtabsize += roundup(SH_SIZE(i), ISELF64 ? 8 : 4);
421 			if ((*symtab = realloc(*symtab, *symtabsize)) == NULL)
422 				goto out;
423 
424 			if (lseek(fd, SH_OFFSET(i), SEEK_SET) < 0)
425 				goto out;
426 			if (read(fd, *symtab + osymtabsize, SH_SIZE(i)) !=
427 			    SH_SIZE(i))
428 				goto out;
429 			if (ISELF64) {
430 				bfd_put_64(abfd, osymtabsize,
431 				    s64hdr[i].sh_offset);
432 			} else {
433 				bfd_put_32(abfd, osymtabsize,
434 				    s32hdr[i].sh_offset);
435 			}
436 		}
437 	}
438 
439 	if (*symtab == NULL)
440 		goto out;
441 
442 	/*
443 	 * Copy updated section headers.
444 	 */
445 	memcpy(*symtab + sh_offset, shdr, sh_size);
446 
447 	/*
448 	 * Update and copy the exec header.
449 	 */
450 	if (ISELF64) {
451 		bfd_put_64(abfd, 0, e64_hdr.e_phoff);
452 		bfd_put_64(abfd, sizeof(Elf64_External_Ehdr), e64_hdr.e_shoff);
453 		bfd_put_16(abfd, 0, e64_hdr.e_phentsize);
454 		bfd_put_16(abfd, 0, e64_hdr.e_phnum);
455 	} else {
456 		bfd_put_32(abfd, 0, e32_hdr.e_phoff);
457 		bfd_put_32(abfd, sizeof(Elf32_External_Ehdr), e32_hdr.e_shoff);
458 		bfd_put_16(abfd, 0, e32_hdr.e_phentsize);
459 		bfd_put_16(abfd, 0, e32_hdr.e_phnum);
460 	}
461 	memcpy(*symtab, &ehdr, sizeof(ehdr));
462 
463 	free(shdr);
464 	return (0);
465 out:
466 	free(shdr);
467 	return (1);
468 }
469