270 lines
9.0 KiB
C
270 lines
9.0 KiB
C
/* dump-hp9k.c: Dump for the HP-PA. It needs some work; for instance, it
|
|
* currently assumes that the data space is the last space in the a.out
|
|
* file. If it weren't the last space, the code would have to adjust
|
|
* pointers (such as header.space_location) that point into spaces beyond
|
|
* the data space, as the data space in the new a.out is larger than that
|
|
* in the original a.out.
|
|
*
|
|
* Also, it is unclear how the checksum field in the a.out header has
|
|
* to be computed.
|
|
*
|
|
* An a.out file must not have holes in HP-UX (or exec(2) would complain
|
|
* about an invalid data segment), therefore we cannot lseek over the
|
|
* ununsed parts of the heap.
|
|
*
|
|
* The code to support dump with a dynamically linked a.out is a hack.
|
|
* I have no idea why it works and if it will continue to work in
|
|
* newer OS releases.
|
|
*
|
|
* $Id$
|
|
*
|
|
* Copyright 1990, 1991, 1992, 1993, 1994, 1995, Oliver Laumann, Berlin
|
|
* Copyright 2002, 2003 Sam Hocevar <sam@zoy.org>, Paris
|
|
*
|
|
* This software was derived from Elk 1.2, which was Copyright 1987, 1988,
|
|
* 1989, Nixdorf Computer AG and TELES GmbH, Berlin (Elk 1.2 has been written
|
|
* by Oliver Laumann for TELES Telematic Services, Berlin, in a joint project
|
|
* between TELES and Nixdorf Microprocessor Engineering, Berlin).
|
|
*
|
|
* Oliver Laumann, TELES GmbH, Nixdorf Computer AG and Sam Hocevar, as co-
|
|
* owners or individual owners of copyright in this software, grant to any
|
|
* person or company a worldwide, royalty free, license to
|
|
*
|
|
* i) copy this software,
|
|
* ii) prepare derivative works based on this software,
|
|
* iii) distribute copies of this software or derivative works,
|
|
* iv) perform this software, or
|
|
* v) display this software,
|
|
*
|
|
* provided that this notice is not removed and that neither Oliver Laumann
|
|
* nor Teles nor Nixdorf are deemed to have made any representations as to
|
|
* the suitability of this software for any purpose nor are held responsible
|
|
* for any defects of this software.
|
|
*
|
|
* THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
|
|
*/
|
|
|
|
#include AOUT_H
|
|
|
|
#define copy(from,to,size) {\
|
|
char buf[4096];\
|
|
unsigned int len = (size), n;\
|
|
\
|
|
while (len > 0) {\
|
|
if ((n = read (from, buf, 4096)) == -1) {\
|
|
Dump_Finalize;\
|
|
Primitive_Error ("error reading old a.out: ~E");\
|
|
}\
|
|
if (write (to, buf, n) == -1) {\
|
|
Dump_Finalize;\
|
|
Primitive_Error ("error writing new a.out: ~E");\
|
|
}\
|
|
len -= n;\
|
|
}\
|
|
}
|
|
|
|
Object P_Dump (Object ofile) {
|
|
struct header hdr;
|
|
struct som_exec_auxhdr auxhdr;
|
|
unsigned int data_size;
|
|
int delta;
|
|
struct stat stat;
|
|
extern void *sbrk();
|
|
|
|
Dump_Prolog;
|
|
|
|
/* Read a.out header and first aux header
|
|
*/
|
|
if (read (afd, (char *)&hdr, sizeof (hdr)) != sizeof (hdr) ||
|
|
lseek (afd, (off_t)hdr.aux_header_location, SEEK_SET) == -1 ||
|
|
read (afd, (char *)&auxhdr, sizeof (auxhdr)) != sizeof (auxhdr)) {
|
|
Dump_Finalize;
|
|
Primitive_Error ("can't read a.out headers");
|
|
}
|
|
if (hdr.a_magic != EXEC_MAGIC && hdr.a_magic != SHARE_MAGIC &&
|
|
hdr.a_magic != DEMAND_MAGIC) {
|
|
Dump_Finalize;
|
|
Primitive_Error ("bad magic number ~s in a.out",
|
|
Make_Integer (hdr.a_magic));
|
|
}
|
|
if (auxhdr.som_auxhdr.type != HPUX_AUX_ID) {
|
|
Dump_Finalize;
|
|
Primitive_Error ("bad aux header id ~s in a.out",
|
|
Make_Integer (auxhdr.som_auxhdr.type));
|
|
}
|
|
|
|
/* Copy old file up to beginning of data space
|
|
*/
|
|
(void)lseek (afd, (off_t)0, SEEK_SET);
|
|
copy (afd, ofd, auxhdr.exec_dfile);
|
|
|
|
#ifdef HPSHLIB
|
|
/* Save data segments of shared libraries
|
|
*/
|
|
Save_Shared_Data ();
|
|
#endif
|
|
|
|
/* Write data space (doesn't skip holes in heap yet)
|
|
*/
|
|
Was_Dumped = 1;
|
|
Brk_On_Dump = sbrk (0);
|
|
data_size = Brk_On_Dump - (char *)auxhdr.exec_dmem;
|
|
if (write (ofd, (char *)auxhdr.exec_dmem, data_size) != data_size) {
|
|
Dump_Finalize;
|
|
Primitive_Error ("error writing data space: ~E");
|
|
}
|
|
|
|
/* Check if data space was last space in a.out file.
|
|
* Should not just quit, but adjust all pointers that point
|
|
* beyond end of data space
|
|
*/
|
|
(void)fstat (afd, &stat);
|
|
if (lseek (afd, (off_t)auxhdr.exec_dsize, SEEK_CUR) != stat.st_size)
|
|
Primitive_Error ("$DATA$ not last space in a.out file");
|
|
|
|
/* Write new headers.
|
|
* Do we have to recalculate the checksum? The manual doesn't
|
|
* say how the checksum is calculated.
|
|
*/
|
|
delta = data_size - auxhdr.exec_dsize;
|
|
hdr.som_length += delta;
|
|
auxhdr.exec_dsize = data_size;
|
|
auxhdr.exec_bsize = 0;
|
|
(void)lseek (ofd, (off_t)0, SEEK_SET);
|
|
if (write (ofd, (char *)&hdr, sizeof (hdr)) == -1 ||
|
|
lseek (ofd, (off_t)hdr.aux_header_location, SEEK_SET) == -1 ||
|
|
write (ofd, (char *)&auxhdr, sizeof (auxhdr)) == -1) {
|
|
Dump_Finalize;
|
|
Primitive_Error ("error writing a.out headers: ~E");
|
|
}
|
|
|
|
Dump_Epilog;
|
|
}
|
|
|
|
#ifdef HPSHLIB
|
|
|
|
/* Save and restore data segments of shared libraries.
|
|
*
|
|
* When the running program is dumped, we copy the data segment of
|
|
* each shared library into a malloced area so that it gets saved
|
|
* into the newly created a.out.
|
|
*
|
|
* On startup of the new a.out, we have to restore the data segments.
|
|
* To do so, we first have to re-load all libraries that were present
|
|
* in the old a.out when dump was called.
|
|
* As the libraries may now get mapped to different locations, we
|
|
* call mmap with an anonymous file to make the memory at the old
|
|
* locations accessible again.
|
|
*/
|
|
|
|
#include <dl.h>
|
|
#include <sys/mman.h>
|
|
|
|
#define MAX_SHARED 1024
|
|
|
|
struct shared_data {
|
|
struct shl_descriptor desc;
|
|
char *oldaddr; /* Start of data segment */
|
|
char *saved; /* Saved contents of data segment */
|
|
} shared_data[MAX_SHARED], *lsp = shared_data;
|
|
|
|
#ifdef DEBUG_DUMP
|
|
static char Z[1024];
|
|
# define W write(1,Z,strlen(Z))
|
|
#endif
|
|
|
|
Save_Shared_Data () {
|
|
struct shl_descriptor *p;
|
|
struct shared_data *sp;
|
|
int i;
|
|
|
|
/* Assumptions: 1st shared library has index 1;
|
|
* we can stop as soon as shl_get fails
|
|
*/
|
|
for (i = 1; shl_get (i, &p) != -1 ; i++) {
|
|
#ifdef DEBUG_DUMP
|
|
sprintf (Z, "Saving shared lib %s\n", p->filename); W;
|
|
#endif
|
|
for (sp = shared_data; sp != lsp &&
|
|
strcmp (sp->desc.filename, p->filename) != 0; sp++)
|
|
;
|
|
if (sp == lsp) {
|
|
#ifdef DEBUG_DUMP
|
|
sprintf (Z, " (new library)\n"); W;
|
|
#endif
|
|
if (sp == shared_data + MAX_SHARED)
|
|
Primitive_Error ("too many shared libraries");
|
|
lsp++;
|
|
sp->desc = *p;
|
|
sp->saved = Safe_Malloc (p->dend - p->dstart);
|
|
sp->oldaddr = (char *)p->dstart;
|
|
}
|
|
}
|
|
for (sp = shared_data; sp != lsp; sp++) {
|
|
#ifdef DEBUG_DUMP
|
|
sprintf (Z, " copy data seg from %x to %x len %d\n",
|
|
sp->oldaddr, sp->saved, sp->desc.dend - sp->desc.dstart); W;
|
|
#endif
|
|
memcpy (sp->saved, sp->oldaddr, sp->desc.dend - sp->desc.dstart);
|
|
}
|
|
}
|
|
|
|
Restore_Shared_Data () {
|
|
struct shared_data *sp;
|
|
struct shl_descriptor *p;
|
|
shl_t tmp;
|
|
|
|
for (sp = shared_data; sp != lsp; sp++) {
|
|
/*
|
|
* Assumption: libraries whose names start with /lib/ or
|
|
* with /usr/lib/ were present in the original a.out and
|
|
* need not be re-loaded
|
|
*/
|
|
#ifdef DEBUG_DUMP
|
|
sprintf (Z, "Restoring shared lib %s\n", sp->desc.filename); W;
|
|
#endif
|
|
if (strncmp (sp->desc.filename, "/lib/", 5) != 0 &&
|
|
strncmp (sp->desc.filename, "/usr/lib/", 8) != 0) {
|
|
/*
|
|
* Re-load the library and make sure memory locations
|
|
* at the old start of data segment are mapped
|
|
*/
|
|
#ifdef DEBUG_DUMP
|
|
sprintf (Z, " (re-loading)\n"); W;
|
|
#endif
|
|
tmp = shl_load (sp->desc.filename, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
|
|
if (tmp == 0)
|
|
exit (1); /* There's nothing we can do... */
|
|
(void)shl_gethandle (tmp, &p);
|
|
sp->desc = *p;
|
|
|
|
/* Try to mnumap the region in any case. If MAP_REPLACE is
|
|
* there, use it.
|
|
*/
|
|
(void)munmap (sp->oldaddr, sp->desc.dend - sp->desc.dstart);
|
|
#ifndef MAP_REPLACE
|
|
# define MAP_REPLACE 0
|
|
#endif
|
|
if (mmap (sp->oldaddr, sp->desc.dend - sp->desc.dstart,
|
|
PROT_READ|PROT_WRITE,
|
|
MAP_REPLACE|MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
|
|
-1, 0) == (char *)-1) {
|
|
sprintf (Z, "mmap failed[%d]\n", errno); W;
|
|
exit (1);
|
|
}
|
|
}
|
|
#ifdef DEBUG_DUMP
|
|
sprintf (Z, " copy data seg from %x to %x len %d\n", sp->saved,
|
|
sp->oldaddr, sp->desc.dend-sp->desc.dstart); W;
|
|
#endif
|
|
memcpy (sp->oldaddr, sp->saved, sp->desc.dend - sp->desc.dstart);
|
|
/*
|
|
* Initial break must be set as soon as data segment of
|
|
* C library is restored
|
|
*/
|
|
if (strcmp (sp->desc.filename, "/lib/libc.sl") == 0)
|
|
(void)brk (Brk_On_Dump);
|
|
}
|
|
}
|
|
#endif /* HPSHLIB */
|