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.
This commit is contained in:
bde 2002-02-21 05:52:49 +00:00
parent d697d82de9
commit 9fe42a4fee
2 changed files with 34 additions and 5 deletions

View File

@ -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;

View File

@ -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);
/*