1 /* $NetBSD: mdsetimage.c,v 1.19 2009/07/30 15:16:38 tsutsui 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("@(#) Copyright (c) 1996\ 35 Christopher G. Demetriou. All rights reserved."); 36 #endif /* not lint */ 37 38 #ifndef lint 39 __RCSID("$NetBSD: mdsetimage.c,v 1.19 2009/07/30 15:16:38 tsutsui Exp $"); 40 #endif /* not lint */ 41 42 #include <sys/types.h> 43 #include <sys/mman.h> 44 #include <sys/stat.h> 45 46 #include <err.h> 47 #include <fcntl.h> 48 #include <limits.h> 49 #include <nlist.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <unistd.h> 53 54 #include "extern.h" 55 56 int main __P((int, char *[])); 57 static void usage __P((void)) __dead; 58 static int find_md_root __P((const char *, const char *, size_t, 59 const struct nlist *, size_t *, u_int32_t *)); 60 61 static struct nlist md_root_nlist[] = { 62 #define X_MD_ROOT_IMAGE 0 63 { "_md_root_image", 0, 0, 0, 0 }, 64 #define X_MD_ROOT_SIZE 1 65 { "_md_root_size", 0, 0, 0, 0 }, 66 { NULL, 0, 0, 0, 0 } 67 }; 68 69 int verbose; 70 #ifdef NLIST_AOUT 71 /* 72 * Since we can't get the text address from an a.out executable, we 73 * need to be able to specify it. Note: there's no way to test to 74 * see if the user entered a valid address! 75 */ 76 int T_flag_specified; /* the -T flag was specified */ 77 u_long text_start; /* Start of kernel text */ 78 #endif /* NLIST_AOUT */ 79 80 int 81 main(argc, argv) 82 int argc; 83 char *argv[]; 84 { 85 struct stat ksb, fssb; 86 size_t md_root_offset; 87 u_int32_t md_root_size; 88 const char *kfile, *fsfile; 89 char *mappedkfile; 90 int ch, kfd, fsfd, rv; 91 92 setprogname(argv[0]); 93 94 while ((ch = getopt(argc, argv, "T:v")) != -1) 95 switch (ch) { 96 case 'v': 97 verbose = 1; 98 break; 99 case 'T': 100 #ifdef NLIST_AOUT 101 T_flag_specified = 1; 102 text_start = strtoul(optarg, NULL, 0); 103 break; 104 #endif /* NLIST_AOUT */ 105 /* FALLTHROUGH */ 106 case '?': 107 default: 108 usage(); 109 } 110 argc -= optind; 111 argv += optind; 112 113 if (argc != 2) 114 usage(); 115 kfile = argv[0]; 116 fsfile = argv[1]; 117 118 if ((kfd = open(kfile, O_RDWR, 0)) == -1) 119 err(1, "open %s", kfile); 120 121 if ((rv = __fdnlist(kfd, md_root_nlist)) != 0) 122 errx(1, "could not find symbols in %s", kfile); 123 if (verbose) 124 fprintf(stderr, "got symbols from %s\n", kfile); 125 126 if (fstat(kfd, &ksb) == -1) 127 err(1, "fstat %s", kfile); 128 if (ksb.st_size != (size_t)ksb.st_size) 129 errx(1, "%s too big to map", kfile); 130 131 if ((mappedkfile = mmap(NULL, ksb.st_size, PROT_READ | PROT_WRITE, 132 MAP_FILE | MAP_SHARED, kfd, 0)) == (caddr_t)-1) 133 err(1, "mmap %s", kfile); 134 if (verbose) 135 fprintf(stderr, "mapped %s\n", kfile); 136 137 if (find_md_root(kfile, mappedkfile, ksb.st_size, md_root_nlist, 138 &md_root_offset, &md_root_size) != 0) 139 errx(1, "could not find md root buffer in %s", kfile); 140 141 if ((fsfd = open(fsfile, O_RDONLY, 0)) == -1) 142 err(1, "open %s", fsfile); 143 if (fstat(fsfd, &fssb) == -1) 144 err(1, "fstat %s", fsfile); 145 if (fssb.st_size != (size_t)fssb.st_size) 146 errx(1, "fs image is too big"); 147 if (fssb.st_size > md_root_size) 148 errx(1, "fs image (%lld bytes) too big for buffer (%lu bytes)", 149 (long long)fssb.st_size, (unsigned long)md_root_size); 150 151 if (verbose) 152 fprintf(stderr, "copying image from %s into %s\n", fsfile, 153 kfile); 154 if ((rv = read(fsfd, mappedkfile + md_root_offset, 155 fssb.st_size)) != fssb.st_size) { 156 if (rv == -1) 157 err(1, "read %s", fsfile); 158 else 159 errx(1, "unexpected EOF reading %s", fsfile); 160 } 161 if (verbose) 162 fprintf(stderr, "done copying image\n"); 163 164 close(fsfd); 165 166 munmap(mappedkfile, ksb.st_size); 167 close(kfd); 168 169 if (verbose) 170 fprintf(stderr, "exiting\n"); 171 exit(0); 172 } 173 174 static void 175 usage() 176 { 177 178 fprintf(stderr, 179 "usage: %s kernel_file fsimage_file\n", 180 getprogname()); 181 exit(1); 182 } 183 184 185 struct { 186 const char *name; 187 int (*check) __P((const char *, size_t)); 188 int (*findoff) __P((const char *, size_t, u_long, size_t *)); 189 } exec_formats[] = { 190 #ifdef NLIST_AOUT 191 { "a.out", check_aout, findoff_aout, }, 192 #endif 193 #ifdef NLIST_ECOFF 194 { "ECOFF", check_ecoff, findoff_ecoff, }, 195 #endif 196 #ifdef NLIST_ELF32 197 { "ELF32", check_elf32, findoff_elf32, }, 198 #endif 199 #ifdef NLIST_ELF64 200 { "ELF64", check_elf64, findoff_elf64, }, 201 #endif 202 #ifdef NLIST_COFF 203 { "COFF", check_coff, findoff_coff, }, 204 #endif 205 }; 206 207 static int 208 find_md_root(fname, mappedfile, mappedsize, nl, rootoffp, rootsizep) 209 const char *fname, *mappedfile; 210 size_t mappedsize; 211 const struct nlist *nl; 212 size_t *rootoffp; 213 u_int32_t *rootsizep; 214 { 215 int i, n; 216 size_t rootsizeoff; 217 218 n = sizeof exec_formats / sizeof exec_formats[0]; 219 for (i = 0; i < n; i++) { 220 if ((*exec_formats[i].check)(mappedfile, mappedsize) == 0) 221 break; 222 } 223 if (i == n) { 224 warnx("%s: unknown executable format", fname); 225 return (1); 226 } 227 228 if (verbose) { 229 fprintf(stderr, "%s is an %s binary\n", fname, 230 exec_formats[i].name); 231 #ifdef NLIST_AOUT 232 if (T_flag_specified) 233 fprintf(stderr, "kernel text loads at 0x%lx\n", 234 text_start); 235 #endif 236 } 237 238 if ((*exec_formats[i].findoff)(mappedfile, mappedsize, 239 nl[X_MD_ROOT_SIZE].n_value, &rootsizeoff) != 0) { 240 warnx("couldn't find offset for %s in %s", 241 nl[X_MD_ROOT_SIZE].n_name, fname); 242 return (1); 243 } 244 if (verbose) 245 fprintf(stderr, "%s is at offset %#lx in %s\n", 246 nl[X_MD_ROOT_SIZE].n_name, 247 (unsigned long)rootsizeoff, fname); 248 *rootsizep = *(const u_int32_t *)&mappedfile[rootsizeoff]; 249 if (verbose) 250 fprintf(stderr, "%s has value %#x\n", 251 nl[X_MD_ROOT_SIZE].n_name, *rootsizep); 252 253 if ((*exec_formats[i].findoff)(mappedfile, mappedsize, 254 nl[X_MD_ROOT_IMAGE].n_value, rootoffp) != 0) { 255 warnx("couldn't find offset for %s in %s", 256 nl[X_MD_ROOT_IMAGE].n_name, fname); 257 return (1); 258 } 259 if (verbose) 260 fprintf(stderr, "%s is at offset %#lx in %s\n", 261 nl[X_MD_ROOT_IMAGE].n_name, 262 (unsigned long)(*rootoffp), fname); 263 264 return (0); 265 } 266