Module Name: src Committed By: tsutsui Date: Thu Aug 20 15:14:49 UTC 2009
Modified Files: src/share/man/man8/man8.atari: binpatch.8 src/sys/arch/atari/stand/binpatch: Makefile binpatch.c Log Message: Rewrite binpatch(8) utility to add support for ELF binaries, using implementation of old src/usr.sbin/mdsetimage sources which supports misc executable formats without LGPL'ed libbfd. No particular comments on port-at...@. XXX1: amiga also has the similar utility in amiga/stand/binpatch but it has slightly different options. XXX2: Is it worth to put this utility into MI src/usr.sbin to patch rtc_offset etc. in GENERIC kernel binaries in distribution? To generate a diff of this commit: cvs rdiff -u -r1.5 -r1.6 src/share/man/man8/man8.atari/binpatch.8 cvs rdiff -u -r1.5 -r1.6 src/sys/arch/atari/stand/binpatch/Makefile \ src/sys/arch/atari/stand/binpatch/binpatch.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/share/man/man8/man8.atari/binpatch.8 diff -u src/share/man/man8/man8.atari/binpatch.8:1.5 src/share/man/man8/man8.atari/binpatch.8:1.6 --- src/share/man/man8/man8.atari/binpatch.8:1.5 Wed Dec 26 01:26:44 2001 +++ src/share/man/man8/man8.atari/binpatch.8 Thu Aug 20 15:14:49 2009 @@ -1,4 +1,4 @@ -.\" $NetBSD: binpatch.8,v 1.5 2001/12/26 01:26:44 wiz Exp $ +.\" $NetBSD: binpatch.8,v 1.6 2009/08/20 15:14:49 tsutsui Exp $ .\" .\" Copyright (c) 1994 Christian E. Hopps .\" All rights reserved. @@ -28,22 +28,24 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd February 2, 1994 +.Dd August 20, 2009 .Dt BINPATCH 8 atari .Os .Sh NAME .Nm binpatch -.Nd "examine and or modify initialized data in a binary file" +.Nd "examine and or modify initialized data in an executable binary" .Sh SYNOPSIS .Nm binpatch -.Op Fl b | Fl w | Fl l +.Op Fl b | Fl w | Fl l | Fl d .Op Fl o Ar offset +.Op Fl T Ar saddr .Fl s Ar symname .Op Fl r Ar value .Ar binfile .Nm binpatch -.Op Fl b | Fl w | Fl l +.Op Fl b | Fl w | Fl l | Fl d .Op Fl o Ar offset +.Op Fl T Ar saddr .Fl a Ar addr .Op Fl r Ar value .Ar binfile @@ -52,20 +54,39 @@ is used to modify or examine the data associated with a symbol in a binary file .Ar binfile . +.Pp The flags .Fl b , -.Fl w +.Fl w , +.Fl l , and +.Fl d +specify the size of the data to be modified or examined. +.Fl b +is for 8bit +.Pq Li int8_t , +.Fl w +is for 16bit +.Pq Li int16_t , .Fl l -specify the size of the data to be modified or examined -(byte, word and long respectively.) The +is for 32bit +.Pq Li int32_t , +and +.Fl d +is for 64bit +.Pq Li int64_t +variables. +.Pp +The .Ar binfile is scanned in search of the symbol .Ar symname (specified with the .Fl s flag.) -If the symbol is found the current data and address are printed. Next if the +If the symbol is found the current data and address are printed. +.Pp +Next if the .Fl r flag has been given, the current data is replaced with that of .Ar value . @@ -79,11 +100,17 @@ .Pp The .Fl o -flag specifies an offset in byte, word or long +flag specifies an offset in +.Li int8_t , +.Li int16_t , +.Li int32_t , +and +.Li int64_t .Fl ( b , .Fl w , +.Fl l , or -.Fl l ) +.Fl d ) units from the given locator .Fl ( s or @@ -91,3 +118,28 @@ for .Nm to perform its described actions. +This might be useful to patch a member of array or structure. +.Pp +The +.Fl T +flag is used to specify the starting address of a.out binary text segment. +Ignored for other binary executable formats. +.Sh SEE ALSO +.Xr gdb 1 , +.Xr mdsetimage 8 +.Sh BUGS +The +.Nm +command doesn't check if size of specified symbol is same with the +specified size by +.Fl b , +.Fl w , +.Fl l , +or +.Fl d +flag. +.Pp +The +.Nm +command doesn't check if specified address or symbol is a patchable variable +and it might corrupts the specified executable binary. Index: src/sys/arch/atari/stand/binpatch/Makefile diff -u src/sys/arch/atari/stand/binpatch/Makefile:1.5 src/sys/arch/atari/stand/binpatch/Makefile:1.6 --- src/sys/arch/atari/stand/binpatch/Makefile:1.5 Wed Dec 12 01:49:38 2001 +++ src/sys/arch/atari/stand/binpatch/Makefile Thu Aug 20 15:14:49 2009 @@ -1,9 +1,50 @@ -# $NetBSD: Makefile,v 1.5 2001/12/12 01:49:38 tv Exp $ +# $NetBSD: Makefile,v 1.6 2009/08/20 15:14:49 tsutsui Exp $ -PROG=binpatch -NOMAN= # defined +BINDIR?= /sbin +WARNS?= 4 -BINDIR=/sbin -LDFLAGS+=-static +PROG= binpatch +SRCS= binpatch.c +SRCS+= exec_aout.c exec_ecoff.c exec_elf32.c exec_elf64.c exec_coff.c + +#MAN= binpatch.8 # currently it's in src/share/man/man8/man8.atari +NOMAN= + +MDSETIMAGE=${NETBSDSRCDIR}/usr.sbin/mdsetimage +CPPFLAGS+= -I${MDSETIMAGE} +.PATH: ${MDSETIMAGE} + +.include <bsd.own.mk> # for ${MACHINE_CPU} + +.if ${MACHINE_ARCH} == "alpha" +CPPFLAGS+=-DNLIST_ECOFF +CPPFLAGS+=-DNLIST_ELF64 +.elif ${MACHINE_CPU} == "mips" +CPPFLAGS+=-DNLIST_ECOFF +CPPFLAGS+=-DNLIST_ELF32 +CPPFLAGS+=-DNLIST_AOUT +.elif ${MACHINE_ARCH} == "powerpc" +CPPFLAGS+=-DNLIST_ELF32 +.elif ${MACHINE_ARCH} == "m68k" || \ + ${MACHINE_ARCH} == "m68000" || \ + ${MACHINE_ARCH} == "vax" || \ + ${MACHINE_CPU} == "arm" +CPPFLAGS+=-DNLIST_ELF32 +CPPFLAGS+=-DNLIST_AOUT +.elif ${MACHINE_CPU} == "sh3" +CPPFLAGS+=-DNLIST_COFF +CPPFLAGS+=-DNLIST_ELF32 +.elif ${MACHINE_ARCH} == "sparc" || ${MACHINE_ARCH} == "sparc64" || \ + ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "x86_64" +CPPFLAGS+=-DNLIST_ELF64 +CPPFLAGS+=-DNLIST_ELF32 +CPPFLAGS+=-DNLIST_AOUT +.else +#CPPFLAGS+=-DNLIST_AOUT +#CPPFLAGS+=-DNLIST_ECOFF +CPPFLAGS+=-DNLIST_ELF32 +#CPPFLAGS+=-DNLIST_ELF64 +#CPPFLAGS+=-DNLIST_COFF +.endif .include <bsd.prog.mk> Index: src/sys/arch/atari/stand/binpatch/binpatch.c diff -u src/sys/arch/atari/stand/binpatch/binpatch.c:1.5 src/sys/arch/atari/stand/binpatch/binpatch.c:1.6 --- src/sys/arch/atari/stand/binpatch/binpatch.c:1.5 Sat Mar 14 21:04:07 2009 +++ src/sys/arch/atari/stand/binpatch/binpatch.c Thu Aug 20 15:14:49 2009 @@ -1,8 +1,7 @@ -/* $NetBSD: binpatch.c,v 1.5 2009/03/14 21:04:07 dsl Exp $ */ +/* $NetBSD: binpatch.c,v 1.6 2009/08/20 15:14:49 tsutsui Exp $ */ -/* - * Copyright (c) 1994 Christian E. Hopps - * All rights reserved. +/*- + * Copyright (c) 2009 Izumi Tsutsui. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,11 +11,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Christian E. Hopps. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -30,211 +24,352 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* + * Copyright (c) 1996 Christopher G. Demetriou + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>> + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1996\ + Christopher G. Demetriou. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +__RCSID("$NetBSD: binpatch.c,v 1.6 2009/08/20 15:14:49 tsutsui Exp $"); +#endif /* not lint */ + #include <sys/types.h> -#include <a.out.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/inttypes.h> + +#include <err.h> +#include <fcntl.h> +#include <limits.h> +#include <nlist.h> #include <stdio.h> #include <stdlib.h> +#include <stdbool.h> +#include <unistd.h> -extern char *optarg; -extern int optind; +#include "extern.h" -void error (char *) __attribute__((__noreturn__)); +int main(int, char *[]); +static void usage(void) __dead; -int test = 1; -int testbss; -char foo = 23; +bool replace, verbose; +u_long addr, offset; +char *symbol; +size_t size; +uint64_t val; + +#ifdef NLIST_AOUT +/* + * Since we can't get the text address from an a.out executable, we + * need to be able to specify it. Note: there's no way to test to + * see if the user entered a valid address! + */ +int T_flag_specified; /* the -T flag was specified */ +u_long text_start; /* Start of kernel text */ +#endif /* NLIST_AOUT */ + +static const struct { + const char *name; + int (*check)(const char *, size_t); + int (*findoff)(const char *, size_t, u_long, size_t *); +} exec_formats[] = { +#ifdef NLIST_AOUT + { "a.out", check_aout, findoff_aout, }, +#endif +#ifdef NLIST_ECOFF + { "ECOFF", check_ecoff, findoff_ecoff, }, +#endif +#ifdef NLIST_ELF32 + { "ELF32", check_elf32, findoff_elf32, }, +#endif +#ifdef NLIST_ELF64 + { "ELF64", check_elf64, findoff_elf64, }, +#endif +#ifdef NLIST_COFF + { "COFF", check_coff, findoff_coff, }, +#endif +}; int main(int argc, char *argv[]) { - struct exec e; - int c; - u_long addr = 0, offset = 0; - u_long replace = 0, do_replace = 0; - char *symbol = 0; - char size = 4; /* default to long */ - char *fname; - int fd; - int type, off; - u_long lval; - u_short sval; - u_char cval; - - - while ((c = getopt (argc, argv, "a:bwlr:s:o:")) != -1) - switch (c) - { - case 'a': - if (addr || symbol) - error ("only one address/symbol allowed"); - if (! strncmp (optarg, "0x", 2)) - sscanf (optarg, "%x", &addr); - else - addr = atoi (optarg); - if (! addr) - error ("invalid address"); - break; - - case 'b': - size = 1; - break; - - case 'w': - size = 2; - break; - - case 'l': - size = 4; - break; - - case 'r': - do_replace = 1; - if (! strncmp (optarg, "0x", 2)) - sscanf (optarg, "%x", &replace); - else - replace = atoi (optarg); - break; + const char *fname; + struct stat sb; + struct nlist nl[2]; + char *mappedfile; + size_t valoff; + void *valp; + uint8_t uval8; + int8_t sval8; + uint16_t uval16; + int16_t sval16; + uint32_t uval32; + int32_t sval32; + uint64_t uval64; + int64_t sval64; + int ch, fd, rv, i, n; + + setprogname(argv[0]); + + while ((ch = getopt(argc, argv, "bwldT:a:s:o:r:v")) != -1) + switch (ch) { + case 'b': + size = sizeof(uint8_t); + break; + case 'w': + size = sizeof(uint16_t); + break; + case 'l': + size = sizeof(uint32_t); + break; + case 'd': + size = sizeof(uint64_t); + break; + case 'a': + if (addr != 0 || symbol != NULL) + errx(EXIT_FAILURE, + "only one address/symbol allowed"); + addr = strtoul(optarg, NULL, 0); + break; + case 's': + if (addr != 0 || symbol != NULL) + errx(EXIT_FAILURE, + "only one address/symbol allowed"); + symbol = optarg; + break; + case 'o': + if (offset != 0) + err(EXIT_FAILURE, + "only one offset allowed"); + offset = strtoul(optarg, NULL, 0); + break; + case 'r': + replace = true; + val = strtoull(optarg, NULL, 0); + break; + case 'v': + verbose = true; + break; + case 'T': +#ifdef NLIST_AOUT + T_flag_specified = 1; + text_start = strtoul(optarg, NULL, 0); + break; +#else + fprintf(stderr, "%s: unknown option -- %c\n", + getprogname(), (char)ch); + /*FALLTHROUGH*/ +#endif /* NLIST_AOUT */ + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 1) + usage(); + + if (addr == 0 && symbol == NULL) { + warnx("no address or symbol specified"); + usage(); + } + + if (size == 0) + size = sizeof(uint32_t); /* default to int */ + + fname = argv[0]; + + if ((fd = open(fname, replace ? O_RDWR : O_RDONLY, 0)) == -1) + err(EXIT_FAILURE, "open %s", fname); + + if (symbol != NULL) { + nl[0].n_name = symbol; + nl[1].n_name = NULL; + if ((rv = __fdnlist(fd, nl)) != 0) + errx(EXIT_FAILURE, "could not find symbol %s in %s", + symbol, fname); + addr = nl[0].n_value; + if (verbose) + fprintf(stderr, "got symbol address 0x%lx from %s\n", + addr, fname); + } - case 's': - if (addr || symbol) - error ("only one address/symbol allowed"); - symbol = optarg; - break; - - case 'o': - if (offset) - error ("only one offset allowed"); - if (! strncmp (optarg, "0x", 2)) - sscanf (optarg, "%x", &offset); + addr += offset * size; + + if (fstat(fd, &sb) == -1) + err(EXIT_FAILURE, "fstat %s", fname); + if (sb.st_size != (ssize_t)sb.st_size) + errx(EXIT_FAILURE, "%s too big to map", fname); + + if ((mappedfile = mmap(NULL, sb.st_size, + replace ? PROT_READ | PROT_WRITE : PROT_READ, + MAP_FILE | MAP_SHARED, fd, 0)) == (char *)-1) + err(EXIT_FAILURE, "mmap %s", fname); + if (verbose) + fprintf(stderr, "mapped %s\n", fname); + + n = __arraycount(exec_formats); + for (i = 0; i < n; i++) { + if ((*exec_formats[i].check)(mappedfile, sb.st_size) == 0) + break; + } + if (i == n) + errx(EXIT_FAILURE, "%s: unknown executable format", fname); + + if (verbose) { + fprintf(stderr, "%s is an %s binary\n", fname, + exec_formats[i].name); +#ifdef NLIST_AOUT + if (T_flag_specified) + fprintf(stderr, "kernel text loads at 0x%lx\n", + text_start); +#endif + } + + if ((*exec_formats[i].findoff)(mappedfile, sb.st_size, + addr, &valoff) != 0) + errx(EXIT_FAILURE, "couldn't find file offset for %s in %s", + symbol != NULL ? nl[0].n_name : "address" , fname); + + valp = mappedfile + valoff; + + if (symbol) + printf("%s(0x%lx): ", symbol, addr); else - offset = atoi (optarg); - break; - } - - argv += optind; - argc -= optind; - - - if (argc < 1) - error ("No file to patch."); - - fname = argv[0]; - if ((fd = open (fname, 0)) < 0) - error ("Can't open file"); - - if (read (fd, &e, sizeof (e)) != sizeof (e) - || N_BADMAG (e)) - error ("Not a valid executable."); - - /* fake mid, so the N_ macros work on the amiga.. */ - e.a_midmag |= 127 << 16; - - if (symbol) - { - struct nlist nl[2]; - nl[0].n_un.n_name = symbol; - nl[1].n_un.n_name = 0; - if (nlist (fname, nl) != 0) - error ("Symbol not found."); - addr = nl[0].n_value; - type = nl[0].n_type & N_TYPE; - } - else - { - type = N_UNDF; - if (addr >= N_TXTADDR(e) && addr < N_DATADDR(e)) - type = N_TEXT; - else if (addr >= N_DATADDR(e) && addr < N_DATADDR(e) + e.a_data) - type = N_DATA; - } - addr += offset; - - /* if replace-mode, have to reopen the file for writing. - Can't do that from the beginning, or nlist() will not - work (at least not under AmigaDOS) */ - if (do_replace) - { - close (fd); - if ((fd = open (fname, 2)) == -1) - error ("Can't reopen file for writing."); - } - - if (type != N_TEXT && type != N_DATA) - error ("address/symbol is not in text or data section."); - - if (type == N_TEXT) - off = addr - N_TXTADDR(e) + N_TXTOFF(e); - else - off = addr - N_DATADDR(e) + N_DATOFF(e); - - if (lseek (fd, off, 0) == -1) - error ("lseek"); - - /* not beautiful, but works on big and little endian machines */ - switch (size) - { - case 1: - if (read (fd, &cval, 1) != 1) - error ("cread"); - lval = cval; - break; - - case 2: - if (read (fd, &sval, 2) != 2) - error ("sread"); - lval = sval; - break; - - case 4: - if (read (fd, &lval, 4) != 4) - error ("lread"); - break; - } - - - if (symbol) - printf ("%s(0x%x): %d (0x%x)\n", symbol, addr, lval, lval); - else - printf ("0x%x: %d (0x%x)\n", addr, lval, lval); - - if (do_replace) - { - if (lseek (fd, off, 0) == -1) - error ("write-lseek"); - switch (size) - { - case 1: - cval = replace; - if (cval != replace) - error ("byte-value overflow."); - if (write (fd, &cval, 1) != 1) - error ("cwrite"); - break; - - case 2: - sval = replace; - if (sval != replace) - error ("word-value overflow."); - if (write (fd, &sval, 2) != 2) - error ("swrite"); - break; - - case 4: - if (write (fd, &replace, 4) != 4) - error ("lwrite"); - break; + printf("0x%lx: ", addr); + + switch (size) { + case sizeof(uint8_t): + uval8 = *(uint8_t *)valp; + sval8 = *(int8_t *)valp; + printf("0x%02" PRIx8 " (%" PRIu8, uval8, uval8); + if (sval8 < 0) + printf("/%" PRId8, sval8); + printf(")"); + break; + case sizeof(uint16_t): + uval16 = *(uint16_t *)valp; + sval16 = *(int16_t *)valp; + printf("0x%04" PRIx16 " (%" PRIu16, uval16, uval16); + if (sval16 < 0) + printf("/%" PRId16, sval16); + printf(")"); + break; + case sizeof(uint32_t): + uval32 = *(uint32_t *)valp; + sval32 = *(int32_t *)valp; + printf("0x%08" PRIx32 " (%" PRIu32, uval32, uval32); + if (sval32 < 0) + printf("/%" PRId32, sval32); + printf(")"); + break; + case sizeof(uint64_t): + uval64 = *(uint64_t *)valp; + sval64 = *(int64_t *)valp; + printf("0x%016" PRIx64 " (%" PRIu64, uval64, uval64); + if (sval64 < 0) + printf("/%" PRId64, sval64); + printf(")"); + break; } - } + printf(", at offset %#lx in %s\n", (unsigned long)valoff, fname); - close (fd); -} + if (!replace) + goto done; + printf("new value: "); + switch (size) { + case sizeof(uint8_t): + uval8 = (uint8_t)val; + sval8 = (int8_t)val; + printf("0x%02" PRIx8 " (%" PRIu8, uval8, uval8); + if (sval8 < 0) + printf("/%" PRId8, sval8); + printf(")"); + *(uint8_t *)valp = uval8; + break; + case sizeof(uint16_t): + uval16 = (uint16_t)val; + sval16 = (int16_t)val; + printf("0x%04" PRIx16 " (%" PRIu16, uval16, uval16); + if (sval16 < 0) + printf("/%" PRId16, sval16); + printf(")"); + *(uint16_t *)valp = uval16; + break; + case sizeof(uint32_t): + uval32 = (uint32_t)val; + sval32 = (int32_t)val; + printf("0x%08" PRIx32 " (%" PRIu32, uval32, uval32); + if (sval32 < 0) + printf("/%" PRId32, sval32); + printf(")"); + *(uint32_t *)valp = uval32; + break; + case sizeof(uint64_t): + uval64 = (uint64_t)val; + sval64 = (int64_t)val; + printf("0x%016" PRIx64 " (%" PRIu64, uval64, uval64); + if (sval64 < 0) + printf("/%" PRId64, sval64); + printf(")"); + *(uint64_t *)valp = uval64; + break; + } + printf("\n"); + + done: + munmap(mappedfile, sb.st_size); + close(fd); + + if (verbose) + fprintf(stderr, "exiting\n"); + exit(EXIT_SUCCESS); +} -void error (str) - char *str; +static void +usage(void) { - fprintf (stderr, "%s\n", str); - exit (1); + + fprintf(stderr, + "usage: %s [-b|-w|-l|-d] [-a address | -s symbol] [-o offset]\n" + " [-r value] " +#ifdef NLIST_AOUT + "[-T text_start] " +#endif + "[-v] binary\n", getprogname()); + exit(EXIT_FAILURE); }