V10/cmd/dumpcatch.c

Compare this file to the similar file:
Show the results in this format:

/*
 *             D U M P  C A T C H
 *
 * This program examines kernel memory through /dev/kmem, and looks at
 * the dump buffers in the dumpld line discipline (see /usr/sys/dev/dumpld.c).
 * The command takes a filename prefix.  For any active dump buffers,
 * an identification code is appended to the filename prefix, and everything
 * placed into the buffer by dumpld is appended to the resulting file.
 * The identification code is 'M.m.ls', where 'M' is the major device number,
 * 'm' is the minor device number, 'l' is the line-discipline number (from 0),
 * and 's' (side) is 'w' for the writer or 'r' for the reader.  If the old
 * version of dumpld is installed in the kernel, the identification code is
 * just the buffer number (from 0).
 *
 *
 * Written by Kurt Gollhardt  (Nirvonics, Inc.)
 * Last update Sun Mar 31 03:32:57 1985
 *
 */

#include <stdio.h>
#include <ctype.h>
#include <nlist.h>
#include <sys/types.h>
#include <sys/dumpl.h>
#include <sys/stream.h>

#define getme(s, kind, off, type)  _get(kind, off, 1, sizeof(type), &s)
#define getarray(s, kind, n, type) _get(kind, 0, n, sizeof(type), s)
#define getspace(s, n, type)  s = (type *)malloc((n) * sizeof(type))

struct nlist nl[] = {
#define _ndumpbuf   0
     {"_ndumpbuf"},
#define _dumpld     1
     {"_dumpld"},
#define _dumpver    2
     {"_dumpver"},
#define _dumpinf   3
     {"_dumpinf"},
     {""}
};

#define MEMFILE     "/dev/kmem"
#define SYMFILE     "/unix"

struct blockdump {
     struct dumpheader	 h;
     char		 buf[1024];
     char		 *fillp;
};

int  mem;
struct dumpld	    *dumpld;
struct dumpinf	    *dumpinf;
struct blockdump    *bdump;
int  ndumpbuf, dumpver;
FILE **file;
char **readp;

char *malloc(), *calloc();


main(ac, av)
     char *av[];
{
     struct dumpld  *di;
     register int   i;

     if (ac != 2) {
          fprintf(stderr, "Usage: %s filename_prefix\n", av[0]);
	  exit(1);
     }

     if (access(SYMFILE, 0) < 0) {
          perror(SYMFILE);
	  exit(2);
     }
     if ((mem = open(MEMFILE, 0)) < 0) {
          perror(MEMFILE);
	  exit(2);
     }

     nlist(SYMFILE, nl);
     if (nl[_ndumpbuf].n_value == 0) {
          fprintf(stderr, "No dumpld line-discipline present\n");
	  exit(5);
     }
     getme(ndumpbuf, _ndumpbuf, 0, int);

     if (nl[_dumpver].n_value == 0)
	  dumpver = 0;
     else
	  getme(dumpver, _dumpver, 0, int);

     getspace(dumpld, ndumpbuf, struct dumpld);
     getspace(readp, ndumpbuf, char *);
     file = (FILE **)calloc(sizeof(FILE *), ndumpbuf);
     if (dumpld == NULL || file == NULL || readp == NULL) {
          fprintf(stderr, "Can't allocate enough memory\n");
	  exit(3);
     }
     if (dumpver > 0) {
	  getspace(dumpinf, ndumpbuf, struct dumpinf);
	  getspace(bdump, ndumpbuf, struct blockdump);
	  if (dumpinf == NULL || bdump== NULL) {
	       fprintf(stderr, "Can't allocate enough memory\n");
	       exit(3);
	  }
	  for (i = 0; i < ndumpbuf; ++i)
	       bdump[i].fillp = (char *)&bdump[i];
     }

     for (;;) {
          getarray(dumpld, _dumpld, ndumpbuf, struct dumpld);
	  if (dumpver > 0)
	       getarray(dumpinf, _dumpinf, ndumpbuf, struct dumpinf);
	  for (di = dumpld; di < &dumpld[ndumpbuf]; di++)
	       if (di->base != NULL) {
	            if (file[di - dumpld] == 0)
		         new_file(di - dumpld, av[1]);
                    if (readp[di - dumpld] != di->fillp)
		         read_buf(di - dumpld, di);
               }
     }
}


new_file(i, prefix)
     char *prefix;
{
     char filename[100];

     if (dumpver == 0)
	  sprintf(filename, "%s%d", prefix, i);
     else
	  sprintf(filename, "%s%d.%d.%d%c", prefix, major(dumpinf[i].dev),
			      minor(dumpinf[i].dev), i/2, (i&1 ? 'w' : 'r'));
     if ((file[i] = fopen(filename, "a")) == NULL) {
          perror(filename);
	  exit(4);
     }

     readp[i] = dumpld[i].base;
}


read_buf(i, di)
     register struct dumpld   *di;
{
     if (di->fillp < readp[i]) {
          dump(readp[i], (di->base + di->size) - readp[i], file[i], i);
	  readp[i] = di->base;
     }
     if (di->fillp > readp[i]) {
          dump(readp[i], di->fillp - readp[i], file[i], i);
	  readp[i] = di->fillp;
     }
     fflush(file[i]);
}


char buf[BUFSIZ];

dump(loc, n, stream, i)
     char *loc;
     FILE *stream;
{
     int  count;

     if (dumpver > 0)
	  return fancy_dump(loc, n, stream, i);

     while (n > 0) {
          count = (n > BUFSIZ ? BUFSIZ : n);
	  getarray(buf, loc, count, char);
	  fwrite(buf, 1, count, stream);
	  n -= count;
	  loc += count;
     }
}


fancy_dump(loc, count, stream, i)
     char      *loc;
     FILE      *stream;
{
     register struct blockdump	   *bd = &bdump[i];
     register int   n, have_block;

     while (count > 0) {
	  have_block = 0;
	  n = bd->buf - bd->fillp;
	  if (n <= 0) {
	       have_block = 1;
	       n += bd->h.count;
	  }
	  if (count < n) {
	       have_block = 0;
	       n = count;
	  }
	  if (n > 0) {
	       getarray(bd->fillp, loc, n, char);
	       loc += n;  bd->fillp += n;
	       count -= n;
	  }
	  if (have_block) {
	       dump_block(bd, stream);
	       bd->fillp = (char *)bd;
	  }
     }
}


#define BYTE_PER_LINE	 16

dump_block(bd, stream)
     struct blockdump	 *bd;
     FILE		 *stream;
{
     print_type(bd->h.type, stream);
     fprintf(stream, ":%s", (bd->h.count == 0 ? "\n" : ""));
     bd->fillp = bd->buf;
     while (bd->h.count > 0) {
	  dump_line(bd, stream);
	  bd->h.count -= BYTE_PER_LINE;
	  bd->fillp += BYTE_PER_LINE;
     }
}


dump_line(bd, stream)
     struct blockdump	 *bd;
     FILE		 *stream;
{
     register int   n, byte;
     register char  *p;
     char ascii[BYTE_PER_LINE+1];

     putc('\t', stream);
     p = bd->fillp;
     for (n = 0; n < BYTE_PER_LINE; n++) {
	  byte = *p++ & 0xFF;
	  if (n < bd->h.count)
	       fprintf(stream, "%02x ", byte);
	  else
	       fprintf(stream, "   ");
	  ascii[n] = (n < bd->h.count && isprint(byte) ? byte : '.');
     }
     ascii[BYTE_PER_LINE] = '\0';
     fprintf(stream, "!%s!\n", ascii);
}


char *mtype_names[] = {
     "DATA",   "BREAK",	 "HANGUP", "DELIM",  "ECHO",   "ACK",	 "IOCTL",
     "DELAY",  "CTL",	 "PASS",   "SIGNAL", "FLUSH",  "STOP",	 "START",
     "IOCACK", "IOCNAK", "CLOSE",  "YDEL",   "NDEL",   "IOCWAIT",NULL
};
int  mtype_codes[] = {
     M_DATA,   M_BREAK,	 M_HANGUP, M_DELIM,  M_ECHO,   M_ACK,	 M_IOCTL,
     M_DELAY,  M_CTL,	 M_PASS,   M_SIGNAL, M_FLUSH,  M_STOP,	 M_START,
     M_IOCACK, M_IOCNAK, M_CLOSE,  M_YDEL,   M_NDEL,   M_IOCWAIT,0
};

print_type(type, stream)
     FILE      *stream;
{
     register int   i;

     for (i = 0; mtype_names[i] != NULL; ++i)
	  if (mtype_codes[i] == type) {
	       fputs(mtype_names[i], stream);
	       return;
	  }

     fprintf(stream, "[%02x]", type);
}


_get(addr, off, n, size, loc)
unsigned long addr;
char *loc;
{
     if (addr < sizeof(nl)/sizeof(nl[0]))
          addr = nl[addr].n_value;
     addr += off*size;
     lseek(mem, addr, 0);
     read(mem, loc, n*size);
     return(addr);
}