Portability fixes.
[binutils.git] / gprof / vax.c
blob58e7de3820becba8e903eef037e5f5b32824b2e6
1 /*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved.
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.
19 #include "gprof.h"
20 #include "cg_arcs.h"
21 #include "corefile.h"
22 #include "hist.h"
23 #include "symtab.h"
26 * opcode of the `calls' instruction
28 #define CALLS 0xfb
31 * register for pc relative addressing
33 #define PC 0xf
35 enum opermodes
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
42 typedef enum opermodes operandenum;
44 struct modebyte
46 unsigned int regfield:4;
47 unsigned int modefield:4;
51 * A symbol to be the child of indirect calls:
53 Sym indirectchild;
56 static operandenum
57 vax_operandmode (modep)
58 struct modebyte *modep;
60 long usesreg = modep->regfield;
62 switch (modep->modefield)
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;
94 /* NOTREACHED */
95 abort ();
98 static char *
99 vax_operandname (mode)
100 operandenum mode;
103 switch (mode)
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";
148 /* NOTREACHED */
149 abort ();
152 static long
153 vax_operandlength (modep)
154 struct modebyte *modep;
157 switch (vax_operandmode (modep))
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);
186 /* NOTREACHED */
187 abort ();
190 static bfd_vma
191 vax_reladdr (modep)
192 struct modebyte *modep;
194 operandenum mode = vax_operandmode (modep);
195 char *cp;
196 short *sp;
197 long *lp;
199 cp = (char *) modep;
200 ++cp; /* skip over the mode */
201 switch (mode)
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);
218 void
219 vax_find_call (parent, p_lowpc, p_highpc)
220 Sym *parent;
221 bfd_vma p_lowpc;
222 bfd_vma p_highpc;
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;
232 if (!inited)
234 inited = TRUE;
235 sym_init (&indirectchild);
236 indirectchild.cg.prop.fract = 1.0;
237 indirectchild.cg.cyc.head = &indirectchild;
240 if (core_text_space == 0)
242 return;
244 if (p_lowpc < s_lowpc)
246 p_lowpc = s_lowpc;
248 if (p_highpc > s_highpc)
250 p_highpc = s_highpc;
252 DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
253 parent->name, (unsigned long) p_lowpc,
254 (unsigned long) p_highpc));
255 for (instructp = (unsigned char *) core_text_space + p_lowpc;
256 instructp < (unsigned char *) core_text_space + p_highpc;
257 instructp += length)
259 length = 1;
260 if (*instructp == CALLS)
263 * maybe a calls, better check it out.
264 * skip the count of the number of arguments.
266 DBG (CALLDEBUG,
267 printf ("[findcall]\t0x%lx:calls",
268 ((unsigned long)
269 (instructp - (unsigned char *) core_text_space))));
270 firstmode = vax_operandmode ((struct modebyte *) (instructp + length));
271 switch (firstmode)
273 case literal:
274 case immediate:
275 break;
276 default:
277 goto botched;
279 length += vax_operandlength ((struct modebyte *) (instructp + length));
280 mode = vax_operandmode ((struct modebyte *) (instructp + length));
281 DBG (CALLDEBUG,
282 printf ("\tfirst operand is %s", vax_operandname (firstmode));
283 printf ("\tsecond operand is %s\n", vax_operandname (mode)));
284 switch (mode)
286 case regdef:
287 case bytedispdef:
288 case worddispdef:
289 case longdispdef:
290 case bytereldef:
291 case wordreldef:
292 case longreldef:
294 * indirect call: call through pointer
295 * either *d(r) as a parameter or local
296 * (r) as a return value
297 * *f as a global pointer
298 * [are there others that we miss?,
299 * e.g. arrays of pointers to functions???]
301 arc_add (parent, &indirectchild, (unsigned long) 0);
302 length += vax_operandlength (
303 (struct modebyte *) (instructp + length));
304 continue;
305 case byterel:
306 case wordrel:
307 case longrel:
309 * regular pc relative addressing
310 * check that this is the address of
311 * a function.
313 destpc = vax_reladdr ((struct modebyte *) (instructp + length))
314 - (bfd_vma) core_text_space;
315 if (destpc >= s_lowpc && destpc <= s_highpc)
317 child = sym_lookup (&symtab, destpc);
318 DBG (CALLDEBUG,
319 printf ("[findcall]\tdestpc 0x%lx",
320 (unsigned long) destpc);
321 printf (" child->name %s", child->name);
322 printf (" child->addr 0x%lx\n",
323 (unsigned long) child->addr);
325 if (child->addr == destpc)
328 * a hit
330 arc_add (parent, child, (unsigned long) 0);
331 length += vax_operandlength ((struct modebyte *)
332 (instructp + length));
333 continue;
335 goto botched;
338 * else:
339 * it looked like a calls,
340 * but it wasn't to anywhere.
342 goto botched;
343 default:
344 botched:
346 * something funny going on.
348 DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
349 length = 1;
350 continue;