1/* $NetBSD: dbsym.c,v 1.1 2009/08/18 20:22:20 skrll 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.1 2009/08/18 20:22:20 skrll 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
61struct 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
72int	main(int, char **);
73void	usage(void) __attribute__((noreturn));
74int	find_symtab(bfd *, struct symbols *);
75int	load_symtab(bfd *, int fd, char **, u_int32_t *);
76
77int	verbose;
78
79int
80main(int argc, char **argv)
81{
82	int ch, kfd;
83	struct stat ksb;
84	size_t symtab_offset;
85	u_int32_t symtab_space, symtabsize;
86	const char *kfile;
87	char *bfdname, *mappedkfile, *symtab;
88	bfd *abfd;
89
90	setprogname(argv[0]);
91
92	bfdname = NULL;
93	while ((ch = getopt(argc, argv, "b:v")) != -1)
94		switch (ch) {
95		case 'b':
96			bfdname = optarg;
97			break;
98		case 'v':
99			verbose = 1;
100			break;
101		case '?':
102		default:
103			usage();
104	}
105	argc -= optind;
106	argv += optind;
107
108	if (argc != 1)
109		usage();
110	kfile = argv[0];
111
112	if ((kfd = open(kfile, O_RDWR, 0))  == -1)
113		err(1, "open %s", kfile);
114
115	bfd_init();
116	if ((abfd = bfd_fdopenr(kfile, bfdname, kfd)) == NULL) {
117		bfd_perror("open");
118		exit(1);
119	}
120	if (!bfd_check_format(abfd, bfd_object)) {
121		bfd_perror("check format");
122		exit(1);
123	}
124
125	if (!(bfd_get_file_flags(abfd) & HAS_SYMS))
126		errx(1, "no symbol table in %s", kfile);
127
128	if (find_symtab(abfd, db_symtab_symbols) != 0)
129		errx(1, "could not find SYMTAB_SPACE in %s", kfile);
130	if (verbose)
131		fprintf(stderr, "got SYMTAB_SPACE symbols from %s\n", kfile);
132
133	if (load_symtab(abfd, kfd, &symtab, &symtabsize) != 0)
134		errx(1, "could not load symbol table from %s", kfile);
135	if (verbose)
136		fprintf(stderr, "loaded symbol table from %s\n", kfile);
137
138	if (fstat(kfd, &ksb) == -1)
139		err(1, "fstat %s", kfile);
140	if (ksb.st_size != (size_t)ksb.st_size)
141		errx(1, "%s too big to map", kfile);
142
143	if ((mappedkfile = mmap(NULL, ksb.st_size, PROT_READ | PROT_WRITE,
144	    MAP_FILE | MAP_SHARED, kfd, 0)) == (caddr_t)-1)
145		err(1, "mmap %s", kfile);
146	if (verbose)
147		fprintf(stderr, "mapped %s\n", kfile);
148
149	symtab_offset = db_symtab_symbols[X_DB_SYMTAB].offset;
150	symtab_space = bfd_get_32(abfd,
151	    &mappedkfile[db_symtab_symbols[X_DB_SYMTABSIZE].offset]);
152
153	if (symtabsize > symtab_space)
154		errx(1, "symbol table (%u bytes) too big for buffer (%u bytes)\n"
155		    "Increase options SYMTAB_SPACE in your kernel config",
156		    symtabsize, symtab_space);
157
158	if (verbose)
159		fprintf(stderr, "symtab size %d, space available %d\n",
160		    symtabsize, symtab_space);
161
162	memcpy(mappedkfile + symtab_offset, symtab, symtabsize);
163
164	if (verbose)
165		fprintf(stderr, "done copying image to file offset %#lx\n",
166		    (long)db_symtab_symbols[X_DB_SYMTAB].offset);
167
168	bfd_put_32(abfd, symtabsize,
169	    &mappedkfile[db_symtab_symbols[X_DB_SYMTABSIZE].offset]);
170
171	munmap(mappedkfile, ksb.st_size);
172	close(kfd);
173
174	if (verbose)
175		fprintf(stderr, "exiting\n");
176
177	bfd_close_all_done(abfd);
178	exit(0);
179}
180
181void
182usage(void)
183{
184	const char **list;
185
186	fprintf(stderr,
187	    "usage: %s [-b bfdname] [-v] kernel_file\n",
188	    getprogname());
189	fprintf(stderr, "supported targets:");
190	for (list = bfd_target_list(); *list != NULL; list++)
191		fprintf(stderr, " %s", *list);
192	fprintf(stderr, "\n");
193	exit(1);
194}
195
196int
197find_symtab(bfd *abfd, struct symbols *symbols)
198{
199	long i;
200	long storage_needed;
201	long number_of_symbols;
202	asymbol **symbol_table = NULL;
203	struct symbols *s;
204
205	storage_needed = bfd_get_symtab_upper_bound(abfd);
206	if (storage_needed <= 0)
207		return (1);
208
209	if ((symbol_table = (asymbol **)malloc(storage_needed)) == NULL)
210		return (1);
211
212	number_of_symbols = bfd_canonicalize_symtab(abfd, symbol_table);
213	if (number_of_symbols <= 0) {
214		free(symbol_table);
215		return (1);
216	}
217
218	for (i = 0; i < number_of_symbols; i++) {
219		for (s = symbols; s->name != NULL; s++) {
220		  const char *sym = symbol_table[i]->name;
221
222			/*
223			 * match symbol prefix '_' or ''.
224			 * XXX: use bfd_get_symbol_leading_char() here?
225			 */
226			if (!strcmp(s->name, sym) ||
227			    !strcmp(s->name + 1, sym)) {
228				s->offset = (size_t)
229				    (symbol_table[i]->section->filepos
230                                    + symbol_table[i]->value);
231
232			}
233		}
234	}
235
236	free(symbol_table);
237
238	for (s = symbols; s->name != NULL; s++) {
239		if (s->offset == 0)
240			return (1);
241	}
242
243	return (0);
244}
245
246/* --------------------------- ELF gunk follows --------------------------- */
247
248/*
249 * The format of the symbols loaded by the boot program is:
250 *
251 *      Elf exec header
252 *      first section header
253 *      . . .
254 *      . . .
255 *      last section header
256 *      first symbol or string table section
257 *      . . .
258 *      . . .
259 *      last symbol or string table section
260 */
261
262
263/* Note elftype is local to load_symtab()... */
264#define	ELF_TYPE_64	0x01
265#define	ISELF64		(elftype & ELF_TYPE_64)
266
267/*
268 * Field sizes for the Elf exec header:
269 *
270 *    ELF32    ELF64
271 *
272 *    unsigned char      e_ident[ELF_NIDENT];    # Id bytes
273 *     16       16       e_type;                 # file type
274 *     16       16       e_machine;              # machine type
275 *     32       32       e_version;              # version number
276 *     32       64       e_entry;                # entry point
277 *     32       64       e_phoff;                # Program hdr offset
278 *     32       64       e_shoff;                # Section hdr offset
279 *     32       32       e_flags;                # Processor flags
280 *     16       16       e_ehsize;               # sizeof ehdr
281 *     16       16       e_phentsize;            # Program header entry size
282 *     16       16       e_phnum;                # Number of program headers
283 *     16       16       e_shentsize;            # Section header entry size
284 *     16       16       e_shnum;                # Number of section headers
285 *     16       16       e_shstrndx;             # String table index
286 */
287
288typedef union {
289	Elf32_External_Ehdr e32hdr;
290	Elf64_External_Ehdr e64hdr;
291	char e_ident[16];		/* XXX MAGIC NUMBER */
292} elf_ehdr;
293
294#define	e32_hdr	ehdr.e32hdr
295#define	e64_hdr	ehdr.e64hdr
296
297/*
298 * Field sizes for Elf section headers
299 *
300 *    ELF32    ELF64
301 *
302 *     32       32       sh_name;        # section name (.shstrtab index)
303 *     32       32       sh_type;        # section type
304 *     32       64       sh_flags;       # section flags
305 *     32       64       sh_addr;        # virtual address
306 *     32       64       sh_offset;      # file offset
307 *     32       64       sh_size;        # section size
308 *     32       32       sh_link;        # link to another
309 *     32       32       sh_info;        # misc info
310 *     32       64       sh_addralign;   # memory alignment
311 *     32       64       sh_entsize;     # table entry size
312 */
313
314/* Extract a 32 bit field from Elf32_Shdr */
315#define	SH_E32_32(x, n)		bfd_get_32(abfd, s32hdr[(x)].n)
316
317/* Extract a 32 bit field from Elf64_Shdr */
318#define	SH_E64_32(x, n)		bfd_get_32(abfd, s64hdr[(x)].n)
319
320/* Extract a 64 bit field from Elf64_Shdr */
321#define	SH_E64_64(x, n)		bfd_get_64(abfd, s64hdr[(x)].n)
322
323/* Extract a 32 bit field from either size Shdr */
324#define	SH_E32E32(x, n)	(ISELF64 ? SH_E64_32(x, n) : SH_E32_32(x, n))
325
326/* Extract a 32 bit field from Elf32_Shdr or 64 bit field from Elf64_Shdr */
327#define	SH_E32E64(x, n)	(ISELF64 ? SH_E64_64(x, n) : SH_E32_32(x, n))
328
329#define	SH_NAME(x)	SH_E32E32(x, sh_name)
330#define	SH_TYPE(x)	SH_E32E32(x, sh_type)
331#define	SH_FLAGS(x)	SH_E32E64(x, sh_flags)
332#define	SH_ADDR(x)	SH_E32E64(x, sh_addr)
333#define	SH_OFFSET(x)	SH_E32E64(x, sh_offset)
334#define	SH_SIZE(x)	SH_E32E64(x, sh_size)
335#define	SH_LINK(x)	SH_E32E32(x, sh_link)
336#define	SH_INFO(x)	SH_E32E32(x, sh_info)
337#define	SH_ADDRALIGN(x)	SH_E32E64(x, sh_addralign)
338#define	SH_ENTSIZE(x)	SH_E32E64(x, sh_entsize)
339
340int
341load_symtab(bfd *abfd, int fd, char **symtab, u_int32_t *symtabsize)
342{
343	elf_ehdr ehdr;
344	Elf32_External_Shdr *s32hdr = NULL;
345	Elf64_External_Shdr *s64hdr = NULL;
346	void *shdr;
347	u_int32_t osymtabsize, sh_offset;
348	int elftype, e_shnum, i, sh_size;
349	off_t e_shoff;
350
351	if (lseek(fd, 0, SEEK_SET) < 0)
352		return (1);
353	if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
354		return (1);
355
356	/*
357	 * Check that we are targetting an Elf binary.
358	 */
359	if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
360	    ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
361	    ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
362	    ehdr.e_ident[EI_MAG3] != ELFMAG3)
363		return (1);
364
365	/*
366	 * Determine Elf size and endianness.
367	 */
368	elftype = 0;
369	if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
370		elftype |= ELF_TYPE_64;
371
372	/*
373	 * Elf exec header.  Only need to allocate space for now,
374	 * the header is copied into place at the end.
375	 */
376	*symtabsize = ISELF64 ? sizeof(Elf64_External_Ehdr)
377			      : sizeof(Elf32_External_Ehdr);
378	*symtab = NULL;
379
380	/*
381	 * Section headers.  Allocate a temporary copy that will
382	 * be copied into place at the end.
383	 */
384	sh_offset = osymtabsize = *symtabsize;
385	e_shnum = (ISELF64
386	    ? bfd_get_16(abfd, e64_hdr.e_shnum)
387	    : bfd_get_16(abfd, e32_hdr.e_shnum));
388	sh_size = e_shnum * (ISELF64 ? sizeof(Elf64_External_Shdr)
389				     : sizeof(Elf32_External_Shdr));
390	if ((shdr = malloc(sh_size)) == NULL)
391		return (1);
392	if (ISELF64)
393		s64hdr = shdr;
394	else
395		s32hdr = shdr;
396
397	*symtabsize += roundup(sh_size, ISELF64 ? 8 : 4);
398
399	e_shoff = (ISELF64
400	   ? bfd_get_64(abfd, e64_hdr.e_shoff)
401	   : bfd_get_32(abfd, e32_hdr.e_shoff));
402	if (lseek(fd, e_shoff, SEEK_SET) < 0)
403		goto out;
404	if (read(fd, shdr, sh_size) != sh_size)
405		goto out;
406
407	for (i = 0; i < e_shnum; i++) {
408		if (SH_TYPE(i) == SHT_SYMTAB || SH_TYPE(i) == SHT_STRTAB) {
409			osymtabsize = *symtabsize;
410			*symtabsize += roundup(SH_SIZE(i), ISELF64 ? 8 : 4);
411			if ((*symtab = realloc(*symtab, *symtabsize)) == NULL)
412				goto out;
413
414			if (lseek(fd, SH_OFFSET(i), SEEK_SET) < 0)
415				goto out;
416			if (read(fd, *symtab + osymtabsize, SH_SIZE(i)) !=
417			    SH_SIZE(i))
418				goto out;
419			if (ISELF64) {
420				bfd_put_64(abfd, osymtabsize,
421				    s64hdr[i].sh_offset);
422			} else {
423				bfd_put_32(abfd, osymtabsize,
424				    s32hdr[i].sh_offset);
425			}
426		}
427	}
428
429	if (*symtab == NULL)
430		goto out;
431
432	/*
433	 * Copy updated section headers.
434	 */
435	memcpy(*symtab + sh_offset, shdr, sh_size);
436
437	/*
438	 * Update and copy the exec header.
439	 */
440	if (ISELF64) {
441		bfd_put_64(abfd, 0, e64_hdr.e_phoff);
442		bfd_put_64(abfd, sizeof(Elf64_External_Ehdr), e64_hdr.e_shoff);
443		bfd_put_16(abfd, 0, e64_hdr.e_phentsize);
444		bfd_put_16(abfd, 0, e64_hdr.e_phnum);
445	} else {
446		bfd_put_32(abfd, 0, e32_hdr.e_phoff);
447		bfd_put_32(abfd, sizeof(Elf32_External_Ehdr), e32_hdr.e_shoff);
448		bfd_put_16(abfd, 0, e32_hdr.e_phentsize);
449		bfd_put_16(abfd, 0, e32_hdr.e_phnum);
450	}
451	memcpy(*symtab, &ehdr, sizeof(ehdr));
452
453	free(shdr);
454	return (0);
455out:
456	free(shdr);
457	return (1);
458}
459