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