1157188Sache/* 221308Sache * Copyright (c) 1998 Robert Nordier 321308Sache * All rights reserved. 4157188Sache * 521308Sache * Redistribution and use in source and binary forms, with or without 621308Sache * modification, are permitted provided that the following conditions 721308Sache * are met: 821308Sache * 1. Redistributions of source code must retain the above copyright 921308Sache * notice, this list of conditions and the following disclaimer. 1021308Sache * 2. Redistributions in binary form must reproduce the above copyright 1158314Sache * notice, this list of conditions and the following disclaimer in the 1221308Sache * documentation and/or other materials provided with the distribution. 1321308Sache * 1421308Sache * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND 1521308Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1621308Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 1721308Sache * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 1821308Sache * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 1921308Sache * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 2021308Sache * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 2121308Sache * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2258314Sache * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23123279Sobrien * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 2421308Sache * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2521308Sache */ 2621308Sache 2747563Sache#ifndef lint 2847563Sachestatic const char rcsid[] = 2947563Sache "$FreeBSD$"; 3047563Sache#endif /* not lint */ 3121308Sache 3247563Sache#include <sys/param.h> 33119614Sache#include <sys/endian.h> 3421308Sache#include <sys/stat.h> 3521308Sache#include <sys/mman.h> 3621308Sache 3747563Sache/* XXX make this work as an i386/amd64 cross-tool */ 38119614Sache#include <machine/exec.h> 3921308Sache#undef __LDPGSZ 4021308Sache#define __LDPGSZ 4096 4121308Sache 4221308Sache#include <netinet/in.h> 43119614Sache 44165675Sache#include <a.out.h> 45136652Sache#include <err.h> 46165675Sache#include <errno.h> 47119614Sache#include <fcntl.h> 4821308Sache#include <stdarg.h> 4921308Sache#include <stdio.h> 5021308Sache#include <stdlib.h> 5121308Sache#include <string.h> 5221308Sache#include <unistd.h> 5321308Sache 5421308Sache#include "btx.h" 5521308Sache#include "elfh.h" 5621308Sache 5721308Sache#define BTX_PATH "/sys/boot/i386/btx" 5821308Sache 5921308Sache#define I_LDR 0 /* BTX loader */ 6021308Sache#define I_BTX 1 /* BTX kernel */ 6121308Sache#define I_CLNT 2 /* Client program */ 6221308Sache 6321308Sache#define F_BIN 0 /* Binary */ 6421308Sache#define F_AOUT 1 /* ZMAGIC a.out */ 6521308Sache#define F_ELF 2 /* 32-bit ELF */ 6621308Sache#define F_CNT 3 /* Number of formats */ 6721308Sache 6821308Sache#define IMPURE 1 /* Writable text */ 6921308Sache#define MAXU32 0xffffffff /* Maximum unsigned 32-bit quantity */ 7021308Sache 7175409Sache#define align(x, y) (((x) + (y) - 1) & ~((y) - 1)) 7275409Sache 7321308Sachestruct hdr { 7421308Sache uint32_t fmt; /* Format */ 7521308Sache uint32_t flags; /* Bit flags */ 7621308Sache uint32_t size; /* Size of file */ 7747563Sache uint32_t text; /* Size of text segment */ 7847563Sache uint32_t data; /* Size of data segment */ 7947563Sache uint32_t bss; /* Size of bss segment */ 8047563Sache uint32_t org; /* Program origin */ 8147563Sache uint32_t entry; /* Program entry point */ 8221308Sache}; 8347563Sache 84119614Sachestatic const char *const fmtlist[] = {"bin", "aout", "elf"}; 85119614Sache 8621308Sachestatic const char binfo[] = 8747563Sache "kernel: ver=%u.%02u size=%x load=%x entry=%x map=%uM " 88119614Sache "pgctl=%x:%x\n"; 89119614Sachestatic const char cinfo[] = 90119614Sache "client: fmt=%s size=%x text=%x data=%x bss=%x entry=%x\n"; 91119614Sachestatic const char oinfo[] = 92119614Sache "output: fmt=%s size=%x text=%x data=%x org=%x entry=%x\n"; 93119614Sache 94119614Sachestatic const char *lname = 95119614Sache BTX_PATH "/btxldr/btxldr"; /* BTX loader */ 96119614Sachestatic const char *bname = 97119614Sache BTX_PATH "/btx/btx"; /* BTX kernel */ 98119614Sachestatic const char *oname = 99119614Sache "a.out"; /* Output filename */ 100119614Sache 10121308Sachestatic int ppage = -1; /* First page present */ 10247563Sachestatic int wpage = -1; /* First page writable */ 103119614Sache 104119614Sachestatic unsigned int format; /* Output format */ 105119614Sache 106119614Sachestatic uint32_t centry; /* Client entry address */ 107119614Sachestatic uint32_t lentry; /* Loader entry address */ 108119614Sache 109119614Sachestatic int Eflag; /* Client entry option */ 110119614Sache 111119614Sachestatic int quiet; /* Inhibit warnings */ 112119614Sachestatic int verbose; /* Display information */ 113119614Sache 11447563Sachestatic const char *tname; /* Temporary output file */ 11547563Sachestatic const char *fname; /* Current input file */ 116119614Sache 117119614Sachestatic void cleanup(void); 118119614Sachestatic void btxld(const char *); 11947563Sachestatic void getbtx(int, struct btx_hdr *); 12047563Sachestatic void gethdr(int, struct hdr *); 121119614Sachestatic void puthdr(int, struct hdr *); 122119614Sachestatic void copy(int, int, size_t, off_t); 12347563Sachestatic size_t readx(int, void *, size_t, off_t); 12447563Sachestatic void writex(int, const void *, size_t); 125119614Sachestatic void seekx(int, off_t); 126119614Sachestatic unsigned int optfmt(const char *); 12747563Sachestatic uint32_t optaddr(const char *); 12847563Sachestatic int optpage(const char *, int); 129119614Sachestatic void Warn(const char *, const char *, ...); 130119614Sachestatic void usage(void); 131119614Sache 132119614Sache/* 13347563Sache * A link editor for BTX clients. 13447563Sache */ 135119614Sacheint 136119614Sachemain(int argc, char *argv[]) 13747563Sache{ 13847563Sache int c; 139119614Sache 140119614Sache while ((c = getopt(argc, argv, "qvb:E:e:f:l:o:P:W:")) != -1) 14147563Sache switch (c) { 142119614Sache case 'q': 143119614Sache quiet = 1; 144119614Sache break; 14547563Sache case 'v': 146119614Sache verbose = 1; 147119614Sache break; 148119614Sache case 'b': 149119614Sache bname = optarg; 15047563Sache break; 15147563Sache case 'E': 152119614Sache centry = optaddr(optarg); 153119614Sache Eflag = 1; 154119614Sache break; 155119614Sache case 'e': 15647563Sache lentry = optaddr(optarg); 15747563Sache break; 158119614Sache case 'f': 159119614Sache format = optfmt(optarg); 160119614Sache break; 161119614Sache case 'l': 162119614Sache lname = optarg; 163119614Sache break; 164136652Sache case 'o': 165119614Sache oname = optarg; 166119614Sache break; 167119614Sache case 'P': 168119614Sache ppage = optpage(optarg, 1); 169119614Sache break; 170119614Sache case 'W': 171119614Sache wpage = optpage(optarg, BTX_MAXCWR); 172119614Sache break; 173119614Sache default: 17475409Sache usage(); 17575409Sache } 176119614Sache argc -= optind; 17735493Sache argv += optind; 17835493Sache if (argc != 1) 17947563Sache usage(); 180119614Sache atexit(cleanup); 181119614Sache btxld(*argv); 18221308Sache return 0; 18347563Sache} 184119614Sache 185119614Sache/* 186119614Sache * Clean up after errors. 18721308Sache */ 18847563Sachestatic void 189119614Sachecleanup(void) 190119614Sache{ 19147563Sache if (tname) 19247563Sache remove(tname); 193119614Sache} 19447563Sache 19547563Sache/* 196119614Sache * Read the input files; write the output file; display information. 197119614Sache */ 19847563Sachestatic void 19947563Sachebtxld(const char *iname) 200119614Sache{ 201119614Sache char name[FILENAME_MAX]; 20247563Sache struct btx_hdr btx, btxle; 20347563Sache struct hdr ihdr, ohdr; 204119614Sache unsigned int ldr_size, cwr; 205119614Sache int fdi[3], fdo, i; 206119614Sache 207119614Sache ldr_size = 0; 208119614Sache 209119614Sache for (i = I_LDR; i <= I_CLNT; i++) { 21047563Sache fname = i == I_LDR ? lname : i == I_BTX ? bname : iname; 21158314Sache if ((fdi[i] = open(fname, O_RDONLY)) == -1) 212119614Sache err(2, "%s", fname); 21347563Sache switch (i) { 21447563Sache case I_LDR: 215119614Sache gethdr(fdi[i], &ihdr); 216119614Sache if (ihdr.fmt != F_BIN) 217119614Sache Warn(fname, "Loader format is %s; processing as %s", 21847563Sache fmtlist[ihdr.fmt], fmtlist[F_BIN]); 21921308Sache ldr_size = ihdr.size; 22047563Sache break; 221119614Sache case I_BTX: 222119614Sache getbtx(fdi[i], &btx); 223119614Sache break; 224119614Sache case I_CLNT: 225119614Sache gethdr(fdi[i], &ihdr); 226119614Sache if (ihdr.org && ihdr.org != BTX_PGSIZE) 227119614Sache Warn(fname, 228119614Sache "Client origin is 0x%x; expecting 0 or 0x%x", 229119614Sache ihdr.org, BTX_PGSIZE); 230119614Sache } 231119614Sache } 232119614Sache memset(&ohdr, 0, sizeof(ohdr)); 233119614Sache ohdr.fmt = format; 234119614Sache ohdr.text = ldr_size; 235119614Sache ohdr.data = btx.btx_textsz + ihdr.size; 236119614Sache ohdr.org = lentry; 237119614Sache ohdr.entry = lentry; 238119614Sache cwr = 0; 239119614Sache if (wpage > 0 || (wpage == -1 && !(ihdr.flags & IMPURE))) { 240119614Sache if (wpage > 0) 241119614Sache cwr = wpage; 242119614Sache else { 243119614Sache cwr = howmany(ihdr.text, BTX_PGSIZE); 244119614Sache if (cwr > BTX_MAXCWR) 245157188Sache cwr = BTX_MAXCWR; 246119614Sache } 247119614Sache } 248119614Sache if (ppage > 0 || (ppage && wpage && ihdr.org >= BTX_PGSIZE)) { 249119614Sache btx.btx_flags |= BTX_MAPONE; 250119614Sache if (!cwr) 251119614Sache cwr++; 252119614Sache } 253119614Sache btx.btx_pgctl -= cwr; 254119614Sache btx.btx_entry = Eflag ? centry : ihdr.entry; 255119614Sache if ((size_t)snprintf(name, sizeof(name), "%s.tmp", oname) >= sizeof(name)) 256119614Sache errx(2, "%s: Filename too long", oname); 257119614Sache if ((fdo = open(name, O_CREAT | O_TRUNC | O_WRONLY, 0666)) == -1) 25821308Sache err(2, "%s", name); 25947563Sache if (!(tname = strdup(name))) 260119614Sache err(2, NULL); 261119614Sache puthdr(fdo, &ohdr); 262119614Sache for (i = I_LDR; i <= I_CLNT; i++) { 26321308Sache fname = i == I_LDR ? lname : i == I_BTX ? bname : iname; 264136652Sache switch (i) { 265136652Sache case I_LDR: 26647563Sache copy(fdi[i], fdo, ldr_size, 0); 267119614Sache seekx(fdo, ohdr.size += ohdr.text); 268119614Sache break; 269119614Sache case I_BTX: 270119614Sache btxle = btx; 271119614Sache btxle.btx_pgctl = htole16(btxle.btx_pgctl); 272119614Sache btxle.btx_textsz = htole16(btxle.btx_textsz); 27321308Sache btxle.btx_entry = htole32(btxle.btx_entry); 27421308Sache writex(fdo, &btxle, sizeof(btxle)); 27521308Sache copy(fdi[i], fdo, btx.btx_textsz - sizeof(btx), 27621308Sache sizeof(btx)); 27721308Sache break; 27821308Sache case I_CLNT: 27921308Sache copy(fdi[i], fdo, ihdr.size, 0); 28021308Sache if (ftruncate(fdo, ohdr.size += ohdr.data)) 28121308Sache err(2, "%s", tname); 282119614Sache } 28321308Sache if (close(fdi[i])) 284119614Sache err(2, "%s", fname); 285119614Sache } 28675409Sache if (close(fdo)) 287119614Sache err(2, "%s", tname); 28821308Sache if (rename(tname, oname)) 28975409Sache err(2, "%s: Can't rename to %s", tname, oname); 290119614Sache tname = NULL; 29121308Sache if (verbose) { 29247563Sache printf(binfo, btx.btx_majver, btx.btx_minver, btx.btx_textsz, 293119614Sache BTX_ORIGIN(btx), BTX_ENTRY(btx), BTX_MAPPED(btx) * 294119614Sache BTX_PGSIZE / 0x100000, !!(btx.btx_flags & BTX_MAPONE), 295119614Sache BTX_MAPPED(btx) - btx.btx_pgctl - BTX_PGBASE / 296119614Sache BTX_PGSIZE - BTX_MAPPED(btx) * 4 / BTX_PGSIZE); 297119614Sache printf(cinfo, fmtlist[ihdr.fmt], ihdr.size, ihdr.text, 298136652Sache ihdr.data, ihdr.bss, ihdr.entry); 299136652Sache printf(oinfo, fmtlist[ohdr.fmt], ohdr.size, ohdr.text, 300119614Sache ohdr.data, ohdr.org, ohdr.entry); 301119614Sache } 302136652Sache} 303136652Sache 304136652Sache/* 305136652Sache * Read BTX file header. 306119614Sache */ 307157188Sachestatic void 308157188Sachegetbtx(int fd, struct btx_hdr * btx) 309119614Sache{ 31047563Sache if (readx(fd, btx, sizeof(*btx), 0) != sizeof(*btx) || 311136652Sache btx->btx_magic[0] != BTX_MAG0 || 312136652Sache btx->btx_magic[1] != BTX_MAG1 || 313136652Sache btx->btx_magic[2] != BTX_MAG2) 31421308Sache errx(1, "%s: Not a BTX kernel", fname); 315119614Sache btx->btx_pgctl = le16toh(btx->btx_pgctl); 31621308Sache btx->btx_textsz = le16toh(btx->btx_textsz); 31747563Sache btx->btx_entry = le32toh(btx->btx_entry); 318119614Sache} 319119614Sache 32021308Sache/* 321119614Sache * Get file size and read a.out or ELF header. 322119614Sache */ 32321308Sachestatic void 324119614Sachegethdr(int fd, struct hdr *hdr) 325119614Sache{ 326119614Sache struct stat sb; 32747563Sache const struct exec *ex; 328119614Sache const Elf32_Ehdr *ee; 329119614Sache const Elf32_Phdr *ep; 330119614Sache void *p; 33121308Sache unsigned int fmt, x, n, i; 332119614Sache 333119614Sache memset(hdr, 0, sizeof(*hdr)); 33421308Sache if (fstat(fd, &sb)) 33547563Sache err(2, "%s", fname); 336119614Sache if (sb.st_size > MAXU32) 337119614Sache errx(1, "%s: Too big", fname); 338119614Sache hdr->size = sb.st_size; 339119614Sache if (!hdr->size) 340119614Sache return; 341119614Sache if ((p = mmap(NULL, hdr->size, PROT_READ, MAP_SHARED, fd, 342119614Sache 0)) == MAP_FAILED) 343119614Sache err(2, "%s", fname); 344119614Sache for (fmt = F_CNT - 1; !hdr->fmt && fmt; fmt--) 34575409Sache switch (fmt) { 346119614Sache case F_AOUT: 347119614Sache ex = p; 34847563Sache if (hdr->size >= sizeof(struct exec) && !N_BADMAG(*ex)) { 34947563Sache hdr->fmt = fmt; 350119614Sache x = N_GETMAGIC(*ex); 351119614Sache if (x == OMAGIC || x == NMAGIC) { 35275409Sache if (x == NMAGIC) 35375409Sache Warn(fname, "Treating %s NMAGIC as OMAGIC", 354119614Sache fmtlist[fmt]); 35547563Sache hdr->flags |= IMPURE; 35647563Sache } 357119614Sache hdr->text = le32toh(ex->a_text); 35847563Sache hdr->data = le32toh(ex->a_data); 35947563Sache hdr->bss = le32toh(ex->a_bss); 360119614Sache hdr->entry = le32toh(ex->a_entry); 361119614Sache if (le32toh(ex->a_entry) >= BTX_PGSIZE) 362119614Sache hdr->org = BTX_PGSIZE; 363119614Sache } 364119614Sache break; 365119614Sache case F_ELF: 36647563Sache ee = p; 36721308Sache if (hdr->size >= sizeof(Elf32_Ehdr) && IS_ELF(*ee)) { 368119614Sache hdr->fmt = fmt; 369119614Sache for (n = i = 0; i < le16toh(ee->e_phnum); i++) { 370119614Sache ep = (void *)((uint8_t *)p + le32toh(ee->e_phoff) + 371119614Sache le16toh(ee->e_phentsize) * i); 372119614Sache if (le32toh(ep->p_type) == PT_LOAD) 373119614Sache switch (n++) { 374119614Sache case 0: 37521308Sache hdr->text = le32toh(ep->p_filesz); 376136652Sache hdr->org = le32toh(ep->p_paddr); 377119614Sache if (le32toh(ep->p_flags) & PF_W) 37821308Sache hdr->flags |= IMPURE; 37921308Sache break; 38021308Sache case 1: 38121308Sache hdr->data = le32toh(ep->p_filesz); 382119614Sache hdr->bss = le32toh(ep->p_memsz) - 38375409Sache le32toh(ep->p_filesz); 38421308Sache break; 385119614Sache case 2: 38621308Sache Warn(fname, 38747563Sache "Ignoring extra %s PT_LOAD segments", 388119614Sache fmtlist[fmt]); 389119614Sache } 39047563Sache } 39121308Sache hdr->entry = le32toh(ee->e_entry); 392119614Sache } 393119614Sache } 394119614Sache if (munmap(p, hdr->size)) 395119614Sache err(2, "%s", fname); 396119614Sache} 39721308Sache 39847563Sache/* 399119614Sache * Write a.out or ELF header. 400119614Sache */ 401119614Sachestatic void 402136652Sacheputhdr(int fd, struct hdr *hdr) 40321308Sache{ 404119614Sache struct exec ex; 405119614Sache struct elfh eh; 406119614Sache 407119614Sache switch (hdr->fmt) { 408157188Sache case F_AOUT: 40921308Sache memset(&ex, 0, sizeof(ex)); 410119614Sache N_SETMAGIC(ex, ZMAGIC, MID_I386, 0); 411119614Sache hdr->text = N_ALIGN(ex, hdr->text); 41247563Sache ex.a_text = htole32(hdr->text); 413119614Sache hdr->data = N_ALIGN(ex, hdr->data); 414119614Sache ex.a_data = htole32(hdr->data); 415119614Sache ex.a_entry = htole32(hdr->entry); 416119614Sache writex(fd, &ex, sizeof(ex)); 417119614Sache hdr->size = N_ALIGN(ex, sizeof(ex)); 418119614Sache seekx(fd, hdr->size); 41947563Sache break; 42075409Sache case F_ELF: 421119614Sache eh = elfhdr; 422119614Sache eh.e.e_entry = htole32(hdr->entry); 423119614Sache eh.p[0].p_vaddr = eh.p[0].p_paddr = htole32(hdr->org); 42475409Sache eh.p[0].p_filesz = eh.p[0].p_memsz = htole32(hdr->text); 42547563Sache eh.p[1].p_offset = htole32(le32toh(eh.p[0].p_offset) + 426119614Sache le32toh(eh.p[0].p_filesz)); 427119614Sache eh.p[1].p_vaddr = eh.p[1].p_paddr = 428119614Sache htole32(align(le32toh(eh.p[0].p_paddr) + le32toh(eh.p[0].p_memsz), 429119614Sache 4096)); 430119614Sache eh.p[1].p_filesz = eh.p[1].p_memsz = htole32(hdr->data); 43147563Sache eh.sh[2].sh_addr = eh.p[0].p_vaddr; 432119614Sache eh.sh[2].sh_offset = eh.p[0].p_offset; 43321308Sache eh.sh[2].sh_size = eh.p[0].p_filesz; 43475409Sache eh.sh[3].sh_addr = eh.p[1].p_vaddr; 435119614Sache eh.sh[3].sh_offset = eh.p[1].p_offset; 436119614Sache eh.sh[3].sh_size = eh.p[1].p_filesz; 437119614Sache writex(fd, &eh, sizeof(eh)); 43847563Sache hdr->size = sizeof(eh); 43921308Sache } 440119614Sache} 441119614Sache 44221308Sache/* 443119614Sache * Safe copy from input file to output file. 444119614Sache */ 445119614Sachestatic void 44621308Sachecopy(int fdi, int fdo, size_t nbyte, off_t offset) 447119614Sache{ 448119614Sache char buf[8192]; 449124575Sobrien size_t n; 45075409Sache 451119614Sache while (nbyte) { 452119614Sache if ((n = sizeof(buf)) > nbyte) 453119614Sache n = nbyte; 454119614Sache if (readx(fdi, buf, n, offset) != n) 45575409Sache errx(2, "%s: Short read", fname); 456119614Sache writex(fdo, buf, n); 457119614Sache nbyte -= n; 458119614Sache offset = -1; 45975409Sache } 460119614Sache} 461119614Sache 462119614Sache/* 463119614Sache * Safe read from input file. 46475409Sache */ 46521308Sachestatic size_t 46621308Sachereadx(int fd, void *buf, size_t nbyte, off_t offset) 46721308Sache{ 46821308Sache ssize_t n; 46921308Sache 47021308Sache if (offset != -1 && lseek(fd, offset, SEEK_SET) != offset) 47121308Sache err(2, "%s", fname); 472119614Sache if ((n = read(fd, buf, nbyte)) == -1) 473119614Sache err(2, "%s", fname); 47421308Sache return n; 47558314Sache} 47658314Sache 47758314Sache/* 47875409Sache * Safe write to output file. 47975409Sache */ 48075409Sachestatic void 48175409Sachewritex(int fd, const void *buf, size_t nbyte) 48275409Sache{ 48375409Sache ssize_t n; 48475409Sache 485119614Sache if ((n = write(fd, buf, nbyte)) == -1) 486119614Sache err(2, "%s", tname); 487119614Sache if ((size_t)n != nbyte) 488119614Sache errx(2, "%s: Short write", tname); 48921308Sache} 49021308Sache 49175409Sache/* 49221308Sache * Safe seek in output file. 49326500Sache */ 49426500Sachestatic void 49526500Sacheseekx(int fd, off_t offset) 49626500Sache{ 49721308Sache if (lseek(fd, offset, SEEK_SET) != offset) 49821308Sache err(2, "%s", tname); 49921308Sache} 50021308Sache 50175409Sache/* 50275409Sache * Convert an option argument to a format code. 50321308Sache */ 50447563Sachestatic unsigned int 50521308Sacheoptfmt(const char *arg) 50621308Sache{ 50747563Sache unsigned int i; 50847563Sache 50921308Sache for (i = 0; i < F_CNT && strcmp(arg, fmtlist[i]); i++); 51021308Sache if (i == F_CNT) 51147563Sache errx(1, "%s: Unknown format", arg); 51221308Sache return i; 51321308Sache} 51426500Sache 51526500Sache/* 51626500Sache * Convert an option argument to an address. 51730974Sache */ 51826500Sachestatic uint32_t 51975409Sacheoptaddr(const char *arg) 52075409Sache{ 52175409Sache char *s; 52275409Sache unsigned long x; 52375409Sache 52475409Sache errno = 0; 52575409Sache x = strtoul(arg, &s, 0); 52675409Sache if (errno || !*arg || *s || x > MAXU32) 52775409Sache errx(1, "%s: Illegal address", arg); 52875409Sache return x; 52921308Sache} 53075409Sache 53121308Sache/* 53221308Sache * Convert an option argument to a page number. 53375409Sache */ 53475409Sachestatic int 53521308Sacheoptpage(const char *arg, int hi) 536157188Sache{ 537157188Sache char *s; 538157188Sache long x; 539157188Sache 540157188Sache errno = 0; 54121308Sache x = strtol(arg, &s, 0); 54221308Sache if (errno || !*arg || *s || x < 0 || x > hi) 54375409Sache errx(1, "%s: Illegal page number", arg); 54421308Sache return x; 54547563Sache} 54647563Sache 54747563Sache/* 54875409Sache * Display a warning. 54947563Sache */ 55021308Sachestatic void 55121308SacheWarn(const char *locus, const char *fmt, ...) 55275409Sache{ 55321308Sache va_list ap; 55475409Sache char *s; 55575409Sache 55675409Sache if (!quiet) { 55721308Sache asprintf(&s, "%s: Warning: %s", locus, fmt); 55875409Sache va_start(ap, fmt); 55975409Sache vwarnx(s, ap); 56075409Sache va_end(ap); 56175409Sache free(s); 56275409Sache } 56321308Sache} 56421308Sache 56521308Sache/* 56621308Sache * Display usage information. 56747563Sache */ 56847563Sachestatic void 56947563Sacheusage(void) 57047563Sache{ 57147563Sache fprintf(stderr, "%s\n%s\n", 57247563Sache "usage: btxld [-qv] [-b file] [-E address] [-e address] [-f format]", 57358314Sache " [-l file] [-o filename] [-P page] [-W page] file"); 57458314Sache exit(1); 57558314Sache} 57658314Sache