xref: /netbsd-src/sys/arch/atari/stand/binpatch/binpatch.c (revision de844269213ac89b34982086c5efb7e68e91ce32)
1 /* $NetBSD: binpatch.c,v 1.7 2016/09/22 17:08:16 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 2009 Izumi Tsutsui.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 /*
28  * Copyright (c) 1996 Christopher G. Demetriou
29  * All rights reserved.
30  *
31  * Redistribution and use in source and binary forms, with or without
32  * modification, are permitted provided that the following conditions
33  * are met:
34  * 1. Redistributions of source code must retain the above copyright
35  *    notice, this list of conditions and the following disclaimer.
36  * 2. Redistributions in binary form must reproduce the above copyright
37  *    notice, this list of conditions and the following disclaimer in the
38  *    documentation and/or other materials provided with the distribution.
39  * 3. The name of the author may not be used to endorse or promote products
40  *    derived from this software without specific prior written permission.
41  *
42  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
43  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
44  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
45  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
46  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
48  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
49  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
50  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
51  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52  *
53  * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
54  */
55 
56 #include <sys/cdefs.h>
57 #ifndef lint
58 __COPYRIGHT("@(#) Copyright (c) 1996\
59  Christopher G. Demetriou.  All rights reserved.");
60 #endif /* not lint */
61 
62 #ifndef lint
63 __RCSID("$NetBSD: binpatch.c,v 1.7 2016/09/22 17:08:16 christos Exp $");
64 #endif /* not lint */
65 
66 #include <sys/types.h>
67 #include <sys/mman.h>
68 #include <sys/stat.h>
69 #include <sys/inttypes.h>
70 
71 #include <err.h>
72 #include <fcntl.h>
73 #include <limits.h>
74 #include <nlist.h>
75 #include <stdio.h>
76 #include <stdlib.h>
77 #include <stdbool.h>
78 #include <unistd.h>
79 
80 #include "extern.h"
81 
82 static void	usage(void) __dead;
83 
84 bool replace, verbose;
85 u_long addr, offset;
86 char *symbol;
87 size_t size;
88 uint64_t val;
89 
90 static const struct {
91 	const char *name;
92 	int	(*check)(const char *, size_t);
93 	int	(*findoff)(const char *, size_t, u_long, size_t *, u_long);
94 } exec_formats[] = {
95 #ifdef NLIST_AOUT
96 	{	"a.out",	check_aout,	findoff_aout,	},
97 #endif
98 #ifdef NLIST_ECOFF
99 	{	"ECOFF",	check_ecoff,	findoff_ecoff,	},
100 #endif
101 #ifdef NLIST_ELF32
102 	{	"ELF32",	check_elf32,	findoff_elf32,	},
103 #endif
104 #ifdef NLIST_ELF64
105 	{	"ELF64",	check_elf64,	findoff_elf64,	},
106 #endif
107 #ifdef NLIST_COFF
108 	{	"COFF",		check_coff,	findoff_coff,	},
109 #endif
110 };
111 
112 
113 int
main(int argc,char * argv[])114 main(int argc, char *argv[])
115 {
116 	const char *fname;
117 	struct stat sb;
118 	struct nlist nl[2];
119 	char *mappedfile;
120 	size_t valoff;
121 	void *valp;
122 	uint8_t uval8;
123 	int8_t  sval8;
124 	uint16_t uval16;
125 	int16_t  sval16;
126 	uint32_t uval32;
127 	int32_t  sval32;
128 	uint64_t uval64;
129 	int64_t  sval64;
130 	int ch, fd, rv, i, n;
131 	u_long	text_start;		/* Start of kernel text (a.out) */
132 
133 	setprogname(argv[0]);
134 	text_start = (unsigned long)~0;
135 
136 	while ((ch = getopt(argc, argv, "bwldT:a:s:o:r:v")) != -1)
137 		switch (ch) {
138 		case 'b':
139 			size = sizeof(uint8_t);
140 			break;
141 		case 'w':
142 			size = sizeof(uint16_t);
143 			break;
144 		case 'l':
145 			size = sizeof(uint32_t);
146 			break;
147 		case 'd':
148 			size = sizeof(uint64_t);
149 			break;
150 		case 'a':
151 			if (addr != 0 || symbol != NULL)
152 				errx(EXIT_FAILURE,
153 				    "only one address/symbol allowed");
154 			addr = strtoul(optarg, NULL, 0);
155 			break;
156 		case 's':
157 			if (addr != 0 || symbol != NULL)
158 				errx(EXIT_FAILURE,
159 				    "only one address/symbol allowed");
160 			symbol = optarg;
161 			break;
162 		case 'o':
163 			if (offset != 0)
164 				err(EXIT_FAILURE,
165 				    "only one offset allowed");
166 			offset = strtoul(optarg, NULL, 0);
167 			break;
168 		case 'r':
169 			replace = true;
170 			val = strtoull(optarg, NULL, 0);
171 			break;
172 		case 'v':
173 			verbose = true;
174 			break;
175 		case 'T':
176 			text_start = strtoul(optarg, NULL, 0);
177 			break;
178 		case '?':
179 		default:
180 			usage();
181 	}
182 	argc -= optind;
183 	argv += optind;
184 
185 	if (argc != 1)
186 		usage();
187 
188 	if (addr == 0 && symbol == NULL) {
189 		warnx("no address or symbol specified");
190 		usage();
191 	}
192 
193 	if (size == 0)
194 		size = sizeof(uint32_t);	/* default to int */
195 
196 	fname = argv[0];
197 
198 	if ((fd = open(fname, replace ? O_RDWR : O_RDONLY, 0))  == -1)
199 		err(EXIT_FAILURE, "open %s", fname);
200 
201 	if (symbol != NULL) {
202 		nl[0].n_name = symbol;
203 		nl[1].n_name = NULL;
204 		if ((rv = __fdnlist(fd, nl)) != 0)
205 			errx(EXIT_FAILURE, "could not find symbol %s in %s",
206 			    symbol, fname);
207 		addr = nl[0].n_value;
208 		if (verbose)
209 			fprintf(stderr, "got symbol address 0x%lx from %s\n",
210 			    addr, fname);
211 	}
212 
213 	addr += offset * size;
214 
215 	if (fstat(fd, &sb) == -1)
216 		err(EXIT_FAILURE, "fstat %s", fname);
217 	if (sb.st_size != (ssize_t)sb.st_size)
218 		errx(EXIT_FAILURE, "%s too big to map", fname);
219 
220 	if ((mappedfile = mmap(NULL, sb.st_size,
221 	    replace ? PROT_READ | PROT_WRITE : PROT_READ,
222 	    MAP_FILE | MAP_SHARED, fd, 0)) == (char *)-1)
223 		err(EXIT_FAILURE, "mmap %s", fname);
224 	if (verbose)
225 		fprintf(stderr, "mapped %s\n", fname);
226 
227 	n = __arraycount(exec_formats);
228 	for (i = 0; i < n; i++) {
229 		if ((*exec_formats[i].check)(mappedfile, sb.st_size) == 0)
230 			break;
231 	}
232 	if (i == n)
233 		errx(EXIT_FAILURE, "%s: unknown executable format", fname);
234 
235 	if (verbose) {
236 		fprintf(stderr, "%s is an %s binary\n", fname,
237 		    exec_formats[i].name);
238 		if (text_start != (u_long)~0)
239 			fprintf(stderr, "kernel text loads at 0x%lx\n",
240 			    text_start);
241 	}
242 
243 	if ((*exec_formats[i].findoff)(mappedfile, sb.st_size,
244 	    addr, &valoff, text_start) != 0)
245 		errx(EXIT_FAILURE, "couldn't find file offset for %s in %s",
246 		    symbol != NULL ? nl[0].n_name : "address" , fname);
247 
248 	valp = mappedfile + valoff;
249 
250 	if (symbol)
251 		printf("%s(0x%lx): ", symbol, addr);
252 	else
253 		printf("0x%lx: ", addr);
254 
255 	switch (size) {
256 	case sizeof(uint8_t):
257 		uval8 = *(uint8_t *)valp;
258 		sval8 = *(int8_t *)valp;
259 		printf("0x%02" PRIx8 " (%" PRIu8, uval8, uval8);
260 		if (sval8 < 0)
261 			printf("/%" PRId8, sval8);
262 		printf(")");
263 		break;
264 	case sizeof(uint16_t):
265 		uval16 = *(uint16_t *)valp;
266 		sval16 = *(int16_t *)valp;
267 		printf("0x%04" PRIx16 " (%" PRIu16, uval16, uval16);
268 		if (sval16 < 0)
269 			printf("/%" PRId16, sval16);
270 		printf(")");
271 		break;
272 	case sizeof(uint32_t):
273 		uval32 = *(uint32_t *)valp;
274 		sval32 = *(int32_t *)valp;
275 		printf("0x%08" PRIx32 " (%" PRIu32, uval32, uval32);
276 		if (sval32 < 0)
277 			printf("/%" PRId32, sval32);
278 		printf(")");
279 		break;
280 	case sizeof(uint64_t):
281 		uval64 = *(uint64_t *)valp;
282 		sval64 = *(int64_t *)valp;
283 		printf("0x%016" PRIx64 " (%" PRIu64, uval64, uval64);
284 		if (sval64 < 0)
285 			printf("/%" PRId64, sval64);
286 		printf(")");
287 		break;
288 	}
289 	printf(", at offset %#lx in %s\n", (unsigned long)valoff, fname);
290 
291 	if (!replace)
292 		goto done;
293 
294 	printf("new value: ");
295 
296 	switch (size) {
297 	case sizeof(uint8_t):
298 		uval8 = (uint8_t)val;
299 		sval8 = (int8_t)val;
300 		printf("0x%02" PRIx8 " (%" PRIu8, uval8, uval8);
301 		if (sval8 < 0)
302 			printf("/%" PRId8, sval8);
303 		printf(")");
304 		*(uint8_t *)valp = uval8;
305 		break;
306 	case sizeof(uint16_t):
307 		uval16 = (uint16_t)val;
308 		sval16 = (int16_t)val;
309 		printf("0x%04" PRIx16 " (%" PRIu16, uval16, uval16);
310 		if (sval16 < 0)
311 			printf("/%" PRId16, sval16);
312 		printf(")");
313 		*(uint16_t *)valp = uval16;
314 		break;
315 	case sizeof(uint32_t):
316 		uval32 = (uint32_t)val;
317 		sval32 = (int32_t)val;
318 		printf("0x%08" PRIx32 " (%" PRIu32, uval32, uval32);
319 		if (sval32 < 0)
320 			printf("/%" PRId32, sval32);
321 		printf(")");
322 		*(uint32_t *)valp = uval32;
323 		break;
324 	case sizeof(uint64_t):
325 		uval64 = (uint64_t)val;
326 		sval64 = (int64_t)val;
327 		printf("0x%016" PRIx64 " (%" PRIu64, uval64, uval64);
328 		if (sval64 < 0)
329 			printf("/%" PRId64, sval64);
330 		printf(")");
331 		*(uint64_t *)valp = uval64;
332 		break;
333 	}
334 	printf("\n");
335 
336  done:
337 	munmap(mappedfile, sb.st_size);
338 	close(fd);
339 
340 	if (verbose)
341 		fprintf(stderr, "exiting\n");
342 	exit(EXIT_SUCCESS);
343 }
344 
345 static void
usage(void)346 usage(void)
347 {
348 
349 	fprintf(stderr,
350 	    "Usage: %s [-b|-w|-l|-d] [-a address | -s symbol] [-o offset]"
351 	    " [-r value] [-T text_start] [-v] binary\n", getprogname());
352 	exit(EXIT_FAILURE);
353 }
354