/* Copyright (c) 1982 Regents of the University of California */

static char sccsid[] = "@(#)coredump.c 1.4 1/25/83";

/*
 * Deal with the core dump anachronism.
 *
 * If I understood this code, I'd try to make it readable.
 */

#include "defs.h"
#include "coredump.h"
#include "machine.h"
#include "object.h"
#include "main.h"
#include <sys/param.h>
#include <sys/dir.h>
#include <machine/psl.h>
#include <machine/pte.h>
#include <sys/user.h>
#include <sys/vm.h>
#include <machine/reg.h>
#include <a.out.h>

#ifndef public
#define coredump_readin(m, r, s) coredump_xreadin(&(m), r, &(s))

#include "machine.h"
#endif

#define MAXSTKADDR (0x80000000 - ctob(UPAGES))	/* highest stack address */

typedef struct {
    Address begin;
    Address end;
    Address seekaddr;
} Map;

private Map datamap, stkmap;
private File objfile;
private struct exec hdr;

/*
 * Read the user area information from the core dump.
 */

public coredump_xreadin(mask, reg, signo)
int *mask;
Word reg[];
int *signo;
{
    register struct user *up;
    register Word *savreg;
    union {
	struct user u;
	char dummy[ctob(UPAGES)];
    } ustruct;

    objfile = fopen(objname, "r");
    if (objfile == nil) {
	fatal("can't read \"%s\"", objname);
    }
    get(objfile, hdr);
    up = &(ustruct.u);
    fread(up, ctob(UPAGES), 1, corefile);
    savreg = (Word *) &(ustruct.dummy[ctob(UPAGES)]);
    *mask = savreg[PS];
    reg[0] = savreg[R0];
    reg[1] = savreg[R1];
    reg[2] = savreg[R2];
    reg[3] = savreg[R3];
    reg[4] = savreg[R4];
    reg[5] = savreg[R5];
    reg[6] = savreg[R6];
    reg[7] = savreg[R7];
    reg[8] = savreg[R8];
    reg[9] = savreg[R9];
    reg[10] = savreg[R10];
    reg[11] = savreg[R11];
    reg[ARGP] = savreg[AP];
    reg[FRP] = savreg[FP];
    reg[STKP] = savreg[SP];
    reg[PROGCTR] = savreg[PC];
    *signo = up->u_arg[0];
    datamap.seekaddr = ctob(UPAGES);
    stkmap.begin = MAXSTKADDR - ctob(up->u_ssize);
    stkmap.end = MAXSTKADDR;
    stkmap.seekaddr = datamap.seekaddr + ctob(up->u_dsize);
    switch (hdr.a_magic) {
	case OMAGIC:
	    datamap.begin = 0;
	    datamap.end = ctob(up->u_tsize) + ctob(up->u_dsize);
	    break;

	case NMAGIC:
	case ZMAGIC:
	    datamap.begin = (Address) ptob(btop(ctob(up->u_tsize) - 1) + 1);
	    datamap.end = datamap.begin + ctob(up->u_dsize);
	    break;

	default:
	    fatal("bad magic number 0x%x", hdr.a_magic);
    }
    /*
     * Core dump not from this object file?
     */
    if (hdr.a_magic != 0 and up->u_exdata.ux_mag  != 0 and
      hdr.a_magic != up->u_exdata.ux_mag) {
	warning("core dump ignored");
	coredump = false;
	fclose(corefile);
	fclose(objfile);
	start(nil, nil, nil);
    }
}

public coredump_close()
{
    fclose(objfile);
}

public coredump_readtext(buff, addr, nbytes)
char *buff;
Address addr;
int nbytes;
{
    if (hdr.a_magic == OMAGIC) {
	coredump_readdata(buff, addr, nbytes);
    } else {
	fseek(objfile, N_TXTOFF(hdr) + addr, 0);
	fread(buff, nbytes, sizeof(Byte), objfile);
    }
}

public coredump_readdata(buff, addr, nbytes)
char *buff;
Address addr;
int nbytes;
{
    if (addr < datamap.begin) {
	if (addr < hdr.a_text && hdr.a_magic != OMAGIC) {
	    fseek(objfile, N_TXTOFF(hdr) + addr, 0);
	    fread(buff, nbytes, sizeof(Byte), objfile);
	}
	else
	    error("data address 0x%x too low (lb = 0x%x)", addr, datamap.begin);
    } else if (addr > stkmap.end) {
	error("data address 0x%x too high (ub = 0x%x)", addr, stkmap.end);
    } else if (addr < stkmap.begin) {
	fseek(corefile, datamap.seekaddr + addr - datamap.begin, 0);
	fread(buff, nbytes, sizeof(Byte), corefile);
    } else {
	fseek(corefile, stkmap.seekaddr + addr - stkmap.begin, 0);
	fread(buff, nbytes, sizeof(Byte), corefile);
    }
}
