CFLAGS+=-DINET6 -I${.CURDIR}/../../sys
SRCS= cmds.c cmdtab.c convtbl.c devs.c fetch.c ifcmds.c ifstat.c iostat.c \
keyboard.c main.c mbufs.c netcmds.c netstat.c pigs.c sensors.c swap.c \
- icmp.c mode.c ip.c tcp.c vmstat.c ip6.c icmp6.c vmmeter.c
+ icmp.c mode.c ip.c tcp.c vmstat.c ip6.c icmp6.c vmmeter.c symbols.c
DPADD= ${LIBCURSES} ${LIBTERMCAP} ${LIBM} ${LIBKVM} ${LIBDEVSTAT} ${LIBKINFO}
LDADD= -lcurses -ltermcap -lm -lkvm -ldevstat -lkinfo
BINGRP= kmem
--- /dev/null
+/*
+ * Copyright (c) 2010 The DragonFly Project. All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <ctype.h>
+#include <devinfo.h>
+#include <err.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <nlist.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <evtr.h>
+#include <stdarg.h>
+#include "symbols.h"
+
+struct symdata {
+ TAILQ_ENTRY(symdata) link;
+ const char *symname;
+ char *symaddr;
+ char symtype;
+};
+
+static TAILQ_HEAD(symlist, symdata) symlist;
+static struct symdata *symcache;
+static char *symbegin;
+static char *symend;
+
+void
+read_symbols(const char *file)
+{
+ char buf[256];
+ char cmd[256];
+ size_t buflen = sizeof(buf);
+ FILE *fp;
+ struct symdata *sym;
+ char *s1;
+ char *s2;
+ char *s3;
+
+ TAILQ_INIT(&symlist);
+
+ if (file == NULL) {
+ if (sysctlbyname("kern.bootfile", buf, &buflen, NULL, 0) < 0)
+ file = "/boot/kernel";
+ else
+ file = buf;
+ }
+ snprintf(cmd, sizeof(cmd), "nm -n %s", file);
+ if ((fp = popen(cmd, "r")) != NULL) {
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ s1 = strtok(buf, " \t\n");
+ s2 = strtok(NULL, " \t\n");
+ s3 = strtok(NULL, " \t\n");
+ if (s1 && s2 && s3) {
+ sym = malloc(sizeof(struct symdata));
+ sym->symaddr = (char *)strtoul(s1, NULL, 16);
+ sym->symtype = s2[0];
+ sym->symname = strdup(s3);
+ if (strcmp(s3, "kernbase") == 0)
+ symbegin = sym->symaddr;
+ if (strcmp(s3, "end") == 0)
+ symend = sym->symaddr;
+ TAILQ_INSERT_TAIL(&symlist, sym, link);
+ }
+ }
+ pclose(fp);
+ }
+ symcache = TAILQ_FIRST(&symlist);
+}
+
+const char *
+address_to_symbol(void *kptr, struct save_ctx *ctx)
+{
+ char *buf = ctx->save_buf;
+ int size = sizeof(ctx->save_buf);
+
+ if (symcache == NULL ||
+ (char *)kptr < symbegin || (char *)kptr >= symend
+ ) {
+ snprintf(buf, size, "%p", kptr);
+ return(buf);
+ }
+ while ((char *)symcache->symaddr < (char *)kptr) {
+ if (TAILQ_NEXT(symcache, link) == NULL)
+ break;
+ symcache = TAILQ_NEXT(symcache, link);
+ }
+ while ((char *)symcache->symaddr > (char *)kptr) {
+ if (symcache != TAILQ_FIRST(&symlist))
+ symcache = TAILQ_PREV(symcache, symlist, link);
+ }
+ snprintf(buf, size, "%s+%d", symcache->symname,
+ (int)((char *)kptr - symcache->symaddr));
+ return(buf);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010 The DragonFly Project. All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+struct save_ctx {
+ char save_buf[512];
+ const void *save_kptr;
+};
+
+void read_symbols(const char *);
+const char *address_to_symbol(void *, struct save_ctx *);
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
+#include "symbols.h"
#include <err.h>
#include <kinfo.h>
#define X_START 1
#define CPU_START 1
+#define CPU_STARTX (3 + vmm_ncpus)
#define CPU_LABEL_W 7
#define DRAW_ROW(n, y, w, fmt, args...) \
static int vmm_fetched;
static struct vmmeter *vmm_cur, *vmm_prev;
static struct kinfo_cputime *vmm_cptime_cur, *vmm_cptime_prev;
+static struct save_ctx symctx;
+static int symbols_read;
static void
getvmm(void)
#undef CPUV
#undef CPUD
+#define CPUC(idx, field) vmm_cptime_cur[idx].cp_##field
+
+ n = X_START + CPU_LABEL_W;
+
+ DRAW_ROW(n, CPU_STARTX + i, 15, "%-*s", CPUC(i, msg));
+ DRAW_ROW(n, CPU_STARTX + i, 35, "%-*s",
+ address_to_symbol((void *)(intptr_t)CPUC(i, stallpc),
+ &symctx));
+#undef CPUC
}
}
n = X_START + CPU_LABEL_W;
- DRAW_ROW(n, 0, 6, "%*s", "timer");
- DRAW_ROW(n, 0, 8, "%*s", "ipi");
- DRAW_ROW(n, 0, 8, "%*s", "extint");
- DRAW_ROW(n, 0, 7, "%*s", "user%");
- DRAW_ROW(n, 0, 7, "%*s", "nice%");
- DRAW_ROW(n, 0, 7, "%*s", "sys%");
- DRAW_ROW(n, 0, 7, "%*s", "intr%");
- DRAW_ROW(n, 0, 7, "%*s", "idle%");
+ DRAW_ROW(n, CPU_START - 1, 6, "%*s", "timer");
+ DRAW_ROW(n, CPU_START - 1, 8, "%*s", "ipi");
+ DRAW_ROW(n, CPU_START - 1, 8, "%*s", "extint");
+ DRAW_ROW(n, CPU_START - 1, 7, "%*s", "user%");
+ DRAW_ROW(n, CPU_START - 1, 7, "%*s", "nice%");
+ DRAW_ROW(n, CPU_START - 1, 7, "%*s", "sys%");
+ DRAW_ROW(n, CPU_START - 1, 7, "%*s", "intr%");
+ DRAW_ROW(n, CPU_START - 1, 7, "%*s", "idle%");
for (i = 0; i < vmm_ncpus; ++i)
mvprintw(CPU_START + i, X_START, "cpu%d", i);
+
+ n = X_START + CPU_LABEL_W;
+ DRAW_ROW(n, CPU_STARTX - 1, 15, "%-*s", "contention");
+ DRAW_ROW(n, CPU_STARTX - 1, 35, "%-*s", "function");
+
+ for (i = 0; i < vmm_ncpus; ++i)
+ mvprintw(CPU_STARTX + i, X_START, "cpu%d", i);
}
WINDOW *
openvmm(void)
{
+ if (symbols_read == 0) {
+ symbols_read = 1;
+ read_symbols(NULL);
+ }
+
if (kinfo_get_cpus(&vmm_ncpus))
err(1, "kinfo_get_cpus");