#ifndef emacs
#define PERROR(arg) perror (arg); return -1
#else
#define IN_UNEXEC
#include <config.h>
#define PERROR(file) report_error (file, new)
#endif
#ifndef CANNOT_DUMP
#if defined(COFF) && !defined(ISC4_1)
#include <coff.h>
#ifdef MSDOS
#if __DJGPP__ > 1
#include <fcntl.h>
#include <crt0.h>
static int save_djgpp_startup_flags;
#endif
#define filehdr external_filehdr
#define scnhdr external_scnhdr
#define syment external_syment
#define auxent external_auxent
#define n_numaux e_numaux
#define n_type e_type
struct aouthdr
{
unsigned short magic;
unsigned short vstamp;
unsigned long tsize;
unsigned long dsize;
unsigned long bsize;
unsigned long entry;
unsigned long text_start;
unsigned long data_start;
};
#endif
#else
#ifdef COFF_ENCAPSULATE
int need_coff_header = 1;
#include <coff-encap/a.out.encap.h>
#else
#include <a.out.h>
#endif
#endif
#include "getpagesize.h"
#ifndef makedev
#include <sys/types.h>
#endif
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/file.h>
#ifdef USG5
#include <fcntl.h>
#endif
#ifndef O_RDONLY
#define O_RDONLY 0
#endif
#ifndef O_RDWR
#define O_RDWR 2
#endif
extern char *start_of_text ();
extern char *start_of_data ();
#ifdef COFF
static long block_copy_start;
static struct filehdr f_hdr;
static struct aouthdr f_ohdr;
long bias;
long lnnoptr;
#define SYMS_START block_copy_start
static long text_scnptr;
static long data_scnptr;
static long coff_offset;
#else
#ifdef HPUX
extern void *sbrk ();
#else
#if 0
#ifdef __STDC__
extern void *sbrk ();
#else
extern char *sbrk ();
#endif
#endif
#endif
#define SYMS_START ((long) N_SYMOFF (ohdr))
#ifndef EXEC_HDR_TYPE
#define EXEC_HDR_TYPE struct exec
#endif
#ifdef HPUX
#ifdef HP9000S200_ID
#define MY_ID HP9000S200_ID
#else
#include <model.h>
#define MY_ID MYSYS
#endif
static MAGIC OLDMAGIC = {MY_ID, SHARE_MAGIC};
static MAGIC NEWMAGIC = {MY_ID, DEMAND_MAGIC};
#define N_TXTOFF(x) TEXT_OFFSET(x)
#define N_SYMOFF(x) LESYM_OFFSET(x)
static EXEC_HDR_TYPE hdr, ohdr;
#else
#if defined (USG) && !defined (IBMAIX) && !defined (IRIS) && !defined (COFF_ENCAPSULATE) && !defined (LINUX)
static struct bhdr hdr, ohdr;
#define a_magic fmagic
#define a_text tsize
#define a_data dsize
#define a_bss bsize
#define a_syms ssize
#define a_trsize rtsize
#define a_drsize rdsize
#define a_entry entry
#define N_BADMAG(x) \
(((x).fmagic)!=OMAGIC && ((x).fmagic)!=NMAGIC &&\
((x).fmagic)!=FMAGIC && ((x).fmagic)!=IMAGIC)
#define NEWMAGIC FMAGIC
#else
static EXEC_HDR_TYPE hdr, ohdr;
#define NEWMAGIC ZMAGIC
#endif
#endif
static int unexec_text_start;
static int unexec_data_start;
#ifdef COFF_ENCAPSULATE
struct coffheader coffheader;
#endif
#endif
static int pagemask;
#ifndef ADDR_CORRECT
#define ADDR_CORRECT(x) ((char *)(x) - (char*)0)
#endif
#ifdef emacs
#include "lisp.h"
static
report_error (file, fd)
char *file;
int fd;
{
if (fd)
close (fd);
report_file_error ("Cannot unexec", Fcons (build_string (file), Qnil));
}
#endif
#define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1
#define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1
#define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1
static
report_error_1 (fd, msg, a1, a2)
int fd;
char *msg;
int a1, a2;
{
close (fd);
#ifdef emacs
error (msg, a1, a2);
#else
fprintf (stderr, msg, a1, a2);
fprintf (stderr, "\n");
#endif
}
static int make_hdr ();
static int copy_text_and_data ();
static int copy_sym ();
static void mark_x ();
unexec (new_name, a_name, data_start, bss_start, entry_address)
char *new_name, *a_name;
unsigned data_start, bss_start, entry_address;
{
int new, a_out = -1;
if (a_name && (a_out = open (a_name, O_RDONLY)) < 0)
{
PERROR (a_name);
}
if ((new = creat (new_name, 0666)) < 0)
{
PERROR (new_name);
}
if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0
|| copy_text_and_data (new, a_out) < 0
|| copy_sym (new, a_out, a_name, new_name) < 0
#ifdef COFF
#ifndef COFF_BSD_SYMBOLS
|| adjust_lnnoptrs (new, a_out, new_name) < 0
#endif
#endif
)
{
close (new);
return -1;
}
close (new);
if (a_out >= 0)
close (a_out);
mark_x (new_name);
return 0;
}
static int
make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
int new, a_out;
unsigned data_start, bss_start, entry_address;
char *a_name;
char *new_name;
{
int tem;
#ifdef COFF
auto struct scnhdr f_thdr;
auto struct scnhdr f_dhdr;
auto struct scnhdr f_bhdr;
auto struct scnhdr scntemp;
register int scns;
#endif
#ifdef USG_SHARED_LIBRARIES
extern unsigned int bss_end;
#else
unsigned int bss_end;
#endif
pagemask = getpagesize () - 1;
#ifdef NO_REMAP
data_start = (int) start_of_data ();
#else
if (!data_start)
data_start = (int) start_of_data ();
#endif
data_start = ADDR_CORRECT (data_start);
#ifdef SEGMENT_MASK
data_start = data_start & ~SEGMENT_MASK;
#else
data_start = data_start & ~pagemask;
#endif
bss_end = ADDR_CORRECT (sbrk (0)) + pagemask;
bss_end &= ~ pagemask;
if (bss_start != 0)
{
bss_start = (ADDR_CORRECT (bss_start) + pagemask);
bss_start &= ~ pagemask;
if (bss_start > bss_end)
{
ERROR1 ("unexec: Specified bss_start (%u) is past end of program",
bss_start);
}
}
else
bss_start = bss_end;
if (data_start > bss_start)
{
ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)",
data_start, bss_start);
}
#ifdef COFF
coff_offset = 0L;
if (a_out >= 0)
{
#ifdef MSDOS
#if __DJGPP__ > 1
unsigned short mz_header[3];
if (read (a_out, &mz_header, sizeof (mz_header)) != sizeof (mz_header))
{
PERROR (a_name);
}
if (mz_header[0] == 0x5a4d || mz_header[0] == 0x4d5a)
{
coff_offset = (long)mz_header[2] * 512L;
if (mz_header[1])
coff_offset += (long)mz_header[1] - 512L;
lseek (a_out, coff_offset, 0);
}
else
lseek (a_out, 0L, 0);
#endif
#endif
if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
{
PERROR (a_name);
}
block_copy_start += sizeof (f_hdr);
if (f_hdr.f_opthdr > 0)
{
if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
{
PERROR (a_name);
}
block_copy_start += sizeof (f_ohdr);
}
lseek (a_out, coff_offset + sizeof (f_hdr) + f_hdr.f_opthdr, 0);
for (scns = f_hdr.f_nscns; scns > 0; scns--) {
if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
{
PERROR (a_name);
}
if (scntemp.s_scnptr > 0L)
{
if (block_copy_start < scntemp.s_scnptr + scntemp.s_size)
block_copy_start = scntemp.s_scnptr + scntemp.s_size;
}
if (strcmp (scntemp.s_name, ".text") == 0)
{
f_thdr = scntemp;
}
else if (strcmp (scntemp.s_name, ".data") == 0)
{
f_dhdr = scntemp;
}
else if (strcmp (scntemp.s_name, ".bss") == 0)
{
f_bhdr = scntemp;
}
}
}
else
{
ERROR0 ("can't build a COFF file from scratch yet");
}
#ifdef USG_SHARED_LIBRARIES
bias = bss_start - (f_ohdr.data_start + f_dhdr.s_size);
#endif
f_hdr.f_flags |= (F_RELFLG | F_EXEC);
#ifdef TPIX
f_hdr.f_nscns = 3;
#endif
#ifdef EXEC_MAGIC
f_ohdr.magic = EXEC_MAGIC;
#endif
#ifndef NO_REMAP
f_ohdr.text_start = (long) start_of_text ();
f_ohdr.tsize = data_start - f_ohdr.text_start;
f_ohdr.data_start = data_start;
#endif
f_ohdr.dsize = bss_start - f_ohdr.data_start;
f_ohdr.bsize = bss_end - bss_start;
#ifndef KEEP_OLD_TEXT_SCNPTR
f_thdr.s_size = f_ohdr.tsize;
f_thdr.s_scnptr = sizeof (f_hdr) + sizeof (f_ohdr);
f_thdr.s_scnptr += (f_hdr.f_nscns) * (sizeof (f_thdr));
#endif
#ifdef ADJUST_TEXT_SCNHDR_SIZE
f_thdr.s_size -= f_thdr.s_scnptr;
#endif
lnnoptr = f_thdr.s_lnnoptr;
#ifdef SECTION_ALIGNMENT
f_thdr.s_scnptr
= (f_thdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT;
#endif
#ifdef TPIX
f_thdr.s_scnptr = 0xd0;
#endif
text_scnptr = f_thdr.s_scnptr;
#ifdef ADJUST_TEXTBASE
text_scnptr = sizeof (f_hdr) + sizeof (f_ohdr) + (f_hdr.f_nscns) * (sizeof (f_thdr));
#endif
#ifndef KEEP_OLD_PADDR
f_dhdr.s_paddr = f_ohdr.data_start;
#endif
f_dhdr.s_vaddr = f_ohdr.data_start;
f_dhdr.s_size = f_ohdr.dsize;
f_dhdr.s_scnptr = f_thdr.s_scnptr + f_thdr.s_size;
#ifdef SECTION_ALIGNMENT
f_dhdr.s_scnptr
= (f_dhdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT;
#endif
#ifdef DATA_SECTION_ALIGNMENT
f_dhdr.s_scnptr
= (f_dhdr.s_scnptr + DATA_SECTION_ALIGNMENT) & ~DATA_SECTION_ALIGNMENT;
#endif
data_scnptr = f_dhdr.s_scnptr;
#ifndef KEEP_OLD_PADDR
f_bhdr.s_paddr = f_ohdr.data_start + f_ohdr.dsize;
#endif
f_bhdr.s_vaddr = f_ohdr.data_start + f_ohdr.dsize;
f_bhdr.s_size = f_ohdr.bsize;
f_bhdr.s_scnptr = 0L;
#ifndef USG_SHARED_LIBRARIES
bias = f_dhdr.s_scnptr + f_dhdr.s_size - block_copy_start;
#endif
if (f_hdr.f_symptr > 0L)
{
f_hdr.f_symptr += bias;
}
if (f_thdr.s_lnnoptr > 0L)
{
f_thdr.s_lnnoptr += bias;
}
#ifdef ADJUST_EXEC_HEADER
ADJUST_EXEC_HEADER;
#endif
if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
{
PERROR (new_name);
}
if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
{
PERROR (new_name);
}
#ifndef USG_SHARED_LIBRARIES
if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr))
{
PERROR (new_name);
}
if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr))
{
PERROR (new_name);
}
if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr))
{
PERROR (new_name);
}
#else
lseek (a_out, sizeof (f_hdr) + f_hdr.f_opthdr, 0);
for (scns = f_hdr.f_nscns; scns > 0; scns--)
{
if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
PERROR (a_name);
if (!strcmp (scntemp.s_name, f_thdr.s_name))
{
if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr))
PERROR (new_name);
}
else if (!strcmp (scntemp.s_name, f_dhdr.s_name))
{
if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr))
PERROR (new_name);
}
else if (!strcmp (scntemp.s_name, f_bhdr.s_name))
{
if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr))
PERROR (new_name);
}
else
{
if (scntemp.s_scnptr)
scntemp.s_scnptr += bias;
if (write (new, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
PERROR (new_name);
}
}
#endif
return (0);
#else
if (a_out >= 0)
{
#ifdef COFF_ENCAPSULATE
if (read (a_out, &coffheader, sizeof coffheader) != sizeof coffheader)
{
PERROR(a_name);
}
if (coffheader.f_magic != COFF_MAGIC)
{
ERROR1("%s doesn't have legal coff magic number\n", a_name);
}
#endif
if (read (a_out, &ohdr, sizeof hdr) != sizeof hdr)
{
PERROR (a_name);
}
if (N_BADMAG (ohdr))
{
ERROR1 ("invalid magic number in %s", a_name);
}
hdr = ohdr;
}
else
{
#ifdef COFF_ENCAPSULATE
ERROR0 ("can't build a COFF file from scratch yet");
#else
#ifdef MSDOS
bzero ((void *)&hdr, sizeof hdr);
#else
bzero (&hdr, sizeof hdr);
#endif
#endif
}
unexec_text_start = (long) start_of_text ();
unexec_data_start = data_start;
#ifdef ADJUST_EXEC_HEADER
ADJUST_EXEC_HEADER;
#endif
hdr.a_trsize = 0;
hdr.a_drsize = 0;
if (entry_address != 0)
hdr.a_entry = entry_address;
hdr.a_bss = bss_end - bss_start;
hdr.a_data = bss_start - data_start;
#ifdef NO_REMAP
hdr.a_text = ohdr.a_text;
#else
hdr.a_text = data_start - unexec_text_start;
#ifdef A_TEXT_OFFSET
hdr.a_text += A_TEXT_OFFSET (ohdr);
#endif
#endif
#ifdef COFF_ENCAPSULATE
{
struct coffscn *tp, *dp, *bp;
tp = &coffheader.scns[0];
dp = &coffheader.scns[1];
bp = &coffheader.scns[2];
tp->s_size = hdr.a_text + sizeof(struct exec);
dp->s_paddr = data_start;
dp->s_vaddr = data_start;
dp->s_size = hdr.a_data;
bp->s_paddr = dp->s_vaddr + dp->s_size;
bp->s_vaddr = bp->s_paddr;
bp->s_size = hdr.a_bss;
coffheader.tsize = tp->s_size;
coffheader.dsize = dp->s_size;
coffheader.bsize = bp->s_size;
coffheader.text_start = tp->s_vaddr;
coffheader.data_start = dp->s_vaddr;
}
if (write (new, &coffheader, sizeof coffheader) != sizeof coffheader)
{
PERROR(new_name);
}
#endif
if (write (new, &hdr, sizeof hdr) != sizeof hdr)
{
PERROR (new_name);
}
#if 0
#endif
#ifdef A_TEXT_OFFSET
hdr.a_text -= A_TEXT_OFFSET (ohdr);
#endif
return 0;
#endif
}
static int
copy_text_and_data (new, a_out)
int new, a_out;
{
register char *end;
register char *ptr;
#ifdef COFF
#ifdef USG_SHARED_LIBRARIES
int scns;
struct scnhdr scntemp;
lseek (a_out, sizeof (struct filehdr) + sizeof (struct aouthdr), 0);
for (scns = f_hdr.f_nscns; scns > 0; scns--)
{
if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
PERROR ("temacs");
if (!strcmp (scntemp.s_name, ".text"))
{
lseek (new, (long) text_scnptr, 0);
ptr = (char *) f_ohdr.text_start;
end = ptr + f_ohdr.tsize;
write_segment (new, ptr, end);
}
else if (!strcmp (scntemp.s_name, ".data"))
{
lseek (new, (long) data_scnptr, 0);
ptr = (char *) f_ohdr.data_start;
end = ptr + f_ohdr.dsize;
write_segment (new, ptr, end);
}
else if (!scntemp.s_scnptr)
;
else
{
char page[BUFSIZ];
int size, n;
long old_a_out_ptr = lseek (a_out, 0, 1);
lseek (a_out, scntemp.s_scnptr, 0);
for (size = scntemp.s_size; size > 0; size -= sizeof (page))
{
n = size > sizeof (page) ? sizeof (page) : size;
if (read (a_out, page, n) != n || write (new, page, n) != n)
PERROR ("emacs");
}
lseek (a_out, old_a_out_ptr, 0);
}
}
#else
#ifdef MSDOS
#if __DJGPP__ >= 2
__djgpp_exception_toggle ();
save_djgpp_startup_flags = _crt0_startup_flags;
_crt0_startup_flags &= ~(_CRT0_FLAG_NO_LFN | _CRT0_FLAG_NEARPTR);
#endif
#endif
lseek (new, (long) text_scnptr, 0);
ptr = (char *) f_ohdr.text_start;
#ifdef HEADER_INCL_IN_TEXT
ptr = (char *) (ptr + text_scnptr);
#endif
end = ptr + f_ohdr.tsize;
write_segment (new, ptr, end);
lseek (new, (long) data_scnptr, 0);
ptr = (char *) f_ohdr.data_start;
end = ptr + f_ohdr.dsize;
write_segment (new, ptr, end);
#ifdef MSDOS
#if __DJGPP__ >= 2
__djgpp_exception_toggle ();
_crt0_startup_flags = save_djgpp_startup_flags;
#endif
#endif
#endif
#else
#ifdef A_TEXT_SEEK
lseek (new, (long) A_TEXT_SEEK (hdr), 0);
#else
lseek (new, (long) N_TXTOFF (hdr), 0);
#endif
#ifdef RISCiX
{
char command[1024];
char errbuf[1024];
char address_text[32];
int proforma[4];
FILE *pfile;
char *temp_ptr;
char c;
int mcount_address, mcount_offset, count;
extern char *_execname;
sprintf (command, "nm %s | fgrep mcount", _execname);
if ( (pfile = popen(command, "r")) == NULL)
{
sprintf (errbuf, "Could not open pipe");
PERROR (errbuf);
}
count=0;
while ( ((c=getc(pfile)) != EOF) && (c != ' ') && (count < 31))
address_text[count++]=c;
address_text[count]=0;
if ((count == 0) || pclose(pfile) != NULL)
{
sprintf (errbuf, "Failed to execute the command '%s'\n", command);
PERROR (errbuf);
}
sscanf(address_text, "%x", &mcount_address);
ptr = (char *) unexec_text_start;
mcount_offset = (char *)mcount_address - ptr;
#ifdef RISCiX_1_1
#define EDATA_OFFSET 0x2c
#else
#define EDATA_OFFSET 0x30
#endif
end = ptr + mcount_offset - EDATA_OFFSET;
write_segment (new, ptr, end);
proforma[0] = bss_end;
proforma[1] = bss_end;
proforma[2] = bss_end;
proforma[3] = bss_end;
write (new, proforma, 16);
temp_ptr = ptr;
ptr = end + 16;
end = temp_ptr + hdr.a_text;
write_segment (new, ptr, end);
}
#else
ptr = (char *) unexec_text_start;
end = ptr + hdr.a_text;
write_segment (new, ptr, end);
#endif
ptr = (char *) unexec_data_start;
end = ptr + hdr.a_data;
write_segment (new, ptr, end);
#endif
return 0;
}
write_segment (new, ptr, end)
int new;
register char *ptr, *end;
{
register int i, nwrite, ret;
char buf[80];
#ifndef USE_CRT_DLL
extern int errno;
#endif
int writesize = 1 << 13;
int pagesize = getpagesize ();
char zeros[1 << 13];
bzero (zeros, sizeof (zeros));
for (i = 0; ptr < end;)
{
nwrite = (((int) ptr + writesize) & -writesize) - (int) ptr;
if (nwrite > end - ptr) nwrite = end - ptr;
ret = write (new, ptr, nwrite);
if (ret == -1
#ifdef EFAULT
&& errno == EFAULT
#endif
)
{
if (nwrite > pagesize)
nwrite = pagesize;
write (new, zeros, nwrite);
}
#if 0
else if (nwrite != ret)
{
sprintf (buf,
"unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d",
ptr, new, nwrite, ret, errno);
PERROR (buf);
}
#endif
i += nwrite;
ptr += nwrite;
}
}
static int
copy_sym (new, a_out, a_name, new_name)
int new, a_out;
char *a_name, *new_name;
{
char page[1024];
int n;
if (a_out < 0)
return 0;
#ifdef COFF
if (SYMS_START == 0L)
return 0;
#endif
#ifdef COFF
if (lnnoptr)
lseek (a_out, coff_offset + lnnoptr, 0);
else
lseek (a_out, coff_offset + SYMS_START, 0);
#else
lseek (a_out, SYMS_START, 0);
#endif
while ((n = read (a_out, page, sizeof page)) > 0)
{
if (write (new, page, n) != n)
{
PERROR (new_name);
}
}
if (n < 0)
{
PERROR (a_name);
}
return 0;
}
static void
mark_x (name)
char *name;
{
struct stat sbuf;
int um;
int new = 0;
um = umask (777);
umask (um);
if (stat (name, &sbuf) == -1)
{
PERROR (name);
}
sbuf.st_mode |= 0111 & ~um;
if (chmod (name, sbuf.st_mode) == -1)
PERROR (name);
}
#ifdef COFF
#ifndef COFF_BSD_SYMBOLS
adjust_lnnoptrs (writedesc, readdesc, new_name)
int writedesc;
int readdesc;
char *new_name;
{
register int nsyms;
register int new;
#if defined (amdahl_uts) || defined (pfa)
SYMENT symentry;
AUXENT auxentry;
#else
struct syment symentry;
union auxent auxentry;
#endif
if (!lnnoptr || !f_hdr.f_symptr)
return 0;
#ifdef MSDOS
if ((new = writedesc) < 0)
#else
if ((new = open (new_name, O_RDWR)) < 0)
#endif
{
PERROR (new_name);
return -1;
}
lseek (new, f_hdr.f_symptr, 0);
for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++)
{
read (new, &symentry, SYMESZ);
if (symentry.n_numaux)
{
read (new, &auxentry, AUXESZ);
nsyms++;
if (ISFCN (symentry.n_type) || symentry.n_type == 0x2400)
{
auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias;
lseek (new, -AUXESZ, 1);
write (new, &auxentry, AUXESZ);
}
}
}
#ifndef MSDOS
close (new);
#endif
return 0;
}
#endif
#endif
#endif