Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!uunet!husc6!think!ames!hao!boulder!sunybcs!rutgers!iuvax!pur-ee!j.cc.purdue.edu!h.cc.purdue.edu!s.cc.purdue.edu!rsk
From: rsk@s.cc.purdue.edu (Rich Kulawiec)
Newsgroups: comp.sys.sequent
Subject: undump.shar (Msg 3.0)
Message-ID: <1695@s.cc.purdue.edu>
Date: Wed, 2-Dec-87 08:52:46 EST
Article-I.D.: s.1695
Posted: Wed Dec 2 08:52:46 1987
Date-Received: Sun, 6-Dec-87 02:44:36 EST
Organization: Purdue University Computing Center
Lines: 806
Keywords: core
Approved: rsk@s.cc.purdue.edu
Thanks to fletcher@godzilla.cs.utexas.edu for bugfixes; this version has
been in use here for a few months now, and appears to be okay. The Makefile
is set up according to our local conventions; your mileage may vary.
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# Makefile
# scanargs.c
# undump.1l
# undump.c
# This archive created: Wed Dec 2 08:49:08 1987
# By: Rich Kulawiec (Purdue University Computing Center)
cat << \SHAR_EOF > Makefile
# Makefile for undump.
#
#
BIN= ${DESTDIR}/usr/local/bin
I=/usr/include
S=/usr/include/sys
DEBUG= -O
INCLUDE=
CDEFS=
CFLAGS= ${DEBUG} ${CDEFS} ${INCLUDE}
HDR=
SRC= scanargs.c undump.c
OBJ= scanargs.o undump.o
SOURCE= Makefile ${SRC} ${HDR}
all: undump
undump: ${OBJ}
${CC} ${CFLAGS} -o undump ${OBJ}
clean: FRC
rm -f undump *.o Makefile.bak a.out core errs lint.errs
depend: ${HDR} ${SRC}
maketd -a ${CDEFS} ${INCLUDE} ${SRC}
install: undump
install -c -m 751 -o binary -g system -s undump ${BIN}
lint: ${HDR} ${SRC}
lint -hxn ${CDEFS} ${INCLUDE} ${SRC}
print: ${HDR} ${SRC}
pr -f ${SOURCE} | lpr -J"Undump Source"
source: ${SOURCE}
spotless: clean FRC
rcsclean Makefile ${HDR} ${SRC}
${SOURCE}:
co $@
FRC:
# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT
scanargs.o: $I/ctype.h $I/stdio.h scanargs.c
undump.o: $I/a.out.h $I/errno.h $I/machine/exec.h $I/machine/fpu.h \
$I/machine/param.h $I/machine/ptrace.h $I/machine/vmparam.h \
$I/signal.h $I/stdio.h $S/dir.h $S/dmap.h $S/errno.h $S/mman.h \
$S/param.h $S/resource.h $S/stat.h $S/time.h $S/types.h $S/universe.h \
$S/user.h undump.c
# *** Do not add anything here - It will go away. ***
SHAR_EOF
cat << \SHAR_EOF > scanargs.c
/*
Version 7 compatible
Argument scanner, scans argv style argument list.
Some stuff is a kludge because sscanf screws up
Gary Newman - 10/4/1979 - Ampex Corp.
Modified by Spencer W. Thomas, Univ. of Utah, 5/81 to
add args introduced by a flag, add qscanargs call,
allow empty flags.
Compiling with QUICK defined generates 'qscanargs' ==
scanargs w/o floating point support; avoids huge size
of scanf.
If you make improvements we'd like to get them too.
Jay Lepreau lepreau@utah-20, decvax!{harpo,randvax}!utah-cs!lepreau
Spencer Thomas thomas@utah-20, decvax!{harpo,randvax}!utah-cs!thomas
(There seems to be a bug here in that if the last option you have
is a flag, and the user enters args incorrectly, sometimes the usage
message printed will miss the null and go flying off thru core...)
--jay for spencer
*/
#include
#include
#define YES 1
#define NO 0
#define ERROR(msg) {fprintf(stderr, "msg\n"); goto error; }
char *prformat();
#ifndef QUICK
scanargs (argc, argv, format, arglist)
#else
qscanargs (argc, argv, format, arglist)
#endif
int argc;
char **argv;
char *format;
int arglist[];
{
#ifndef QUICK
_scanargs (argc, argv, format, &arglist);
#else
_qscanargs (argc, argv, format, &arglist);
#endif
}
#ifndef QUICK
_scanargs (argc, argv, format, arglist)
#else
_qscanargs (argc, argv, format, arglist)
#endif
int argc;
char **argv;
char *format;
int *arglist[];
{
register check; /* check counter to be sure all argvs
are processed */
register char *cp;
register cnt;
char tmpflg; /* temp flag */
char c;
char numnum; /* number of numbers already processed
*/
char numstr; /* count # of strings already
processed */
char tmpcnt; /* temp count of # things already
processed */
char required;
char exflag; /* when set, one of a set of exclusive
flags is set */
char excnt; /* count of which exclusive flag is
being processed */
char *ncp; /* remember cp during flag scanning */
#ifndef QUICK
char *cntrl; /* control string for scanf's */
char junk[2]; /* junk buffer for scanf's */
cntrl = "% %1s"; /* control string initialization for
scanf's */
#endif
check = numnum = numstr = 0;
cp = format;
while (*cp)
{
required = NO;
switch (*(cp++))
{
default: /* all other chars */
break;
case '!': /* required argument */
required = YES;
case '%': /* not required argument */
switch (tmpflg = *(cp++))
{
case '-': /* argument is flag */
/* go back to label */
ncp = cp-1; /* remember */
cp -= 3;
for (excnt = exflag = 0
; *cp != ' ' && !(*cp=='-' &&(cp[-1]=='!'||cp[-1]=='%'));
(--cp, excnt++))
{
for (cnt = 1; cnt < argc; cnt++)
{
/* flags all start with - */
if (*argv[cnt] == '-' && !isdigit(argv[cnt][1]))
if (*(argv[cnt] + 1) == *cp)
{
if (*(argv[cnt] + 2) != 0)
ERROR (extra flags ignored);
if (exflag)
ERROR (more than one exclusive flag chosen);
exflag++;
required = NO;
check += cnt;
**arglist |=
(1 << excnt);
break;
}
}
}
if (required)
ERROR (flag argument missing);
cp = ncp;
if (!exflag) /* if no flags scanned, skip */
{
while (*++cp != ' ' && *cp)
if (*cp == '!' || *cp == '%')
arglist++;
}
else
cp++; /* skip over - */
while (*cp == ' ')
cp++;
arglist++;
break;
case 's': /* char string */
case 'd': /* decimal # */
case 'o': /* octal # */
case 'x': /* hexadecimal # */
#ifndef QUICK
case 'f': /* floating # */
#endif
case 'D': /* long decimal # */
case 'O': /* long octal # */
case 'X': /* long hexadecimal # */
#ifndef QUICK
case 'F': /* double precision floating # */
#endif
tmpcnt = tmpflg == 's' ? numstr : numnum;
for (cnt = 1; cnt < argc; cnt++)
{
if (tmpflg == 's')/* string */
{
if ((c = *argv[cnt]) == '-')
continue;
if (c >= '0' && c <= '9')
continue;
if (tmpcnt-- != 0)
continue;
**arglist = (int) argv[cnt];
check += cnt;
numstr++;
required = NO;
break;
}
if (*argv[cnt] == '-')
{
if(!isdigit (*(argv[cnt] + 1)))
continue;
}
else if (!isdigit(*argv[cnt]))
continue;
if (tmpcnt-- != 0)/* skip to new one */
continue;
#ifndef QUICK
/* kludge for sscanf */
if ((tmpflg == 'o' || tmpflg == 'O')
&& *argv[cnt] > '7')
ERROR (Bad numeric argument);
cntrl[1] = tmpflg;/* put in conversion */
if (sscanf (argv[cnt], cntrl, *arglist
,junk) != 1)
#else
if (numcvt(argv[cnt], tmpflg, *arglist) != 1)
#endif
ERROR (Bad numeric argument);
check += cnt;
numnum++;
required = NO;
break;
}
if (required)
switch (tmpflg)
{
case 'x':
case 'X':
ERROR (missing hexadecimal argument);
case 's':
ERROR (missing string argument);
case 'o':
case 'O':
ERROR (missing octal argument);
case 'd':
case 'D':
ERROR (missing decimal argument);
case 'f':
case 'F':
ERROR (missing floating argument);
}
arglist++;
while (*cp == ' ')
cp++;
break;
default: /* error */
fprintf (stderr, "error in call to scanargs\n");
return (0);
}
}
}
/* Count up empty flags */
for (cnt=1; cnt= '0' && *str < '0'+base)
d = *str - '0';
else if (base == 16 && *str >= 'a' && *str <= 'f')
d = 10 + *str - 'a';
else if (base == 16 && *str >= 'A' && *str <= 'F')
d = 10 + *str - 'A';
else
return 0;
retval = retval*base + d;
str++;
}
if (neg)
retval = -retval;
if (conv == 'D' || conv == 'O' || conv == 'X')
*(long *) val = retval;
else
*val = (int) retval;
return 1;
}
#endif QUICK
SHAR_EOF
cat << \SHAR_EOF > undump.1l
.TH UNDUMP 1L LOCAL
.SH NAME
undump \- convert a core dump to an executable a.out file
.SH SYNOPSIS
.B undump
.I new-a.out-file
[
.I old-a.out-file
] [
.I core-file
]
.SH DESCRIPTION
Undump reads a core dump file and the executable \*(lqa.out\*(rq file which
caused it and produces a new executable file with all static
variables initialized to the values they held at the time of the
core dump. It is primarily useful for programs which consume a large amount
of time initializing themselves (e.g. Emacs). The idea is to execute all of
the initializations first, then create a core dump (e.g. with the abort()
call). After the core dump, one uses undump to make a new executable file
with all of the initialization completed. This usually implies the use of a
global flag variable which indicates whether or not initialization has been
done.
.PP
Undump's arguments, old-a.out-file and core-file, have the default values of
\*(lqa.out\*(rq and \*(lqcore\*(rq, respectively.
.PP
Two important notes:
.IP
Undump does not preserve open files.
.IP
The undumped program will be re-entered at the beginning of main(), not at
the point where the core dump occurred.
.SH AUTHOR
Spencer W. Thomas, University of Utah.
.br
.SH BUGS
Probably should have an option to make old-a.out-file optional if the core
came from a 407 file.
SHAR_EOF
cat << \SHAR_EOF > undump.c
/*
* This program was advertised on unix-wizards. I have had such a large
* response I'm sending it out to the world.
*
* Here is the source. It works fine under 4.1bsd, I see no fundamental
* reason why it shouldn't work on an 11. (Except possibly small format
* changes in exec header or user structure.) No documentation yet.
* Usage is
* undump new-a.out-file [old-a.out-file] [core-file]
* where old-a.out-file and core-file default to "a.out" and "core",
* respectively. Probably should have an option to not require
* old-a.out-file if the core came from a 407 file.
*
* It doesn't preserve open files, and the program is re-entered at main
* when you run it. It's used locally to dump a lisp and restart it.
*
* It requires a local subroutine called scanargs, somewhat similar to
* getopt (I think). You should be able to easily get around this, though.
* =Spencer
*/
/* #define DYNIX2_5 */
/*
* undump.c - Convert a core file to an a.out.
*
* Author: Spencer W. Thomas
* Computer Science Dept.
* University of Utah
* Date: Wed Feb 17 1982
* Copyright (c) 1982 Spencer W. Thomas
*
* Usage:
* undump new-a.out [a.out] [core]
*/
#include
#include
#include
#include
#include
#include
#define PSIZE 10240
struct user u;
struct exec hdr, ohdr;
main(argc, argv)
char **argv;
{
char *new_name, *a_out_name = "a.out", *core_name = "core";
FILE *new, *a_out, *core;
if (scanargs(argc, argv, "undump new-a.out!s a.out%s core%s",
&new_name, &a_out_name, &core_name)
!= 1)
exit(1);
if ((a_out = fopen(a_out_name, "r")) == NULL)
{
perror(a_out_name);
exit(1);
}
if ((core = fopen(core_name, "r")) == NULL)
{
perror(core_name);
exit(1);
}
if ((new = fopen(new_name, "w")) == NULL)
{
perror(new_name);
exit(1);
}
read_u(core);
make_hdr(new, a_out);
copy_text(new, a_out);
copy_data(new, core);
copy_sym(new, a_out);
fclose(new);
fclose(core);
fclose(a_out);
mark_x(new_name);
}
/*
* read the u structure from the core file.
*/
read_u(core)
FILE *core;
{
if ( fread(&u, sizeof u, 1, core) != 1 )
{
perror("Couldn't read user structure from core file");
exit(1);
}
}
/*
* Make the header in the new a.out from the header in the old one
* modified by the new data size.
*/
make_hdr(new, a_out)
FILE *new, *a_out;
{
if (fread(&hdr, sizeof hdr, 1, a_out) != 1)
{
perror("Couldn't read header from a.out file");
exit(1);
}
ohdr = hdr;
if N_BADMAG(hdr)
{
fprintf(stderr, "a.out file doesn't have legal magic number\n");
exit(1);
}
#ifndef sequent
if (hdr.a_magic != u.u_exdata.ux_mag ||
hdr.a_text != u.u_exdata.ux_tsize ||
hdr.a_data != u.u_exdata.ux_dsize ||
hdr.a_entry != u.u_exdata.ux_entloc)
{
fprintf(stderr, "Core file didn't come from this a.out\n");
exit(1);
}
#endif
printf("Data segment size was %u", hdr.a_data);
#ifdef DYNIX2_5
hdr.a_data = ctob(u.u_dsize) - ctob(u.u_tsize);
#else
hdr.a_data = ctob(u.u_dsize);
#endif
hdr.a_bss = 0; /* all data is inited now! */
printf(" now is %u\n", hdr.a_data);
if (fwrite(&hdr, sizeof hdr, 1, new) != 1)
{
perror("Couldn't write header to new a.out file");
exit(1);
}
}
/*
* Copy the text from the a.out to the new a.out
*/
copy_text(new, a_out)
FILE *new, *a_out;
{
char page[PSIZE];
int txtcnt = hdr.a_text;
#ifdef sequent
txtcnt -= sizeof(struct exec);
if (fseek(new, N_TXTOFF(hdr) + sizeof(struct exec), 0) == -1)
perror("fseek new");
if (fseek(a_out, N_TXTOFF(hdr) + sizeof(struct exec), 0) == -1)
perror("fseek a.out");
#else
if (fseek(new, N_TXTOFF(hdr), 0) == -1)
perror("fseek new");
if (fseek(a_out, N_TXTOFF(hdr), 0) == -1)
perror("fseek a.out");
#endif
if (hdr.a_magic == OMAGIC)
{
printf("a.out file is not shared text, getting text from core file\n");
fseek(a_out, hdr.a_text, 1); /* skip over text */
return;
}
while (txtcnt >= PSIZE)
{
if (fread(page, PSIZE, 1, a_out) != 1)
{
perror("Read failure on a.out text");
exit(1);
}
if (fwrite(page, PSIZE, 1, new) != 1)
{
perror("Write failure in text segment");
exit(1);
}
txtcnt -= PSIZE;
}
if (txtcnt)
{
if (fread(page, txtcnt, 1, a_out) != 1)
{
perror("Read failure on a.out text");
exit(1);
}
if (fwrite(page, txtcnt, 1, new) != 1)
{
perror("Write failure in text segment");
exit(1);
}
}
}
/*
* copy the data from the core file to the new a.out
*/
copy_data(new, core)
FILE *new, *core;
{
char page[PSIZE];
#ifdef DYNIX2_5
int datacnt = ctob(u.u_dsize) - ctob(u.u_tsize);
#else
int datacnt = ctob(u.u_dsize);
#endif
#ifdef sequent
if (fseek(new, N_DATAOFF(ohdr), 0) == -1)
perror("fseek new");
#endif
if (hdr.a_magic == OMAGIC)
datacnt += u.u_tsize;
if (fseek(core, ctob(UPAGES), 0) == -1)
perror("fseek core");
while (datacnt >= PSIZE)
{
if (fread(page, PSIZE, 1, core) != 1)
{
perror("Read failure on core data");
exit(1);
}
if (fwrite(page, PSIZE, 1, new) != 1)
{
perror("Write failure in data segment");
exit(1);
}
datacnt -= PSIZE;
}
if (datacnt)
{
if (fread(page, datacnt, 1, core) != 1)
{
perror("Read failure on core data");
exit(1);
}
if (fwrite(page, datacnt, 1, new) != 1)
{
perror("Write failure in data segment");
exit(1);
}
}
}
/*
* Copy the relocation information and symbol table from the a.out to the new
*/
copy_sym(new, a_out)
FILE *new, *a_out;
{
char page[PSIZE];
int n;
#ifdef sequent
if (fseek(a_out, N_TROFF(ohdr), 0) == -1 )
perror("seek to text relocation info in a.out");
#else
fseek(a_out, ohdr.a_data, 1); /* skip over data segment */
#endif
while ((n = fread(page, 1, PSIZE, a_out)) > 0)
{
if (fwrite(page, 1, n, new) != n)
{
perror("Error writing symbol table to new a.out");
fprintf(stderr, "new a.out should be ok otherwise\n");
return;
}
}
if (n < 0)
{
perror("Error reading symbol table from a.out");
fprintf(stderr, "new a.out should be ok otherwise\n");
}
}
/*
* After succesfully building the new a.out, mark it executable
*/
mark_x(name)
char *name;
{
struct stat sbuf;
int um;
um = umask(777);
umask(um);
if (stat(name, &sbuf) == -1)
{
perror ("Can't stat new a.out");
fprintf(stderr, "Setting protection to %o\n", 0777 & ~um);
sbuf.st_mode = 0777;
}
sbuf.st_mode |= 0111 & ~um;
if (chmod(name, sbuf.st_mode) == -1)
perror("Couldn't change mode of new a.out to executable");
}
SHAR_EOF
# End of shell archive
exit 0