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