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)

Reply via email to