Index: share/man/man8/man8.atari/binpatch.8 =================================================================== RCS file: /cvsroot/src/share/man/man8/man8.atari/binpatch.8,v retrieving revision 1.5 diff -u -r1.5 binpatch.8 --- share/man/man8/man8.atari/binpatch.8 26 Dec 2001 01:26:44 -0000 1.5 +++ share/man/man8/man8.atari/binpatch.8 21 Aug 2009 14:02:06 -0000 @@ -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 the same as 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 corrupt the specified executable binary. Index: usr.sbin/mdsetimage/exec_aout.c =================================================================== RCS file: /cvsroot/src/usr.sbin/mdsetimage/exec_aout.c,v retrieving revision 1.6 diff -u -r1.6 exec_aout.c --- usr.sbin/mdsetimage/exec_aout.c 1 Oct 2001 23:32:34 -0000 1.6 +++ usr.sbin/mdsetimage/exec_aout.c 21 Aug 2009 14:02:06 -0000 @@ -53,14 +53,14 @@ const char *mappedfile; size_t mappedsize; { - struct exec *execp; + const struct exec *execp; int rv; rv = 0; if (check(0, sizeof *execp)) BAD; - execp = (struct exec *)&mappedfile[0]; + execp = (const struct exec *)&mappedfile[0]; if (N_BADMAG(*execp)) BAD; @@ -75,11 +75,11 @@ size_t mappedsize, *fileoffp; u_long vmaddr; { - struct exec *execp; + const struct exec *execp; int rv; rv = 0; - execp = (struct exec *)&mappedfile[0]; + execp = (const struct exec *)&mappedfile[0]; if (N_TXTADDR(*execp) + (execp->a_entry & (N_PAGSIZ(*execp)-1)) != execp->a_entry) Index: usr.sbin/mdsetimage/exec_coff.c =================================================================== RCS file: /cvsroot/src/usr.sbin/mdsetimage/exec_coff.c,v retrieving revision 1.5 diff -u -r1.5 exec_coff.c --- usr.sbin/mdsetimage/exec_coff.c 1 Oct 2001 23:32:34 -0000 1.5 +++ usr.sbin/mdsetimage/exec_coff.c 21 Aug 2009 14:02:06 -0000 @@ -53,14 +53,14 @@ const char *mappedfile; size_t mappedsize; { - struct coff_exechdr *exechdrp; + const struct coff_exechdr *exechdrp; int rv; rv = 0; if (check(0, sizeof *exechdrp)) BAD; - exechdrp = (struct coff_exechdr *)&mappedfile[0]; + exechdrp = (const struct coff_exechdr *)&mappedfile[0]; if (COFF_BADMAG(&(exechdrp->f))) BAD; @@ -75,11 +75,11 @@ size_t mappedsize, *fileoffp; u_long vmaddr; { - struct coff_exechdr *exechdrp; + const struct coff_exechdr *exechdrp; int rv; rv = 0; - exechdrp = (struct coff_exechdr *)&mappedfile[0]; + exechdrp = (const struct coff_exechdr *)&mappedfile[0]; #define COFF_TXTOFF_XXX(fp, ap) \ (COFF_ROUND(COFF_HDR_SIZE + (fp)->f_nscns * \ @@ -89,12 +89,12 @@ #define COFF_DATOFF_XXX(fp, ap) \ (COFF_TXTOFF_XXX(fp, ap) + (ap)->a_tsize) - if (exechdrp->a.a_tstart <= vmaddr && - vmaddr < (exechdrp->a.a_tstart + exechdrp->a.a_tsize)) + if ((u_long)exechdrp->a.a_tstart <= vmaddr && + vmaddr < (u_long)(exechdrp->a.a_tstart + exechdrp->a.a_tsize)) *fileoffp = vmaddr - exechdrp->a.a_tstart + COFF_TXTOFF(&exechdrp->f, &(exechdrp->a)); - else if (exechdrp->a.a_dstart <= vmaddr && - vmaddr < (exechdrp->a.a_dstart + exechdrp->a.a_dsize)) + else if ((u_long)exechdrp->a.a_dstart <= vmaddr && + vmaddr < (u_long)(exechdrp->a.a_dstart + exechdrp->a.a_dsize)) *fileoffp = vmaddr - exechdrp->a.a_dstart + COFF_DATOFF_XXX(&exechdrp->f, &(exechdrp->a)); else Index: usr.sbin/mdsetimage/exec_ecoff.c =================================================================== RCS file: /cvsroot/src/usr.sbin/mdsetimage/exec_ecoff.c,v retrieving revision 1.5 diff -u -r1.5 exec_ecoff.c --- usr.sbin/mdsetimage/exec_ecoff.c 1 Oct 2001 23:32:34 -0000 1.5 +++ usr.sbin/mdsetimage/exec_ecoff.c 21 Aug 2009 14:02:06 -0000 @@ -50,14 +50,14 @@ const char *mappedfile; size_t mappedsize; { - struct ecoff_exechdr *exechdrp; + const struct ecoff_exechdr *exechdrp; int rv; rv = 0; if (check(0, sizeof *exechdrp)) BAD; - exechdrp = (struct ecoff_exechdr *)&mappedfile[0]; + exechdrp = (const struct ecoff_exechdr *)&mappedfile[0]; if (ECOFF_BADMAG(exechdrp)) BAD; @@ -72,11 +72,11 @@ size_t mappedsize, *fileoffp; u_long vmaddr; { - struct ecoff_exechdr *exechdrp; + const struct ecoff_exechdr *exechdrp; int rv; rv = 0; - exechdrp = (struct ecoff_exechdr *)&mappedfile[0]; + exechdrp = (const struct ecoff_exechdr *)&mappedfile[0]; if (exechdrp->a.text_start <= vmaddr && vmaddr < (exechdrp->a.text_start + exechdrp->a.tsize)) Index: usr.sbin/mdsetimage/exec_elf32.c =================================================================== RCS file: /cvsroot/src/usr.sbin/mdsetimage/exec_elf32.c,v retrieving revision 1.9 diff -u -r1.9 exec_elf32.c --- usr.sbin/mdsetimage/exec_elf32.c 1 Oct 2001 23:32:34 -0000 1.9 +++ usr.sbin/mdsetimage/exec_elf32.c 21 Aug 2009 14:02:06 -0000 @@ -58,14 +58,14 @@ const char *mappedfile; size_t mappedsize; { - Elf_Ehdr *ehdrp; + const Elf_Ehdr *ehdrp; int rv; rv = 0; if (check(0, sizeof *ehdrp)) BAD; - ehdrp = (Elf_Ehdr *)&mappedfile[0]; + ehdrp = (const Elf_Ehdr *)&mappedfile[0]; if (memcmp(ehdrp->e_ident, ELFMAG, SELFMAG) != 0 || ehdrp->e_ident[EI_CLASS] != ELFCLASS) @@ -88,38 +88,41 @@ size_t mappedsize, *fileoffp; u_long vmaddr; { - Elf_Ehdr *ehdrp; - Elf_Shdr *shdrp; - Elf_Off shdr_off; - Elf_Word shdr_size; + const Elf_Ehdr *ehdrp; + const Elf_Phdr *phdrp; + Elf_Off phdr_off; + Elf_Word phdr_size; #if (ELFSIZE == 32) - Elf32_Half nshdr, i; + Elf32_Half nphdr, i; #elif (ELFSIZE == 64) - Elf64_Half nshdr, i; + Elf64_Half nphdr, i; #endif int rv; rv = 0; - ehdrp = (Elf_Ehdr *)&mappedfile[0]; - nshdr = ehdrp->e_shnum; - shdr_off = ehdrp->e_shoff; - shdr_size = ehdrp->e_shentsize * nshdr; + ehdrp = (const Elf_Ehdr *)&mappedfile[0]; + nphdr = ehdrp->e_phnum; + phdr_off = ehdrp->e_phoff; + phdr_size = sizeof(Elf_Phdr) * nphdr; - if (check(shdr_off, shdr_size) || - (sizeof *shdrp != ehdrp->e_shentsize)) + if (check(0, phdr_off + phdr_size)) BAD; - shdrp = (Elf_Shdr *)&mappedfile[shdr_off]; + phdrp = (const Elf_Phdr *)&mappedfile[phdr_off]; - for (i = 0; i < nshdr; i++) { - if (shdrp[i].sh_addr <= vmaddr && - vmaddr < (shdrp[i].sh_addr + shdrp[i].sh_size)) { +#define IS_TEXT(p) (p.p_flags & PF_X) +#define IS_DATA(p) (p.p_flags & PF_W) + + for (i = 0; i < nphdr; i++) { + if ((IS_TEXT(phdrp[i]) || IS_DATA(phdrp[i])) && + phdrp[i].p_vaddr <= vmaddr && + vmaddr < phdrp[i].p_vaddr + phdrp[i].p_filesz) { *fileoffp = vmaddr - - shdrp[i].sh_addr + shdrp[i].sh_offset; + phdrp[i].p_vaddr + phdrp[i].p_offset; break; } } - if (i == nshdr) + if (i == nphdr) BAD; out: Index: usr.sbin/mdsetimage/mdsetimage.c =================================================================== RCS file: /cvsroot/src/usr.sbin/mdsetimage/mdsetimage.c,v retrieving revision 1.16 diff -u -r1.16 mdsetimage.c --- usr.sbin/mdsetimage/mdsetimage.c 1 Oct 2001 23:32:34 -0000 1.16 +++ usr.sbin/mdsetimage/mdsetimage.c 21 Aug 2009 14:02:06 -0000 @@ -61,10 +61,10 @@ static struct nlist md_root_nlist[] = { #define X_MD_ROOT_IMAGE 0 - { "_md_root_image" }, + { "_md_root_image", 0, 0, 0, 0 }, #define X_MD_ROOT_SIZE 1 - { "_md_root_size" }, - { NULL } + { "_md_root_size", 0, 0, 0, 0 }, + { NULL, 0, 0, 0, 0 } }; int verbose; @@ -246,7 +246,7 @@ fprintf(stderr, "%s is at offset %#lx in %s\n", nl[X_MD_ROOT_SIZE].n_name, (unsigned long)rootsizeoff, fname); - *rootsizep = *(u_int32_t *)&mappedfile[rootsizeoff]; + *rootsizep = *(const u_int32_t *)&mappedfile[rootsizeoff]; if (verbose) fprintf(stderr, "%s has value %#x\n", nl[X_MD_ROOT_SIZE].n_name, *rootsizep); Index: sys/arch/atari/stand/binpatch/Makefile =================================================================== RCS file: /cvsroot/src/sys/arch/atari/stand/binpatch/Makefile,v retrieving revision 1.5 diff -u -r1.5 Makefile --- sys/arch/atari/stand/binpatch/Makefile 12 Dec 2001 01:49:38 -0000 1.5 +++ sys/arch/atari/stand/binpatch/Makefile 21 Aug 2009 14:02:06 -0000 @@ -1,9 +1,50 @@ # $NetBSD: Makefile,v 1.5 2001/12/12 01:49:38 tv 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 # 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 Index: sys/arch/atari/stand/binpatch/binpatch.c =================================================================== RCS file: /cvsroot/src/sys/arch/atari/stand/binpatch/binpatch.c,v retrieving revision 1.4 diff -u -r1.4 binpatch.c --- sys/arch/atari/stand/binpatch/binpatch.c 4 Aug 2006 01:48:02 -0000 1.4 +++ sys/arch/atari/stand/binpatch/binpatch.c 21 Aug 2009 14:02:06 -0000 @@ -1,8 +1,7 @@ /* $NetBSD: binpatch.c,v 1.4 2006/08/04 01:48:02 mhitch 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,19 +24,101 @@ * 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. + * + * <> + */ + +#include +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1996\ + Christopher G. Demetriou. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +__RCSID("$NetBSD$"); +#endif /* not lint */ + #include -#include +#include +#include +#include + +#include +#include +#include +#include #include #include +#include +#include -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 @@ -50,193 +126,252 @@ 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); }