/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos720 src/bos/usr/bin/sysdumpdev/dumpfmt/unpack.c.S 1.1               */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* Restricted Materials of IBM                                            */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 1996                   */
/* All Rights Reserved                                                    */
/*                                                                        */
/* US Government Users Restricted Rights - Use, duplication or            */
/* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.      */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
static char sccsid[] = "@(#)69	1.1  src/bos/usr/bin/sysdumpdev/dumpfmt/unpack.c.S, cmdcrash, bos720 1/11/96 14:48:08";
/*
 * COMPONENT_NAME: (CMDCRASH) dump table extraction routines
 *
 * FUNCTIONS: 
 *	get_cdt - get a component dump table's header and entry structures.
 *	unpack - return data for a table entry.
 *
 * ORIGINS: 27
 *
 * (C) COPYRIGHT International Business Machines Corp. 1996
 * All Rights Reserved
 * Licensed Materials - Property of IBM
 *
 * US Government Users Restricted Rights - Use, duplication or
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 */
#ifdef _KERNEL
#undef _KERNEL
#endif
#include <ctype.h>
#include <sys/dump.h>
#include <sys/param.h>
#include <sys/cblock.h>
#include <stdio.h>
#include <errno.h>

#define min(a,b) ((a)<(b)?(a):(b))

/*
 * Read the component dump table from where mem is positioned at.
 * This reads the data structures, but not the dumped data.
 *
 * Input:  mem - memory object's file descriptor.
 *	   struct cdt * - Address of table to fill in.
 *	   (see /usr/include/sys/dump.h)
 *	   len - length of the structure area.
 *
 * Returns:
 *	0 - success, -1 failure and errno is set as follows:
 *	EINVAL - The header did not contain DMP_MAGIC (apparently it's
 *		 not a dump table.)
 *	ENOMEM - Not enough memory was specified.  The file will be positioned
 *		 back at the original place.  The function reads as much data
 *		 as it can.
 *	error from read() - returned if read() fails.
 */
int
get_cdt(int mem, struct cdt *c,int len)
{
    ulong start;
    int rc = 0;

    /* Make sure there's enough memory to read the header. */
    if (len < sizeof(struct cdt_head)) {
	errno = ENOMEM;
	return(-1);
    }

    /* read header */
    start = lseek(mem,0,SEEK_CUR);	/* Get current mem offset */
    if(read(mem,c,sizeof(struct cdt_head)) != sizeof(struct cdt_head)) {
	return(-1);
    }

    /* Make sure the magic number is right */
    if (c->cdt_magic != DMP_MAGIC) {
	errno = EINVAL;			/* Not a dump table */
	return(-1);
    }

    /* Read in the entries */
    if (len < c->cdt_len) {
	/* Not enough buffer space */
	rc = ENOMEM;
    } else {
	len = c->cdt_len;
    }

    /* Read the entries. */
    len = len - sizeof(struct cdt_head);
    if(read(mem,c->cdt_entry,len) != len) {
	return(-1);
    }
    if (rc) {
	lseek(mem,start,SEEK_SET);	/* Reposition mem */
	errno = rc;
	rc = -1;
    }
    return(rc);
}

/*
 * unpack cdt's data from a dump into callers buffer,
 * filling in holes with 0BADD, and return bytes read
 *
 * Input:
 *	mem - memory file descriptor.
 *	index - index of entry to retrieve, the first one is index 0.
 *	c - pointer to component dump table structure.
 *	ubuf - output buffer.
 *
 * Returns:
 *	number of bytes read.
 *	-1 on error and errno is set.
 *	errno = EINVAL if the index is out of range.
 *	errno = read() result on a read error.
 *	mem is not repositioned on an error.
 */
ulong
unpack(int mem, int index, struct cdt *c, char *ubuf)
{
    ulong bitmap_off;			/* will go back here when finished. */
    bitmap_t bitmap[8192];		/* allows up to 64M per data area */
    ulong npages;			/* # pages represented in bitmap */
    int i,j,k;
    char *buf;				/* Working buffer pointer */
    ulong addr,count,actual_cnt;

    /* check the index. */
    if (index >= NUM_ENTRIES(c)) {
	errno = EINVAL;
	return(-1);
    }

    buf = ubuf;

    /* position offset at start of data areas (at the bitmap) */
    bitmap_off = lseek(mem,0,SEEK_CUR);

    /* for each data area in this cdt */
    for(j=0; j<=index; j++) {
	/* Get # pages involved */
	npages = (ulong) NPAGES(c->cdt_entry[j].d_ptr,c->cdt_entry[j].d_len);

	/* read bitmap for this data area. */
	i = BITMAPSIZE(c->cdt_entry[j].d_ptr,c->cdt_entry[j].d_len);
	if (read(mem,bitmap,i) != i) return(-1);

	addr = (ulong)c->cdt_entry[j].d_ptr;
	count = (ulong)c->cdt_entry[j].d_len;

	/* for each page */
	for(i = 0; i < npages; i++) {
	    /* Actual # bytes to read on this page. */
	    actual_cnt = min(count,PAGESIZE-(addr%PAGESIZE));
	    /* if the page is in the dump. */
	    if(ISBITMAP(bitmap,i)) {
		/* If this is the data we want. */
		if(j==index) {
		    /* Get the data. */
		    if (read(mem,buf,actual_cnt) != actual_cnt) return(-1);

		    buf = (char *)((ulong)buf + actual_cnt);
		}
		else {
		    /* Not the entry we want.  just seek past this data. */
		    lseek(mem,actual_cnt,SEEK_CUR);
		}
	    }
	    else {
		/* page is NOT in dump. */
		if (j==index) {
		    /* we want this data, fill in zeros. */
		    for (k=actual_cnt; k==0; k--) *(buf++) = '\0';
#ifndef DONT_PRINT
		    printf("page at address 0x%x is not in the dump.\n",addr);
#endif
		}
	    }
	    count -= actual_cnt;
	    addr  += actual_cnt;
	}
    }

    /* Finished, seek back to the start of the 1st bitmap. */
    lseek(mem,bitmap_off,SEEK_SET);

    return(c->cdt_entry[j].d_len);
}