These are the current versions (actually already 2 years old).
[unix-history] / usr / src / usr.bin / gprof / tahoe.c
CommitLineData
ddb85eed
KB
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
2124b336
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
ddb85eed
KB
16 */
17
82a8b820 18#ifndef lint
2124b336 19static char sccsid[] = "@(#)tahoe.c 1.4 (Berkeley) %G%";
ddb85eed 20#endif /* not lint */
82a8b820
SL
21
22#include "gprof.h"
23
24 /*
25 * a namelist entry to be the child of indirect callf
26 */
27nltype indirectchild = {
28 "(*)" , /* the name */
29 (unsigned long) 0 , /* the pc entry point */
30 (unsigned long) 0 , /* entry point aligned to histogram */
31 (double) 0.0 , /* ticks in this routine */
32 (double) 0.0 , /* cumulative ticks in children */
33 (long) 0 , /* how many times called */
34 (long) 0 , /* how many calls to self */
35 (double) 1.0 , /* propagation fraction */
36 (double) 0.0 , /* self propagation time */
37 (double) 0.0 , /* child propagation time */
38 (bool) 0 , /* print flag */
39 (int) 0 , /* index in the graph list */
40 (int) 0 , /* graph call chain top-sort order */
41 (int) 0 , /* internal number of cycle on */
42 (struct nl *) &indirectchild , /* pointer to head of cycle */
43 (struct nl *) 0 , /* pointer to next member of cycle */
44 (arctype *) 0 , /* list of caller arcs */
45 (arctype *) 0 /* list of callee arcs */
46 };
47
48operandenum
49operandmode( modep )
50 unsigned char *modep;
51{
52 long usesreg = ((long)*modep) & 0xf;
53
54 switch ( ((long)*modep) >> 4 ) {
55 case 0:
56 case 1:
57 case 2:
58 case 3:
59 return literal;
60 case 4:
61 return indexed;
62 case 5:
63 return reg;
64 case 6:
65 return regdef;
66 case 7:
67 return autodec;
68 case 8:
69 return ( usesreg != 0xe ? autoinc : immediate );
70 case 9:
71 return ( usesreg != PC ? autoincdef : absolute );
72 case 10:
73 return ( usesreg != PC ? bytedisp : byterel );
74 case 11:
75 return ( usesreg != PC ? bytedispdef : bytereldef );
76 case 12:
77 return ( usesreg != PC ? worddisp : wordrel );
78 case 13:
79 return ( usesreg != PC ? worddispdef : wordreldef );
80 case 14:
81 return ( usesreg != PC ? longdisp : longrel );
82 case 15:
83 return ( usesreg != PC ? longdispdef : longreldef );
84 }
85 /* NOTREACHED */
86}
87
88char *
89operandname( mode )
90 operandenum mode;
91{
92
93 switch ( mode ) {
94 case literal:
95 return "literal";
96 case indexed:
97 return "indexed";
98 case reg:
99 return "register";
100 case regdef:
101 return "register deferred";
102 case autodec:
103 return "autodecrement";
104 case autoinc:
105 return "autoincrement";
106 case autoincdef:
107 return "autoincrement deferred";
108 case bytedisp:
109 return "byte displacement";
110 case bytedispdef:
111 return "byte displacement deferred";
112 case byterel:
113 return "byte relative";
114 case bytereldef:
115 return "byte relative deferred";
116 case worddisp:
117 return "word displacement";
118 case worddispdef:
119 return "word displacement deferred";
120 case wordrel:
121 return "word relative";
122 case wordreldef:
123 return "word relative deferred";
124 case immediate:
125 return "immediate";
126 case absolute:
127 return "absolute";
128 case longdisp:
129 return "long displacement";
130 case longdispdef:
131 return "long displacement deferred";
132 case longrel:
133 return "long relative";
134 case longreldef:
135 return "long relative deferred";
136 }
137 /* NOTREACHED */
138}
139
140long
141operandlength( modep )
142 unsigned char *modep;
143{
144
145 switch ( operandmode( modep ) ) {
146 case literal:
147 case reg:
148 case regdef:
149 case autodec:
150 case autoinc:
151 case autoincdef:
152 return 1;
153 case bytedisp:
154 case bytedispdef:
155 case byterel:
156 case bytereldef:
157 return 2;
158 case worddisp:
159 case worddispdef:
160 case wordrel:
161 case wordreldef:
162 return 3;
163 case immediate:
164 case absolute:
165 case longdisp:
166 case longdispdef:
167 case longrel:
168 case longreldef:
169 return 5;
170 case indexed:
171 return 1+operandlength( modep + 1 );
172 }
173 /* NOTREACHED */
174}
175
176unsigned long
177reladdr( modep )
178 char *modep;
179{
180 operandenum mode = operandmode( modep );
181 char *cp;
182 short *sp;
183 long *lp;
184 int i;
185 long value = 0;
186
187 cp = modep;
188 cp += 1; /* skip over the mode */
189 switch ( mode ) {
190 default:
191 fprintf( stderr , "[reladdr] not relative address\n" );
192 return (unsigned long) modep;
193 case byterel:
194 return (unsigned long) ( cp + sizeof *cp + *cp );
195 case wordrel:
196 for (i = 0; i < sizeof *sp; i++)
197 value = (value << 8) + (cp[i] & 0xff);
198 return (unsigned long) ( cp + sizeof *sp + value );
199 case longrel:
200 for (i = 0; i < sizeof *lp; i++)
201 value = (value << 8) + (cp[i] & 0xff);
202 return (unsigned long) ( cp + sizeof *lp + value );
203 }
204}
205
da50c4dd 206findcall( parentp , p_lowpc , p_highpc )
82a8b820
SL
207 nltype *parentp;
208 unsigned long p_lowpc;
209 unsigned long p_highpc;
210{
211 unsigned char *instructp;
212 long length;
213 nltype *childp;
214 operandenum mode;
215 operandenum firstmode;
216 unsigned long destpc;
217
218 if ( textspace == 0 ) {
219 return;
220 }
221 if ( p_lowpc < s_lowpc ) {
222 p_lowpc = s_lowpc;
223 }
224 if ( p_highpc > s_highpc ) {
225 p_highpc = s_highpc;
226 }
227# ifdef DEBUG
228 if ( debug & CALLDEBUG ) {
da50c4dd 229 printf( "[findcall] %s: 0x%x to 0x%x\n" ,
82a8b820
SL
230 parentp -> name , p_lowpc , p_highpc );
231 }
232# endif DEBUG
233 for ( instructp = textspace + p_lowpc ;
234 instructp < textspace + p_highpc ;
235 instructp += length ) {
236 length = 1;
237 if ( *instructp == CALLF ) {
238 /*
239 * maybe a callf, better check it out.
240 * skip the count of the number of arguments.
241 */
242# ifdef DEBUG
243 if ( debug & CALLDEBUG ) {
da50c4dd 244 printf( "[findcall]\t0x%x:callf" , instructp - textspace );
82a8b820
SL
245 }
246# endif DEBUG
247 firstmode = operandmode( instructp+length );
248 switch ( firstmode ) {
249 case literal:
250 case immediate:
251 break;
252 default:
253 goto botched;
254 }
255 length += operandlength( instructp+length );
256 mode = operandmode( instructp + length );
257# ifdef DEBUG
258 if ( debug & CALLDEBUG ) {
259 printf( "\tfirst operand is %s", operandname( firstmode ) );
260 printf( "\tsecond operand is %s\n" , operandname( mode ) );
261 }
262# endif DEBUG
263 switch ( mode ) {
264 case regdef:
265 case bytedispdef:
266 case worddispdef:
267 case longdispdef:
268 case bytereldef:
269 case wordreldef:
270 case longreldef:
271 /*
272 * indirect call: call through pointer
273 * either *d(r) as a parameter or local
274 * (r) as a return value
275 * *f as a global pointer
276 * [are there others that we miss?,
277 * e.g. arrays of pointers to functions???]
278 */
279 addarc( parentp , &indirectchild , (long) 0 );
280 length += operandlength( instructp + length );
281 continue;
282 case byterel:
283 case wordrel:
284 case longrel:
285 /*
286 * regular pc relative addressing
287 * check that this is the address of
288 * a function.
289 */
290 destpc = reladdr( instructp+length )
291 - (unsigned long) textspace;
292 if ( destpc >= s_lowpc && destpc <= s_highpc ) {
293 childp = nllookup( destpc );
294# ifdef DEBUG
295 if ( debug & CALLDEBUG ) {
da50c4dd 296 printf( "[findcall]\tdestpc 0x%x" , destpc );
82a8b820
SL
297 printf( " childp->name %s" , childp -> name );
298 printf( " childp->value 0x%x\n" ,
299 childp -> value );
300 }
301# endif DEBUG
302 if ( childp -> value == destpc ) {
303 /*
304 * a hit
305 */
306 addarc( parentp , childp , (long) 0 );
307 length += operandlength( instructp + length );
308 continue;
309 }
310 goto botched;
311 }
312 /*
313 * else:
314 * it looked like a callf,
315 * but it wasn't to anywhere.
316 */
317 goto botched;
318 default:
319 botched:
320 /*
321 * something funny going on.
322 */
323# ifdef DEBUG
324 if ( debug & CALLDEBUG ) {
da50c4dd 325 printf( "[findcall]\tbut it's a botch\n" );
82a8b820
SL
326 }
327# endif DEBUG
328 length = 1;
329 continue;
330 }
331 }
332 }
333}