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