]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gprof/vax.c
This commit was generated by cvs2svn to track changes on a CVS vendor
[thirdparty/binutils-gdb.git] / gprof / vax.c
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 */
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
35 enum 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 };
42 typedef enum opermodes operandenum;
43
44 struct 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 */
53 Sym indirectchild;
54
55
56 static operandenum
57 vax_operandmode (modep)
58 struct modebyte *modep;
59 {
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;
93 }
94 /* NOTREACHED */
95 abort ();
96 }
97
98 static char *
99 vax_operandname (mode)
100 operandenum mode;
101 {
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";
147 }
148 /* NOTREACHED */
149 abort ();
150 }
151
152 static long
153 vax_operandlength (modep)
154 struct modebyte *modep;
155 {
156
157 switch (vax_operandmode (modep))
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:
184 return 1 + vax_operandlength ((struct modebyte *) ((char *) modep) + 1);
185 }
186 /* NOTREACHED */
187 abort ();
188 }
189
190 static bfd_vma
191 vax_reladdr (modep)
192 struct modebyte *modep;
193 {
194 operandenum mode = vax_operandmode (modep);
195 char *cp;
196 short *sp;
197 long *lp;
198
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);
214 }
215 }
216
217
218 void
219 vax_find_call (parent, p_lowpc, p_highpc)
220 Sym *parent;
221 bfd_vma p_lowpc;
222 bfd_vma p_highpc;
223 {
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;
231
232 if (!inited)
233 {
234 inited = TRUE;
235 sym_init (&indirectchild);
236 indirectchild.cg.prop.fract = 1.0;
237 indirectchild.cg.cyc.head = &indirectchild;
238 }
239
240 if (core_text_space == 0)
241 {
242 return;
243 }
244 if (p_lowpc < s_lowpc)
245 {
246 p_lowpc = s_lowpc;
247 }
248 if (p_highpc > s_highpc)
249 {
250 p_highpc = s_highpc;
251 }
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)
258 {
259 length = 1;
260 if (*instructp == CALLS)
261 {
262 /*
263 * maybe a calls, better check it out.
264 * skip the count of the number of arguments.
265 */
266 DBG (CALLDEBUG,
267 printf ("[findcall]\t0x%x:calls",
268 instructp - (unsigned char *) core_text_space));
269 firstmode = vax_operandmode ((struct modebyte *) (instructp + length));
270 switch (firstmode)
271 {
272 case literal:
273 case immediate:
274 break;
275 default:
276 goto botched;
277 }
278 length += vax_operandlength ((struct modebyte *) (instructp + length));
279 mode = vax_operandmode ((struct modebyte *) (instructp + length));
280 DBG (CALLDEBUG,
281 printf ("\tfirst operand is %s", vax_operandname (firstmode));
282 printf ("\tsecond operand is %s\n", vax_operandname (mode)));
283 switch (mode)
284 {
285 case regdef:
286 case bytedispdef:
287 case worddispdef:
288 case longdispdef:
289 case bytereldef:
290 case wordreldef:
291 case longreldef:
292 /*
293 * indirect call: call through pointer
294 * either *d(r) as a parameter or local
295 * (r) as a return value
296 * *f as a global pointer
297 * [are there others that we miss?,
298 * e.g. arrays of pointers to functions???]
299 */
300 arc_add (parent, &indirectchild, (unsigned long) 0);
301 length += vax_operandlength (
302 (struct modebyte *) (instructp + length));
303 continue;
304 case byterel:
305 case wordrel:
306 case longrel:
307 /*
308 * regular pc relative addressing
309 * check that this is the address of
310 * a function.
311 */
312 destpc = vax_reladdr ((struct modebyte *) (instructp + length))
313 - (bfd_vma) core_text_space;
314 if (destpc >= s_lowpc && destpc <= s_highpc)
315 {
316 child = sym_lookup (&symtab, destpc);
317 DBG (CALLDEBUG,
318 printf ("[findcall]\tdestpc 0x%lx",
319 (unsigned long) destpc);
320 printf (" child->name %s", child->name);
321 printf (" child->addr 0x%lx\n",
322 (unsigned long) child->addr);
323 );
324 if (child->addr == destpc)
325 {
326 /*
327 * a hit
328 */
329 arc_add (parent, child, (unsigned long) 0);
330 length += vax_operandlength ((struct modebyte *)
331 (instructp + length));
332 continue;
333 }
334 goto botched;
335 }
336 /*
337 * else:
338 * it looked like a calls,
339 * but it wasn't to anywhere.
340 */
341 goto botched;
342 default:
343 botched:
344 /*
345 * something funny going on.
346 */
347 DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
348 length = 1;
349 continue;
350 }
351 }
352 }
353 }