]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gprof/vax.c
* config/sh/tm-sh.h (BELIEVE_PCC_PROMOTION): Define, so that
[thirdparty/binutils-gdb.git] / gprof / vax.c
CommitLineData
3d6c6501
SEF
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 */
5489fcc3
KR
19#include "gprof.h"
20#include "cg_arcs.h"
43870aec 21#include "corefile.h"
5489fcc3
KR
22#include "hist.h"
23#include "symtab.h"
3d6c6501 24
c3de2a19
ILT
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
5489fcc3
KR
50/*
51 * A symbol to be the child of indirect calls:
52 */
53Sym indirectchild;
3d6c6501 54
3d6c6501 55
5489fcc3 56static operandenum
c3de2a19 57vax_operandmode (modep)
12516a37 58 struct modebyte *modep;
3d6c6501 59{
12516a37
KR
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;
3d6c6501 93 }
12516a37 94 /* NOTREACHED */
c3de2a19 95 abort ();
3d6c6501
SEF
96}
97
5489fcc3 98static char *
c3de2a19 99vax_operandname (mode)
12516a37 100 operandenum mode;
3d6c6501 101{
12516a37
KR
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";
3d6c6501 147 }
12516a37 148 /* NOTREACHED */
c3de2a19 149 abort ();
3d6c6501
SEF
150}
151
5489fcc3 152static long
c3de2a19 153vax_operandlength (modep)
12516a37 154 struct modebyte *modep;
3d6c6501 155{
12516a37 156
c3de2a19 157 switch (vax_operandmode (modep))
12516a37
KR
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:
c3de2a19 184 return 1 + vax_operandlength ((struct modebyte *) ((char *) modep) + 1);
3d6c6501 185 }
12516a37 186 /* NOTREACHED */
c3de2a19 187 abort ();
3d6c6501
SEF
188}
189
5489fcc3 190static bfd_vma
c3de2a19 191vax_reladdr (modep)
12516a37 192 struct modebyte *modep;
3d6c6501 193{
c3de2a19 194 operandenum mode = vax_operandmode (modep);
12516a37
KR
195 char *cp;
196 short *sp;
197 long *lp;
3d6c6501 198
12516a37
KR
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);
3d6c6501
SEF
214 }
215}
216
5489fcc3
KR
217
218void
c3de2a19 219vax_find_call (parent, p_lowpc, p_highpc)
5489fcc3
KR
220 Sym *parent;
221 bfd_vma p_lowpc;
222 bfd_vma p_highpc;
3d6c6501 223{
12516a37
KR
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;
3d6c6501 231
12516a37
KR
232 if (!inited)
233 {
234 inited = TRUE;
235 sym_init (&indirectchild);
236 indirectchild.cg.prop.fract = 1.0;
237 indirectchild.cg.cyc.head = &indirectchild;
03c35bcb 238 }
5489fcc3 239
12516a37
KR
240 if (core_text_space == 0)
241 {
242 return;
3d6c6501 243 }
12516a37
KR
244 if (p_lowpc < s_lowpc)
245 {
246 p_lowpc = s_lowpc;
3d6c6501 247 }
12516a37
KR
248 if (p_highpc > s_highpc)
249 {
250 p_highpc = s_highpc;
3d6c6501 251 }
12516a37 252 DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
5489fcc3 253 parent->name, p_lowpc, p_highpc));
12516a37
KR
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));
c3de2a19 268 firstmode = vax_operandmode ((struct modebyte *) (instructp + length));
12516a37
KR
269 switch (firstmode)
270 {
271 case literal:
272 case immediate:
273 break;
274 default:
275 goto botched;
3d6c6501 276 }
c3de2a19
ILT
277 length += vax_operandlength ((struct modebyte *) (instructp + length));
278 mode = vax_operandmode ((struct modebyte *) (instructp + length));
12516a37 279 DBG (CALLDEBUG,
c3de2a19
ILT
280 printf ("\tfirst operand is %s", vax_operandname (firstmode));
281 printf ("\tsecond operand is %s\n", vax_operandname (mode)));
12516a37
KR
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 */
8c73afb3 299 arc_add (parent, &indirectchild, (unsigned long) 0);
c3de2a19 300 length += vax_operandlength (
12516a37
KR
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 */
c3de2a19 311 destpc = vax_reladdr ((struct modebyte *) (instructp + length))
12516a37
KR
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 */
8c73afb3 326 arc_add (parent, child, (unsigned long) 0);
c3de2a19
ILT
327 length += vax_operandlength ((struct modebyte *)
328 (instructp + length));
12516a37 329 continue;
3d6c6501 330 }
12516a37
KR
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;
3d6c6501
SEF
347 }
348 }
349 }
350}