864 lines
25 KiB
C
864 lines
25 KiB
C
static char sccsid[] = "@(#)99 1.16 src/bos/usr/bin/sysdumpdev/tbl.c, cmddump, bos411, 9428A410j 6/10/91 16:01:42";
|
|
|
|
/*
|
|
* COMPONENT_NAME: CMDDUMP system dump control and formatting
|
|
*
|
|
* FUNCTIONS: c_tableinit, da_tableinit
|
|
*
|
|
* ORIGINS: 27
|
|
*
|
|
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
|
|
* combined with the aggregated modules for this product)
|
|
* SOURCE MATERIALS
|
|
* (C) COPYRIGHT International Business Machines Corp. 1988, 1989
|
|
* All Rights Reserved
|
|
*
|
|
* US Government Users Restricted Rights - Use, duplication or
|
|
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
|
|
*/
|
|
|
|
/*
|
|
* Fill in the "table of contents" for a dump file.
|
|
* There are two such tables.
|
|
* 1. component_name/starting cdt offset (C_table)
|
|
* 2. data_area_name/starting offset (ZDa_table)
|
|
* One per component.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/dump.h>
|
|
#include <sys/dasd.h>
|
|
#include <sys/hd_config.h>
|
|
#include "dmpfmt.h"
|
|
|
|
#define TBL_INCR 16 /* realloc increment */
|
|
|
|
extern char *malloc(), *realloc();
|
|
|
|
extern checkflg; /* exit with error if sync lost */
|
|
extern char *Dumpfile; /* name of the dump file */
|
|
extern int comp_is_lvm; /* special processing for lvm */
|
|
|
|
struct cdt0 Cdt0; /* current component dump table */
|
|
|
|
static struct c_table *C_table; /* table of cdt headers */
|
|
static c_tbl_size; /* current size. grows by TBL_INCR */
|
|
static c_tbl_idx; /* current index */
|
|
|
|
struct da_table *ZDa_table; /* table of data areas */
|
|
|
|
struct da_table *kern_dt; /* kernel da_table */
|
|
static da_tbl_size; /* current size. grows by TBL_INCR */
|
|
static da_tbl_idx; /* current index */
|
|
|
|
static BMoffset; /* offset to bitmap */
|
|
|
|
static struct c_table *get_ct(); /* ensure space in C_table */
|
|
static struct da_table *get_da(); /* ensure space in ZDa_table */
|
|
|
|
static ce_read();
|
|
|
|
#ifdef _NO_PROTO
|
|
void setupvg();
|
|
struct pvol *getpvol();
|
|
struct lvol* getlvol();
|
|
int getwork_Q();
|
|
struct buf *getbpool();
|
|
static read_da();
|
|
int xread();
|
|
int readfrompage();
|
|
off_t dump_addr();
|
|
int ddistance ();
|
|
int getbitmap();
|
|
void rdpb();
|
|
#else
|
|
void setupvg( struct da_table *kdt, struct volgrp *vg );
|
|
struct pvol *getpvol( struct da_table *kdt, char *addr );
|
|
struct lvol *getlvol(struct da_table *kdt, char *addr);
|
|
int getwork_Q( struct da_table *kdt, struct buf **lvworkq, struct buf ***workq);
|
|
struct buf *getbpool( struct da_table *kdt, struct buf *bp );
|
|
static read_da( struct da_table *da, char *addr, char *buf, int len );
|
|
int xread( struct da_table *da, char *addr, char *buf, int len);
|
|
int readfrompage( int pagen, char *buf, int len );
|
|
off_t dump_addr( struct da_table *da, char *addr);
|
|
int ddistance ( struct da_table *da, char *from, char *to );
|
|
int getbitmap( struct da_table *da );
|
|
void rdpb( struct pbuf *ptr, struct pbuf *buf);
|
|
#endif
|
|
|
|
/*
|
|
* NAME: c_tableinit
|
|
* FUNCTION: make a table of the names of components and their file offsets
|
|
* into the dump file
|
|
* INPUTS: none
|
|
* RETURNS: head of a table of c_table structures, terminated by
|
|
* an entry with c_offset = -1
|
|
*/
|
|
struct c_table *
|
|
c_tableinit()
|
|
{
|
|
struct c_table *ctp;
|
|
struct cdt0 h;
|
|
int offsetsv;
|
|
int offset;
|
|
int n;
|
|
int i;
|
|
|
|
if(C_table) { /* free previous table */
|
|
free( (char *) C_table);
|
|
C_table = 0;
|
|
}
|
|
offsetsv = jtell(); /* get current offset */
|
|
for(;;) {
|
|
offset = jtell(); /* start of this component dump table */
|
|
if(jread(&h,sizeof(h)) != sizeof(h))
|
|
break;
|
|
|
|
if(offset == 0) {
|
|
/* must have a magic number at offset 0 or 512 */
|
|
if(h.cdt_magic != DMP_MAGIC) {
|
|
offsetsv = offset = 512;
|
|
if((jseek(offset) != 0) ||
|
|
(jread(&h,sizeof(h)) != sizeof(h)) ||
|
|
(h.cdt_magic != DMP_MAGIC)) {
|
|
cat_eprint(CAT_DMPMAGIC,
|
|
"bad magic: %08x offset 0x%x file %s\n",
|
|
h.cdt_magic,offset,Dumpfile);
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(h.cdt_magic == 0)
|
|
break;
|
|
if(h.cdt_magic != DMP_MAGIC) { /* check for loss of sync */
|
|
cat_eprint(CAT_DMPMAGIC,
|
|
"bad magic: %08x offset 0x%x file %s\n",
|
|
h.cdt_magic,offset,Dumpfile);
|
|
exit(1);
|
|
}
|
|
ctp = get_ct(); /* set a c_table entry */
|
|
strncpy(ctp->c_name,h.cdt_name,C_NAMESIZE); /* fill in name */
|
|
ctp->c_offset = offset; /* and offset */
|
|
n = NUM_ENTRIES(&h); /* number of data areas for this component */
|
|
BMoffset = offset + sizeof(h) + n * sizeof(struct cdt_entry);
|
|
for(i = 0; i < n; i++) /* skip over each one to get to the */
|
|
ce_read(0); /* next component dump table */
|
|
jseek(BMoffset);
|
|
}
|
|
jseek(offsetsv); /* reset file pointer */
|
|
ctp = get_ct(); /* "NULL" terminate the c_table list */
|
|
ctp->c_name[0] = '\0';
|
|
ctp->c_offset = -1; /* "NULL" is -1 */
|
|
return(C_table); /* return head of table */
|
|
}
|
|
|
|
/*
|
|
* NAME: da_tableinit
|
|
* FUNCTION: make a table of the names of data areas and their file offsets
|
|
* into the dump file
|
|
* INPUTS: none
|
|
* RETURNS: head of a table of da_table structures, terminated by
|
|
* an entry with da_offset = -1
|
|
*/
|
|
struct da_table *
|
|
da_tableinit()
|
|
{
|
|
int offsetsv;
|
|
int n;
|
|
int i;
|
|
struct cdt_entry ce;
|
|
struct da_table *tp;
|
|
static int lvm_init_count;
|
|
extern void lvm_da_tableinit();
|
|
|
|
Debug("da_tableinit: offset %x\n",jtell());
|
|
if(ZDa_table && ZDa_table != (struct da_table*)(-1)) { /* free previous table */
|
|
free( (char *) ZDa_table);
|
|
ZDa_table = 0;
|
|
}
|
|
offsetsv = jtell(); /* save starting offset */
|
|
if(jread(&Cdt0,sizeof(Cdt0)) != sizeof(Cdt0)) /* read cdt header */
|
|
goto da_exit;
|
|
|
|
if(offsetsv == 0) {
|
|
/* must have a magic number at offset 0 or 512 */
|
|
if(Cdt0.cdt_magic != DMP_MAGIC) {
|
|
offsetsv = 512;
|
|
if((jseek(offsetsv) != 0) ||
|
|
(jread(&Cdt0,sizeof(Cdt0)) != sizeof(Cdt0)))
|
|
goto da_exit;
|
|
}
|
|
}
|
|
|
|
if(Cdt0.cdt_magic == 0)
|
|
goto da_exit;
|
|
if(Cdt0.cdt_magic != DMP_MAGIC) {
|
|
cat_eprint(CAT_DMPMAGIC,
|
|
"bad magic: %08x offset 0x%x file %s\n",
|
|
Cdt0.cdt_magic,offsetsv,Dumpfile);
|
|
goto da_exit;
|
|
}
|
|
n = NUM_ENTRIES(&Cdt0);
|
|
BMoffset = offsetsv + sizeof(Cdt0) + n * sizeof(ce);
|
|
bzero(&ce,sizeof(ce));
|
|
for(i = 0; i < n; i++) {
|
|
tp = get_da();
|
|
tp->da_bmoffset = BMoffset;
|
|
tp->da_offset = tp->da_bmoffset + BITMAPSIZE(ce.d_ptr,ce.d_len);
|
|
ce_read(&ce); /* sets BMoffset to start of next bitmap */
|
|
strncpy(tp->da_name,ce.d_name,DA_NAMESIZE);
|
|
tp->da_ptr = (int)ce.d_ptr;
|
|
tp->da_len = ce.d_len;
|
|
Debug("da_tableinit: tp=%x bmoffset=%x offset=%x name='%s'\n",
|
|
tp,tp->da_bmoffset,tp->da_offset,ce.d_name);
|
|
}
|
|
jseek(offsetsv); /* restore file offset */
|
|
tp = get_da();
|
|
tp->da_name[0] = '\0';
|
|
tp->da_offset = -1; /* "NULL" terminate */
|
|
|
|
/*
|
|
* if this is the LVM component,
|
|
* use the tp's to find the vg's and refill in the component entry table.
|
|
* Also, switch to the kernel dump to use the kernel segment for finding
|
|
* the LVM structures.
|
|
*
|
|
* Set a kernel_segment_offset for use in displaying the lvm structures
|
|
* in the display options. Also, form a table of lbufs and associated
|
|
* pbufs.
|
|
*/
|
|
comp_is_lvm = FALSE; /* lvm_da_tableinit not used */
|
|
if (lvm_init_count++ == 0 && !strcmp(Cdt0.cdt_name, "lvm")) {
|
|
lvm_da_tableinit();
|
|
}
|
|
lvm_init_count--;
|
|
|
|
da_exit:
|
|
return(ZDa_table);
|
|
}
|
|
|
|
/*
|
|
* NAME: get_ct
|
|
* FUNCTION: allocate a c_table structure
|
|
* INPUTS: none
|
|
* RETURNS: pointer to c_table structure.
|
|
*
|
|
* This routine internally allocates TBL_INCR structures at a time
|
|
* to reduce the number of calls to realloc().
|
|
*/
|
|
static struct c_table *
|
|
get_ct()
|
|
{
|
|
|
|
|
|
if(C_table == 0 || c_tbl_size == 0) {
|
|
c_tbl_size = 0;
|
|
c_tbl_idx = 0;
|
|
if((C_table = MALLOC(TBL_INCR,struct c_table)) == 0) {
|
|
perror("malloc");
|
|
exit(1);
|
|
}
|
|
c_tbl_size += TBL_INCR;
|
|
} else if(c_tbl_idx == c_tbl_size) {
|
|
c_tbl_size += TBL_INCR;
|
|
if((C_table = REALLOC(C_table,c_tbl_size,struct c_table)) == 0) {
|
|
perror("realloc");
|
|
exit(1);
|
|
}
|
|
}
|
|
memset(&C_table[c_tbl_idx],0,sizeof(C_table[0]));
|
|
return(&C_table[c_tbl_idx++]);
|
|
}
|
|
|
|
/*
|
|
* NAME: get_da
|
|
* FUNCTION: allocate a da_table structure
|
|
* INPUTS: none
|
|
* RETURNS: pointer to da_table structure.
|
|
*
|
|
* This routine internally allocates TBL_INCR structures at a time
|
|
* to reduce the number of calls to realloc().
|
|
*/
|
|
static struct da_table *
|
|
get_da()
|
|
{
|
|
if(ZDa_table == 0 || da_tbl_size == 0) {
|
|
da_tbl_size = 0;
|
|
da_tbl_idx = 0;
|
|
if((ZDa_table = MALLOC(TBL_INCR,struct da_table)) == 0) {
|
|
perror("malloc");
|
|
exit(1);
|
|
}
|
|
da_tbl_size += TBL_INCR;
|
|
} else if(da_tbl_idx == da_tbl_size) {
|
|
da_tbl_size += TBL_INCR;
|
|
if((ZDa_table = REALLOC(ZDa_table,da_tbl_size,struct da_table)) == 0) {
|
|
perror("realloc");
|
|
exit(1);
|
|
}
|
|
}
|
|
memset(&ZDa_table[da_tbl_idx],0,sizeof(ZDa_table[0]));
|
|
return(&ZDa_table[da_tbl_idx++]);
|
|
}
|
|
|
|
/*
|
|
* NAME: ce_read
|
|
* FUNCTION: read the next component dump entry structure
|
|
* INPUTS: cep pointer to dump entry structure to fill
|
|
* if 0, allocate an internal structure.
|
|
* RETURNS: none
|
|
*
|
|
* The variable BMoffset is set to just after the last byte in the data area.
|
|
*/
|
|
|
|
static bitmap_t bm[DMP_MAXPAGES / sizeof(bitmap_t)];
|
|
|
|
static
|
|
ce_read(cep0)
|
|
struct cdt_entry *cep0;
|
|
{
|
|
int i;
|
|
int count;
|
|
int tcount;
|
|
int addr;
|
|
int npages;
|
|
int bitmapsize;
|
|
int offsetsv;
|
|
struct cdt_entry *cep;
|
|
struct cdt_entry ce;
|
|
|
|
cep = cep0 ? cep0 : &ce;
|
|
Debug("ce_read: offset=%x\n",jtell());
|
|
jread(cep,sizeof(*cep));
|
|
offsetsv = jtell();
|
|
bitmapsize = BITMAPSIZE(cep->d_ptr,cep->d_len);
|
|
npages = NPAGES(cep->d_ptr,cep->d_len);
|
|
Debug("ce_read: cep->d_ptr=%x len=%x bmsize=%x npages=%x BMoffset=%x\n",
|
|
cep->d_ptr,cep->d_len,bitmapsize,npages,BMoffset);
|
|
jseek(BMoffset);
|
|
jread(bm,bitmapsize);
|
|
addr = (int)cep->d_ptr;
|
|
count = cep->d_len;
|
|
BMoffset += bitmapsize;
|
|
Debug("ce_read: offset=%x PAGESIZE=%x bm[0]=%x\n",jtell(),PAGESIZE,bm[0]);
|
|
for(i = 0; i < npages; i++) {
|
|
tcount = MIN(count,PAGESIZE-(unsigned)addr % PAGESIZE);
|
|
Debug("tcount=%x addr=%x\n",tcount,addr);
|
|
if(ISBITMAP(bm,i))
|
|
BMoffset += tcount;
|
|
else
|
|
Debug("PAGE %d not in mem\n",i);
|
|
count -= tcount;
|
|
addr += tcount;
|
|
}
|
|
Debug("return: BMoffset=%x\n",BMoffset);
|
|
jseek(offsetsv);
|
|
}
|
|
|
|
int lvm_debug;
|
|
#define LVM_DEBUG(da) if (lvm_debug) { \
|
|
printf("LVM_DA_SET: da=%x bmoffset=%x offset=%x\n", \
|
|
da, da->da_bmoffset, da->da_offset); \
|
|
printf("\tda_name=%s da_ptr=%x da_len=%x\n", \
|
|
da->da_name, da->da_ptr, da->da_len); }
|
|
|
|
/* set component dump table entries for LVM */
|
|
#define LVM_DA_SET(name, ptr, len) da = get_da(); \
|
|
strncpy(da->da_name,name,DA_NAMESIZE); \
|
|
da->da_bmoffset = kern_dt->da_bmoffset;\
|
|
da->da_offset = kern_dt->da_offset; \
|
|
da->da_ptr = ptr; \
|
|
da->da_len = len; \
|
|
LVM_DEBUG(da)
|
|
|
|
static struct pbuf *hd_pbuf; /* anchor pbuf list for LVM */
|
|
|
|
/*
|
|
* NAME: lvm_da_tableinit
|
|
*
|
|
* FUNCTION: make a table of the names of data areas and their file offsets
|
|
* into the dump file. This routine takes the lvm dump component
|
|
* list of addresses of volgrp structures in the kernel segment
|
|
* to construct a dump table of addresses into the kernel segment
|
|
* for LVM data structures. The lvm component table in the dump
|
|
* is used to construct this more useful table for lvm dumps
|
|
* unless the kernel component, with the kernel segment, was
|
|
* not part of the dump.
|
|
* INPUTS: none
|
|
*
|
|
* RETURNS: none
|
|
*/
|
|
void
|
|
lvm_da_tableinit()
|
|
{
|
|
int i, n;
|
|
struct c_table *c;
|
|
struct cdt_entry ce;
|
|
struct da_table *da;
|
|
struct da_table *ldt; /* LVM data table */
|
|
struct vglist { /* vglist as in sysx/lvm/hd_top.c */
|
|
struct volgrp *vgp;
|
|
long major_num;
|
|
} *vglistp;
|
|
struct volgrp *vg; /* LVM volume group */
|
|
off_t lvmoffsetv; /* offset to LVM component */
|
|
int nvgs; /* number of volume groups */
|
|
int lvm_comp_set;
|
|
|
|
lvm_comp_set = FALSE;
|
|
lvmoffsetv = jtell(); /* save offset to lvm component */
|
|
|
|
if ((i = c_lookup("bos")) == -1) /* find "bos" component */
|
|
goto lvm_out; /* kernel segment not in the dump */
|
|
c = &C_table[i]; /* get bos component dump table */
|
|
jseek(c->c_offset); /* seek to bos component dump table*/
|
|
|
|
/* kerrnel segment is in the dump, form the LVM table */
|
|
ldt = ZDa_table; /* save lvm table */
|
|
|
|
ZDa_table = 0; /* da_tableinit would frees ZDa_table*/
|
|
|
|
if (kern_dt == NULL) {
|
|
kern_dt = da_tableinit(); /* bos component da_table entry */
|
|
ZDa_table = 0;
|
|
}
|
|
if (kern_dt == NULL || strcmp("kernel", kern_dt->da_name))
|
|
goto lvm_out;
|
|
/* !!! i = Da_lookup("kernel") !!! */
|
|
/* !!! kern_dt += i; !!! *//* select "kernel" da_table entry */
|
|
|
|
ZDa_table = 0; /* so get_da allocates new table */
|
|
/* first entry in the LVM component is the address of the pbuf anchor */
|
|
hd_pbuf = (struct pbuf *)ldt->da_ptr;
|
|
LVM_DA_SET("dmpbuf", (int)hd_pbuf, sizeof(struct pbuf *));
|
|
|
|
/* get volume group addresses to be looked up in the kernel segment */
|
|
vglistp = (struct vglist *) malloc((ldt+1)->da_len);
|
|
if (vglistp == NULL)
|
|
goto lvm_out;
|
|
|
|
if (read_da(ldt+1, (char *)(ldt+1)->da_ptr, (char *)vglistp, (ldt+1)->da_len) <= 0)
|
|
goto lvm_out;
|
|
|
|
/* scan array of vg pointers, lookup data in kernel segment */
|
|
nvgs = (ldt+1)->da_len / sizeof(struct vglist);
|
|
for ( ; nvgs > 0; nvgs--, vglistp++) {
|
|
if (vglistp->vgp) {
|
|
setupvg(kern_dt, vglistp->vgp);
|
|
}
|
|
}
|
|
|
|
da = get_da();
|
|
da->da_name[0] = '\0';
|
|
da->da_offset = -1; /* "NULL" terminate */
|
|
|
|
free( (char *) ldt); /* done with init LVM da_table */
|
|
ldt = ZDa_table;
|
|
ZDa_table = 0;
|
|
lvm_comp_set = TRUE;
|
|
|
|
lvm_out:
|
|
/* efficiency is no concern here */
|
|
jseek(lvmoffsetv); /* reset offset to start of lvm */
|
|
da_tableinit(); /* re-initialize Cdt0 to LVM */
|
|
if (lvm_comp_set == TRUE)
|
|
comp_is_lvm = TRUE;
|
|
ZDa_table = ldt; /* set ZDa_table to lvm */
|
|
/* no need to reset Cdt0->cdt_len, it will not be used again */
|
|
}
|
|
|
|
/*
|
|
* NAME: setupvg
|
|
*
|
|
* FUNCTION: make a table of the names of data areas and their file offsets
|
|
* into the dump file for a volume gruop.
|
|
*
|
|
* INPUTS: kdt (pointer to the kernel dump table), vg (volume group pointer)
|
|
*
|
|
* RETURNS: none
|
|
*/
|
|
void
|
|
setupvg( struct da_table *kdt, struct volgrp *vg )
|
|
{
|
|
int i, n, numpps, numbytes;
|
|
struct da_table *da;
|
|
struct volgrp v;
|
|
struct buf *b, *pb;
|
|
struct buf **workq;
|
|
struct lvol *lv;
|
|
struct pvol *pv;
|
|
|
|
if (read_da(kdt, (char *)vg, (char *)&v, sizeof(struct volgrp))
|
|
== sizeof(struct volgrp)) {
|
|
LVM_DA_SET( "volgrp", (int)vg, sizeof(struct volgrp) );
|
|
|
|
vg = &v;
|
|
/* dump the physical volumes in the volume group */
|
|
for (n = 0; n < MAXPVS; ++n) { /* loop thru pvol structs */
|
|
if (vg->pvols[n] == NULL)
|
|
continue;
|
|
pv = getpvol(kdt, (char *)vg->pvols[n]);
|
|
if (pv && pv->dev != HD_NODEVICE) {
|
|
LVM_DA_SET( "pvol", (int)vg->pvols[n], sizeof(struct pvol) );
|
|
if (pv->defect_tbl)
|
|
LVM_DA_SET( "dfct_tbl", /* defect table entry */
|
|
(int)pv->defect_tbl,
|
|
sizeof(struct defect_tbl));
|
|
} /* PV dump info set */
|
|
} /* end PVs for loop */
|
|
|
|
/* dump the logical volumes in the volume group */
|
|
for (n=0; n < MAXLVS; ++n) { /* loop thru lvol structs */
|
|
if (vg->lvols[n]) {
|
|
lv = getlvol(kdt, (char *)vg->lvols[n]); /* dump the LV */
|
|
if (lv == NULL)
|
|
continue;
|
|
LVM_DA_SET( "lvol", (int)vg->lvols[n], sizeof(struct lvol) );
|
|
|
|
/* dump work_Q and buffers */
|
|
if (lv->work_Q) {
|
|
LVM_DA_SET( "work_Q", (int)lv->work_Q,
|
|
(sizeof(struct buf *)) * WORKQ_SIZE);
|
|
|
|
if (getwork_Q(kdt, lv->work_Q, &workq) > 0)
|
|
for (i = 0; i < WORKQ_SIZE; i++) {
|
|
if (pb = workq[i]) {
|
|
LVM_DA_SET("workqbuf", (int)pb,
|
|
sizeof(struct buf));
|
|
b = getbpool(kdt, pb);
|
|
for (; b && b->av_back;) {
|
|
LVM_DA_SET("workqbuf", (int)b->av_back,
|
|
sizeof(struct buf));
|
|
b = getbpool(kdt, b->av_back);
|
|
}
|
|
}
|
|
}
|
|
} /* end the work buf for loop */
|
|
|
|
/* dump the partitions for the mirrors */
|
|
for (i = 0; i < 3; i++) { /* up to 3 PPs per LP */
|
|
if (lv->parts[i]) {
|
|
numpps = BLK2PART(vg->partshift, lv->nblocks);
|
|
numbytes = numpps * sizeof(struct part);
|
|
LVM_DA_SET("parts", (int)lv->parts[i], numbytes);
|
|
}
|
|
}
|
|
}
|
|
} /* end LVs for loop */
|
|
}
|
|
}
|
|
|
|
struct pvol *
|
|
getpvol( struct da_table *kdt, char *addr )
|
|
{
|
|
static struct pvol pv;
|
|
int len = sizeof(struct pvol);
|
|
|
|
return( read_da( kdt, addr, (char *)&pv, len ) == len ? &pv : NULL );
|
|
}
|
|
|
|
struct lvol *
|
|
getlvol(struct da_table *kdt, char *addr)
|
|
{
|
|
static struct lvol lv;
|
|
int len = sizeof(struct lvol);
|
|
|
|
return ( read_da( kdt, addr, (char *)&lv, len) == len ? &lv : NULL );
|
|
}
|
|
|
|
getwork_Q( struct da_table *kdt, struct buf **lvworkq, struct buf ***workq)
|
|
{
|
|
int n;
|
|
|
|
n = WORKQ_SIZE * (sizeof(struct buf *));
|
|
*workq = (struct buf **)malloc( n );
|
|
if (workq == NULL)
|
|
return (-1);
|
|
if (read_da(kdt, (char *)lvworkq, (char *)*workq, n) != n) {
|
|
free(workq);
|
|
n = -1;
|
|
}
|
|
return(n);
|
|
}
|
|
|
|
struct buf *
|
|
getbpool( struct da_table *kdt, struct buf *bp )
|
|
{
|
|
static struct buf b;
|
|
int nbytes;
|
|
|
|
nbytes = read_da( kdt, (char *)bp, (char *)&b, sizeof(struct buf));
|
|
return (nbytes == sizeof(struct buf) ? &b : NULL);
|
|
}
|
|
|
|
/*
|
|
* NAME: read_da
|
|
*
|
|
* FUNCTION: used to emulate addressing virtual memory
|
|
*
|
|
* INPUTS: da - data area table of a component entry
|
|
* addr - virtual memory address of dumped component
|
|
* buf - data copied to this buffer
|
|
* len - length of memory to copy to buf
|
|
*
|
|
* RETURNS: 0 (success), -1 failure
|
|
*
|
|
* BITMAPSIZE(ptr,len) is the size in bytes of the bitmap.
|
|
* NPAGES(ptr,len) is the number of pages spanned by the virtual address
|
|
* range of the data area.
|
|
* ISBITMAP(n) is true if relative page 'n' is in the bitmap.
|
|
* These macros are also used in the dsp_da and wr_cdt() routine of the
|
|
* dmp_do() kernel dump routine, and are defined in sys/dump.h .
|
|
*/
|
|
|
|
static bitmap_t bm[DMP_MAXPAGES / sizeof(bitmap_t)];
|
|
|
|
static
|
|
read_da( struct da_table *da, char *addr, char *buf, int len )
|
|
{
|
|
off_t data_offset;
|
|
|
|
getbitmap(da); /* bitmap indicates if page is in dump image */
|
|
|
|
if ((data_offset = dump_addr(da, addr)) != -1)
|
|
if (jseek(data_offset) != -1)
|
|
return( xread(da, addr, buf, len) );
|
|
return ( -1 );
|
|
}
|
|
|
|
/* round down to block address of block containing address */
|
|
#define BALIGN(address) ( (unsigned) address & ~(PAGESIZE - 1) )
|
|
/* determine relative block number: how many blocks addr is from saddr */
|
|
#define PAGENUM(saddr, addr) ((BALIGN(addr) - BALIGN(saddr)) / PAGESIZE)
|
|
|
|
/*
|
|
* NAME: xread
|
|
*
|
|
* FUNCTION: read from a dumpfile as though reading from memory
|
|
*
|
|
* INPUTS: saddr - dumped memory address, (struct da_table)->da_ptr
|
|
* addr - read from this virtual memory address
|
|
* buf - copy into this buffer
|
|
* len - length of read to copy into buffer
|
|
*
|
|
* RETURNS: number of bytes read
|
|
*/
|
|
xread( struct da_table *da, /* data table in component */
|
|
char *addr, /* virtual memory address to read */
|
|
char *buf, /* read copies into buf */
|
|
int len /* length of memory to copy */ )
|
|
{
|
|
int pagen; /* specifies page to read from */
|
|
int offset_in_page; /* address position in first page */
|
|
int lastpage; /* last page to read from */
|
|
int count; /* count of data remaining to be read */
|
|
int n;
|
|
|
|
pagen = PAGENUM(da->da_ptr, addr);
|
|
lastpage = pagen + NPAGES(addr, len);
|
|
offset_in_page = (unsigned) addr % PAGESIZE;
|
|
count = len;
|
|
|
|
/* read first page */
|
|
count -= readfrompage( pagen, buf, MIN(count, PAGESIZE - offset_in_page) );
|
|
|
|
/* read more pages */
|
|
for( pagen++; pagen <= lastpage; pagen++, buf += n, count -= n )
|
|
n = readfrompage(pagen, buf, MIN(count, PAGESIZE));
|
|
|
|
return ( len - count );
|
|
}
|
|
|
|
/*
|
|
* NAME: readfrompage
|
|
*
|
|
* FUNCTION: read from a dumpfile as though reading from a page in memory
|
|
*
|
|
* INPUTS: pagen - page number from start of dumped pages to be read
|
|
* buf - read into buf buffer
|
|
* len - length of read to copy into buffer
|
|
*
|
|
* RETURNS: number of bytes read
|
|
*
|
|
* ISBITMAP(n) is true if relative page 'n' is in the bitmap.
|
|
*/
|
|
readfrompage( int pagen, char *buf, int len )
|
|
{
|
|
int rc;
|
|
|
|
if (len < 0 || len > PAGESIZE)
|
|
rc = -1; /* len must be 0 to PAGESIZE */
|
|
else if ( ISBITMAP(bm, pagen) )
|
|
rc = jread(buf, len); /* read data */
|
|
else {
|
|
memset(buf, 0, len); /* memory paged out or never used */
|
|
rc = len;
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
/*
|
|
* NAME: dump_addr
|
|
*
|
|
* FUNCTION: return offset of addr in dump file.
|
|
*
|
|
* INPUTS: tp - da_table for a component dump table entry
|
|
* addr - address of memory within this dump table entry
|
|
*
|
|
* RETURNS: offset of addr in the dump file.
|
|
*
|
|
* ISBITMAP(n) is true if relative page 'n' is in the bitmap.
|
|
*/
|
|
off_t
|
|
dump_addr( struct da_table *da, char *addr)
|
|
{
|
|
off_t offset; /* offset in dump image */
|
|
|
|
offset = ddistance ( da, (char *)da->da_ptr, addr );
|
|
if (offset != -1)
|
|
offset += da->da_bmoffset + BITMAPSIZE(da->da_ptr, da->da_len);
|
|
return (offset);
|
|
}
|
|
|
|
/*
|
|
* NAME: ddistance
|
|
*
|
|
* FUNCTION: distance between two addresses in a dumpfile
|
|
*
|
|
* INPUTS: da - da_table for a component dump table entry
|
|
* from - first address
|
|
* to - second address
|
|
*
|
|
* RETURNS: separation of addresses in dump file or -1 on failure
|
|
*
|
|
* ISBITMAP(n) is true if relative page 'n' is in the bitmap.
|
|
*/
|
|
ddistance ( struct da_table *da, char *from, char *to )
|
|
{
|
|
int realdist, dumpdist; /* real distance, distance in dumpfile */
|
|
int pagen; /* block dumped */
|
|
int offset_in_page; /* offset in a block */
|
|
|
|
if ((realdist = to - from) == 0)
|
|
dumpdist = 0; /* same address */
|
|
else if (realdist < 0)
|
|
dumpdist = -1; /* first address not before second address */
|
|
else if ((int)from < da->da_ptr || (int)to >= (da->da_ptr + da->da_len))
|
|
dumpdist = -1; /* address(es) outside of dumped entry */
|
|
else {
|
|
/* determine distance from beginning of data to first address */
|
|
dumpdist = 0;
|
|
pagen = PAGENUM(da->da_ptr, from); /* blocks from start of data */
|
|
offset_in_page = (unsigned) from % PAGESIZE; /* offset in first page */
|
|
|
|
getbitmap( da ); /* initialize bit map for this da_table */
|
|
|
|
/* first page may be a partial block */
|
|
if (ISBITMAP(bm, pagen))
|
|
dumpdist += MIN(realdist, PAGESIZE - offset_in_page);
|
|
realdist -= MIN(realdist, PAGESIZE - offset_in_page);
|
|
|
|
/* more pages */
|
|
for ( ; realdist > 0; pagen++, realdist -= PAGESIZE)
|
|
if ( ISBITMAP(bm, pagen) )
|
|
dumpdist += MIN(realdist, PAGESIZE);
|
|
}
|
|
|
|
return (dumpdist); /* separation of addresses in dumpfile */
|
|
}
|
|
|
|
/*
|
|
* NAME: getbitmap
|
|
*
|
|
* FUNCTION: get the bitmap for the requested da_table
|
|
*
|
|
* INPUTS: da - da_table for a component dump table entry
|
|
*
|
|
* RETURNS: none
|
|
*/
|
|
getbitmap( struct da_table *da )
|
|
{
|
|
static struct da_table *da_bm; /* indicates which da's bitmap is set */
|
|
|
|
if (da_bm != da) {
|
|
jseek(da->da_bmoffset); /* seek to bitmap */
|
|
jread(bm, BITMAPSIZE(da->da_ptr, da->da_len)); /* read bitmap */
|
|
da_bm = da; /* bitmap is set for this da_table */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* NAME: dsplookuplbuf
|
|
*
|
|
* FUNCTION: given an lbuf address, display the corresponding pbuf(s)
|
|
*
|
|
* INPUTS: addr - address of an lbuf
|
|
*
|
|
* NOTE: hd_pbuf anchors the pbufs. The pbuf field pb_forw links pbufs.
|
|
* The list is NULL terminated.
|
|
*
|
|
* MESSAGE NOTE: This is called from xtr.c which is used in crash. Will
|
|
* not be messagified/translated.
|
|
* RETURNS: none
|
|
*/
|
|
void
|
|
dsplookuplbuf(int addr)
|
|
{
|
|
int found=0; /* pbuf found */
|
|
struct pbuf pb; /* pbuf pointer */
|
|
struct pbuf *paddr; /* pbuf address */
|
|
static struct pbuf *saddr; /* start pbuf address */
|
|
|
|
printf("%x: ", (unsigned int) addr);
|
|
|
|
if (hd_pbuf && kern_dt) {
|
|
if (saddr == NULL) {
|
|
if (read_da(kern_dt, (char *)hd_pbuf, (char *) &saddr,
|
|
sizeof(struct pbuf *)) != sizeof(struct pubf *))
|
|
saddr = NULL;
|
|
}
|
|
}
|
|
if (saddr) {
|
|
rdpb(paddr = saddr, &pb);
|
|
do {
|
|
if ((int)pb.pb_lbuf == addr) {
|
|
found = 1;
|
|
printf("%x\t", (unsigned int) paddr);
|
|
}
|
|
/* Don't ever use a NULL pointer */
|
|
if( pb.pb_forw == NULL )
|
|
break;
|
|
|
|
rdpb(paddr = pb.pb_forw, &pb);
|
|
} while( paddr != saddr );
|
|
|
|
if ( found )
|
|
printf("\n");
|
|
else
|
|
printf("No pbufs found\n");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* NAME: rdpb
|
|
*
|
|
* FUNCTION: read a pbuf from the kernel dump image
|
|
*
|
|
* INPUTS: ptr - address of a pbuf in the kernel dump image
|
|
* buf - copy the pbuf into buf
|
|
*/
|
|
void
|
|
rdpb( struct pbuf *ptr, struct pbuf *buf)
|
|
{
|
|
int rc;
|
|
|
|
rc = read_da(kern_dt, (char *)ptr, (char *)buf, sizeof(struct pbuf));
|
|
if (rc != sizeof(struct pbuf)) {
|
|
buf->pb_lbuf = NULL;
|
|
buf->pb_forw = NULL;
|
|
}
|
|
}
|