1/* $NetBSD$ */ 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$"); 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 82int main(int, char *[]); 83static void usage(void) __dead; 84 85bool replace, verbose; 86u_long addr, offset; 87char *symbol; 88size_t size; 89uint64_t val; 90 91#ifdef NLIST_AOUT 92/* 93 * Since we can't get the text address from an a.out executable, we 94 * need to be able to specify it. Note: there's no way to test to 95 * see if the user entered a valid address! 96 */ 97int T_flag_specified; /* the -T flag was specified */ 98u_long text_start; /* Start of kernel text */ 99#endif /* NLIST_AOUT */ 100 101static const struct { 102 const char *name; 103 int (*check)(const char *, size_t); 104 int (*findoff)(const char *, size_t, u_long, size_t *); 105} exec_formats[] = { 106#ifdef NLIST_AOUT 107 { "a.out", check_aout, findoff_aout, }, 108#endif 109#ifdef NLIST_ECOFF 110 { "ECOFF", check_ecoff, findoff_ecoff, }, 111#endif 112#ifdef NLIST_ELF32 113 { "ELF32", check_elf32, findoff_elf32, }, 114#endif 115#ifdef NLIST_ELF64 116 { "ELF64", check_elf64, findoff_elf64, }, 117#endif 118#ifdef NLIST_COFF 119 { "COFF", check_coff, findoff_coff, }, 120#endif 121}; 122 123 124int 125main(int argc, char *argv[]) 126{ 127 const char *fname; 128 struct stat sb; 129 struct nlist nl[2]; 130 char *mappedfile; 131 size_t valoff; 132 void *valp; 133 uint8_t uval8; 134 int8_t sval8; 135 uint16_t uval16; 136 int16_t sval16; 137 uint32_t uval32; 138 int32_t sval32; 139 uint64_t uval64; 140 int64_t sval64; 141 int ch, fd, rv, i, n; 142 143 setprogname(argv[0]); 144 145 while ((ch = getopt(argc, argv, "bwldT:a:s:o:r:v")) != -1) 146 switch (ch) { 147 case 'b': 148 size = sizeof(uint8_t); 149 break; 150 case 'w': 151 size = sizeof(uint16_t); 152 break; 153 case 'l': 154 size = sizeof(uint32_t); 155 break; 156 case 'd': 157 size = sizeof(uint64_t); 158 break; 159 case 'a': 160 if (addr != 0 || symbol != NULL) 161 errx(EXIT_FAILURE, 162 "only one address/symbol allowed"); 163 addr = strtoul(optarg, NULL, 0); 164 break; 165 case 's': 166 if (addr != 0 || symbol != NULL) 167 errx(EXIT_FAILURE, 168 "only one address/symbol allowed"); 169 symbol = optarg; 170 break; 171 case 'o': 172 if (offset != 0) 173 err(EXIT_FAILURE, 174 "only one offset allowed"); 175 offset = strtoul(optarg, NULL, 0); 176 break; 177 case 'r': 178 replace = true; 179 val = strtoull(optarg, NULL, 0); 180 break; 181 case 'v': 182 verbose = true; 183 break; 184 case 'T': 185#ifdef NLIST_AOUT 186 T_flag_specified = 1; 187 text_start = strtoul(optarg, NULL, 0); 188 break; 189#else 190 fprintf(stderr, "%s: unknown option -- %c\n", 191 getprogname(), (char)ch); 192 /*FALLTHROUGH*/ 193#endif /* NLIST_AOUT */ 194 case '?': 195 default: 196 usage(); 197 } 198 argc -= optind; 199 argv += optind; 200 201 if (argc != 1) 202 usage(); 203 204 if (addr == 0 && symbol == NULL) { 205 warnx("no address or symbol specified"); 206 usage(); 207 } 208 209 if (size == 0) 210 size = sizeof(uint32_t); /* default to int */ 211 212 fname = argv[0]; 213 214 if ((fd = open(fname, replace ? O_RDWR : O_RDONLY, 0)) == -1) 215 err(EXIT_FAILURE, "open %s", fname); 216 217 if (symbol != NULL) { 218 nl[0].n_name = symbol; 219 nl[1].n_name = NULL; 220 if ((rv = __fdnlist(fd, nl)) != 0) 221 errx(EXIT_FAILURE, "could not find symbol %s in %s", 222 symbol, fname); 223 addr = nl[0].n_value; 224 if (verbose) 225 fprintf(stderr, "got symbol address 0x%lx from %s\n", 226 addr, fname); 227 } 228 229 addr += offset * size; 230 231 if (fstat(fd, &sb) == -1) 232 err(EXIT_FAILURE, "fstat %s", fname); 233 if (sb.st_size != (ssize_t)sb.st_size) 234 errx(EXIT_FAILURE, "%s too big to map", fname); 235 236 if ((mappedfile = mmap(NULL, sb.st_size, 237 replace ? PROT_READ | PROT_WRITE : PROT_READ, 238 MAP_FILE | MAP_SHARED, fd, 0)) == (char *)-1) 239 err(EXIT_FAILURE, "mmap %s", fname); 240 if (verbose) 241 fprintf(stderr, "mapped %s\n", fname); 242 243 n = __arraycount(exec_formats); 244 for (i = 0; i < n; i++) { 245 if ((*exec_formats[i].check)(mappedfile, sb.st_size) == 0) 246 break; 247 } 248 if (i == n) 249 errx(EXIT_FAILURE, "%s: unknown executable format", fname); 250 251 if (verbose) { 252 fprintf(stderr, "%s is an %s binary\n", fname, 253 exec_formats[i].name); 254#ifdef NLIST_AOUT 255 if (T_flag_specified) 256 fprintf(stderr, "kernel text loads at 0x%lx\n", 257 text_start); 258#endif 259 } 260 261 if ((*exec_formats[i].findoff)(mappedfile, sb.st_size, 262 addr, &valoff) != 0) 263 errx(EXIT_FAILURE, "couldn't find file offset for %s in %s", 264 symbol != NULL ? nl[0].n_name : "address" , fname); 265 266 valp = mappedfile + valoff; 267 268 if (symbol) 269 printf("%s(0x%lx): ", symbol, addr); 270 else 271 printf("0x%lx: ", addr); 272 273 switch (size) { 274 case sizeof(uint8_t): 275 uval8 = *(uint8_t *)valp; 276 sval8 = *(int8_t *)valp; 277 printf("0x%02" PRIx8 " (%" PRIu8, uval8, uval8); 278 if (sval8 < 0) 279 printf("/%" PRId8, sval8); 280 printf(")"); 281 break; 282 case sizeof(uint16_t): 283 uval16 = *(uint16_t *)valp; 284 sval16 = *(int16_t *)valp; 285 printf("0x%04" PRIx16 " (%" PRIu16, uval16, uval16); 286 if (sval16 < 0) 287 printf("/%" PRId16, sval16); 288 printf(")"); 289 break; 290 case sizeof(uint32_t): 291 uval32 = *(uint32_t *)valp; 292 sval32 = *(int32_t *)valp; 293 printf("0x%08" PRIx32 " (%" PRIu32, uval32, uval32); 294 if (sval32 < 0) 295 printf("/%" PRId32, sval32); 296 printf(")"); 297 break; 298 case sizeof(uint64_t): 299 uval64 = *(uint64_t *)valp; 300 sval64 = *(int64_t *)valp; 301 printf("0x%016" PRIx64 " (%" PRIu64, uval64, uval64); 302 if (sval64 < 0) 303 printf("/%" PRId64, sval64); 304 printf(")"); 305 break; 306 } 307 printf(", at offset %#lx in %s\n", (unsigned long)valoff, fname); 308 309 if (!replace) 310 goto done; 311 312 printf("new value: "); 313 314 switch (size) { 315 case sizeof(uint8_t): 316 uval8 = (uint8_t)val; 317 sval8 = (int8_t)val; 318 printf("0x%02" PRIx8 " (%" PRIu8, uval8, uval8); 319 if (sval8 < 0) 320 printf("/%" PRId8, sval8); 321 printf(")"); 322 *(uint8_t *)valp = uval8; 323 break; 324 case sizeof(uint16_t): 325 uval16 = (uint16_t)val; 326 sval16 = (int16_t)val; 327 printf("0x%04" PRIx16 " (%" PRIu16, uval16, uval16); 328 if (sval16 < 0) 329 printf("/%" PRId16, sval16); 330 printf(")"); 331 *(uint16_t *)valp = uval16; 332 break; 333 case sizeof(uint32_t): 334 uval32 = (uint32_t)val; 335 sval32 = (int32_t)val; 336 printf("0x%08" PRIx32 " (%" PRIu32, uval32, uval32); 337 if (sval32 < 0) 338 printf("/%" PRId32, sval32); 339 printf(")"); 340 *(uint32_t *)valp = uval32; 341 break; 342 case sizeof(uint64_t): 343 uval64 = (uint64_t)val; 344 sval64 = (int64_t)val; 345 printf("0x%016" PRIx64 " (%" PRIu64, uval64, uval64); 346 if (sval64 < 0) 347 printf("/%" PRId64, sval64); 348 printf(")"); 349 *(uint64_t *)valp = uval64; 350 break; 351 } 352 printf("\n"); 353 354 done: 355 munmap(mappedfile, sb.st_size); 356 close(fd); 357 358 if (verbose) 359 fprintf(stderr, "exiting\n"); 360 exit(EXIT_SUCCESS); 361} 362 363static void 364usage(void) 365{ 366 367 fprintf(stderr, 368 "usage: %s [-b|-w|-l|-d] [-a address | -s symbol] [-o offset]\n" 369 " [-r value] " 370#ifdef NLIST_AOUT 371 "[-T text_start] " 372#endif 373 "[-v] binary\n", getprogname()); 374 exit(EXIT_FAILURE); 375} 376