1
0
Files
irix-657m-src/eoe/cmd/kprf/tracex.c
2022-09-29 17:59:04 +03:00

553 lines
9.2 KiB
C

#ident "$Revision: 1.1 $"
/*
* Name:
* tracex
*
* Usage:
* tracex ordfile funcfile outfile kernel cmd [ args ]
*
* Description:
* 'ordfile' is a binary funcname-to-ordinal config file
* created by "nm -B /unix | ord > ordfile"
* 'funcfile' is an ascii list of kernel function names,
* one per line
* 'outfile' is the output file basename
* 'kernel' is the name of the booted kernel
* 'cmd' is the command to exec
* 'args' are the args for that command
*
* Example:
* tracex ordfile funcfile /tmp/out kernel sleep 3000
*/
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/sysmp.h>
#include <sys/time.h>
#include <sys/prctl.h>
#include <sys/schedctl.h>
#include <sys/utsname.h>
#include <limits.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <nlist.h>
#include <signal.h>
#define UNIXFILE "/unix"
#define KMEMFILE "/dev/kmem"
/*
* Conversion between machine-specific realtime clock ticks
* and microseconds is done at the time trace records
* are read from the kernel.
*/
int ticksperus;
int tickwrap;
#define USPERSEC 1000000
#define BITSPERINT 32
#define HIHALF 0xffff0000
#define LOHALF 0x0000ffff
#define MAXNAMETAB 10000
struct nameent {
char name[28];
int ord;
};
int numnames = 0;
struct nameent nametab[MAXNAMETAB];
#if (_MIPS_SZPTR == 64) || (_MIPS_SZLONG == 64) || (_MIPS_SZINT == 64)
struct nlist64 nl[] = {
#else
struct nlist nl[] = {
#endif
{ "_trrectab" },
{ "_trenabletab" },
{ "_trindextab" },
""
};
off_t _trrectab_off, _trenabletab_off, _trindextab_off;
extern void sigcld();
struct tracerec {
uint_t ord;
uint_t time;
};
#define MAXNCPU 12
int ncpu;
#define TRRECSZ (sizeof (struct tracerec))
#define TRRECTABSZ (64 * 1024)
#define TRENABLETABSZ (1024)
#define TRMAXINDEX (TRRECTABSZ/sizeof(struct tracerec))
#define TRINDEXMASK (TRMAXINDEX-1)
struct tracerec trrectab[TRMAXINDEX];
uint_t trindextab[MAXNCPU];
uint_t trenabletab[TRENABLETABSZ/sizeof(int)];
int kmemfd;
char *ordfile;
char *funcfile;
char *outfile;
char *kernfile;
FILE *outfptab[MAXNCPU];
int lastindextab[MAXNCPU];
extern int optind;
extern char *findname();
main(ac, av)
int ac;
char *av[];
{
int fd;
off_t off;
int rc;
int i;
int start;
int n;
int pid;
if (ac < 6)
usage(av[0]);
ordfile = av[1];
funcfile = av[2];
outfile = av[3];
kernfile = av[4];
optind = 5;
if ((ncpu = sysmp(MP_NPROCS)) < 0)
syserr("sysmp(MP_NPROCS)");
#if (_MIPS_SZPTR == 64) || (_MIPS_SZLONG == 64) || (_MIPS_SZINT == 64)
if ((rc = nlist64(kernfile, nl)) < 0) {
#else
if ((rc = nlist(kernfile, nl)) < 0) {
#endif
fprintf(stderr, "nlist returned %d\n", rc);
exit(1);
}
if ((nl[0].n_value == 0) || (nl[1].n_value == 0) || (nl[2].n_value == 0)) {
fprintf(stderr, "missing symbols - not a trace kernel\n");
exit(1);
}
_trrectab_off = nl[0].n_value;
_trenabletab_off = nl[1].n_value;
_trindextab_off = nl[2].n_value;
loadnametab(ordfile);
kmemfd = open(KMEMFILE, O_RDWR);
if (kmemfd < 0)
syserr(KMEMFILE);
openoutfiles();
/*
* Reset trace buffer index values to zero.
*/
bzero((caddr_t) trindextab, (ncpu * sizeof (int)));
wmem(kmemfd, _trindextab_off, trindextab, (ncpu * sizeof (int)));
sigset(SIGINT, sigcld);
sigset(SIGCLD, sigcld);
pid = fork();
if (pid < 0)
syserr("fork");
if (pid == 0) { /* child */
enable(funcfile);
close(kmemfd);
if (execvp(av[optind], &av[optind]) < 0)
syserr(av[optind]);
}
/* parent */
scheddeadline();
trout();
while (sginap(1) == 0)
trout();
disableall();
closeoutfiles();
}
void
sigcld()
{
disableall();
trout();
closeoutfiles();
exit(0);
}
openoutfiles()
{
char buf[BUFSIZ];
int i;
for (i = 0; i < ncpu; i++) {
sprintf(buf, "%s.cpu%d", outfile, i);
if ((outfptab[i] = fopen(buf, "w")) == NULL)
syserr(buf);
}
}
closeoutfiles()
{
int i;
for (i = 0; i < ncpu; i++)
fclose(outfptab[i]);
}
/*
* Write whatever trace records have accumulated
* for all cpus to the output files.
*/
trout()
{
int i;
int j;
int index;
int lastindex;
struct tracerec *tr;
off_t off;
int size;
sighold(SIGCLD);
rmem(kmemfd, _trindextab_off, trindextab, (ncpu * sizeof (uint_t)));
tr = trrectab;
for (i = 0; i < ncpu; i++) {
index = trindextab[i];
lastindex = lastindextab[i];
if (index == lastindex)
continue;
/*
* read() in new trace records
*/
off = _trrectab_off + (i * TRRECTABSZ);
if (index > lastindex) {
off += lastindex * TRRECSZ;
size = (index - lastindex) * TRRECSZ;
rmem(kmemfd, off, &tr[lastindex], size);
} else {
size = index * TRRECSZ;
rmem(kmemfd, off, trrectab, size);
off += lastindex * TRRECSZ;
size = (TRMAXINDEX - lastindex) * TRRECSZ;
rmem(kmemfd, off, &trrectab[lastindex], size);
}
for (j = lastindex; j != index; j = (++j & TRINDEXMASK))
prtrec(outfptab[i], &tr[j]);
lastindextab[i] = index;
}
sigrelse(SIGCLD);
}
prtrec(fp, p)
struct tracerec *p;
FILE *fp;
{
if (fwrite(p, sizeof (struct tracerec), 1, fp) != 1)
syserr("prtrec: fwrite");
}
scheddeadline()
{
struct sched_deadline dl;
dl.dl_period.tv_sec = 0;
dl.dl_period.tv_nsec = 10 * 1000 * 1000; /* 10 ms */
dl.dl_alloc.tv_sec = 0;
dl.dl_alloc.tv_nsec = 1000 * 1000; /* 1 ms */
if (schedctl(DEADLINE, 0, &dl) < 0)
syserr("sched_ctl");
}
#ifdef notdef
maptabs()
{
void *pa;
int pagesize;
int pagemask;
off_t addr;
int size;
off_t off;
pagesize = getpagesize();
pagemask = ~(pagesize - 1);
/*
* mmap() each of the three kernel tables
*
* - 5.2 io/mem.c mmmap() supports only restricted
* addresses for /dev/mmem only, not /dev/kmem
* (fixed in 5.3?)
*
* - mmap() requires 'off' to be page aligned, so
* we have to adjust it for each case below.
*/
addr = _trrectab_off & pagemask;
off = _trrectab_off - addr;
size = (ncpu * TRRECTABSZ) + off;
if ((pa = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED,
kmemfd, addr)) == (void*) -1)
syserr("mmap");
trrectab = (struct tracerec*) ((off_t)pa + off);
addr = _trenabletab_off & pagemask;
off = _trenabletab_off - addr;
size = TRENABLETABSZ + off;
if ((pa = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED,
kmemfd, addr)) == (void*) -1)
syserr("mmap");
trenabletab = (uint_t*) ((off_t)pa + off);
addr = _trindextab_off & pagemask;
off = _trindextab_off - addr;
size = (ncpu * sizeof (int)) + off;
if ((pa = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED,
kmemfd, addr)) == (void*) -1)
syserr("mmap");
trindextab = (uint_t*) ((off_t)pa + off);
}
#endif
syserr(s)
char *s;
{
perror(s);
exit(1);
}
loadnametab(file)
char *file;
{
int fd;
int n;
if ((fd = open(file, 0)) < 0)
syserr(file);
if ((n = read(fd, nametab,
MAXNAMETAB * sizeof (struct nameent))) < 0)
syserr(file);
close(fd);
/*
* ordinals start at "1" and must be sorted
*/
if (nametab[0].ord != 1) {
fprintf(stderr, "invalid ordfile: %s\n", file);
exit(1);
}
numnames = n / sizeof (struct nameent);
}
/*
* Binary sort exact match.
*/
findord(name)
char *name;
{
int i, low, high;
low = 0;
high = numnames;
i = (low + high)/2;
while (1) {
if (strcmp(name, nametab[i].name) == 0)
return (nametab[i].ord);
if ((high - low) <= 1)
break;
if (strcmp(name, nametab[i].name) < 0)
high = i;
else
low = i;
i = (low + high) / 2;
}
return (0); /* unrecognized name */
}
/*
* Binary sort exact match.
*/
char*
findname(ord)
int ord;
{
int i, low, high;
static char string[80];
int saveord;
saveord = ord;
ord &= 0x7fffffff; /* ignore hi bit */
low = 0;
high = numnames;
i = (low + high)/2;
while (1) {
if (nametab[i].ord == ord) {
strcpy(string, nametab[i].name);
if (saveord & 0x80000000)
strcat(string, "_exit");
else
strcat(string, "_enter");
return (string);
}
if ((high - low) <= 1)
break;
if (ord < nametab[i].ord)
high = i;
else
low = i;
i = (low + high) / 2;
}
sprintf(string, "ord%d", ord);
return (string);
}
rmem(fd, offset, addr, len)
int fd;
off_t offset;
int *addr;
int len;
{
lseek(fd, offset, 0L);
if (read(fd, addr, len) < 0)
syserr("read");
}
wmem(fd, offset, addr, len)
int fd;
off_t offset;
int *addr;
int len;
{
lseek(fd, offset, 0L);
if (write(fd, addr, len) < 0)
syserr("write");
}
enable(file)
char *file;
{
char line[BUFSIZ];
FILE *fp;
int ord;
int word;
if ((fp = fopen(file, "r")) == NULL)
syserr(file);
bzero(trenabletab, TRENABLETABSZ);
while (fgets(line, BUFSIZ, fp)) {
if (line[0] == '#') /* comment */
continue;
line[strlen(line)-1] = '\0'; /* strip newline */
if (strcmp(line, "ALL") == 0) {
enableall();
fclose(fp);
return;
}
ord = findord(line);
if (ord == 0) {
/*
fprintf(stderr,
"unknown func (ignored): \"%s\"\n", line);
*/
continue;
}
trenabletab[ord/BITSPERINT] |= (1 << (ord % BITSPERINT));
}
fclose(fp);
wmem(kmemfd, _trenabletab_off, trenabletab, TRENABLETABSZ);
}
disableall()
{
bzero(trenabletab, TRENABLETABSZ);
wmem(kmemfd, _trenabletab_off, trenabletab, TRENABLETABSZ);
}
enableall()
{
memset(trenabletab, 0xff, TRENABLETABSZ);
wmem(kmemfd, _trenabletab_off, trenabletab, TRENABLETABSZ);
}
err(fmt, a1, a2, a3, a4)
char *fmt;
char *a1, *a2, *a3, *a4;
{
fprintf(stderr, fmt, a1, a2, a3, a4);
fprintf(stderr, "\n");
exit(1);
}
usage(s)
char *s;
{
fprintf(stderr, "Usage: %s ordfile funcfile outfile kernel cmd [args]\n",
s);
exit(1);
}