Subject: Re: building a userland interface to a kernel structure
To: David Maxwell <david@fundy.ca>
From: Michael L. Hitch <mhitch@lightning.oscs.montana.edu>
List: current-users
Date: 01/12/1999 11:31:00
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