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