xref: /csrg-svn/usr.bin/gprof/vax.c (revision 34881)
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[] = "@(#)vax.c	5.5 (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 calls
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     struct modebyte	*modep;
51 {
52     long	usesreg = modep -> regfield;
53 
54     switch ( modep -> modefield ) {
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 != PC ? 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     struct modebyte	*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( (struct modebyte *) ((char *) modep) + 1 );
172     }
173     /* NOTREACHED */
174 }
175 
176 unsigned long
177 reladdr( modep )
178     struct modebyte	*modep;
179 {
180     operandenum	mode = operandmode( modep );
181     char	*cp;
182     short	*sp;
183     long	*lp;
184 
185     cp = (char *) modep;
186     cp += 1;			/* skip over the mode */
187     switch ( mode ) {
188 	default:
189 	    fprintf( stderr , "[reladdr] not relative address\n" );
190 	    return (unsigned long) modep;
191 	case byterel:
192 	    return (unsigned long) ( cp + sizeof *cp + *cp );
193 	case wordrel:
194 	    sp = (short *) cp;
195 	    return (unsigned long) ( cp + sizeof *sp + *sp );
196 	case longrel:
197 	    lp = (long *) cp;
198 	    return (unsigned long) ( cp + sizeof *lp + *lp );
199     }
200 }
201 
202 findcall( parentp , p_lowpc , p_highpc )
203     nltype		*parentp;
204     unsigned long	p_lowpc;
205     unsigned long	p_highpc;
206 {
207     unsigned char	*instructp;
208     long		length;
209     nltype		*childp;
210     operandenum		mode;
211     operandenum		firstmode;
212     unsigned long	destpc;
213 
214     if ( textspace == 0 ) {
215 	return;
216     }
217     if ( p_lowpc < s_lowpc ) {
218 	p_lowpc = s_lowpc;
219     }
220     if ( p_highpc > s_highpc ) {
221 	p_highpc = s_highpc;
222     }
223 #   ifdef DEBUG
224 	if ( debug & CALLDEBUG ) {
225 	    printf( "[findcall] %s: 0x%x to 0x%x\n" ,
226 		    parentp -> name , p_lowpc , p_highpc );
227 	}
228 #   endif DEBUG
229     for (   instructp = textspace + p_lowpc ;
230 	    instructp < textspace + p_highpc ;
231 	    instructp += length ) {
232 	length = 1;
233 	if ( *instructp == CALLS ) {
234 		/*
235 		 *	maybe a calls, better check it out.
236 		 *	skip the count of the number of arguments.
237 		 */
238 #	    ifdef DEBUG
239 		if ( debug & CALLDEBUG ) {
240 		    printf( "[findcall]\t0x%x:calls" , instructp - textspace );
241 		}
242 #	    endif DEBUG
243 	    firstmode = operandmode( (struct modebyte *) (instructp+length) );
244 	    switch ( firstmode ) {
245 		case literal:
246 		case immediate:
247 		    break;
248 		default:
249 		    goto botched;
250 	    }
251 	    length += operandlength( (struct modebyte *) (instructp+length) );
252 	    mode = operandmode( (struct modebyte *) ( instructp + length ) );
253 #	    ifdef DEBUG
254 		if ( debug & CALLDEBUG ) {
255 		    printf( "\tfirst operand is %s", operandname( firstmode ) );
256 		    printf( "\tsecond operand is %s\n" , operandname( mode ) );
257 		}
258 #	    endif DEBUG
259 	    switch ( mode ) {
260 		case regdef:
261 		case bytedispdef:
262 		case worddispdef:
263 		case longdispdef:
264 		case bytereldef:
265 		case wordreldef:
266 		case longreldef:
267 			/*
268 			 *	indirect call: call through pointer
269 			 *	either	*d(r)	as a parameter or local
270 			 *		(r)	as a return value
271 			 *		*f	as a global pointer
272 			 *	[are there others that we miss?,
273 			 *	 e.g. arrays of pointers to functions???]
274 			 */
275 		    addarc( parentp , &indirectchild , (long) 0 );
276 		    length += operandlength(
277 				(struct modebyte *) ( instructp + length ) );
278 		    continue;
279 		case byterel:
280 		case wordrel:
281 		case longrel:
282 			/*
283 			 *	regular pc relative addressing
284 			 *	check that this is the address of
285 			 *	a function.
286 			 */
287 		    destpc = reladdr( (struct modebyte *) (instructp+length) )
288 				- (unsigned long) textspace;
289 		    if ( destpc >= s_lowpc && destpc <= s_highpc ) {
290 			childp = nllookup( destpc );
291 #			ifdef DEBUG
292 			    if ( debug & CALLDEBUG ) {
293 				printf( "[findcall]\tdestpc 0x%x" , destpc );
294 				printf( " childp->name %s" , childp -> name );
295 				printf( " childp->value 0x%x\n" ,
296 					childp -> value );
297 			    }
298 #			endif DEBUG
299 			if ( childp -> value == destpc ) {
300 				/*
301 				 *	a hit
302 				 */
303 			    addarc( parentp , childp , (long) 0 );
304 			    length += operandlength( (struct modebyte *)
305 					    ( instructp + length ) );
306 			    continue;
307 			}
308 			goto botched;
309 		    }
310 			/*
311 			 *	else:
312 			 *	it looked like a calls,
313 			 *	but it wasn't to anywhere.
314 			 */
315 		    goto botched;
316 		default:
317 		botched:
318 			/*
319 			 *	something funny going on.
320 			 */
321 #		    ifdef DEBUG
322 			if ( debug & CALLDEBUG ) {
323 			    printf( "[findcall]\tbut it's a botch\n" );
324 			}
325 #		    endif DEBUG
326 		    length = 1;
327 		    continue;
328 	    }
329 	}
330     }
331 }
332