2001-11-06 Fred Fish <fnf@redhat.com>
[deliverable/binutils-gdb.git] / gprof / vax.c
CommitLineData
252b5132 1/*
0eee5820 2 * Copyright (c) 1983, 2001 Regents of the University of California.
252b5132
RH
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 "corefile.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
35enum 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 };
42typedef enum opermodes operandenum;
43
44struct 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 */
53Sym indirectchild;
54
55
5789ecea
AM
56static operandenum vax_operandmode PARAMS ((struct modebyte *));
57static char *vax_operandname PARAMS ((operandenum));
58static long vax_operandlength PARAMS ((struct modebyte *));
59static bfd_vma vax_reladdr PARAMS ((struct modebyte *));
60void vax_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
61
252b5132
RH
62static operandenum
63vax_operandmode (modep)
64 struct modebyte *modep;
65{
66 long usesreg = modep->regfield;
67
68 switch (modep->modefield)
69 {
70 case 0:
71 case 1:
72 case 2:
73 case 3:
74 return literal;
75 case 4:
76 return indexed;
77 case 5:
78 return reg;
79 case 6:
80 return regdef;
81 case 7:
82 return autodec;
83 case 8:
84 return usesreg != PC ? autoinc : immediate;
85 case 9:
86 return usesreg != PC ? autoincdef : absolute;
87 case 10:
88 return usesreg != PC ? bytedisp : byterel;
89 case 11:
90 return usesreg != PC ? bytedispdef : bytereldef;
91 case 12:
92 return usesreg != PC ? worddisp : wordrel;
93 case 13:
94 return usesreg != PC ? worddispdef : wordreldef;
95 case 14:
96 return usesreg != PC ? longdisp : longrel;
97 case 15:
98 return usesreg != PC ? longdispdef : longreldef;
99 }
100 /* NOTREACHED */
101 abort ();
102}
103
104static char *
105vax_operandname (mode)
106 operandenum mode;
107{
108
109 switch (mode)
110 {
111 case literal:
112 return "literal";
113 case indexed:
114 return "indexed";
115 case reg:
116 return "register";
117 case regdef:
118 return "register deferred";
119 case autodec:
120 return "autodecrement";
121 case autoinc:
122 return "autoincrement";
123 case autoincdef:
124 return "autoincrement deferred";
125 case bytedisp:
126 return "byte displacement";
127 case bytedispdef:
128 return "byte displacement deferred";
129 case byterel:
130 return "byte relative";
131 case bytereldef:
132 return "byte relative deferred";
133 case worddisp:
134 return "word displacement";
135 case worddispdef:
136 return "word displacement deferred";
137 case wordrel:
138 return "word relative";
139 case wordreldef:
140 return "word relative deferred";
141 case immediate:
142 return "immediate";
143 case absolute:
144 return "absolute";
145 case longdisp:
146 return "long displacement";
147 case longdispdef:
148 return "long displacement deferred";
149 case longrel:
150 return "long relative";
151 case longreldef:
152 return "long relative deferred";
153 }
154 /* NOTREACHED */
155 abort ();
156}
157
158static long
159vax_operandlength (modep)
160 struct modebyte *modep;
161{
162
163 switch (vax_operandmode (modep))
164 {
165 case literal:
166 case reg:
167 case regdef:
168 case autodec:
169 case autoinc:
170 case autoincdef:
171 return 1;
172 case bytedisp:
173 case bytedispdef:
174 case byterel:
175 case bytereldef:
176 return 2;
177 case worddisp:
178 case worddispdef:
179 case wordrel:
180 case wordreldef:
181 return 3;
182 case immediate:
183 case absolute:
184 case longdisp:
185 case longdispdef:
186 case longrel:
187 case longreldef:
188 return 5;
189 case indexed:
190 return 1 + vax_operandlength ((struct modebyte *) ((char *) modep) + 1);
191 }
192 /* NOTREACHED */
193 abort ();
194}
195
196static bfd_vma
197vax_reladdr (modep)
198 struct modebyte *modep;
199{
200 operandenum mode = vax_operandmode (modep);
201 char *cp;
202 short *sp;
203 long *lp;
204
205 cp = (char *) modep;
206 ++cp; /* skip over the mode */
207 switch (mode)
208 {
209 default:
210 fprintf (stderr, "[reladdr] not relative address\n");
211 return (bfd_vma) modep;
212 case byterel:
213 return (bfd_vma) (cp + sizeof *cp + *cp);
214 case wordrel:
215 sp = (short *) cp;
216 return (bfd_vma) (cp + sizeof *sp + *sp);
217 case longrel:
218 lp = (long *) cp;
219 return (bfd_vma) (cp + sizeof *lp + *lp);
220 }
221}
222
223
224void
225vax_find_call (parent, p_lowpc, p_highpc)
226 Sym *parent;
227 bfd_vma p_lowpc;
228 bfd_vma p_highpc;
229{
230 unsigned char *instructp;
231 long length;
232 Sym *child;
233 operandenum mode;
234 operandenum firstmode;
235 bfd_vma destpc;
236 static bool inited = FALSE;
237
238 if (!inited)
239 {
240 inited = TRUE;
241 sym_init (&indirectchild);
242 indirectchild.cg.prop.fract = 1.0;
243 indirectchild.cg.cyc.head = &indirectchild;
244 }
245
246 if (core_text_space == 0)
247 {
248 return;
249 }
250 if (p_lowpc < s_lowpc)
251 {
252 p_lowpc = s_lowpc;
253 }
254 if (p_highpc > s_highpc)
255 {
256 p_highpc = s_highpc;
257 }
258 DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
fdcf7d43
ILT
259 parent->name, (unsigned long) p_lowpc,
260 (unsigned long) p_highpc));
252b5132
RH
261 for (instructp = (unsigned char *) core_text_space + p_lowpc;
262 instructp < (unsigned char *) core_text_space + p_highpc;
263 instructp += length)
264 {
265 length = 1;
266 if (*instructp == CALLS)
267 {
268 /*
269 * maybe a calls, better check it out.
270 * skip the count of the number of arguments.
271 */
272 DBG (CALLDEBUG,
0e69fcbc
ILT
273 printf ("[findcall]\t0x%lx:calls",
274 ((unsigned long)
275 (instructp - (unsigned char *) core_text_space))));
252b5132
RH
276 firstmode = vax_operandmode ((struct modebyte *) (instructp + length));
277 switch (firstmode)
278 {
279 case literal:
280 case immediate:
281 break;
282 default:
283 goto botched;
284 }
285 length += vax_operandlength ((struct modebyte *) (instructp + length));
286 mode = vax_operandmode ((struct modebyte *) (instructp + length));
287 DBG (CALLDEBUG,
288 printf ("\tfirst operand is %s", vax_operandname (firstmode));
289 printf ("\tsecond operand is %s\n", vax_operandname (mode)));
290 switch (mode)
291 {
292 case regdef:
293 case bytedispdef:
294 case worddispdef:
295 case longdispdef:
296 case bytereldef:
297 case wordreldef:
298 case longreldef:
299 /*
300 * indirect call: call through pointer
301 * either *d(r) as a parameter or local
302 * (r) as a return value
303 * *f as a global pointer
304 * [are there others that we miss?,
305 * e.g. arrays of pointers to functions???]
306 */
307 arc_add (parent, &indirectchild, (unsigned long) 0);
308 length += vax_operandlength (
309 (struct modebyte *) (instructp + length));
310 continue;
311 case byterel:
312 case wordrel:
313 case longrel:
314 /*
315 * regular pc relative addressing
0eee5820 316 * check that this is the address of
252b5132
RH
317 * a function.
318 */
319 destpc = vax_reladdr ((struct modebyte *) (instructp + length))
320 - (bfd_vma) core_text_space;
321 if (destpc >= s_lowpc && destpc <= s_highpc)
322 {
323 child = sym_lookup (&symtab, destpc);
324 DBG (CALLDEBUG,
fdcf7d43
ILT
325 printf ("[findcall]\tdestpc 0x%lx",
326 (unsigned long) destpc);
252b5132 327 printf (" child->name %s", child->name);
fdcf7d43
ILT
328 printf (" child->addr 0x%lx\n",
329 (unsigned long) child->addr);
252b5132
RH
330 );
331 if (child->addr == destpc)
332 {
333 /*
334 * a hit
335 */
336 arc_add (parent, child, (unsigned long) 0);
337 length += vax_operandlength ((struct modebyte *)
338 (instructp + length));
339 continue;
340 }
341 goto botched;
342 }
343 /*
344 * else:
345 * it looked like a calls,
346 * but it wasn't to anywhere.
347 */
348 goto botched;
349 default:
350 botched:
351 /*
352 * something funny going on.
353 */
354 DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
355 length = 1;
356 continue;
357 }
358 }
359 }
360}
This page took 0.094844 seconds and 4 git commands to generate.