1 /* $NetBSD: mdsetimage.c,v 1.16 2001/10/01 23:32:34 cgd Exp $ */ 2 3 /* 4 * Copyright (c) 1996 Christopher G. Demetriou 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. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>> 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT( 35 "@(#) Copyright (c) 1996 Christopher G. Demetriou.\ 36 All rights reserved.\n"); 37 #endif /* not lint */ 38 39 #ifndef lint 40 __RCSID("$NetBSD: mdsetimage.c,v 1.16 2001/10/01 23:32:34 cgd Exp $"); 41 #endif /* not lint */ 42 43 #include <sys/types.h> 44 #include <sys/mman.h> 45 #include <sys/stat.h> 46 47 #include <err.h> 48 #include <fcntl.h> 49 #include <limits.h> 50 #include <nlist.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <unistd.h> 54 55 #include "extern.h" 56 57 int main __P((int, char *[])); 58 static void usage __P((void)) __attribute__((noreturn)); 59 static int find_md_root __P((const char *, const char *, size_t, 60 const struct nlist *, size_t *, u_int32_t *)); 61 62 static struct nlist md_root_nlist[] = { 63 #define X_MD_ROOT_IMAGE 0 64 { "_md_root_image" }, 65 #define X_MD_ROOT_SIZE 1 66 { "_md_root_size" }, 67 { NULL } 68 }; 69 70 int verbose; 71 #ifdef NLIST_AOUT 72 /* 73 * Since we can't get the text address from an a.out executable, we 74 * need to be able to specify it. Note: there's no way to test to 75 * see if the user entered a valid address! 76 */ 77 int T_flag_specified; /* the -T flag was specified */ 78 u_long text_start; /* Start of kernel text */ 79 #endif /* NLIST_AOUT */ 80 81 int 82 main(argc, argv) 83 int argc; 84 char *argv[]; 85 { 86 struct stat ksb, fssb; 87 size_t md_root_offset; 88 u_int32_t md_root_size; 89 const char *kfile, *fsfile; 90 char *mappedkfile; 91 int ch, kfd, fsfd, rv; 92 93 setprogname(argv[0]); 94 95 while ((ch = getopt(argc, argv, "T:v")) != -1) 96 switch (ch) { 97 case 'v': 98 verbose = 1; 99 break; 100 case 'T': 101 #ifdef NLIST_AOUT 102 T_flag_specified = 1; 103 text_start = strtoul(optarg, NULL, 0); 104 break; 105 #endif /* NLIST_AOUT */ 106 /* FALLTHROUGH */ 107 case '?': 108 default: 109 usage(); 110 } 111 argc -= optind; 112 argv += optind; 113 114 if (argc != 2) 115 usage(); 116 kfile = argv[0]; 117 fsfile = argv[1]; 118 119 if ((kfd = open(kfile, O_RDWR, 0)) == -1) 120 err(1, "open %s", kfile); 121 122 if ((rv = __fdnlist(kfd, md_root_nlist)) != 0) 123 errx(1, "could not find symbols in %s", kfile); 124 if (verbose) 125 fprintf(stderr, "got symbols from %s\n", kfile); 126 127 if (fstat(kfd, &ksb) == -1) 128 err(1, "fstat %s", kfile); 129 if (ksb.st_size != (size_t)ksb.st_size) 130 errx(1, "%s too big to map", kfile); 131 132 if ((mappedkfile = mmap(NULL, ksb.st_size, PROT_READ | PROT_WRITE, 133 MAP_FILE | MAP_SHARED, kfd, 0)) == (caddr_t)-1) 134 err(1, "mmap %s", kfile); 135 if (verbose) 136 fprintf(stderr, "mapped %s\n", kfile); 137 138 if (find_md_root(kfile, mappedkfile, ksb.st_size, md_root_nlist, 139 &md_root_offset, &md_root_size) != 0) 140 errx(1, "could not find md root buffer in %s", kfile); 141 142 if ((fsfd = open(fsfile, O_RDONLY, 0)) == -1) 143 err(1, "open %s", fsfile); 144 if (fstat(fsfd, &fssb) == -1) 145 err(1, "fstat %s", fsfile); 146 if (fssb.st_size != (size_t)fssb.st_size) 147 errx(1, "fs image is too big"); 148 if (fssb.st_size > md_root_size) 149 errx(1, "fs image (%lld bytes) too big for buffer (%lu bytes)", 150 (long long)fssb.st_size, (unsigned long)md_root_size); 151 152 if (verbose) 153 fprintf(stderr, "copying image from %s into %s\n", fsfile, 154 kfile); 155 if ((rv = read(fsfd, mappedkfile + md_root_offset, 156 fssb.st_size)) != fssb.st_size) { 157 if (rv == -1) 158 err(1, "read %s", fsfile); 159 else 160 errx(1, "unexpected EOF reading %s", fsfile); 161 } 162 if (verbose) 163 fprintf(stderr, "done copying image\n"); 164 165 close(fsfd); 166 167 munmap(mappedkfile, ksb.st_size); 168 close(kfd); 169 170 if (verbose) 171 fprintf(stderr, "exiting\n"); 172 exit(0); 173 } 174 175 static void 176 usage() 177 { 178 179 fprintf(stderr, 180 "usage: %s kernel_file fsimage_file\n", 181 getprogname()); 182 exit(1); 183 } 184 185 186 struct { 187 const char *name; 188 int (*check) __P((const char *, size_t)); 189 int (*findoff) __P((const char *, size_t, u_long, size_t *)); 190 } exec_formats[] = { 191 #ifdef NLIST_AOUT 192 { "a.out", check_aout, findoff_aout, }, 193 #endif 194 #ifdef NLIST_ECOFF 195 { "ECOFF", check_ecoff, findoff_ecoff, }, 196 #endif 197 #ifdef NLIST_ELF32 198 { "ELF32", check_elf32, findoff_elf32, }, 199 #endif 200 #ifdef NLIST_ELF64 201 { "ELF64", check_elf64, findoff_elf64, }, 202 #endif 203 #ifdef NLIST_COFF 204 { "COFF", check_coff, findoff_coff, }, 205 #endif 206 }; 207 208 static int 209 find_md_root(fname, mappedfile, mappedsize, nl, rootoffp, rootsizep) 210 const char *fname, *mappedfile; 211 size_t mappedsize; 212 const struct nlist *nl; 213 size_t *rootoffp; 214 u_int32_t *rootsizep; 215 { 216 int i, n; 217 size_t rootsizeoff; 218 219 n = sizeof exec_formats / sizeof exec_formats[0]; 220 for (i = 0; i < n; i++) { 221 if ((*exec_formats[i].check)(mappedfile, mappedsize) == 0) 222 break; 223 } 224 if (i == n) { 225 warnx("%s: unknown executable format", fname); 226 return (1); 227 } 228 229 if (verbose) { 230 fprintf(stderr, "%s is an %s binary\n", fname, 231 exec_formats[i].name); 232 #ifdef NLIST_AOUT 233 if (T_flag_specified) 234 fprintf(stderr, "kernel text loads at 0x%lx\n", 235 text_start); 236 #endif 237 } 238 239 if ((*exec_formats[i].findoff)(mappedfile, mappedsize, 240 nl[X_MD_ROOT_SIZE].n_value, &rootsizeoff) != 0) { 241 warnx("couldn't find offset for %s in %s", 242 nl[X_MD_ROOT_SIZE].n_name, fname); 243 return (1); 244 } 245 if (verbose) 246 fprintf(stderr, "%s is at offset %#lx in %s\n", 247 nl[X_MD_ROOT_SIZE].n_name, 248 (unsigned long)rootsizeoff, fname); 249 *rootsizep = *(u_int32_t *)&mappedfile[rootsizeoff]; 250 if (verbose) 251 fprintf(stderr, "%s has value %#x\n", 252 nl[X_MD_ROOT_SIZE].n_name, *rootsizep); 253 254 if ((*exec_formats[i].findoff)(mappedfile, mappedsize, 255 nl[X_MD_ROOT_IMAGE].n_value, rootoffp) != 0) { 256 warnx("couldn't find offset for %s in %s", 257 nl[X_MD_ROOT_IMAGE].n_name, fname); 258 return (1); 259 } 260 if (verbose) 261 fprintf(stderr, "%s is at offset %#lx in %s\n", 262 nl[X_MD_ROOT_IMAGE].n_name, 263 (unsigned long)(*rootoffp), fname); 264 265 return (0); 266 } 267