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