2004-04-21 Andrew Cagney <cagney@redhat.com>
[binutils.git] / gprof / vax.c
blob56f5f4f0ceb3437bbaf42ca1b990d82f001ed15a
1 /*
2 * Copyright (c) 1983, 1993, 2001
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
29 #include "gprof.h"
30 #include "search_list.h"
31 #include "source.h"
32 #include "symtab.h"
33 #include "cg_arcs.h"
34 #include "corefile.h"
35 #include "hist.h"
38 * opcode of the `calls' instruction
40 #define CALLS 0xfb
43 * register for pc relative addressing
45 #define PC 0xf
47 enum opermodes
49 literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
50 bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef,
51 immediate, absolute, byterel, bytereldef, wordrel, wordreldef,
52 longrel, longreldef
54 typedef enum opermodes operandenum;
56 #if 0
57 /* Here to document only. We can't use this when cross compiling as
58 the bitfield layout might not be the same as native. */
59 struct modebyte
61 unsigned int regfield:4;
62 unsigned int modefield:4;
64 #endif
67 * A symbol to be the child of indirect calls:
69 static Sym indirectchild;
71 static operandenum vax_operandmode PARAMS ((unsigned char *));
72 static char *vax_operandname PARAMS ((operandenum));
73 static long vax_operandlength PARAMS ((unsigned char *));
74 static bfd_signed_vma vax_offset PARAMS ((unsigned char *));
75 void vax_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
77 static operandenum
78 vax_operandmode (modep)
79 unsigned char *modep;
81 int usesreg = *modep & 0xf;
83 switch ((*modep >> 4) & 0xf)
85 case 0:
86 case 1:
87 case 2:
88 case 3:
89 return literal;
90 case 4:
91 return indexed;
92 case 5:
93 return reg;
94 case 6:
95 return regdef;
96 case 7:
97 return autodec;
98 case 8:
99 return usesreg != PC ? autoinc : immediate;
100 case 9:
101 return usesreg != PC ? autoincdef : absolute;
102 case 10:
103 return usesreg != PC ? bytedisp : byterel;
104 case 11:
105 return usesreg != PC ? bytedispdef : bytereldef;
106 case 12:
107 return usesreg != PC ? worddisp : wordrel;
108 case 13:
109 return usesreg != PC ? worddispdef : wordreldef;
110 case 14:
111 return usesreg != PC ? longdisp : longrel;
112 case 15:
113 return usesreg != PC ? longdispdef : longreldef;
115 /* NOTREACHED */
116 abort ();
119 static char *
120 vax_operandname (mode)
121 operandenum mode;
124 switch (mode)
126 case literal:
127 return "literal";
128 case indexed:
129 return "indexed";
130 case reg:
131 return "register";
132 case regdef:
133 return "register deferred";
134 case autodec:
135 return "autodecrement";
136 case autoinc:
137 return "autoincrement";
138 case autoincdef:
139 return "autoincrement deferred";
140 case bytedisp:
141 return "byte displacement";
142 case bytedispdef:
143 return "byte displacement deferred";
144 case byterel:
145 return "byte relative";
146 case bytereldef:
147 return "byte relative deferred";
148 case worddisp:
149 return "word displacement";
150 case worddispdef:
151 return "word displacement deferred";
152 case wordrel:
153 return "word relative";
154 case wordreldef:
155 return "word relative deferred";
156 case immediate:
157 return "immediate";
158 case absolute:
159 return "absolute";
160 case longdisp:
161 return "long displacement";
162 case longdispdef:
163 return "long displacement deferred";
164 case longrel:
165 return "long relative";
166 case longreldef:
167 return "long relative deferred";
169 /* NOTREACHED */
170 abort ();
173 static long
174 vax_operandlength (modep)
175 unsigned char *modep;
178 switch (vax_operandmode (modep))
180 case literal:
181 case reg:
182 case regdef:
183 case autodec:
184 case autoinc:
185 case autoincdef:
186 return 1;
187 case bytedisp:
188 case bytedispdef:
189 case byterel:
190 case bytereldef:
191 return 2;
192 case worddisp:
193 case worddispdef:
194 case wordrel:
195 case wordreldef:
196 return 3;
197 case immediate:
198 case absolute:
199 case longdisp:
200 case longdispdef:
201 case longrel:
202 case longreldef:
203 return 5;
204 case indexed:
205 return 1 + vax_operandlength (modep + 1);
207 /* NOTREACHED */
208 abort ();
211 static bfd_signed_vma
212 vax_offset (modep)
213 unsigned char *modep;
215 operandenum mode = vax_operandmode (modep);
217 ++modep; /* skip over the mode */
218 switch (mode)
220 default:
221 fprintf (stderr, "[reladdr] not relative address\n");
222 return 0;
223 case byterel:
224 return 1 + bfd_get_signed_8 (core_bfd, modep);
225 case wordrel:
226 return 2 + bfd_get_signed_16 (core_bfd, modep);
227 case longrel:
228 return 4 + bfd_get_signed_32 (core_bfd, modep);
233 void
234 vax_find_call (parent, p_lowpc, p_highpc)
235 Sym *parent;
236 bfd_vma p_lowpc;
237 bfd_vma p_highpc;
239 unsigned char *instructp;
240 long length;
241 Sym *child;
242 operandenum mode;
243 operandenum firstmode;
244 bfd_vma pc, destpc;
245 static bfd_boolean inited = FALSE;
247 if (!inited)
249 inited = TRUE;
250 sym_init (&indirectchild);
251 indirectchild.cg.prop.fract = 1.0;
252 indirectchild.cg.cyc.head = &indirectchild;
255 if (core_text_space == 0)
257 return;
259 if (p_lowpc < s_lowpc)
261 p_lowpc = s_lowpc;
263 if (p_highpc > s_highpc)
265 p_highpc = s_highpc;
267 DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
268 parent->name, (unsigned long) p_lowpc,
269 (unsigned long) p_highpc));
270 for (pc = p_lowpc; pc < p_highpc; pc += length)
272 length = 1;
273 instructp = ((unsigned char *) core_text_space
274 + pc - core_text_sect->vma);
275 if ((*instructp & 0xff) == CALLS)
278 * maybe a calls, better check it out.
279 * skip the count of the number of arguments.
281 DBG (CALLDEBUG,
282 printf ("[findcall]\t0x%lx:calls", (unsigned long) pc));
283 firstmode = vax_operandmode (instructp + length);
284 switch (firstmode)
286 case literal:
287 case immediate:
288 break;
289 default:
290 goto botched;
292 length += vax_operandlength (instructp + length);
293 mode = vax_operandmode (instructp + length);
294 DBG (CALLDEBUG,
295 printf ("\tfirst operand is %s", vax_operandname (firstmode));
296 printf ("\tsecond operand is %s\n", vax_operandname (mode)));
297 switch (mode)
299 case regdef:
300 case bytedispdef:
301 case worddispdef:
302 case longdispdef:
303 case bytereldef:
304 case wordreldef:
305 case longreldef:
307 * indirect call: call through pointer
308 * either *d(r) as a parameter or local
309 * (r) as a return value
310 * *f as a global pointer
311 * [are there others that we miss?,
312 * e.g. arrays of pointers to functions???]
314 arc_add (parent, &indirectchild, (unsigned long) 0);
315 length += vax_operandlength (instructp + length);
316 continue;
317 case byterel:
318 case wordrel:
319 case longrel:
321 * regular pc relative addressing
322 * check that this is the address of
323 * a function.
325 destpc = pc + vax_offset (instructp + length);
326 if (destpc >= s_lowpc && destpc <= s_highpc)
328 child = sym_lookup (&symtab, destpc);
329 DBG (CALLDEBUG,
330 printf ("[findcall]\tdestpc 0x%lx",
331 (unsigned long) destpc);
332 printf (" child->name %s", child->name);
333 printf (" child->addr 0x%lx\n",
334 (unsigned long) child->addr);
336 if (child->addr == destpc)
339 * a hit
341 arc_add (parent, child, (unsigned long) 0);
342 length += vax_operandlength (instructp + length);
343 continue;
345 goto botched;
348 * else:
349 * it looked like a calls,
350 * but it wasn't to anywhere.
352 goto botched;
353 default:
354 botched:
356 * something funny going on.
358 DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
359 length = 1;
360 continue;