Module Name: src Committed By: pgoyette Date: Mon Jan 2 01:48:56 UTC 2017
Modified Files: src/usr.bin/vmstat: vmstat.c Log Message: Restore the kvm-grovelling code for use on crash files (where sysctl(3) is not available). Otherwise, this would always report on the current running kernel regardless of the use of -M option. To generate a diff of this commit: cvs rdiff -u -r1.209 -r1.210 src/usr.bin/vmstat/vmstat.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/vmstat/vmstat.c diff -u src/usr.bin/vmstat/vmstat.c:1.209 src/usr.bin/vmstat/vmstat.c:1.210 --- src/usr.bin/vmstat/vmstat.c:1.209 Mon Jan 2 01:02:19 2017 +++ src/usr.bin/vmstat/vmstat.c Mon Jan 2 01:48:56 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: vmstat.c,v 1.209 2017/01/02 01:02:19 pgoyette Exp $ */ +/* $NetBSD: vmstat.c,v 1.210 2017/01/02 01:48:56 pgoyette Exp $ */ /*- * Copyright (c) 1998, 2000, 2001, 2007 The NetBSD Foundation, Inc. @@ -70,7 +70,7 @@ __COPYRIGHT("@(#) Copyright (c) 1980, 19 #if 0 static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 3/1/95"; #else -__RCSID("$NetBSD: vmstat.c,v 1.209 2017/01/02 01:02:19 pgoyette Exp $"); +__RCSID("$NetBSD: vmstat.c,v 1.210 2017/01/02 01:48:56 pgoyette Exp $"); #endif #endif /* not lint */ @@ -309,7 +309,9 @@ __dead static void usage(void); void doforkst(void); void hist_traverse(int, const char *); -void hist_dodump(int[], unsigned int); +void hist_dodump(struct kern_history *); +void hist_traverse_sysctl(int, const char *); +void hist_dodump_sysctl(int[], unsigned int); char **choosedrives(char **); @@ -475,7 +477,10 @@ main(int argc, char *argv[]) (HISTLIST|HISTDUMP)) errx(1, "you may list or dump," " but not both!"); - hist_traverse(todo, histname); + if (memf != NULL) + hist_traverse(todo, histname); + else + hist_traverse_sysctl(todo, histname); (void)putchar('\n'); } if (todo & FORKSTAT) { @@ -2000,6 +2005,127 @@ deref_kptr(const void *kptr, void *ptr, void hist_traverse(int todo, const char *histname) { + struct kern_history_head histhead; + struct kern_history hist, *histkva; + char *name = NULL; + size_t namelen = 0; + + if (histnl[0].n_value == 0) { + warnx("kernel history is not compiled into the kernel."); + return; + } + + deref_kptr((void *)histnl[X_KERN_HISTORIES].n_value, &histhead, + sizeof(histhead), histnl[X_KERN_HISTORIES].n_name); + + if (histhead.lh_first == NULL) { + warnx("No active kernel history logs."); + return; + } + + if (todo & HISTLIST) + (void)printf("Active kernel histories:"); + + for (histkva = LIST_FIRST(&histhead); histkva != NULL; + histkva = LIST_NEXT(&hist, list)) { + deref_kptr(histkva, &hist, sizeof(hist), "histkva"); + if (name == NULL || hist.namelen > namelen) { + if (name != NULL) + free(name); + namelen = hist.namelen; + if ((name = malloc(namelen + 1)) == NULL) + err(1, "malloc history name"); + } + + deref_kptr(hist.name, name, namelen, "history name"); + name[namelen] = '\0'; + if (todo & HISTLIST) + (void)printf(" %s", name); + else { + /* + * If we're dumping all histories, do it, else + * check to see if this is the one we want. + */ + if (histname == NULL || strcmp(histname, name) == 0) { + if (histname == NULL) + (void)printf( + "\nkernel history `%s':\n", name); + hist_dodump(&hist); + } + } + } + + if (todo & HISTLIST) + (void)putchar('\n'); + + if (name != NULL) + free(name); +} + +/* + * Actually dump the history buffer at the specified KVA. + */ +void +hist_dodump(struct kern_history *histp) +{ + struct kern_history_ent *histents, *e; + size_t histsize; + char *fmt = NULL, *fn = NULL; + size_t fmtlen = 0, fnlen = 0; + unsigned i; + + histsize = sizeof(struct kern_history_ent) * histp->n; + + if ((histents = malloc(histsize)) == NULL) + err(1, "malloc history entries"); + + (void)memset(histents, 0, histsize); + + deref_kptr(histp->e, histents, histsize, "history entries"); + i = histp->f; + do { + e = &histents[i]; + if (e->fmt != NULL) { + if (fmt == NULL || e->fmtlen > fmtlen) { + if (fmt != NULL) + free(fmt); + fmtlen = e->fmtlen; + if ((fmt = malloc(fmtlen + 1)) == NULL) + err(1, "malloc printf format"); + } + if (fn == NULL || e->fnlen > fnlen) { + if (fn != NULL) + free(fn); + fnlen = e->fnlen; + if ((fn = malloc(fnlen + 1)) == NULL) + err(1, "malloc function name"); + } + + deref_kptr(e->fmt, fmt, fmtlen, "printf format"); + fmt[fmtlen] = '\0'; + + deref_kptr(e->fn, fn, fnlen, "function name"); + fn[fnlen] = '\0'; + + (void)printf("%06ld.%06ld ", (long int)e->tv.tv_sec, + (long int)e->tv.tv_usec); + (void)printf("%s#%ld@%d: ", fn, e->call, e->cpunum); + (void)printf(fmt, e->v[0], e->v[1], e->v[2], e->v[3]); + (void)putchar('\n'); + } + i = (i + 1) % histp->n; + } while (i != histp->f); + + free(histents); + if (fmt != NULL) + free(fmt); + if (fn != NULL) + free(fn); +} + +void +hist_traverse_sysctl(int todo, const char *histname) +{ int error; int mib[4]; unsigned int i; @@ -2010,14 +2136,14 @@ hist_traverse(int todo, const char *hist miblen = __arraycount(mib); error = sysctlnametomib("kern.hist", mib, &miblen); if (error == ENOENT) { - warnx("kernel history is not compiled into the kernel."); - return; - } + warnx("kernel history is not compiled into the kernel."); + return; + } if (error != 0) { err(1, "nametomib failed"); return; } - + /* get the list of nodenames below kern.hist */ mib[2] = CTL_QUERY; memset(&query, 0, sizeof(query)); @@ -2029,56 +2155,56 @@ hist_traverse(int todo, const char *hist return; } if (len == 0) { - warnx("No active kernel history logs."); - return; - } - + warnx("No active kernel history logs."); + return; + } + len = len / sizeof(histnode[0]); /* get # of entries returned */ - if (todo & HISTLIST) - (void)printf("Active kernel histories:"); - + if (todo & HISTLIST) + (void)printf("Active kernel histories:"); + for (i = 0; i < len; i++) { - if (todo & HISTLIST) + if (todo & HISTLIST) (void)printf(" %s", histnode[i].sysctl_name); - else { - /* - * If we're dumping all histories, do it, else - * check to see if this is the one we want. - */ + else { + /* + * If we're dumping all histories, do it, else + * check to see if this is the one we want. + */ if (histname == NULL || strcmp(histname, histnode[i].sysctl_name) == 0) { - if (histname == NULL) - (void)printf( + if (histname == NULL) + (void)printf( "\nkernel history `%s':\n", histnode[i].sysctl_name); mib[2] = histnode[i].sysctl_num; mib[3] = CTL_EOL; - hist_dodump(mib, 4); - } - } - } - - if (todo & HISTLIST) - (void)putchar('\n'); -} - -/* - * Actually dump the history buffer at the specified KVA. - */ -void -hist_dodump(int mib[], unsigned int miblen) -{ + hist_dodump_sysctl(mib, 4); + } + } + } + + if (todo & HISTLIST) + (void)putchar('\n'); + } + + /* + * Actually dump the history buffer at the specified KVA. + */ + void +hist_dodump_sysctl(int mib[], unsigned int miblen) + { struct sysctl_history *hist; struct sysctl_history_event *e; - size_t histsize; + size_t histsize; char *strp; - unsigned i; + unsigned i; char *fmt = NULL, *fn = NULL; - + hist = NULL; histsize = 0; - do { + do { errno = 0; if (sysctl(mib, miblen, hist, &histsize, NULL, 0) == 0) break; @@ -2089,13 +2215,13 @@ hist_dodump(int mib[], unsigned int mibl } while (errno == ENOMEM); if (errno != 0) err(1, "sysctl failed"); - + strp = (char *)(&hist->sh_events[hist->sh_listentry.shle_numentries]); - + (void)printf("%"PRIu32" entries, next is %"PRIu32"\n", hist->sh_listentry.shle_numentries, hist->sh_listentry.shle_nextfree); - + i = hist->sh_listentry.shle_nextfree; do { @@ -2110,13 +2236,13 @@ hist_dodump(int mib[], unsigned int mibl e->she_cpunum); (void)printf(fmt, e->she_values[0], e->she_values[1], e->she_values[2], e->she_values[3]); - (void)putchar('\n'); - } + (void)putchar('\n'); + } i = (i + 1) % hist->sh_listentry.shle_numentries; } while (i != hist->sh_listentry.shle_nextfree); - + free(hist); -} + } static void usage(void)