xref: /original-bsd/usr.bin/gprof/tahoe.c (revision b4971bb3)
1 /*
2  * Copyright (c) 1983, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)tahoe.c	8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11 
12 #include	"gprof.h"
13 
14     /*
15      *	a namelist entry to be the child of indirect callf
16      */
17 nltype	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 
38 operandenum
39 operandmode( 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 
78 char *
79 operandname( 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 
130 long
131 operandlength( 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 
166 unsigned long
167 reladdr( 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 
196 findcall( parentp , p_lowpc , p_highpc )
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 ) {
219 	    printf( "[findcall] %s: 0x%x to 0x%x\n" ,
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 ) {
234 		    printf( "[findcall]\t0x%x:callf" , instructp - textspace );
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 ) {
286 				printf( "[findcall]\tdestpc 0x%x" , destpc );
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 ) {
315 			    printf( "[findcall]\tbut it's a botch\n" );
316 			}
317 #		    endif DEBUG
318 		    length = 1;
319 		    continue;
320 	    }
321 	}
322     }
323 }
324