home *** CD-ROM | disk | FTP | other *** search
- /* Routines with the same name as in gmon, to make compilation easier
- for the user, who only has to specify -pg when linking. The
- drawback is that it is a lot less portable than having the user
- call a hypothetical bmon() routine at the start of their program,
- which would then use atexit(_mcleanup). */
-
- #include <sys/time.h>
- #include <signal.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #include <memory.h>
- #include <stdio.h>
-
- /* sigcontext copied from linux/kernel/signal.c
- Why is this not in any linux/.h file? */
-
- struct sigcontext_struct {
- unsigned short gs, __gsh;
- unsigned short fs, __fsh;
- unsigned short es, __esh;
- unsigned short ds, __dsh;
- unsigned long edi;
- unsigned long esi;
- unsigned long ebp;
- unsigned long esp;
- unsigned long ebx;
- unsigned long edx;
- unsigned long ecx;
- unsigned long eax;
- unsigned long trapno;
- unsigned long err;
- unsigned long eip;
- unsigned short cs, __csh;
- unsigned long eflags;
- unsigned long esp_at_signal;
- unsigned short ss, __ssh;
- unsigned long i387;
- unsigned long oldmask;
- unsigned long cr2;
- };
-
- /* I should have used the profil() routine to ease porting, but it
- cannot use a finer scale than one counter per two bytes. */
-
- static unsigned long lowpc, highpc;
- static unsigned int *bbuf;
- static unsigned long bbufsize;
-
- static void profhandler(int signr, struct sigcontext_struct sigcon)
- {
- unsigned long index = sigcon.eip - lowpc;
- if (index < bbufsize)
- bbuf[index]++;
- }
-
- void monstartup(unsigned long low, unsigned long high)
- {
- struct sigaction sigact;
- struct itimerval value;
- sigset_t sigset;
-
- lowpc = low;
- highpc = high;
- bbufsize = high - low;
- bbuf = sbrk(bbufsize * sizeof(*bbuf));
- if (bbuf == (typeof(bbuf))-1) {
- perror("monstartup");
- exit(1);
- }
- /* sbrk-ed memory is supposed to be zero, but I've seen otherwise */
- memset(bbuf, 0, bbufsize * sizeof(*bbuf));
-
- sigact.sa_handler = (void (*)(int))profhandler;
- sigemptyset(&sigset);
- sigact.sa_mask = sigset;
- sigact.sa_flags = SA_RESTART;
-
- value.it_interval.tv_sec = 0;
- value.it_interval.tv_usec = 1; /* Gets rounded up to 1e6/HZ */
- value.it_value.tv_sec = 0;
- value.it_value.tv_usec = 1;
-
- sigaction(SIGVTALRM, &sigact, 0);
- setitimer(ITIMER_VIRTUAL, &value, 0);
- }
-
- void _mcleanup(void)
- {
- int fd;
- const char *dir;
- unsigned long i;
-
- if ((dir = getenv("BPROFDIR"))) {
- if (chdir(dir)) {
- perror("mcleanup: could not chdir to BPROFDIR");
- return;
- }
- }
-
- fd = creat("bmon.out", 0666);
- if (fd == -1) {
- perror("mcleanup: bmon.out");
- return;
- }
-
- for (i = 0; i < bbufsize; i++) {
- if (bbuf[i]) {
- unsigned long pc = lowpc + i;
- if (write(fd, &pc, sizeof(pc)) != sizeof(pc) ||
- write(fd, bbuf + i, sizeof(*bbuf)) != sizeof(*bbuf)) {
- fprintf(stderr, "Error writing bmon.out\n");
- return;
- }
- }
- }
- close(fd);
- }
-
- void mcount(void)
- {
- /* Do nothing to save overhead of mcount() from libgmon */
- }
-