]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gprof/vax.c
Tue Feb 3 14:25:25 1998 Brent Baccala <baccala@freesoft.org>
[thirdparty/binutils-gdb.git] / gprof / vax.c
1 /*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that: (1) source distributions retain this entire copyright
7 * notice and comment, and (2) distributions including binaries display
8 * the following acknowledgement: ``This product includes software
9 * developed by the University of California, Berkeley and its contributors''
10 * in the documentation or other materials provided with the distribution
11 * and in all advertising materials mentioning features or use of this
12 * software. Neither the name of the University nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 */
19 #include "gprof.h"
20 #include "cg_arcs.h"
21 #include "core.h"
22 #include "hist.h"
23 #include "symtab.h"
24
25 /*
26 * opcode of the `calls' instruction
27 */
28 #define CALLS 0xfb
29
30 /*
31 * register for pc relative addressing
32 */
33 #define PC 0xf
34
35 enum opermodes
36 {
37 literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
38 bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef,
39 immediate, absolute, byterel, bytereldef, wordrel, wordreldef,
40 longrel, longreldef
41 };
42 typedef enum opermodes operandenum;
43
44 struct modebyte
45 {
46 unsigned int regfield:4;
47 unsigned int modefield:4;
48 };
49
50 /*
51 * A symbol to be the child of indirect calls:
52 */
53 Sym indirectchild;
54
55
56 static operandenum
57 vax_operandmode (modep)
58 struct modebyte *modep;
59 {
60 long usesreg = modep->regfield;
61
62 switch (modep->modefield)
63 {
64 case 0:
65 case 1:
66 case 2:
67 case 3:
68 return literal;
69 case 4:
70 return indexed;
71 case 5:
72 return reg;
73 case 6:
74 return regdef;
75 case 7:
76 return autodec;
77 case 8:
78 return usesreg != PC ? autoinc : immediate;
79 case 9:
80 return usesreg != PC ? autoincdef : absolute;
81 case 10:
82 return usesreg != PC ? bytedisp : byterel;
83 case 11:
84 return usesreg != PC ? bytedispdef : bytereldef;
85 case 12:
86 return usesreg != PC ? worddisp : wordrel;
87 case 13:
88 return usesreg != PC ? worddispdef : wordreldef;
89 case 14:
90 return usesreg != PC ? longdisp : longrel;
91 case 15:
92 return usesreg != PC ? longdispdef : longreldef;
93 }
94 /* NOTREACHED */
95 abort ();
96 }
97
98 static char *
99 vax_operandname (mode)
100 operandenum mode;
101 {
102
103 switch (mode)
104 {
105 case literal:
106 return "literal";
107 case indexed:
108 return "indexed";
109 case reg:
110 return "register";
111 case regdef:
112 return "register deferred";
113 case autodec:
114 return "autodecrement";
115 case autoinc:
116 return "autoincrement";
117 case autoincdef:
118 return "autoincrement deferred";
119 case bytedisp:
120 return "byte displacement";
121 case bytedispdef:
122 return "byte displacement deferred";
123 case byterel:
124 return "byte relative";
125 case bytereldef:
126 return "byte relative deferred";
127 case worddisp:
128 return "word displacement";
129 case worddispdef:
130 return "word displacement deferred";
131 case wordrel:
132 return "word relative";
133 case wordreldef:
134 return "word relative deferred";
135 case immediate:
136 return "immediate";
137 case absolute:
138 return "absolute";
139 case longdisp:
140 return "long displacement";
141 case longdispdef:
142 return "long displacement deferred";
143 case longrel:
144 return "long relative";
145 case longreldef:
146 return "long relative deferred";
147 }
148 /* NOTREACHED */
149 abort ();
150 }
151
152 static long
153 vax_operandlength (modep)
154 struct modebyte *modep;
155 {
156
157 switch (vax_operandmode (modep))
158 {
159 case literal:
160 case reg:
161 case regdef:
162 case autodec:
163 case autoinc:
164 case autoincdef:
165 return 1;
166 case bytedisp:
167 case bytedispdef:
168 case byterel:
169 case bytereldef:
170 return 2;
171 case worddisp:
172 case worddispdef:
173 case wordrel:
174 case wordreldef:
175 return 3;
176 case immediate:
177 case absolute:
178 case longdisp:
179 case longdispdef:
180 case longrel:
181 case longreldef:
182 return 5;
183 case indexed:
184 return 1 + vax_operandlength ((struct modebyte *) ((char *) modep) + 1);
185 }
186 /* NOTREACHED */
187 abort ();
188 }
189
190 static bfd_vma
191 vax_reladdr (modep)
192 struct modebyte *modep;
193 {
194 operandenum mode = vax_operandmode (modep);
195 char *cp;
196 short *sp;
197 long *lp;
198
199 cp = (char *) modep;
200 ++cp; /* skip over the mode */
201 switch (mode)
202 {
203 default:
204 fprintf (stderr, "[reladdr] not relative address\n");
205 return (bfd_vma) modep;
206 case byterel:
207 return (bfd_vma) (cp + sizeof *cp + *cp);
208 case wordrel:
209 sp = (short *) cp;
210 return (bfd_vma) (cp + sizeof *sp + *sp);
211 case longrel:
212 lp = (long *) cp;
213 return (bfd_vma) (cp + sizeof *lp + *lp);
214 }
215 }
216
217
218 void
219 vax_find_call (parent, p_lowpc, p_highpc)
220 Sym *parent;
221 bfd_vma p_lowpc;
222 bfd_vma p_highpc;
223 {
224 unsigned char *instructp;
225 long length;
226 Sym *child;
227 operandenum mode;
228 operandenum firstmode;
229 bfd_vma destpc;
230 static bool inited = FALSE;
231
232 if (!inited)
233 {
234 inited = TRUE;
235 sym_init (&indirectchild);
236 indirectchild.cg.prop.fract = 1.0;
237 indirectchild.cg.cyc.head = &indirectchild;
238 }
239
240 if (core_text_space == 0)
241 {
242 return;
243 }
244 if (p_lowpc < s_lowpc)
245 {
246 p_lowpc = s_lowpc;
247 }
248 if (p_highpc > s_highpc)
249 {
250 p_highpc = s_highpc;
251 }
252 DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
253 parent->name, p_lowpc, p_highpc));
254 for (instructp = (unsigned char *) core_text_space + p_lowpc;
255 instructp < (unsigned char *) core_text_space + p_highpc;
256 instructp += length)
257 {
258 length = 1;
259 if (*instructp == CALLS)
260 {
261 /*
262 * maybe a calls, better check it out.
263 * skip the count of the number of arguments.
264 */
265 DBG (CALLDEBUG,
266 printf ("[findcall]\t0x%x:calls",
267 instructp - (unsigned char *) core_text_space));
268 firstmode = vax_operandmode ((struct modebyte *) (instructp + length));
269 switch (firstmode)
270 {
271 case literal:
272 case immediate:
273 break;
274 default:
275 goto botched;
276 }
277 length += vax_operandlength ((struct modebyte *) (instructp + length));
278 mode = vax_operandmode ((struct modebyte *) (instructp + length));
279 DBG (CALLDEBUG,
280 printf ("\tfirst operand is %s", vax_operandname (firstmode));
281 printf ("\tsecond operand is %s\n", vax_operandname (mode)));
282 switch (mode)
283 {
284 case regdef:
285 case bytedispdef:
286 case worddispdef:
287 case longdispdef:
288 case bytereldef:
289 case wordreldef:
290 case longreldef:
291 /*
292 * indirect call: call through pointer
293 * either *d(r) as a parameter or local
294 * (r) as a return value
295 * *f as a global pointer
296 * [are there others that we miss?,
297 * e.g. arrays of pointers to functions???]
298 */
299 arc_add (parent, &indirectchild, (long) 0);
300 length += vax_operandlength (
301 (struct modebyte *) (instructp + length));
302 continue;
303 case byterel:
304 case wordrel:
305 case longrel:
306 /*
307 * regular pc relative addressing
308 * check that this is the address of
309 * a function.
310 */
311 destpc = vax_reladdr ((struct modebyte *) (instructp + length))
312 - (bfd_vma) core_text_space;
313 if (destpc >= s_lowpc && destpc <= s_highpc)
314 {
315 child = sym_lookup (&symtab, destpc);
316 DBG (CALLDEBUG,
317 printf ("[findcall]\tdestpc 0x%lx", destpc);
318 printf (" child->name %s", child->name);
319 printf (" child->addr 0x%lx\n", child->addr);
320 );
321 if (child->addr == destpc)
322 {
323 /*
324 * a hit
325 */
326 arc_add (parent, child, (long) 0);
327 length += vax_operandlength ((struct modebyte *)
328 (instructp + length));
329 continue;
330 }
331 goto botched;
332 }
333 /*
334 * else:
335 * it looked like a calls,
336 * but it wasn't to anywhere.
337 */
338 goto botched;
339 default:
340 botched:
341 /*
342 * something funny going on.
343 */
344 DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
345 length = 1;
346 continue;
347 }
348 }
349 }
350 }