[alt.sources] [sun-spots] Device that gives you access to the running kernel file

guy@uunet.uu.net (Guy Harris) (08/06/90)

Archive-name: dev-vmunix/05-Aug-90
Original-posting-by: auspex!guy@uunet.uu.net (Guy Harris)
Original-subject: Device that gives you access to the running kernel file
Reposted-by: emv@math.lsa.umich.edu (Edward Vielmetti)

[Reposted from comp.sys.sun.
Comments on this service to emv@math.lsa.umich.edu (Edward Vielmetti).]

The following may be useful, or it may just be an entertaining toy.  It's
a device driver for "/dev/vmunix", an idea I came up with a while ago, to
deal with the problem of programs such as "ps" that need to get at the
kernel file that was booted, to find the kernel's symbol table. 

Normally, this isn't a headache, but those of you who have installed new
kernels, calling them something other than "/vmunix", and then tried to
run "ps" or whatever and didn't provide whatever magic argument (if any)
tells it to look elsewhere than "/vmunix", know that it can be a nuisance
on occasion.

With this driver, you open "/dev/vmunix", and you have a file descriptor
that lets you read from the kernel file that was booted, even if it's not
named "/vmunix", even if it was renamed since the system was booted (as
long as you open it once before it gets renamed), or even if it was
unlinked since the system was booted - the driver holds onto the vnode, so
it doesn't go away (well, modulo the usual NFSisms; if it's unlinked on
the client, the system should rename it rather than removing it, but if
it's unlinked on the server, you lose).

It's quite tiny, only 48 lines of code (counting blank lines and comments
:-)).

It has an "open()" routine which, the first time it's called, grabs the
name handed to the boot PROM (and if it's a null string, defaults to
"vmunix"), and opens the file in the current directory with that name. 

(This first open must be done in the root directory; the best way to do
this would be with a toy program run from one of the "/etc/rc*" files.
Ideally, this wouldn't be necessary; SunOS does permit a pseudo-device
driver, such as this one, to have an "init" routine, but it appears to be
called quite early in the boot process, before the system is ready to let
you play around with the root file system.)

It also has a "read" routine that, if the kernel file was successfully
opened, calls the "read" method for the vnode for that file.

You need to modify "sun/conf.c" to have an entry for this device.  You
should be able to just open it and read from it, and get the same data
you'd have gotten had you opened the running kernel file.

NOTE: this is, of course, maximally useful *only* if you can coerce all
kmem-groveling programs to use it.  This means whacking on various
commands and "libkvm"; either you need source, or you need to patch the
binaries to look elsewhere than "/vmunix".  I make no claim that this
driver can drop in and make this problem magically vanish....

Tested under 4.0.3, on a Sun-3E (well, on an NS5000, but "the difference
that makes no difference is no difference"...).  I was able to do "cp
/dev/vmunix /tmp/vmunix" (from the root directory, so that the first
"open" could find the file), and get the currently-running kernel file.
The test was under UFS; I've not tried it under NFS, nor under 4.1.  No
more rigorous testing has been done.  If you find bugs - or, even better,
find bugs *and* the fixes for same - or have any other comments, send 'em
to me.

NOTE: this does not constitute a commitment by Auspex to provide this as
part of SunOS on our systems.

#include <sys/errno.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/user.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/vnode.h>

#include <mon/sunromvec.h>

static struct vnode *vmunixvp;

/*ARGSUSED*/
int
vmunixopen(dev, flags)
	dev_t dev;
	int flags;
{
	register struct bootparam *bp;
	register char *vmunix_name;

	if (vmunixvp == NULL) {
		bp = (*romp->v_bootparam);
		vmunix_name = bp->bp_name;
		if (vmunix_name[0] == '\0') {
			/*
			 * No name given when booting; assume it was
			 * "vmunix".
			 */
			vmunix_name = "vmunix";
		}
		return (vn_open(vmunix_name, UIO_SYSSPACE, FREAD, 0,
		    &vmunixvp));
	} else
		return (0);
}

/*ARGSUSED*/
int
vmunixread(dev, uio)
	dev_t dev;
	register struct uio *uio;
{
	if (vmunixvp == NULL)
		return (ENOENT);

	return (VOP_RDWR(vmunixvp, uio, UIO_READ, 0, u.u_cred));
}