summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/sys/gmon.h5
-rw-r--r--usr.sbin/kgmon/kgmon.c34
2 files changed, 34 insertions, 5 deletions
diff --git a/sys/sys/gmon.h b/sys/sys/gmon.h
index 79434a4..90e4e22 100644
--- a/sys/sys/gmon.h
+++ b/sys/sys/gmon.h
@@ -48,8 +48,8 @@ struct gmonhdr {
int ncnt; /* size of sample buffer (plus this header) */
int version; /* version number */
int profrate; /* profiling clock rate */
- int spare[3]; /* reserved */
- /* XXX should record counter size and density */
+ int histcounter_type; /* size (in bits) and sign of HISTCOUNTER */
+ int spare[2]; /* reserved */
};
#define GMONVERSION 0x00051879
@@ -180,6 +180,7 @@ struct gmonparam {
int mexitcount_overhead;
int mexitcount_post_overhead;
int mexitcount_pre_overhead;
+ int histcounter_type;
};
extern struct gmonparam _gmonparam;
diff --git a/usr.sbin/kgmon/kgmon.c b/usr.sbin/kgmon/kgmon.c
index 8ab4227..3ee5a73 100644
--- a/usr.sbin/kgmon/kgmon.c
+++ b/usr.sbin/kgmon/kgmon.c
@@ -57,6 +57,7 @@ static const char rcsid[] =
#include <limits.h>
#include <nlist.h>
#include <paths.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -272,9 +273,37 @@ getprof(kvp)
if (sysctl(mib, 3, &kvp->gpm, &size, NULL, 0) < 0)
size = 0;
}
- if (size != sizeof kvp->gpm)
+
+ /*
+ * Accept certain undersized "structs" from old kernels. We need
+ * everything up to hashfraction, and want profrate and
+ * histcounter_type. Assume that the kernel doesn't put garbage
+ * in any padding that is returned instead of profrate and
+ * histcounter_type. This is a bad assumption for dead kernels,
+ * since kvm_read() will normally return garbage for bytes beyond
+ * the end of the actual kernel struct, if any.
+ */
+ if (size < offsetof(struct gmonparam, hashfraction) +
+ sizeof(kvp->gpm.hashfraction) || size > sizeof(kvp->gpm))
errx(4, "cannot get gmonparam: %s",
kflag ? kvm_geterr(kvp->kd) : strerror(errno));
+ bzero((char *)&kvp->gpm + size, sizeof(kvp->gpm) - size);
+ if (kvp->gpm.profrate == 0)
+ kvp->gpm.profrate = getprofhz(kvp);
+#ifdef __i386__
+ if (kvp->gpm.histcounter_type == 0) {
+ /*
+ * This fixup only works for not-so-old i386 kernels. The
+ * magic 16 is the kernel FUNCTION_ALIGNMENT. 64-bit
+ * counters are signed; smaller counters are unsigned.
+ */
+ kvp->gpm.histcounter_type = 16 /
+ (kvp->gpm.textsize / kvp->gpm.kcountsize) * CHAR_BIT;
+ if (kvp->gpm.histcounter_type == 64)
+ kvp->gpm.histcounter_type = -64;
+ }
+#endif
+
return (kvp->gpm.state);
}
@@ -344,8 +373,7 @@ dumpstate(kvp)
h.ncnt = kvp->gpm.kcountsize + sizeof(h);
h.version = GMONVERSION;
h.profrate = kvp->gpm.profrate;
- if (h.profrate == 0)
- h.profrate = getprofhz(kvp); /* ancient kernel */
+ h.histcounter_type = kvp->gpm.histcounter_type;
fwrite((char *)&h, sizeof(h), 1, fp);
/*
OpenPOWER on IntegriCloud