2002-06-08 Daniel Jacobowitz <drow@mvista.com>
[binutils.git] / gprof / vax.c
bloba54cce27f47d17456c396b62f0c03cf05fbeccaa
1 /*
2 * Copyright (c) 1983, 2001 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 "search_list.h"
21 #include "source.h"
22 #include "symtab.h"
23 #include "cg_arcs.h"
24 #include "corefile.h"
25 #include "hist.h"
28 * opcode of the `calls' instruction
30 #define CALLS 0xfb
33 * register for pc relative addressing
35 #define PC 0xf
37 enum opermodes
39 literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
40 bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef,
41 immediate, absolute, byterel, bytereldef, wordrel, wordreldef,
42 longrel, longreldef
44 typedef enum opermodes operandenum;
46 #if 0
47 /* Here to document only. We can't use this when cross compiling as
48 the bitfield layout might not be the same as native. */
49 struct modebyte
51 unsigned int regfield:4;
52 unsigned int modefield:4;
54 #endif
57 * A symbol to be the child of indirect calls:
59 static Sym indirectchild;
61 static operandenum vax_operandmode PARAMS ((unsigned char *));
62 static char *vax_operandname PARAMS ((operandenum));
63 static long vax_operandlength PARAMS ((unsigned char *));
64 static bfd_signed_vma vax_offset PARAMS ((unsigned char *));
65 void vax_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
67 static operandenum
68 vax_operandmode (modep)
69 unsigned char *modep;
71 int usesreg = *modep & 0xf;
73 switch ((*modep >> 4) & 0xf)
75 case 0:
76 case 1:
77 case 2:
78 case 3:
79 return literal;
80 case 4:
81 return indexed;
82 case 5:
83 return reg;
84 case 6:
85 return regdef;
86 case 7:
87 return autodec;
88 case 8:
89 return usesreg != PC ? autoinc : immediate;
90 case 9:
91 return usesreg != PC ? autoincdef : absolute;
92 case 10:
93 return usesreg != PC ? bytedisp : byterel;
94 case 11:
95 return usesreg != PC ? bytedispdef : bytereldef;
96 case 12:
97 return usesreg != PC ? worddisp : wordrel;
98 case 13:
99 return usesreg != PC ? worddispdef : wordreldef;
100 case 14:
101 return usesreg != PC ? longdisp : longrel;
102 case 15:
103 return usesreg != PC ? longdispdef : longreldef;
105 /* NOTREACHED */
106 abort ();
109 static char *
110 vax_operandname (mode)
111 operandenum mode;
114 switch (mode)
116 case literal:
117 return "literal";
118 case indexed:
119 return "indexed";
120 case reg:
121 return "register";
122 case regdef:
123 return "register deferred";
124 case autodec:
125 return "autodecrement";
126 case autoinc:
127 return "autoincrement";
128 case autoincdef:
129 return "autoincrement deferred";
130 case bytedisp:
131 return "byte displacement";
132 case bytedispdef:
133 return "byte displacement deferred";
134 case byterel:
135 return "byte relative";
136 case bytereldef:
137 return "byte relative deferred";
138 case worddisp:
139 return "word displacement";
140 case worddispdef:
141 return "word displacement deferred";
142 case wordrel:
143 return "word relative";
144 case wordreldef:
145 return "word relative deferred";
146 case immediate:
147 return "immediate";
148 case absolute:
149 return "absolute";
150 case longdisp:
151 return "long displacement";
152 case longdispdef:
153 return "long displacement deferred";
154 case longrel:
155 return "long relative";
156 case longreldef:
157 return "long relative deferred";
159 /* NOTREACHED */
160 abort ();
163 static long
164 vax_operandlength (modep)
165 unsigned char *modep;
168 switch (vax_operandmode (modep))
170 case literal:
171 case reg:
172 case regdef:
173 case autodec:
174 case autoinc:
175 case autoincdef:
176 return 1;
177 case bytedisp:
178 case bytedispdef:
179 case byterel:
180 case bytereldef:
181 return 2;
182 case worddisp:
183 case worddispdef:
184 case wordrel:
185 case wordreldef:
186 return 3;
187 case immediate:
188 case absolute:
189 case longdisp:
190 case longdispdef:
191 case longrel:
192 case longreldef:
193 return 5;
194 case indexed:
195 return 1 + vax_operandlength (modep + 1);
197 /* NOTREACHED */
198 abort ();
201 static bfd_signed_vma
202 vax_offset (modep)
203 unsigned char *modep;
205 operandenum mode = vax_operandmode (modep);
207 ++modep; /* skip over the mode */
208 switch (mode)
210 default:
211 fprintf (stderr, "[reladdr] not relative address\n");
212 return 0;
213 case byterel:
214 return 1 + bfd_get_signed_8 (core_bfd, modep);
215 case wordrel:
216 return 2 + bfd_get_signed_16 (core_bfd, modep);
217 case longrel:
218 return 4 + bfd_get_signed_32 (core_bfd, modep);
223 void
224 vax_find_call (parent, p_lowpc, p_highpc)
225 Sym *parent;
226 bfd_vma p_lowpc;
227 bfd_vma p_highpc;
229 unsigned char *instructp;
230 long length;
231 Sym *child;
232 operandenum mode;
233 operandenum firstmode;
234 bfd_vma pc, destpc;
235 static boolean inited = false;
237 if (!inited)
239 inited = true;
240 sym_init (&indirectchild);
241 indirectchild.cg.prop.fract = 1.0;
242 indirectchild.cg.cyc.head = &indirectchild;
245 if (core_text_space == 0)
247 return;
249 if (p_lowpc < s_lowpc)
251 p_lowpc = s_lowpc;
253 if (p_highpc > s_highpc)
255 p_highpc = s_highpc;
257 DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
258 parent->name, (unsigned long) p_lowpc,
259 (unsigned long) p_highpc));
260 for (pc = p_lowpc; pc < p_highpc; pc += length)
262 length = 1;
263 instructp = ((unsigned char *) core_text_space
264 + pc - core_text_sect->vma);
265 if ((*instructp & 0xff) == CALLS)
268 * maybe a calls, better check it out.
269 * skip the count of the number of arguments.
271 DBG (CALLDEBUG,
272 printf ("[findcall]\t0x%lx:calls", (unsigned long) pc));
273 firstmode = vax_operandmode (instructp + length);
274 switch (firstmode)
276 case literal:
277 case immediate:
278 break;
279 default:
280 goto botched;
282 length += vax_operandlength (instructp + length);
283 mode = vax_operandmode (instructp + length);
284 DBG (CALLDEBUG,
285 printf ("\tfirst operand is %s", vax_operandname (firstmode));
286 printf ("\tsecond operand is %s\n", vax_operandname (mode)));
287 switch (mode)
289 case regdef:
290 case bytedispdef:
291 case worddispdef:
292 case longdispdef:
293 case bytereldef:
294 case wordreldef:
295 case longreldef:
297 * indirect call: call through pointer
298 * either *d(r) as a parameter or local
299 * (r) as a return value
300 * *f as a global pointer
301 * [are there others that we miss?,
302 * e.g. arrays of pointers to functions???]
304 arc_add (parent, &indirectchild, (unsigned long) 0);
305 length += vax_operandlength (instructp + length);
306 continue;
307 case byterel:
308 case wordrel:
309 case longrel:
311 * regular pc relative addressing
312 * check that this is the address of
313 * a function.
315 destpc = pc + vax_offset (instructp + length);
316 if (destpc >= s_lowpc && destpc <= s_highpc)
318 child = sym_lookup (&symtab, destpc);
319 DBG (CALLDEBUG,
320 printf ("[findcall]\tdestpc 0x%lx",
321 (unsigned long) destpc);
322 printf (" child->name %s", child->name);
323 printf (" child->addr 0x%lx\n",
324 (unsigned long) child->addr);
326 if (child->addr == destpc)
329 * a hit
331 arc_add (parent, child, (unsigned long) 0);
332 length += vax_operandlength (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;