Subject: Re: building a userland interface to a kernel structure
To: Michael L. Hitch <mhitch@lightning.oscs.montana.edu>
From: David Brownlee <abs@anim.dreamworks.com>
List: current-users
Date: 01/12/1999 18:07:26
Would it be worth adding this somewhere as a sample piece of
code people could reference?
David/absolute
-=- Resentment is a renewable resource -=-
On Tue, 12 Jan 1999, Michael L. Hitch wrote:
> On Tue, 12 Jan 1999, David Maxwell wrote:
>
> > On Tue, Jan 12, 1999 at 12:08:25AM -0800, dustin sallings wrote:
> > >
> > > For a kernel modification I'm doing, I need to be able to build
> > > and maintain a simple array of (arrays|hashes|linked lists) from a
> > > userland process.
> > >
> > > I don't have the slightest idea where to put this in the kernel,
> > > what to name it, or how to interface it. Can someone give me an idea?
> >
> > I'll tag onto this message and ask... I'd like to write a userland program
> > which can read the kernel disklist linked list. I've looked into the
> > kernel memory syscalls in a fair amount of detail, and looked at some
> > examples in the tree, but I can't find anything in the tree that
> > reads _structures_ from the kernel, just simple variables. I haven't
> > been able to make my code work.
>
> Here's a simple example. I don't remember where I got this - it doesn't
> look like I wrote it, although I may have modified it somewhat. [The
> program is almost 3 years old.] I have written a number of little
> kernel-groveling programs like this to make it easier to see what's going
> on in a live kernel.
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
>
> #include <sys/dkstat.h>
> #include <sys/time.h>
> #include <sys/disk.h>
>
> #include <err.h>
> #include <fcntl.h>
> #include <kvm.h>
> #include <limits.h>
> #include <nlist.h>
>
> static struct nlist namelist[] = {
> #define X_TK_NIN 0
> { "_tk_nin" }, /* tty characters in */
> #define X_TK_NOUT 1
> { "_tk_nout" }, /* tty characters out */
> #define X_CP_TIME 2
> { "_cp_time" }, /* system timer ticks */
> #define X_HZ 3
> { "_hz" }, /* ticks per second */
> #define X_STATHZ 4
> { "_stathz" },
> #define X_DISK_COUNT 5
> { "_disk_count" }, /* number of disks */
> #define X_DISKLIST 6
> { "_disklist" }, /* TAILQ of disks */
> { NULL },
> };
>
> /* Kernel pointers: nlistf and memf defined in calling program. */
> static kvm_t *kd = NULL;
> char *nlistf;
> char *memf;
>
> /* Pointer to list of disks. */
> static struct disk *dk_drivehead = NULL;
>
> /* Backward compatibility references. */
> int dk_ndrive = 0;
>
> #define KVM_ERROR(_string) { \
> warnx((_string)); \
> errx(1, kvm_geterr(kd)); \
> }
>
> /*
> * Dereference the namelist pointer `v' and fill in the local copy
> * 'p' which is of size 's'.
> */
> #define deref_nl(v, p, s) deref_kptr((void *)namelist[(v)].n_value, (p), (s));
>
> static void deref_kptr __P((void *, void *, size_t));
>
> main(int argc, char *argv[])
> {
> int i;
> struct disklist_head disk_head;
> struct disk cur_disk, *p;
> char errbuf[_POSIX2_LINE_MAX];
>
> if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL)
> errx(1, "kvm_openfiles: %s", errbuf);
>
> /* Obtain the namelist symbols from the kernel. */
> if (kvm_nlist(kd, namelist))
> KVM_ERROR("kvm_nlist failed to read symbols.");
>
> /* Get the number of attached drives. */
> deref_nl(X_DISK_COUNT, &dk_ndrive, sizeof(dk_ndrive));
>
> if (dk_ndrive < 0)
> errx(1, "invalid _disk_count %d.", dk_ndrive);
> else if (dk_ndrive == 0) {
> warnx("No drives attached.");
> }
> else {
> /* Get a pointer to the first disk. */
> deref_nl(X_DISKLIST, &disk_head, sizeof(disk_head));
> dk_drivehead = disk_head.tqh_first;
> }
>
> printf("%d drives, header %x\n", dk_ndrive, dk_drivehead);
>
> p = dk_drivehead;
> printf("Address Name Transfers Seeks Bytes\n");
> for (i = 0; i < dk_ndrive; ++i) {
> deref_kptr(p, &cur_disk, sizeof(cur_disk));
> deref_kptr(cur_disk.dk_name, errbuf, 10);
> printf("%08x %-10s%8lld%8lld%10lld\n", p, errbuf,
> cur_disk.dk_xfer, cur_disk.dk_seek, cur_disk.dk_bytes);
> p = cur_disk.dk_link.tqe_next;
> }
> }
>
> /*
> * Dereference the kernel pointer `kptr' and fill in the local copy
> * pointed to by `ptr'. The storage space must be pre-allocated,
> * and the size of the copy passed in `len'.
> */
> static void
> deref_kptr(kptr, ptr, len)
> void *kptr, *ptr;
> size_t len;
> {
> char buf[128];
>
> if (kvm_read(kd, (u_long)kptr, (char *)ptr, len) != len) {
> bzero(buf, sizeof(buf));
> snprintf(buf, (sizeof(buf) - 1),
> "can't dereference kptr 0x%lx", (u_long)kptr);
> KVM_ERROR(buf);
> }
> }
>
> ---
> Michael L. Hitch mhitch@montana.edu
> Computer Consultant
> Information Technology Center
> Montana State University Bozeman, MT USA
>