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