xref: /csrg-svn/usr.bin/gprof/tahoe.c (revision 25712)
1 #ifndef lint
2 static	char *sccsid = "@(#)tahoe.c	1.1 (Berkeley) 01/07/86";
3 #endif not lint
4 
5 #include	"gprof.h"
6 
7     /*
8      *	a namelist entry to be the child of indirect callf
9      */
10 nltype	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 
31 operandenum
32 operandmode( 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 
71 char *
72 operandname( 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 
123 long
124 operandlength( 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 
159 unsigned long
160 reladdr( 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 
189 findcallf( parentp , p_lowpc , p_highpc )
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 ) {
212 	    printf( "[findcallf] %s: 0x%x to 0x%x\n" ,
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 ) {
227 		    printf( "[findcallf]\t0x%x:callf" , instructp - textspace );
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 ) {
279 				printf( "[findcallf]\tdestpc 0x%x" , destpc );
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 ) {
308 			    printf( "[findcallf]\tbut it's a botch\n" );
309 			}
310 #		    endif DEBUG
311 		    length = 1;
312 		    continue;
313 	    }
314 	}
315     }
316 }
317