1 /* $NetBSD: binpatch.c,v 1.2 1997/11/01 06:49:20 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Christian E. Hopps 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Christian E. Hopps. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <a.out.h> 35 #include <stdio.h> 36 37 extern char *optarg; 38 extern int optind; 39 40 volatile void error (); 41 42 int test = 1; 43 int testbss; 44 char foo = 23; 45 46 47 int 48 main(argc, argv) 49 int argc; 50 char *argv[]; 51 { 52 struct exec e; 53 int c; 54 u_long addr = 0, offset = 0; 55 u_long replace = 0, do_replace = 0; 56 char *symbol = 0; 57 char size = 4; /* default to long */ 58 char *fname; 59 int fd; 60 int type, off; 61 u_long lval; 62 u_short sval; 63 u_char cval; 64 65 66 while ((c = getopt (argc, argv, "a:bwlr:s:o:")) != -1) 67 switch (c) 68 { 69 case 'a': 70 if (addr || symbol) 71 error ("only one address/symbol allowed"); 72 if (! strncmp (optarg, "0x", 2)) 73 sscanf (optarg, "%x", &addr); 74 else 75 addr = atoi (optarg); 76 if (! addr) 77 error ("invalid address"); 78 break; 79 80 case 'b': 81 size = 1; 82 break; 83 84 case 'w': 85 size = 2; 86 break; 87 88 case 'l': 89 size = 4; 90 break; 91 92 case 'r': 93 do_replace = 1; 94 if (! strncmp (optarg, "0x", 2)) 95 sscanf (optarg, "%x", &replace); 96 else 97 replace = atoi (optarg); 98 break; 99 100 case 's': 101 if (addr || symbol) 102 error ("only one address/symbol allowed"); 103 symbol = optarg; 104 break; 105 106 case 'o': 107 if (offset) 108 error ("only one offset allowed"); 109 if (! strncmp (optarg, "0x", 2)) 110 sscanf (optarg, "%x", &offset); 111 else 112 offset = atoi (optarg); 113 break; 114 } 115 116 argv += optind; 117 argc -= optind; 118 119 120 if (argc < 1) 121 error ("No file to patch."); 122 123 fname = argv[0]; 124 if ((fd = open (fname, 0)) < 0) 125 error ("Can't open file"); 126 127 if (read (fd, &e, sizeof (e)) != sizeof (e) 128 || N_BADMAG (e)) 129 error ("Not a valid executable."); 130 131 /* fake mid, so the N_ macros work on the amiga.. */ 132 e.a_midmag |= 127 << 16; 133 134 if (symbol) 135 { 136 struct nlist nl[2]; 137 nl[0].n_un.n_name = symbol; 138 nl[1].n_un.n_name = 0; 139 if (nlist (fname, nl) != 0) 140 error ("Symbol not found."); 141 addr = nl[0].n_value; 142 type = nl[0].n_type & N_TYPE; 143 } 144 else 145 { 146 type = N_UNDF; 147 if (addr >= N_TXTADDR(e) && addr < N_DATADDR(e)) 148 type = N_TEXT; 149 else if (addr >= N_DATADDR(e) && addr < N_DATADDR(e) + e.a_data) 150 type = N_DATA; 151 } 152 addr += offset; 153 154 /* if replace-mode, have to reopen the file for writing. 155 Can't do that from the beginning, or nlist() will not 156 work (at least not under AmigaDOS) */ 157 if (do_replace) 158 { 159 close (fd); 160 if ((fd = open (fname, 2)) == -1) 161 error ("Can't reopen file for writing."); 162 } 163 164 if (type != N_TEXT && type != N_DATA) 165 error ("address/symbol is not in text or data section."); 166 167 if (type == N_TEXT) 168 off = addr - N_TXTADDR(e) + N_TXTOFF(e); 169 else 170 off = addr - N_DATADDR(e) + N_DATOFF(e); 171 172 if (lseek (fd, off, 0) == -1) 173 error ("lseek"); 174 175 /* not beautiful, but works on big and little endian machines */ 176 switch (size) 177 { 178 case 1: 179 if (read (fd, &cval, 1) != 1) 180 error ("cread"); 181 lval = cval; 182 break; 183 184 case 2: 185 if (read (fd, &sval, 2) != 2) 186 error ("sread"); 187 lval = sval; 188 break; 189 190 case 4: 191 if (read (fd, &lval, 4) != 4) 192 error ("lread"); 193 break; 194 } 195 196 197 if (symbol) 198 printf ("%s(0x%x): %d (0x%x)\n", symbol, addr, lval, lval); 199 else 200 printf ("0x%x: %d (0x%x)\n", addr, lval, lval); 201 202 if (do_replace) 203 { 204 if (lseek (fd, off, 0) == -1) 205 error ("write-lseek"); 206 switch (size) 207 { 208 case 1: 209 cval = replace; 210 if (cval != replace) 211 error ("byte-value overflow."); 212 if (write (fd, &cval, 1) != 1) 213 error ("cwrite"); 214 break; 215 216 case 2: 217 sval = replace; 218 if (sval != replace) 219 error ("word-value overflow."); 220 if (write (fd, &sval, 2) != 2) 221 error ("swrite"); 222 break; 223 224 case 4: 225 if (write (fd, &replace, 4) != 4) 226 error ("lwrite"); 227 break; 228 } 229 } 230 231 close (fd); 232 } 233 234 235 236 volatile void error (str) 237 char *str; 238 { 239 fprintf (stderr, "%s\n", str); 240 exit (1); 241 } 242