xref: /original-bsd/usr.bin/gprof/tahoe.c (revision 2301fdfb)
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
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.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)tahoe.c	1.4 (Berkeley) 06/29/88";
20 #endif /* not lint */
21 
22 #include	"gprof.h"
23 
24     /*
25      *	a namelist entry to be the child of indirect callf
26      */
27 nltype	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 
48 operandenum
49 operandmode( 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 
88 char *
89 operandname( 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 
140 long
141 operandlength( 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 
176 unsigned long
177 reladdr( 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 
206 findcall( parentp , p_lowpc , p_highpc )
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 ) {
229 	    printf( "[findcall] %s: 0x%x to 0x%x\n" ,
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 ) {
244 		    printf( "[findcall]\t0x%x:callf" , instructp - textspace );
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 ) {
296 				printf( "[findcall]\tdestpc 0x%x" , destpc );
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 ) {
325 			    printf( "[findcall]\tbut it's a botch\n" );
326 			}
327 #		    endif DEBUG
328 		    length = 1;
329 		    continue;
330 	    }
331 	}
332     }
333 }
334