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