xref: /netbsd-src/sys/arch/atari/stand/binpatch/binpatch.c (revision de844269213ac89b34982086c5efb7e68e91ce32)
1*de844269Schristos /* $NetBSD: binpatch.c,v 1.7 2016/09/22 17:08:16 christos Exp $ */
28b0113cfSleo 
30228fe92Stsutsui /*-
40228fe92Stsutsui  * Copyright (c) 2009 Izumi Tsutsui.  All rights reserved.
58b0113cfSleo  *
68b0113cfSleo  * Redistribution and use in source and binary forms, with or without
78b0113cfSleo  * modification, are permitted provided that the following conditions
88b0113cfSleo  * are met:
98b0113cfSleo  * 1. Redistributions of source code must retain the above copyright
108b0113cfSleo  *    notice, this list of conditions and the following disclaimer.
118b0113cfSleo  * 2. Redistributions in binary form must reproduce the above copyright
128b0113cfSleo  *    notice, this list of conditions and the following disclaimer in the
138b0113cfSleo  *    documentation and/or other materials provided with the distribution.
148b0113cfSleo  *
158b0113cfSleo  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
168b0113cfSleo  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
178b0113cfSleo  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
188b0113cfSleo  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
198b0113cfSleo  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
208b0113cfSleo  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
218b0113cfSleo  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
228b0113cfSleo  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
238b0113cfSleo  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
248b0113cfSleo  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
258b0113cfSleo  */
268b0113cfSleo 
270228fe92Stsutsui /*
280228fe92Stsutsui  * Copyright (c) 1996 Christopher G. Demetriou
290228fe92Stsutsui  * All rights reserved.
300228fe92Stsutsui  *
310228fe92Stsutsui  * Redistribution and use in source and binary forms, with or without
320228fe92Stsutsui  * modification, are permitted provided that the following conditions
330228fe92Stsutsui  * are met:
340228fe92Stsutsui  * 1. Redistributions of source code must retain the above copyright
350228fe92Stsutsui  *    notice, this list of conditions and the following disclaimer.
360228fe92Stsutsui  * 2. Redistributions in binary form must reproduce the above copyright
370228fe92Stsutsui  *    notice, this list of conditions and the following disclaimer in the
380228fe92Stsutsui  *    documentation and/or other materials provided with the distribution.
390228fe92Stsutsui  * 3. The name of the author may not be used to endorse or promote products
400228fe92Stsutsui  *    derived from this software without specific prior written permission.
410228fe92Stsutsui  *
420228fe92Stsutsui  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
430228fe92Stsutsui  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
440228fe92Stsutsui  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
450228fe92Stsutsui  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
460228fe92Stsutsui  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
470228fe92Stsutsui  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
480228fe92Stsutsui  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
490228fe92Stsutsui  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
500228fe92Stsutsui  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
510228fe92Stsutsui  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
520228fe92Stsutsui  *
530228fe92Stsutsui  * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
540228fe92Stsutsui  */
550228fe92Stsutsui 
560228fe92Stsutsui #include <sys/cdefs.h>
570228fe92Stsutsui #ifndef lint
580228fe92Stsutsui __COPYRIGHT("@(#) Copyright (c) 1996\
590228fe92Stsutsui  Christopher G. Demetriou.  All rights reserved.");
600228fe92Stsutsui #endif /* not lint */
610228fe92Stsutsui 
620228fe92Stsutsui #ifndef lint
63*de844269Schristos __RCSID("$NetBSD: binpatch.c,v 1.7 2016/09/22 17:08:16 christos Exp $");
640228fe92Stsutsui #endif /* not lint */
650228fe92Stsutsui 
668b0113cfSleo #include <sys/types.h>
670228fe92Stsutsui #include <sys/mman.h>
680228fe92Stsutsui #include <sys/stat.h>
690228fe92Stsutsui #include <sys/inttypes.h>
700228fe92Stsutsui 
710228fe92Stsutsui #include <err.h>
720228fe92Stsutsui #include <fcntl.h>
730228fe92Stsutsui #include <limits.h>
740228fe92Stsutsui #include <nlist.h>
758b0113cfSleo #include <stdio.h>
76c97e01a8Smhitch #include <stdlib.h>
770228fe92Stsutsui #include <stdbool.h>
780228fe92Stsutsui #include <unistd.h>
798b0113cfSleo 
800228fe92Stsutsui #include "extern.h"
818b0113cfSleo 
820228fe92Stsutsui static void	usage(void) __dead;
838b0113cfSleo 
840228fe92Stsutsui bool replace, verbose;
850228fe92Stsutsui u_long addr, offset;
860228fe92Stsutsui char *symbol;
870228fe92Stsutsui size_t size;
880228fe92Stsutsui uint64_t val;
890228fe92Stsutsui 
900228fe92Stsutsui static const struct {
910228fe92Stsutsui 	const char *name;
920228fe92Stsutsui 	int	(*check)(const char *, size_t);
93*de844269Schristos 	int	(*findoff)(const char *, size_t, u_long, size_t *, u_long);
940228fe92Stsutsui } exec_formats[] = {
950228fe92Stsutsui #ifdef NLIST_AOUT
960228fe92Stsutsui 	{	"a.out",	check_aout,	findoff_aout,	},
970228fe92Stsutsui #endif
980228fe92Stsutsui #ifdef NLIST_ECOFF
990228fe92Stsutsui 	{	"ECOFF",	check_ecoff,	findoff_ecoff,	},
1000228fe92Stsutsui #endif
1010228fe92Stsutsui #ifdef NLIST_ELF32
1020228fe92Stsutsui 	{	"ELF32",	check_elf32,	findoff_elf32,	},
1030228fe92Stsutsui #endif
1040228fe92Stsutsui #ifdef NLIST_ELF64
1050228fe92Stsutsui 	{	"ELF64",	check_elf64,	findoff_elf64,	},
1060228fe92Stsutsui #endif
1070228fe92Stsutsui #ifdef NLIST_COFF
1080228fe92Stsutsui 	{	"COFF",		check_coff,	findoff_coff,	},
1090228fe92Stsutsui #endif
1100228fe92Stsutsui };
1118b0113cfSleo 
1128b0113cfSleo 
1138b0113cfSleo int
main(int argc,char * argv[])11482357f6dSdsl main(int argc, char *argv[])
1158b0113cfSleo {
1160228fe92Stsutsui 	const char *fname;
1170228fe92Stsutsui 	struct stat sb;
1180228fe92Stsutsui 	struct nlist nl[2];
1190228fe92Stsutsui 	char *mappedfile;
1200228fe92Stsutsui 	size_t valoff;
1210228fe92Stsutsui 	void *valp;
1220228fe92Stsutsui 	uint8_t uval8;
1230228fe92Stsutsui 	int8_t  sval8;
1240228fe92Stsutsui 	uint16_t uval16;
1250228fe92Stsutsui 	int16_t  sval16;
1260228fe92Stsutsui 	uint32_t uval32;
1270228fe92Stsutsui 	int32_t  sval32;
1280228fe92Stsutsui 	uint64_t uval64;
1290228fe92Stsutsui 	int64_t  sval64;
1300228fe92Stsutsui 	int ch, fd, rv, i, n;
131*de844269Schristos 	u_long	text_start;		/* Start of kernel text (a.out) */
1328b0113cfSleo 
1330228fe92Stsutsui 	setprogname(argv[0]);
134*de844269Schristos 	text_start = (unsigned long)~0;
1358b0113cfSleo 
1360228fe92Stsutsui 	while ((ch = getopt(argc, argv, "bwldT:a:s:o:r:v")) != -1)
1370228fe92Stsutsui 		switch (ch) {
1388b0113cfSleo 		case 'b':
1390228fe92Stsutsui 			size = sizeof(uint8_t);
1408b0113cfSleo 			break;
1418b0113cfSleo 		case 'w':
1420228fe92Stsutsui 			size = sizeof(uint16_t);
1438b0113cfSleo 			break;
1448b0113cfSleo 		case 'l':
1450228fe92Stsutsui 			size = sizeof(uint32_t);
1468b0113cfSleo 			break;
1470228fe92Stsutsui 		case 'd':
1480228fe92Stsutsui 			size = sizeof(uint64_t);
1498b0113cfSleo 			break;
1500228fe92Stsutsui 		case 'a':
1510228fe92Stsutsui 			if (addr != 0 || symbol != NULL)
1520228fe92Stsutsui 				errx(EXIT_FAILURE,
1530228fe92Stsutsui 				    "only one address/symbol allowed");
1540228fe92Stsutsui 			addr = strtoul(optarg, NULL, 0);
1550228fe92Stsutsui 			break;
1568b0113cfSleo 		case 's':
1570228fe92Stsutsui 			if (addr != 0 || symbol != NULL)
1580228fe92Stsutsui 				errx(EXIT_FAILURE,
1590228fe92Stsutsui 				    "only one address/symbol allowed");
1608b0113cfSleo 			symbol = optarg;
1618b0113cfSleo 			break;
1628b0113cfSleo 		case 'o':
1630228fe92Stsutsui 			if (offset != 0)
1640228fe92Stsutsui 				err(EXIT_FAILURE,
1650228fe92Stsutsui 				    "only one offset allowed");
1660228fe92Stsutsui 			offset = strtoul(optarg, NULL, 0);
1678b0113cfSleo 			break;
1680228fe92Stsutsui 		case 'r':
1690228fe92Stsutsui 			replace = true;
1700228fe92Stsutsui 			val = strtoull(optarg, NULL, 0);
1710228fe92Stsutsui 			break;
1720228fe92Stsutsui 		case 'v':
1730228fe92Stsutsui 			verbose = true;
1740228fe92Stsutsui 			break;
1750228fe92Stsutsui 		case 'T':
1760228fe92Stsutsui 			text_start = strtoul(optarg, NULL, 0);
1770228fe92Stsutsui 			break;
1780228fe92Stsutsui 		case '?':
1790228fe92Stsutsui 		default:
1800228fe92Stsutsui 			usage();
1810228fe92Stsutsui 	}
1820228fe92Stsutsui 	argc -= optind;
1830228fe92Stsutsui 	argv += optind;
1840228fe92Stsutsui 
1850228fe92Stsutsui 	if (argc != 1)
1860228fe92Stsutsui 		usage();
1870228fe92Stsutsui 
1880228fe92Stsutsui 	if (addr == 0 && symbol == NULL) {
1890228fe92Stsutsui 		warnx("no address or symbol specified");
1900228fe92Stsutsui 		usage();
1918b0113cfSleo 	}
1928b0113cfSleo 
1930228fe92Stsutsui 	if (size == 0)
1940228fe92Stsutsui 		size = sizeof(uint32_t);	/* default to int */
1958b0113cfSleo 
1968b0113cfSleo 	fname = argv[0];
1978b0113cfSleo 
1980228fe92Stsutsui 	if ((fd = open(fname, replace ? O_RDWR : O_RDONLY, 0))  == -1)
1990228fe92Stsutsui 		err(EXIT_FAILURE, "open %s", fname);
2008b0113cfSleo 
2010228fe92Stsutsui 	if (symbol != NULL) {
2020228fe92Stsutsui 		nl[0].n_name = symbol;
2030228fe92Stsutsui 		nl[1].n_name = NULL;
2040228fe92Stsutsui 		if ((rv = __fdnlist(fd, nl)) != 0)
2050228fe92Stsutsui 			errx(EXIT_FAILURE, "could not find symbol %s in %s",
2060228fe92Stsutsui 			    symbol, fname);
2078b0113cfSleo 		addr = nl[0].n_value;
2080228fe92Stsutsui 		if (verbose)
2090228fe92Stsutsui 			fprintf(stderr, "got symbol address 0x%lx from %s\n",
2100228fe92Stsutsui 			    addr, fname);
2118b0113cfSleo 	}
2128b0113cfSleo 
2130228fe92Stsutsui 	addr += offset * size;
2148b0113cfSleo 
2150228fe92Stsutsui 	if (fstat(fd, &sb) == -1)
2160228fe92Stsutsui 		err(EXIT_FAILURE, "fstat %s", fname);
2170228fe92Stsutsui 	if (sb.st_size != (ssize_t)sb.st_size)
2180228fe92Stsutsui 		errx(EXIT_FAILURE, "%s too big to map", fname);
2198b0113cfSleo 
2200228fe92Stsutsui 	if ((mappedfile = mmap(NULL, sb.st_size,
2210228fe92Stsutsui 	    replace ? PROT_READ | PROT_WRITE : PROT_READ,
2220228fe92Stsutsui 	    MAP_FILE | MAP_SHARED, fd, 0)) == (char *)-1)
2230228fe92Stsutsui 		err(EXIT_FAILURE, "mmap %s", fname);
2240228fe92Stsutsui 	if (verbose)
2250228fe92Stsutsui 		fprintf(stderr, "mapped %s\n", fname);
2268b0113cfSleo 
2270228fe92Stsutsui 	n = __arraycount(exec_formats);
2280228fe92Stsutsui 	for (i = 0; i < n; i++) {
2290228fe92Stsutsui 		if ((*exec_formats[i].check)(mappedfile, sb.st_size) == 0)
2308b0113cfSleo 			break;
2318b0113cfSleo 	}
2320228fe92Stsutsui 	if (i == n)
2330228fe92Stsutsui 		errx(EXIT_FAILURE, "%s: unknown executable format", fname);
2348b0113cfSleo 
2350228fe92Stsutsui 	if (verbose) {
2360228fe92Stsutsui 		fprintf(stderr, "%s is an %s binary\n", fname,
2370228fe92Stsutsui 		    exec_formats[i].name);
238*de844269Schristos 		if (text_start != (u_long)~0)
2390228fe92Stsutsui 			fprintf(stderr, "kernel text loads at 0x%lx\n",
2400228fe92Stsutsui 			    text_start);
2410228fe92Stsutsui 	}
2420228fe92Stsutsui 
2430228fe92Stsutsui 	if ((*exec_formats[i].findoff)(mappedfile, sb.st_size,
244*de844269Schristos 	    addr, &valoff, text_start) != 0)
2450228fe92Stsutsui 		errx(EXIT_FAILURE, "couldn't find file offset for %s in %s",
2460228fe92Stsutsui 		    symbol != NULL ? nl[0].n_name : "address" , fname);
2470228fe92Stsutsui 
2480228fe92Stsutsui 	valp = mappedfile + valoff;
2498b0113cfSleo 
2508b0113cfSleo 	if (symbol)
2510228fe92Stsutsui 		printf("%s(0x%lx): ", symbol, addr);
2528b0113cfSleo 	else
2530228fe92Stsutsui 		printf("0x%lx: ", addr);
2548b0113cfSleo 
2550228fe92Stsutsui 	switch (size) {
2560228fe92Stsutsui 	case sizeof(uint8_t):
2570228fe92Stsutsui 		uval8 = *(uint8_t *)valp;
2580228fe92Stsutsui 		sval8 = *(int8_t *)valp;
2590228fe92Stsutsui 		printf("0x%02" PRIx8 " (%" PRIu8, uval8, uval8);
2600228fe92Stsutsui 		if (sval8 < 0)
2610228fe92Stsutsui 			printf("/%" PRId8, sval8);
2620228fe92Stsutsui 		printf(")");
2638b0113cfSleo 		break;
2640228fe92Stsutsui 	case sizeof(uint16_t):
2650228fe92Stsutsui 		uval16 = *(uint16_t *)valp;
2660228fe92Stsutsui 		sval16 = *(int16_t *)valp;
2670228fe92Stsutsui 		printf("0x%04" PRIx16 " (%" PRIu16, uval16, uval16);
2680228fe92Stsutsui 		if (sval16 < 0)
2690228fe92Stsutsui 			printf("/%" PRId16, sval16);
2700228fe92Stsutsui 		printf(")");
2718b0113cfSleo 		break;
2720228fe92Stsutsui 	case sizeof(uint32_t):
2730228fe92Stsutsui 		uval32 = *(uint32_t *)valp;
2740228fe92Stsutsui 		sval32 = *(int32_t *)valp;
2750228fe92Stsutsui 		printf("0x%08" PRIx32 " (%" PRIu32, uval32, uval32);
2760228fe92Stsutsui 		if (sval32 < 0)
2770228fe92Stsutsui 			printf("/%" PRId32, sval32);
2780228fe92Stsutsui 		printf(")");
2790228fe92Stsutsui 		break;
2800228fe92Stsutsui 	case sizeof(uint64_t):
2810228fe92Stsutsui 		uval64 = *(uint64_t *)valp;
2820228fe92Stsutsui 		sval64 = *(int64_t *)valp;
2830228fe92Stsutsui 		printf("0x%016" PRIx64 " (%" PRIu64, uval64, uval64);
2840228fe92Stsutsui 		if (sval64 < 0)
2850228fe92Stsutsui 			printf("/%" PRId64, sval64);
2860228fe92Stsutsui 		printf(")");
2878b0113cfSleo 		break;
2888b0113cfSleo 	}
2890228fe92Stsutsui 	printf(", at offset %#lx in %s\n", (unsigned long)valoff, fname);
2908b0113cfSleo 
2910228fe92Stsutsui 	if (!replace)
2920228fe92Stsutsui 		goto done;
2930228fe92Stsutsui 
2940228fe92Stsutsui 	printf("new value: ");
2950228fe92Stsutsui 
2960228fe92Stsutsui 	switch (size) {
2970228fe92Stsutsui 	case sizeof(uint8_t):
2980228fe92Stsutsui 		uval8 = (uint8_t)val;
2990228fe92Stsutsui 		sval8 = (int8_t)val;
3000228fe92Stsutsui 		printf("0x%02" PRIx8 " (%" PRIu8, uval8, uval8);
3010228fe92Stsutsui 		if (sval8 < 0)
3020228fe92Stsutsui 			printf("/%" PRId8, sval8);
3030228fe92Stsutsui 		printf(")");
3040228fe92Stsutsui 		*(uint8_t *)valp = uval8;
3050228fe92Stsutsui 		break;
3060228fe92Stsutsui 	case sizeof(uint16_t):
3070228fe92Stsutsui 		uval16 = (uint16_t)val;
3080228fe92Stsutsui 		sval16 = (int16_t)val;
3090228fe92Stsutsui 		printf("0x%04" PRIx16 " (%" PRIu16, uval16, uval16);
3100228fe92Stsutsui 		if (sval16 < 0)
3110228fe92Stsutsui 			printf("/%" PRId16, sval16);
3120228fe92Stsutsui 		printf(")");
3130228fe92Stsutsui 		*(uint16_t *)valp = uval16;
3140228fe92Stsutsui 		break;
3150228fe92Stsutsui 	case sizeof(uint32_t):
3160228fe92Stsutsui 		uval32 = (uint32_t)val;
3170228fe92Stsutsui 		sval32 = (int32_t)val;
3180228fe92Stsutsui 		printf("0x%08" PRIx32 " (%" PRIu32, uval32, uval32);
3190228fe92Stsutsui 		if (sval32 < 0)
3200228fe92Stsutsui 			printf("/%" PRId32, sval32);
3210228fe92Stsutsui 		printf(")");
3220228fe92Stsutsui 		*(uint32_t *)valp = uval32;
3230228fe92Stsutsui 		break;
3240228fe92Stsutsui 	case sizeof(uint64_t):
3250228fe92Stsutsui 		uval64 = (uint64_t)val;
3260228fe92Stsutsui 		sval64 = (int64_t)val;
3270228fe92Stsutsui 		printf("0x%016" PRIx64 " (%" PRIu64, uval64, uval64);
3280228fe92Stsutsui 		if (sval64 < 0)
3290228fe92Stsutsui 			printf("/%" PRId64, sval64);
3300228fe92Stsutsui 		printf(")");
3310228fe92Stsutsui 		*(uint64_t *)valp = uval64;
3320228fe92Stsutsui 		break;
3330228fe92Stsutsui 	}
3340228fe92Stsutsui 	printf("\n");
3350228fe92Stsutsui 
3360228fe92Stsutsui  done:
3370228fe92Stsutsui 	munmap(mappedfile, sb.st_size);
3388b0113cfSleo 	close(fd);
3390228fe92Stsutsui 
3400228fe92Stsutsui 	if (verbose)
3410228fe92Stsutsui 		fprintf(stderr, "exiting\n");
3420228fe92Stsutsui 	exit(EXIT_SUCCESS);
3438b0113cfSleo }
3448b0113cfSleo 
3450228fe92Stsutsui static void
usage(void)3460228fe92Stsutsui usage(void)
3478b0113cfSleo {
3480228fe92Stsutsui 
3490228fe92Stsutsui 	fprintf(stderr,
350*de844269Schristos 	    "Usage: %s [-b|-w|-l|-d] [-a address | -s symbol] [-o offset]"
351*de844269Schristos 	    " [-r value] [-T text_start] [-v] binary\n", getprogname());
3520228fe92Stsutsui 	exit(EXIT_FAILURE);
3538b0113cfSleo }
354