summaryrefslogtreecommitdiff
path: root/usr.sbin/kgmon
diff options
context:
space:
mode:
authorBruce Evans <bde@FreeBSD.org>2002-02-21 05:52:49 +0000
committerBruce Evans <bde@FreeBSD.org>2002-02-21 05:52:49 +0000
commit2ef41c0cb53cff8e5d4a3b0e73e0105216cd93ac (patch)
tree630078cc80ecef913760120de7f79f329132d84e /usr.sbin/kgmon
parent8c09f6fb1fc17153ec3ab2514950cc12ad3c6506 (diff)
downloadsrc-test2-2ef41c0cb53cff8e5d4a3b0e73e0105216cd93ac.tar.gz
src-test2-2ef41c0cb53cff8e5d4a3b0e73e0105216cd93ac.zip
Reserved one of the spare fields in struct gmon to record the history
counter type, as threatened in rev.1.8 (the density doesn't need to be recorded since it can be derived from other fields). This doesn't affect binary compatibility, but new utilities won't be able to depend on the contents of this field because libc/gmon/gmon.c was broken -- it wrote garbage to the spare fields. Added a history counter type field to struct gmonparam. This breaks binary compatibility a little, since kgmon wanted to read the whole struct. Fixed kgmon to only depend on reading the critical earlier parts of the struct. This should also fix 6+ year old breakage of binary compatibility when the profrate field was added. Only initialize the new field in struct gmon for now, so that the compatibility code for this (in kgmon) gets tested. The compatibility code has to guesstimate the value. The new field in struct gmonparam is for the kernel to initialize so that kgmon doesn't have to guess.
Notes
Notes: svn path=/head/; revision=91009
Diffstat (limited to 'usr.sbin/kgmon')
-rw-r--r--usr.sbin/kgmon/kgmon.c34
1 files changed, 31 insertions, 3 deletions
diff --git a/usr.sbin/kgmon/kgmon.c b/usr.sbin/kgmon/kgmon.c
index 8ab42274a750..3ee5a737cee0 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);
/*