xref: /original-bsd/usr.bin/gprof/vax.c (revision 30d60fbe)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)vax.c	5.3 (Berkeley) 01/07/86";
9 #endif not lint
10 
11 #include	"gprof.h"
12 
13     /*
14      *	a namelist entry to be the child of indirect calls
15      */
16 nltype	indirectchild = {
17 	"(*)" ,				/* the name */
18 	(unsigned long) 0 ,		/* the pc entry point */
19 	(unsigned long) 0 ,		/* entry point aligned to histogram */
20 	(double) 0.0 ,			/* ticks in this routine */
21 	(double) 0.0 ,			/* cumulative ticks in children */
22 	(long) 0 ,			/* how many times called */
23 	(long) 0 ,			/* how many calls to self */
24 	(double) 1.0 ,			/* propagation fraction */
25 	(double) 0.0 ,			/* self propagation time */
26 	(double) 0.0 ,			/* child propagation time */
27 	(bool) 0 ,			/* print flag */
28 	(int) 0 ,			/* index in the graph list */
29 	(int) 0 , 			/* graph call chain top-sort order */
30 	(int) 0 ,			/* internal number of cycle on */
31 	(struct nl *) &indirectchild ,	/* pointer to head of cycle */
32 	(struct nl *) 0 ,		/* pointer to next member of cycle */
33 	(arctype *) 0 ,			/* list of caller arcs */
34 	(arctype *) 0 			/* list of callee arcs */
35     };
36 
37 operandenum
38 operandmode( modep )
39     struct modebyte	*modep;
40 {
41     long	usesreg = modep -> regfield;
42 
43     switch ( modep -> modefield ) {
44 	case 0:
45 	case 1:
46 	case 2:
47 	case 3:
48 	    return literal;
49 	case 4:
50 	    return indexed;
51 	case 5:
52 	    return reg;
53 	case 6:
54 	    return regdef;
55 	case 7:
56 	    return autodec;
57 	case 8:
58 	    return ( usesreg != PC ? autoinc : immediate );
59 	case 9:
60 	    return ( usesreg != PC ? autoincdef : absolute );
61 	case 10:
62 	    return ( usesreg != PC ? bytedisp : byterel );
63 	case 11:
64 	    return ( usesreg != PC ? bytedispdef : bytereldef );
65 	case 12:
66 	    return ( usesreg != PC ? worddisp : wordrel );
67 	case 13:
68 	    return ( usesreg != PC ? worddispdef : wordreldef );
69 	case 14:
70 	    return ( usesreg != PC ? longdisp : longrel );
71 	case 15:
72 	    return ( usesreg != PC ? longdispdef : longreldef );
73     }
74     /* NOTREACHED */
75 }
76 
77 char *
78 operandname( mode )
79     operandenum	mode;
80 {
81 
82     switch ( mode ) {
83 	case literal:
84 	    return "literal";
85 	case indexed:
86 	    return "indexed";
87 	case reg:
88 	    return "register";
89 	case regdef:
90 	    return "register deferred";
91 	case autodec:
92 	    return "autodecrement";
93 	case autoinc:
94 	    return "autoincrement";
95 	case autoincdef:
96 	    return "autoincrement deferred";
97 	case bytedisp:
98 	    return "byte displacement";
99 	case bytedispdef:
100 	    return "byte displacement deferred";
101 	case byterel:
102 	    return "byte relative";
103 	case bytereldef:
104 	    return "byte relative deferred";
105 	case worddisp:
106 	    return "word displacement";
107 	case worddispdef:
108 	    return "word displacement deferred";
109 	case wordrel:
110 	    return "word relative";
111 	case wordreldef:
112 	    return "word relative deferred";
113 	case immediate:
114 	    return "immediate";
115 	case absolute:
116 	    return "absolute";
117 	case longdisp:
118 	    return "long displacement";
119 	case longdispdef:
120 	    return "long displacement deferred";
121 	case longrel:
122 	    return "long relative";
123 	case longreldef:
124 	    return "long relative deferred";
125     }
126     /* NOTREACHED */
127 }
128 
129 long
130 operandlength( modep )
131     struct modebyte	*modep;
132 {
133 
134     switch ( operandmode( modep ) ) {
135 	case literal:
136 	case reg:
137 	case regdef:
138 	case autodec:
139 	case autoinc:
140 	case autoincdef:
141 	    return 1;
142 	case bytedisp:
143 	case bytedispdef:
144 	case byterel:
145 	case bytereldef:
146 	    return 2;
147 	case worddisp:
148 	case worddispdef:
149 	case wordrel:
150 	case wordreldef:
151 	    return 3;
152 	case immediate:
153 	case absolute:
154 	case longdisp:
155 	case longdispdef:
156 	case longrel:
157 	case longreldef:
158 	    return 5;
159 	case indexed:
160 	    return 1+operandlength( (struct modebyte *) ((char *) modep) + 1 );
161     }
162     /* NOTREACHED */
163 }
164 
165 unsigned long
166 reladdr( modep )
167     struct modebyte	*modep;
168 {
169     operandenum	mode = operandmode( modep );
170     char	*cp;
171     short	*sp;
172     long	*lp;
173 
174     cp = (char *) modep;
175     cp += 1;			/* skip over the mode */
176     switch ( mode ) {
177 	default:
178 	    fprintf( stderr , "[reladdr] not relative address\n" );
179 	    return (unsigned long) modep;
180 	case byterel:
181 	    return (unsigned long) ( cp + sizeof *cp + *cp );
182 	case wordrel:
183 	    sp = (short *) cp;
184 	    return (unsigned long) ( cp + sizeof *sp + *sp );
185 	case longrel:
186 	    lp = (long *) cp;
187 	    return (unsigned long) ( cp + sizeof *lp + *lp );
188     }
189 }
190 
191 findcall( parentp , p_lowpc , p_highpc )
192     nltype		*parentp;
193     unsigned long	p_lowpc;
194     unsigned long	p_highpc;
195 {
196     unsigned char	*instructp;
197     long		length;
198     nltype		*childp;
199     operandenum		mode;
200     operandenum		firstmode;
201     unsigned long	destpc;
202 
203     if ( textspace == 0 ) {
204 	return;
205     }
206     if ( p_lowpc < s_lowpc ) {
207 	p_lowpc = s_lowpc;
208     }
209     if ( p_highpc > s_highpc ) {
210 	p_highpc = s_highpc;
211     }
212 #   ifdef DEBUG
213 	if ( debug & CALLDEBUG ) {
214 	    printf( "[findcall] %s: 0x%x to 0x%x\n" ,
215 		    parentp -> name , p_lowpc , p_highpc );
216 	}
217 #   endif DEBUG
218     for (   instructp = textspace + p_lowpc ;
219 	    instructp < textspace + p_highpc ;
220 	    instructp += length ) {
221 	length = 1;
222 	if ( *instructp == CALLS ) {
223 		/*
224 		 *	maybe a calls, better check it out.
225 		 *	skip the count of the number of arguments.
226 		 */
227 #	    ifdef DEBUG
228 		if ( debug & CALLDEBUG ) {
229 		    printf( "[findcall]\t0x%x:calls" , instructp - textspace );
230 		}
231 #	    endif DEBUG
232 	    firstmode = operandmode( (struct modebyte *) (instructp+length) );
233 	    switch ( firstmode ) {
234 		case literal:
235 		case immediate:
236 		    break;
237 		default:
238 		    goto botched;
239 	    }
240 	    length += operandlength( (struct modebyte *) (instructp+length) );
241 	    mode = operandmode( (struct modebyte *) ( instructp + length ) );
242 #	    ifdef DEBUG
243 		if ( debug & CALLDEBUG ) {
244 		    printf( "\tfirst operand is %s", operandname( firstmode ) );
245 		    printf( "\tsecond operand is %s\n" , operandname( mode ) );
246 		}
247 #	    endif DEBUG
248 	    switch ( mode ) {
249 		case regdef:
250 		case bytedispdef:
251 		case worddispdef:
252 		case longdispdef:
253 		case bytereldef:
254 		case wordreldef:
255 		case longreldef:
256 			/*
257 			 *	indirect call: call through pointer
258 			 *	either	*d(r)	as a parameter or local
259 			 *		(r)	as a return value
260 			 *		*f	as a global pointer
261 			 *	[are there others that we miss?,
262 			 *	 e.g. arrays of pointers to functions???]
263 			 */
264 		    addarc( parentp , &indirectchild , (long) 0 );
265 		    length += operandlength(
266 				(struct modebyte *) ( instructp + length ) );
267 		    continue;
268 		case byterel:
269 		case wordrel:
270 		case longrel:
271 			/*
272 			 *	regular pc relative addressing
273 			 *	check that this is the address of
274 			 *	a function.
275 			 */
276 		    destpc = reladdr( (struct modebyte *) (instructp+length) )
277 				- (unsigned long) textspace;
278 		    if ( destpc >= s_lowpc && destpc <= s_highpc ) {
279 			childp = nllookup( destpc );
280 #			ifdef DEBUG
281 			    if ( debug & CALLDEBUG ) {
282 				printf( "[findcall]\tdestpc 0x%x" , destpc );
283 				printf( " childp->name %s" , childp -> name );
284 				printf( " childp->value 0x%x\n" ,
285 					childp -> value );
286 			    }
287 #			endif DEBUG
288 			if ( childp -> value == destpc ) {
289 				/*
290 				 *	a hit
291 				 */
292 			    addarc( parentp , childp , (long) 0 );
293 			    length += operandlength( (struct modebyte *)
294 					    ( instructp + length ) );
295 			    continue;
296 			}
297 			goto botched;
298 		    }
299 			/*
300 			 *	else:
301 			 *	it looked like a calls,
302 			 *	but it wasn't to anywhere.
303 			 */
304 		    goto botched;
305 		default:
306 		botched:
307 			/*
308 			 *	something funny going on.
309 			 */
310 #		    ifdef DEBUG
311 			if ( debug & CALLDEBUG ) {
312 			    printf( "[findcall]\tbut it's a botch\n" );
313 			}
314 #		    endif DEBUG
315 		    length = 1;
316 		    continue;
317 	    }
318 	}
319     }
320 }
321