Commit | Line | Data |
---|---|---|
d841a9ba KM |
1 | /* Copyright (c) 1982 Regents of the University of California */ |
2 | ||
3 | #ifndef lint | |
4 | static char sccsid[] = "@(#)kgmon.c 4.1 82/06/21"; | |
5 | #endif | |
6 | ||
7 | #include <sys/param.h> | |
8 | #include <sys/pte.h> | |
9 | #include <stdio.h> | |
10 | #include <nlist.h> | |
11 | #include <ctype.h> | |
12 | #include <sys/crt0.h> | |
13 | ||
14 | #define PROFILING_ON 0 | |
15 | #define PROFILING_OFF 3 | |
16 | ||
17 | /* | |
18 | * froms is actually a bunch of unsigned shorts indexing tos | |
19 | */ | |
20 | u_short *froms; | |
21 | struct tostruct *tos; | |
22 | char *s_lowpc; | |
23 | u_long s_textsize; | |
24 | int ssiz; | |
25 | off_t sbuf; | |
26 | ||
27 | struct nlist nl[] = { | |
28 | #define N_SYSMAP 0 | |
29 | { "_Sysmap" }, | |
30 | #define N_SYSSIZE 1 | |
31 | { "_Syssize" }, | |
32 | #define N_FROMS 2 | |
33 | { "_froms" }, | |
34 | #define N_PROFILING 3 | |
35 | { "_profiling" }, | |
36 | #define N_S_LOWPC 4 | |
37 | { "_s_lowpc" }, | |
38 | #define N_S_TEXTSIZE 5 | |
39 | { "_s_textsize" }, | |
40 | #define N_SBUF 6 | |
41 | { "_sbuf" }, | |
42 | #define N_SSIZ 7 | |
43 | { "_ssiz" }, | |
44 | #define N_TOS 8 | |
45 | { "_tos" }, | |
46 | 0, | |
47 | }; | |
48 | ||
49 | struct pte *Sysmap; | |
50 | ||
51 | char *system = "/vmunix"; | |
52 | char *kmemf = "/dev/kmem"; | |
53 | int kmem; | |
54 | int kflg; | |
55 | ||
56 | main(argc, argv) | |
57 | int argc; | |
58 | char *argv[]; | |
59 | { | |
60 | int i, j, k; | |
61 | char *cp; | |
62 | long conptr; | |
63 | int fd; | |
64 | int fromindex; | |
65 | u_long frompc; | |
66 | int toindex; | |
67 | struct rawarc rawarc; | |
68 | off_t kfroms, ktos; | |
69 | char buf[BUFSIZ]; | |
70 | int debug = 0; | |
71 | ||
72 | argc--, argv++; | |
73 | if (argc > 0) { | |
74 | system = *argv; | |
75 | argv++, argc--; | |
76 | } | |
77 | nlist(system, nl); | |
78 | if (nl[0].n_type == 0) { | |
79 | fprintf(stderr, "%s: no namelist\n", system); | |
80 | exit(1); | |
81 | } | |
82 | if (argc > 0) { | |
83 | kmemf = *argv; | |
84 | kflg++; | |
85 | } | |
86 | kmem = open(kmemf, 2); | |
87 | if (kmem < 0) { | |
88 | kmem = open(kmemf, 0); | |
89 | if (kmem < 0) { | |
90 | fprintf(stderr, "cannot open "); | |
91 | perror(kmemf); | |
92 | exit(1); | |
93 | } | |
94 | fprintf(stderr, | |
95 | "%s opened read-only, data may be inconsistent\n", | |
96 | kmemf); | |
97 | } | |
98 | if (kflg) { | |
99 | off_t off; | |
100 | ||
101 | off = nl[N_SYSMAP].n_value & 0x7fffffff; | |
102 | lseek(kmem, off, 0); | |
103 | nl[N_SYSSIZE].n_value *= 4; | |
104 | Sysmap = (struct pte *)malloc(nl[N_SYSSIZE].n_value); | |
105 | if (Sysmap == 0) { | |
106 | perror("Sysmap"); | |
107 | exit(1); | |
108 | } | |
109 | read(kmem, Sysmap, nl[N_SYSSIZE].n_value); | |
110 | } | |
111 | turnonoff(PROFILING_OFF); | |
112 | fd = creat("gmon.out", 0666); | |
113 | if (fd < 0) { | |
114 | perror("gmon.out"); | |
115 | return; | |
116 | } | |
117 | ssiz = kfetch(N_SSIZ); | |
118 | sbuf = kfetch(N_SBUF); | |
119 | klseek(kmem, (off_t)sbuf, 0); | |
120 | for (i = ssiz; i > 0; i -= BUFSIZ) { | |
121 | read(kmem, buf, i < BUFSIZ ? i : BUFSIZ); | |
122 | write(fd, buf, i < BUFSIZ ? i : BUFSIZ); | |
123 | } | |
124 | s_textsize = kfetch(N_S_TEXTSIZE); | |
125 | froms = (u_short *)malloc(s_textsize); | |
126 | kfroms = kfetch(N_FROMS); | |
127 | klseek(kmem, kfroms, 0); | |
128 | for (i = 0; i < s_textsize; i += BUFSIZ) { | |
129 | j = s_textsize - i; | |
130 | if (j > BUFSIZ) | |
131 | j = BUFSIZ; | |
132 | k = read(kmem, ((char *)(froms)) + i, j); | |
133 | if (j != k) { | |
134 | fprintf(stderr, "read tos: loc %d, request %d, got %d", | |
135 | i, j, k); | |
136 | perror(""); | |
137 | exit(5); | |
138 | } | |
139 | } | |
140 | tos = (struct tostruct *)malloc(s_textsize); | |
141 | ktos = kfetch(N_TOS); | |
142 | klseek(kmem, ktos, 0); | |
143 | for (i = 0; i < s_textsize; i += BUFSIZ) { | |
144 | j = s_textsize - i; | |
145 | if (j > BUFSIZ) | |
146 | j = BUFSIZ; | |
147 | k = read(kmem, ((char *)(tos)) + i, j); | |
148 | if (j != k) { | |
149 | fprintf(stderr, "read tos: loc %d, request %d, got %d", | |
150 | i, j, k); | |
151 | perror(""); | |
152 | exit(6); | |
153 | } | |
154 | } | |
155 | s_lowpc = (char *)kfetch(N_S_LOWPC); | |
156 | if (debug) | |
157 | fprintf(stderr, "s_lowpc 0x%x, s_textsize 0x%x\n", | |
158 | s_lowpc, s_textsize); | |
159 | for (fromindex = 0; fromindex < s_textsize>>1; fromindex++) { | |
160 | if (froms[fromindex] == 0) | |
161 | continue; | |
162 | frompc = (u_long)s_lowpc + (fromindex<<1); | |
163 | for (toindex = froms[fromindex]; toindex != 0; | |
164 | toindex = tos[toindex].link) { | |
165 | if (debug) | |
166 | fprintf(stderr, | |
167 | "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , | |
168 | frompc, tos[toindex].selfpc, tos[toindex].count); | |
169 | rawarc.raw_frompc = frompc; | |
170 | rawarc.raw_selfpc = (u_long)tos[toindex].selfpc; | |
171 | rawarc.raw_count = tos[toindex].count; | |
172 | write(fd, &rawarc, sizeof (rawarc)); | |
173 | } | |
174 | } | |
175 | close(fd); | |
176 | turnonoff(PROFILING_ON); | |
177 | } | |
178 | ||
179 | turnonoff(onoff) | |
180 | int onoff; | |
181 | { | |
182 | off_t off; | |
183 | ||
184 | if ((off = nl[N_PROFILING].n_value) == 0) { | |
185 | printf("profiling: not defined in kernel\n"); | |
186 | exit(1); | |
187 | } | |
188 | klseek(kmem, off, 0); | |
189 | write(kmem, (char *)&onoff, sizeof (onoff)); | |
190 | } | |
191 | ||
192 | kfetch(index) | |
193 | int index; | |
194 | { | |
195 | off_t off; | |
196 | int value; | |
197 | ||
198 | if ((off = nl[index].n_value) == 0) { | |
199 | printf("%s: not defined in kernel\n", nl[index].n_name); | |
200 | exit(1); | |
201 | } | |
202 | if (klseek(kmem, off, 0) == -1) { | |
203 | perror("lseek"); | |
204 | exit(2); | |
205 | } | |
206 | if (read(kmem, (char *)&value, sizeof (value)) != sizeof (value)) { | |
207 | perror("read"); | |
208 | exit(3); | |
209 | } | |
210 | return (value); | |
211 | } | |
212 | ||
213 | klseek(fd, base, off) | |
214 | int fd, base, off; | |
215 | { | |
216 | ||
217 | if (kflg) { | |
218 | /* get kernel pte */ | |
219 | base &= 0x7fffffff; | |
220 | base = Sysmap[base >> 9].pg_pfnum * 512 + (base & 0x1ff); | |
221 | } | |
222 | return (lseek(fd, base, off)); | |
223 | } |