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