File: profil.c

package info (click to toggle)
libc-sparc 5.3.12-3
  • links: PTS
  • area: main
  • in suites: potato, slink
  • size: 17,608 kB
  • ctags: 44,718
  • sloc: ansic: 163,548; asm: 5,080; makefile: 3,340; lex: 521; sh: 439; yacc: 401; awk: 28
file content (115 lines) | stat: -rw-r--r-- 2,859 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
 * profil.c -- user space version of the profil(2) system call
 * Copyright (C) 1992, 1993 Rick Sladkey <jrs@world.std.com>
 * Modified for m68k by Andreas Schwab <schwab@issan.uni-dortmund.de>
 *
 * This file is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 */

/*
 *     IMPORTANT:
 *
 *   This file should never be compiled with -p or -pg!
 *   It will need special consideration in the Makefile for libc_p.a
 *   to ensure that it is not compiled with any profiling flags.
 *
 *     Limitations:
 *
 * - Any program that tries to use SIGPROF itimers and profil at the
 *   same time won't work.
 *
 * - The user's program is free to trash our handler with a call to
 *   signal or sigaction.
 *
 * - Calling profil with an invalid buffer will cause a core dump instead
 *   of just disabling profiling.
 *
 * - The precision of the histogram is worse than with true kernel
 *   profiling.
 *
 */

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

static struct sigaction old_sa;
static struct itimerval old_it;

static unsigned long prof_buf;
static int prof_bufsiz;
static int prof_offset;
static int prof_scale = 0;

struct sigcontext 
{
  unsigned long  sc_mask;
  unsigned long  sc_usp;
  unsigned long  sc_d0;
  unsigned long  sc_d1;
  unsigned long  sc_a0;
  unsigned long  sc_a1;
  unsigned short sc_sr;
  unsigned long  sc_pc;
  unsigned short sc_formatvec;
};
  
static void
_profil_handler(int signr, int code, struct sigcontext *scp)
{
	unsigned long pc, spot;

#ifdef PROFIL_DEBUG
	printf("pc = %#x\n", scp->sc_pc);
#endif
	pc = scp->sc_pc - prof_offset;
	spot = (prof_scale*(pc >> 16)
		+ ((prof_scale*(pc & (0x10000 - 1))) >> 16)) & ~1;
	if (spot < prof_bufsiz)
		++*((unsigned short *) (spot + prof_buf));
}

int
profil(char *buf, int bufsiz, int offset, int scale)
{
	struct sigaction new_sa;
	struct itimerval new_it;
	int old_scale = prof_scale;

	if (!buf || bufsiz == 0 || scale < 2) {
		if (prof_scale) {
			setitimer(ITIMER_PROF, &old_it, &new_it);
			sigaction(SIGPROF, &old_sa, &new_sa);
		}
		prof_scale = 0;
	}
	else {
		prof_buf = (unsigned long) buf;
		prof_bufsiz = bufsiz;
		prof_offset = offset;
		prof_scale = scale;
		if (!old_scale) {
			prof_scale = scale;
			new_sa.sa_handler =
				(void (*)(int)) _profil_handler;
			new_sa.sa_mask = 0;
#ifdef SA_RESTART
			new_sa.sa_flags = SA_RESTART;
#else
			new_sa.sa_flags = 0;
#endif
			new_it.it_interval.tv_sec = 0;
			new_it.it_interval.tv_usec = 1;
			new_it.it_value.tv_sec = 0;
			new_it.it_value.tv_usec = 1;
			sigaction(SIGPROF, &new_sa, &old_sa);
			setitimer(ITIMER_PROF, &new_it, &old_it);
		}
	}
	return 0;
}