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