1/* Unexec for DEC alpha. schoepf@sc.ZIB-Berlin.DE (Rainer Schoepf). 2 3 Copyright (C) 1994, 2000, 2001, 2002, 2003, 2004, 4 2005, 2006, 2007 Free Software Foundation, Inc. 5 6This file is part of GNU Emacs. 7 8GNU Emacs is free software; you can redistribute it and/or modify 9it under the terms of the GNU General Public License as published by 10the Free Software Foundation; either version 2, or (at your option) 11any later version. 12 13GNU Emacs is distributed in the hope that it will be useful, 14but WITHOUT ANY WARRANTY; without even the implied warranty of 15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16GNU General Public License for more details. 17 18You should have received a copy of the GNU General Public License 19along with GNU Emacs; see the file COPYING. If not, write to 20the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21Boston, MA 02110-1301, USA. */ 22 23 24#include <config.h> 25#include <sys/types.h> 26#include <sys/file.h> 27#include <sys/stat.h> 28#include <sys/mman.h> 29#include <stdio.h> 30#include <errno.h> 31#ifdef HAVE_STRING_H 32#include <string.h> 33#endif 34#if !defined (__NetBSD__) && !defined (__OpenBSD__) 35#include <filehdr.h> 36#include <aouthdr.h> 37#include <scnhdr.h> 38#include <syms.h> 39#ifndef __linux__ 40# include <reloc.h> 41# include <elf_abi.h> 42#endif 43#else /* __NetBSD__ or __OpenBSD__ */ 44/* 45 * NetBSD/Alpha does not have 'normal' user-land ECOFF support because 46 * there's no desire to support ECOFF as the executable format in the 47 * long term. 48 */ 49#include <sys/exec_ecoff.h> 50 51/* Structures, constants, etc., that NetBSD defines strangely. */ 52#define filehdr ecoff_filehdr 53#define aouthdr ecoff_aouthdr 54#define scnhdr ecoff_scnhdr 55#define HDRR struct ecoff_symhdr 56#define pHDRR HDRR * 57#define cbHDRR sizeof(HDRR) 58#ifdef __OpenBSD__ 59#define ALPHAMAGIC ECOFF_MAGIC_NATIVE_ALPHA 60#else 61#define ALPHAMAGIC ECOFF_MAGIC_NETBSD_ALPHA 62#endif 63#define ZMAGIC ECOFF_ZMAGIC 64 65/* Misc. constants that NetBSD doesn't define at all. */ 66#define ALPHAUMAGIC 0617 67#define _MIPS_NSCNS_MAX 35 68#define STYP_TEXT 0x00000020 69#define STYP_DATA 0x00000040 70#define STYP_BSS 0x00000080 71#define STYP_RDATA 0x00000100 72#define STYP_SDATA 0x00000200 73#define STYP_SBSS 0x00000400 74#define STYP_INIT 0x80000000 75#define _TEXT ".text" 76#define _DATA ".data" 77#define _BSS ".bss" 78#define _INIT ".init" 79#define _RDATA ".rdata" 80#define _SDATA ".sdata" 81#define _SBSS ".sbss" 82#endif /* __NetBSD__ || __OpenBSD__ */ 83 84static void fatal_unexec __P ((char *, char *)); 85static void mark_x __P ((char *)); 86 87static void update_dynamic_symbols __P ((char *, char *, int, struct aouthdr)); 88 89#define READ(_fd, _buffer, _size, _error_message, _error_arg) \ 90 errno = EEOF; \ 91 if (read (_fd, _buffer, _size) != _size) \ 92 fatal_unexec (_error_message, _error_arg); 93 94#define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \ 95 if (write (_fd, _buffer, _size) != _size) \ 96 fatal_unexec (_error_message, _error_arg); 97 98#define SEEK(_fd, _position, _error_message, _error_arg) \ 99 errno = EEOF; \ 100 if (lseek (_fd, _position, L_SET) != _position) \ 101 fatal_unexec (_error_message, _error_arg); 102 103#ifdef HAVE_UNISTD_H 104#include <unistd.h> 105#else 106void *sbrk (); 107#endif 108 109#define EEOF -1 110 111static struct scnhdr *text_section; 112static struct scnhdr *rel_dyn_section; 113static struct scnhdr *dynstr_section; 114static struct scnhdr *dynsym_section; 115static struct scnhdr *init_section; 116static struct scnhdr *finit_section; 117static struct scnhdr *rdata_section; 118static struct scnhdr *rconst_section; 119static struct scnhdr *data_section; 120static struct scnhdr *pdata_section; 121static struct scnhdr *xdata_section; 122static struct scnhdr *got_section; 123static struct scnhdr *lit8_section; 124static struct scnhdr *lit4_section; 125static struct scnhdr *sdata_section; 126static struct scnhdr *sbss_section; 127static struct scnhdr *bss_section; 128 129static struct scnhdr old_data_scnhdr; 130 131static unsigned long Brk; 132 133struct headers { 134 struct filehdr fhdr; 135 struct aouthdr aout; 136 struct scnhdr section[_MIPS_NSCNS_MAX]; 137}; 138 139 140 141/* Define name of label for entry point for the dumped executable. */ 142 143#ifndef DEFAULT_ENTRY_ADDRESS 144#define DEFAULT_ENTRY_ADDRESS __start 145#endif 146 147void 148unexec (new_name, a_name, data_start, bss_start, entry_address) 149 char *new_name, *a_name; 150 unsigned long data_start, bss_start, entry_address; 151{ 152 int new, old; 153 char * oldptr; 154 struct headers ohdr, nhdr; 155 struct stat stat; 156 long pagesize, brk; 157 long newsyms, symrel; 158 int nread; 159 int i; 160 long vaddr, scnptr; 161#define BUFSIZE 8192 162 char buffer[BUFSIZE]; 163 164 if ((old = open (a_name, O_RDONLY)) < 0) 165 fatal_unexec ("opening %s", a_name); 166 167 new = creat (new_name, 0666); 168 if (new < 0) fatal_unexec ("creating %s", new_name); 169 170 if ((fstat (old, &stat) == -1)) 171 fatal_unexec ("fstat %s", a_name); 172 173 oldptr = (char *)mmap (0, stat.st_size, PROT_READ, MAP_FILE|MAP_SHARED, old, 0); 174 175 if (oldptr == (char *)-1) 176 fatal_unexec ("mmap %s", a_name); 177 178 close (old); 179 180 /* This is a copy of the a.out header of the original executable */ 181 182 ohdr = (*(struct headers *)oldptr); 183 184 /* This is where we build the new header from the in-memory copy */ 185 186 nhdr = *((struct headers *)TEXT_START); 187 188 /* First do some consistency checks */ 189 190 if (nhdr.fhdr.f_magic != ALPHAMAGIC 191 && nhdr.fhdr.f_magic != ALPHAUMAGIC) 192 { 193 fprintf (stderr, "unexec: input file magic number is %x, not %x or %x.\n", 194 nhdr.fhdr.f_magic, ALPHAMAGIC, ALPHAUMAGIC); 195 exit (1); 196 } 197 198 if (nhdr.fhdr.f_opthdr != sizeof (nhdr.aout)) 199 { 200 fprintf (stderr, "unexec: input a.out header is %d bytes, not %d.\n", 201 nhdr.fhdr.f_opthdr, (int)sizeof (nhdr.aout)); 202 exit (1); 203 } 204 if (nhdr.aout.magic != ZMAGIC) 205 { 206 fprintf (stderr, "unexec: input file a.out magic number is %o, not %o.\n", 207 nhdr.aout.magic, ZMAGIC); 208 exit (1); 209 } 210 211 212 /* Now check the existence of certain header section and grab 213 their addresses. */ 214 215#define CHECK_SCNHDR(ptr, name, flags) \ 216 ptr = NULL; \ 217 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \ 218 if (strncmp (nhdr.section[i].s_name, name, 8) == 0) \ 219 { \ 220 if (nhdr.section[i].s_flags != flags) \ 221 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \ 222 nhdr.section[i].s_flags, flags, name); \ 223 ptr = nhdr.section + i; \ 224 } \ 225 226 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT); 227 CHECK_SCNHDR (init_section, _INIT, STYP_INIT); 228#ifdef _REL_DYN 229 CHECK_SCNHDR (rel_dyn_section, _REL_DYN, STYP_REL_DYN); 230#endif /* _REL_DYN */ 231#ifdef _DYNSYM 232 CHECK_SCNHDR (dynsym_section, _DYNSYM, STYP_DYNSYM); 233#endif /* _REL_DYN */ 234#ifdef _DYNSTR 235 CHECK_SCNHDR (dynstr_section, _DYNSTR, STYP_DYNSTR); 236#endif /* _REL_DYN */ 237#ifdef _FINI 238 CHECK_SCNHDR (finit_section, _FINI, STYP_FINI); 239#endif /* _FINI */ 240 CHECK_SCNHDR (rdata_section, _RDATA, STYP_RDATA); 241#ifdef _RCONST 242 CHECK_SCNHDR (rconst_section, _RCONST, STYP_RCONST); 243#endif 244#ifdef _PDATA 245 CHECK_SCNHDR (pdata_section, _PDATA, STYP_PDATA); 246#endif /* _PDATA */ 247#ifdef _GOT 248 CHECK_SCNHDR (got_section, _GOT, STYP_GOT); 249#endif /* _GOT */ 250 CHECK_SCNHDR (data_section, _DATA, STYP_DATA); 251#ifdef _XDATA 252 CHECK_SCNHDR (xdata_section, _XDATA, STYP_XDATA); 253#endif /* _XDATA */ 254#ifdef _LIT8 255 CHECK_SCNHDR (lit8_section, _LIT8, STYP_LIT8); 256 CHECK_SCNHDR (lit4_section, _LIT4, STYP_LIT4); 257#endif /* _LIT8 */ 258 CHECK_SCNHDR (sdata_section, _SDATA, STYP_SDATA); 259 CHECK_SCNHDR (sbss_section, _SBSS, STYP_SBSS); 260 CHECK_SCNHDR (bss_section, _BSS, STYP_BSS); 261 262 263 pagesize = getpagesize (); 264 brk = (((long) (sbrk (0))) + pagesize - 1) & (-pagesize); 265 266 /* Remember the current break */ 267 268 Brk = brk; 269 270 bcopy (data_section, &old_data_scnhdr, sizeof (old_data_scnhdr)); 271 272 nhdr.aout.dsize = brk - DATA_START; 273 nhdr.aout.bsize = 0; 274 if (entry_address == 0) 275 { 276 extern DEFAULT_ENTRY_ADDRESS (); 277 nhdr.aout.entry = (unsigned long)DEFAULT_ENTRY_ADDRESS; 278 } 279 else 280 nhdr.aout.entry = entry_address; 281 282 nhdr.aout.bss_start = nhdr.aout.data_start + nhdr.aout.dsize; 283 284 if (rdata_section != NULL) 285 { 286 rdata_section->s_size = data_start - DATA_START; 287 288 /* Adjust start and virtual addresses of rdata_section, too. */ 289 rdata_section->s_vaddr = DATA_START; 290 rdata_section->s_paddr = DATA_START; 291 rdata_section->s_scnptr = text_section->s_scnptr + nhdr.aout.tsize; 292 } 293 294 data_section->s_vaddr = data_start; 295 data_section->s_paddr = data_start; 296 data_section->s_size = brk - data_start; 297 298 if (rdata_section != NULL) 299 { 300 data_section->s_scnptr = rdata_section->s_scnptr + rdata_section->s_size; 301 } 302 303 vaddr = data_section->s_vaddr + data_section->s_size; 304 scnptr = data_section->s_scnptr + data_section->s_size; 305 if (lit8_section != NULL) 306 { 307 lit8_section->s_vaddr = vaddr; 308 lit8_section->s_paddr = vaddr; 309 lit8_section->s_size = 0; 310 lit8_section->s_scnptr = scnptr; 311 } 312 if (lit4_section != NULL) 313 { 314 lit4_section->s_vaddr = vaddr; 315 lit4_section->s_paddr = vaddr; 316 lit4_section->s_size = 0; 317 lit4_section->s_scnptr = scnptr; 318 } 319 if (sdata_section != NULL) 320 { 321 sdata_section->s_vaddr = vaddr; 322 sdata_section->s_paddr = vaddr; 323 sdata_section->s_size = 0; 324 sdata_section->s_scnptr = scnptr; 325 } 326#ifdef _XDATA 327 if (xdata_section != NULL) 328 { 329 xdata_section->s_vaddr = vaddr; 330 xdata_section->s_paddr = vaddr; 331 xdata_section->s_size = 0; 332 xdata_section->s_scnptr = scnptr; 333 } 334#endif 335#ifdef _GOT 336 if (got_section != NULL) 337 { 338 bcopy (got_section, buffer, sizeof (struct scnhdr)); 339 340 got_section->s_vaddr = vaddr; 341 got_section->s_paddr = vaddr; 342 got_section->s_size = 0; 343 got_section->s_scnptr = scnptr; 344 } 345#endif /*_GOT */ 346 if (sbss_section != NULL) 347 { 348 sbss_section->s_vaddr = vaddr; 349 sbss_section->s_paddr = vaddr; 350 sbss_section->s_size = 0; 351 sbss_section->s_scnptr = scnptr; 352 } 353 if (bss_section != NULL) 354 { 355 bss_section->s_vaddr = vaddr; 356 bss_section->s_paddr = vaddr; 357 bss_section->s_size = 0; 358 bss_section->s_scnptr = scnptr; 359 } 360 361 WRITE (new, (char *)TEXT_START, nhdr.aout.tsize, 362 "writing text section to %s", new_name); 363 WRITE (new, (char *)DATA_START, nhdr.aout.dsize, 364 "writing data section to %s", new_name); 365 366#ifdef _GOT 367#define old_got_section ((struct scnhdr *)buffer) 368 369 if (got_section != NULL) 370 { 371 SEEK (new, old_got_section->s_scnptr, 372 "seeking to start of got_section in %s", new_name); 373 WRITE (new, oldptr + old_got_section->s_scnptr, old_got_section->s_size, 374 "writing new got_section of %s", new_name); 375 SEEK (new, nhdr.aout.tsize + nhdr.aout.dsize, 376 "seeking to end of data section of %s", new_name); 377 } 378 379#undef old_got_section 380#endif 381 382 /* 383 * Construct new symbol table header 384 */ 385 386 bcopy (oldptr + nhdr.fhdr.f_symptr, buffer, cbHDRR); 387 388#define symhdr ((pHDRR)buffer) 389 newsyms = nhdr.aout.tsize + nhdr.aout.dsize; 390 symrel = newsyms - nhdr.fhdr.f_symptr; 391 nhdr.fhdr.f_symptr = newsyms; 392 symhdr->cbLineOffset += symrel; 393 symhdr->cbDnOffset += symrel; 394 symhdr->cbPdOffset += symrel; 395 symhdr->cbSymOffset += symrel; 396 symhdr->cbOptOffset += symrel; 397 symhdr->cbAuxOffset += symrel; 398 symhdr->cbSsOffset += symrel; 399 symhdr->cbSsExtOffset += symrel; 400 symhdr->cbFdOffset += symrel; 401 symhdr->cbRfdOffset += symrel; 402 symhdr->cbExtOffset += symrel; 403 404 WRITE (new, buffer, cbHDRR, "writing symbol table header of %s", new_name); 405 406 /* 407 * Copy the symbol table and line numbers 408 */ 409 WRITE (new, oldptr + ohdr.fhdr.f_symptr + cbHDRR, 410 stat.st_size - ohdr.fhdr.f_symptr - cbHDRR, 411 "writing symbol table of %s", new_name); 412 413#ifdef _REL_DYN 414 if (rel_dyn_section) 415 update_dynamic_symbols (oldptr, new_name, new, nhdr.aout); 416#endif 417 418#undef symhdr 419 420 SEEK (new, 0, "seeking to start of header in %s", new_name); 421 WRITE (new, &nhdr, sizeof (nhdr), 422 "writing header of %s", new_name); 423 424 close (old); 425 close (new); 426 mark_x (new_name); 427} 428 429 430static void 431update_dynamic_symbols (old, new_name, new, aout) 432 char *old; /* Pointer to old executable */ 433 char *new_name; /* Name of new executable */ 434 int new; /* File descriptor for new executable */ 435 struct aouthdr aout; /* a.out info from the file header */ 436{ 437#if !defined (__linux__) && !defined (__NetBSD__) && !defined (__OpenBSD__) 438 439 typedef struct dynrel_info { 440 char * addr; 441 unsigned type:8; 442 unsigned index:24; 443 unsigned info:8; 444 unsigned pad:8; 445 } dr_info; 446 447 int nsyms = rel_dyn_section->s_size / sizeof (struct dynrel_info); 448 int i; 449 dr_info * rd_base = (dr_info *) (old + rel_dyn_section->s_scnptr); 450 Elf32_Sym * ds_base = (Elf32_Sym *) (old + dynsym_section->s_scnptr); 451 452 for (i = 0; i < nsyms; i++) { 453 register Elf32_Sym x; 454 455 if (rd_base[i].index == 0) 456 continue; 457 458 x = ds_base[rd_base[i].index]; 459 460#if 0 461 fprintf (stderr, "Object inspected: %s, addr = %lx, shndx = %x", 462 old + dynstr_section->s_scnptr + x.st_name, rd_base[i].addr, x.st_shndx); 463#endif 464 465 466 if ((ELF32_ST_BIND (x.st_info) == STB_GLOBAL) 467 && (x.st_shndx == 0) 468 /* && (x.st_value == NULL) */ 469 ) { 470 /* OK, this is probably a reference to an object in a shared 471 library, so copy the old value. This is done in several steps: 472 1. reladdr is the address of the location in question relative to 473 the start of the data section, 474 2. oldref is the addr is the mapped in temacs executable, 475 3. newref is the address of the location in question in the 476 undumped executable, 477 4. len is the size of the object reference in bytes -- 478 currently only 4 (long) and 8 (quad) are supported. 479 */ 480 register unsigned long reladdr = (long)rd_base[i].addr - old_data_scnhdr.s_vaddr; 481 char * oldref = old + old_data_scnhdr.s_scnptr + reladdr; 482 unsigned long newref = aout.tsize + reladdr; 483 int len; 484 485#if 0 486 fprintf (stderr, "...relocated\n"); 487#endif 488 489 if (rd_base[i].type == R_REFLONG) 490 len = 4; 491 else if (rd_base[i].type == R_REFQUAD) 492 len = 8; 493 else 494 fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", (char *) i); 495 496 SEEK (new, newref, "seeking to dynamic symbol in %s", new_name); 497 WRITE (new, oldref, len, "writing old dynrel info in %s", new_name); 498 } 499 500#if 0 501 else 502 fprintf (stderr, "...not relocated\n"); 503#endif 504 505 } 506 507#endif /* not __linux__ and not __NetBSD__ and not __OpenBSD__ */ 508} 509 510 511/* 512 * mark_x 513 * 514 * After successfully building the new a.out, mark it executable 515 */ 516 517static void 518mark_x (name) 519 char *name; 520{ 521 struct stat sbuf; 522 int um = umask (777); 523 umask (um); 524 if (stat (name, &sbuf) < 0) 525 fatal_unexec ("getting protection on %s", name); 526 sbuf.st_mode |= 0111 & ~um; 527 if (chmod (name, sbuf.st_mode) < 0) 528 fatal_unexec ("setting protection on %s", name); 529} 530 531static void 532fatal_unexec (s, arg) 533 char *s; 534 char *arg; 535{ 536 if (errno == EEOF) 537 fputs ("unexec: unexpected end of file, ", stderr); 538 else 539 fprintf (stderr, "unexec: %s, ", strerror (errno)); 540 fprintf (stderr, s, arg); 541 fputs (".\n", stderr); 542 exit (1); 543} 544 545/* arch-tag: 46316c49-ee08-4aa3-942b-00798902f5bd 546 (do not change this comment) */ 547