1/* Unexec for MIPS (including IRIS4D). 2 Note that the GNU project considers support for MIPS operation 3 a peripheral activity which should not be allowed to divert effort 4 from development of the GNU system. Changes in this code will be 5 installed when users send them in, but aside from that 6 we don't plan to think about it, or about whether other Emacs 7 maintenance might break it. 8 9 Copyright (C) 1988, 1994, 2001, 2002, 2003, 2004, 10 2005, 2006, 2007 Free Software Foundation, Inc. 11 12This file is part of GNU Emacs. 13 14GNU Emacs is free software; you can redistribute it and/or modify 15it under the terms of the GNU General Public License as published by 16the Free Software Foundation; either version 2, or (at your option) 17any later version. 18 19GNU Emacs is distributed in the hope that it will be useful, 20but WITHOUT ANY WARRANTY; without even the implied warranty of 21MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22GNU General Public License for more details. 23 24You should have received a copy of the GNU General Public License 25along with GNU Emacs; see the file COPYING. If not, write to 26the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 27Boston, MA 02110-1301, USA. */ 28 29 30#include <config.h> 31#include <sys/types.h> 32#include <sys/file.h> 33#include <sys/stat.h> 34#include <stdio.h> 35#include <varargs.h> 36 37#ifdef MACH 38 39#include <a.out.h> 40 41/* I don't know why this isn't defined. */ 42#ifndef STYP_INIT 43#define STYP_INIT 0x80000000 44#endif 45 46/* I don't know why this isn't defined. */ 47#ifndef _RDATA 48#define _RDATA ".rdata" 49#define STYP_RDATA 0x00000100 50#endif 51 52/* Small ("near") data section. */ 53#ifndef _SDATA 54#define _SDATA ".sdata" 55#define STYP_SDATA 0x00000200 56#endif 57 58/* Small ("near") bss section. */ 59#ifndef _SBSS 60#define _SBSS ".sbss" 61#define STYP_SBSS 0x00000400 62#endif 63 64/* We don't seem to have a sym.h or syms.h anywhere, so we'll do it the 65 hard way. This stinks. */ 66typedef struct { 67 short magic; 68 short vstamp; 69 long ilineMax; 70 struct { long foo, offset; } offsets[11]; 71} HDRR, *pHDRR; 72 73#else /* not MACH */ 74 75#include <filehdr.h> 76#include <aouthdr.h> 77#include <scnhdr.h> 78#include <sym.h> 79 80#endif /* not MACH */ 81 82#if defined (IRIS_4D) || defined (sony) 83#include "getpagesize.h" 84#include <fcntl.h> 85#endif 86 87static void fatal_unexec (); 88static void mark_x (); 89 90#define READ(_fd, _buffer, _size, _error_message, _error_arg) \ 91 errno = EEOF; \ 92 if (read (_fd, _buffer, _size) != _size) \ 93 fatal_unexec (_error_message, _error_arg); 94 95#define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \ 96 if (write (_fd, _buffer, _size) != _size) \ 97 fatal_unexec (_error_message, _error_arg); 98 99#define SEEK(_fd, _position, _error_message, _error_arg) \ 100 errno = EEOF; \ 101 if (lseek (_fd, _position, L_SET) != _position) \ 102 fatal_unexec (_error_message, _error_arg); 103 104extern int errno; 105extern char *strerror (); 106#define EEOF -1 107 108static struct scnhdr *text_section; 109static struct scnhdr *init_section; 110static struct scnhdr *finit_section; 111static struct scnhdr *rdata_section; 112static struct scnhdr *data_section; 113static struct scnhdr *lit8_section; 114static struct scnhdr *lit4_section; 115static struct scnhdr *sdata_section; 116static struct scnhdr *sbss_section; 117static struct scnhdr *bss_section; 118 119struct headers { 120 struct filehdr fhdr; 121 struct aouthdr aout; 122 struct scnhdr section[10]; 123}; 124 125/* Define name of label for entry point for the dumped executable. */ 126 127#ifndef DEFAULT_ENTRY_ADDRESS 128#define DEFAULT_ENTRY_ADDRESS __start 129#endif 130 131unexec (new_name, a_name, data_start, bss_start, entry_address) 132 char *new_name, *a_name; 133 unsigned data_start, bss_start, entry_address; 134{ 135 int new, old; 136 int pagesize, brk; 137 int newsyms, symrel; 138 int nread; 139 struct headers hdr; 140 int i; 141 int vaddr, scnptr; 142#define BUFSIZE 8192 143 char buffer[BUFSIZE]; 144 145 old = open (a_name, O_RDONLY, 0); 146 if (old < 0) fatal_unexec ("opening %s", a_name); 147 148 new = creat (new_name, 0666); 149 if (new < 0) fatal_unexec ("creating %s", new_name); 150 151 hdr = *((struct headers *)TEXT_START); 152#ifdef MIPS2 153 if (hdr.fhdr.f_magic != MIPSELMAGIC 154 && hdr.fhdr.f_magic != MIPSEBMAGIC 155 && hdr.fhdr.f_magic != (MIPSELMAGIC | 1) 156 && hdr.fhdr.f_magic != (MIPSEBMAGIC | 1)) 157 { 158 fprintf (stderr, 159 "unexec: input file magic number is %x, not %x, %x, %x or %x.\n", 160 hdr.fhdr.f_magic, 161 MIPSELMAGIC, MIPSEBMAGIC, 162 MIPSELMAGIC | 1, MIPSEBMAGIC | 1); 163 exit(1); 164 } 165#else /* not MIPS2 */ 166 if (hdr.fhdr.f_magic != MIPSELMAGIC 167 && hdr.fhdr.f_magic != MIPSEBMAGIC) 168 { 169 fprintf (stderr, "unexec: input file magic number is %x, not %x or %x.\n", 170 hdr.fhdr.f_magic, MIPSELMAGIC, MIPSEBMAGIC); 171 exit (1); 172 } 173#endif /* not MIPS2 */ 174 if (hdr.fhdr.f_opthdr != sizeof (hdr.aout)) 175 { 176 fprintf (stderr, "unexec: input a.out header is %d bytes, not %d.\n", 177 hdr.fhdr.f_opthdr, sizeof (hdr.aout)); 178 exit (1); 179 } 180 if (hdr.aout.magic != ZMAGIC) 181 { 182 fprintf (stderr, "unexec: input file a.out magic number is %o, not %o.\n", 183 hdr.aout.magic, ZMAGIC); 184 exit (1); 185 } 186 187#define CHECK_SCNHDR(ptr, name, flags) \ 188 ptr = NULL; \ 189 for (i = 0; i < hdr.fhdr.f_nscns && !ptr; i++) \ 190 if (strcmp (hdr.section[i].s_name, name) == 0) \ 191 { \ 192 if (hdr.section[i].s_flags != flags) \ 193 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \ 194 hdr.section[i].s_flags, flags, name); \ 195 ptr = hdr.section + i; \ 196 } \ 197 198 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT); 199 CHECK_SCNHDR (init_section, _INIT, STYP_INIT); 200 CHECK_SCNHDR (rdata_section, _RDATA, STYP_RDATA); 201 CHECK_SCNHDR (data_section, _DATA, STYP_DATA); 202#ifdef _LIT8 203 CHECK_SCNHDR (lit8_section, _LIT8, STYP_LIT8); 204 CHECK_SCNHDR (lit4_section, _LIT4, STYP_LIT4); 205#endif /* _LIT8 */ 206 CHECK_SCNHDR (sdata_section, _SDATA, STYP_SDATA); 207 CHECK_SCNHDR (sbss_section, _SBSS, STYP_SBSS); 208 CHECK_SCNHDR (bss_section, _BSS, STYP_BSS); 209#if 0 /* Apparently this error check goes off on irix 3.3, 210 but it doesn't indicate a real problem. */ 211 if (i != hdr.fhdr.f_nscns) 212 fprintf (stderr, "unexec: %d sections found instead of %d.\n", 213 i, hdr.fhdr.f_nscns); 214#endif 215 216 text_section->s_scnptr = 0; 217 218 pagesize = getpagesize (); 219 /* Casting to int avoids compiler error on NEWS-OS 5.0.2. */ 220 brk = (((int) (sbrk (0))) + pagesize - 1) & (-pagesize); 221 hdr.aout.dsize = brk - DATA_START; 222 hdr.aout.bsize = 0; 223 if (entry_address == 0) 224 { 225 extern DEFAULT_ENTRY_ADDRESS (); 226 hdr.aout.entry = (unsigned)DEFAULT_ENTRY_ADDRESS; 227 } 228 else 229 hdr.aout.entry = entry_address; 230 231 hdr.aout.bss_start = hdr.aout.data_start + hdr.aout.dsize; 232 rdata_section->s_size = data_start - DATA_START; 233 234 /* Adjust start and virtual addresses of rdata_section, too. */ 235 rdata_section->s_vaddr = DATA_START; 236 rdata_section->s_paddr = DATA_START; 237 rdata_section->s_scnptr = text_section->s_scnptr + hdr.aout.tsize; 238 239 data_section->s_vaddr = data_start; 240 data_section->s_paddr = data_start; 241 data_section->s_size = brk - data_start; 242 data_section->s_scnptr = rdata_section->s_scnptr + rdata_section->s_size; 243 vaddr = data_section->s_vaddr + data_section->s_size; 244 scnptr = data_section->s_scnptr + data_section->s_size; 245 if (lit8_section != NULL) 246 { 247 lit8_section->s_vaddr = vaddr; 248 lit8_section->s_paddr = vaddr; 249 lit8_section->s_size = 0; 250 lit8_section->s_scnptr = scnptr; 251 } 252 if (lit4_section != NULL) 253 { 254 lit4_section->s_vaddr = vaddr; 255 lit4_section->s_paddr = vaddr; 256 lit4_section->s_size = 0; 257 lit4_section->s_scnptr = scnptr; 258 } 259 if (sdata_section != NULL) 260 { 261 sdata_section->s_vaddr = vaddr; 262 sdata_section->s_paddr = vaddr; 263 sdata_section->s_size = 0; 264 sdata_section->s_scnptr = scnptr; 265 } 266 if (sbss_section != NULL) 267 { 268 sbss_section->s_vaddr = vaddr; 269 sbss_section->s_paddr = vaddr; 270 sbss_section->s_size = 0; 271 sbss_section->s_scnptr = scnptr; 272 } 273 if (bss_section != NULL) 274 { 275 bss_section->s_vaddr = vaddr; 276 bss_section->s_paddr = vaddr; 277 bss_section->s_size = 0; 278 bss_section->s_scnptr = scnptr; 279 } 280 281 WRITE (new, (char *)TEXT_START, hdr.aout.tsize, 282 "writing text section to %s", new_name); 283 WRITE (new, (char *)DATA_START, hdr.aout.dsize, 284 "writing data section to %s", new_name); 285 286 SEEK (old, hdr.fhdr.f_symptr, "seeking to start of symbols in %s", a_name); 287 errno = EEOF; 288 nread = read (old, buffer, BUFSIZE); 289 if (nread < sizeof (HDRR)) fatal_unexec ("reading symbols from %s", a_name); 290 newsyms = hdr.aout.tsize + hdr.aout.dsize; 291 symrel = newsyms - hdr.fhdr.f_symptr; 292 hdr.fhdr.f_symptr = newsyms; 293#define symhdr ((pHDRR)buffer) 294#ifdef MACH 295 for (i = 0; i < 11; i++) 296 symhdr->offsets[i].offset += symrel; 297#else 298 symhdr->cbLineOffset += symrel; 299 symhdr->cbDnOffset += symrel; 300 symhdr->cbPdOffset += symrel; 301 symhdr->cbSymOffset += symrel; 302 symhdr->cbOptOffset += symrel; 303 symhdr->cbAuxOffset += symrel; 304 symhdr->cbSsOffset += symrel; 305 symhdr->cbSsExtOffset += symrel; 306 symhdr->cbFdOffset += symrel; 307 symhdr->cbRfdOffset += symrel; 308 symhdr->cbExtOffset += symrel; 309#endif 310#undef symhdr 311 do 312 { 313 if (write (new, buffer, nread) != nread) 314 fatal_unexec ("writing symbols to %s", new_name); 315 nread = read (old, buffer, BUFSIZE); 316 if (nread < 0) fatal_unexec ("reading symbols from %s", a_name); 317#undef BUFSIZE 318 } while (nread != 0); 319 320 SEEK (new, 0, "seeking to start of header in %s", new_name); 321 WRITE (new, &hdr, sizeof (hdr), 322 "writing header of %s", new_name); 323 324 close (old); 325 close (new); 326 mark_x (new_name); 327} 328 329/* 330 * mark_x 331 * 332 * After successfully building the new a.out, mark it executable 333 */ 334 335static void 336mark_x (name) 337 char *name; 338{ 339 struct stat sbuf; 340 int um = umask (777); 341 umask (um); 342 if (stat (name, &sbuf) < 0) 343 fatal_unexec ("getting protection on %s", name); 344 sbuf.st_mode |= 0111 & ~um; 345 if (chmod (name, sbuf.st_mode) < 0) 346 fatal_unexec ("setting protection on %s", name); 347} 348 349static void 350fatal_unexec (s, va_alist) 351 va_dcl 352{ 353 va_list ap; 354 if (errno == EEOF) 355 fputs ("unexec: unexpected end of file, ", stderr); 356 else 357 fprintf (stderr, "unexec: %s, ", strerror (errno)); 358 va_start (ap); 359 _doprnt (s, ap, stderr); 360 fputs (".\n", stderr); 361 exit (1); 362} 363 364/* arch-tag: ebdd2058-3bbc-4de4-b5c7-5760379ab153 365 (do not change this comment) */ 366