* emultempl/ppc64elf.em (new_vers_pattern): Warning fix.
[deliverable/binutils-gdb.git] / gprof / vax.c
1 /*
2 * Copyright (c) 1983, 2001 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 "search_list.h"
21 #include "source.h"
22 #include "symtab.h"
23 #include "cg_arcs.h"
24 #include "corefile.h"
25 #include "hist.h"
26
27 /*
28 * opcode of the `calls' instruction
29 */
30 #define CALLS 0xfb
31
32 /*
33 * register for pc relative addressing
34 */
35 #define PC 0xf
36
37 enum opermodes
38 {
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
43 };
44 typedef enum opermodes operandenum;
45
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
50 {
51 unsigned int regfield:4;
52 unsigned int modefield:4;
53 };
54 #endif
55
56 /*
57 * A symbol to be the child of indirect calls:
58 */
59 static Sym indirectchild;
60
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));
66
67 static operandenum
68 vax_operandmode (modep)
69 unsigned char *modep;
70 {
71 int usesreg = *modep & 0xf;
72
73 switch ((*modep >> 4) & 0xf)
74 {
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;
104 }
105 /* NOTREACHED */
106 abort ();
107 }
108
109 static char *
110 vax_operandname (mode)
111 operandenum mode;
112 {
113
114 switch (mode)
115 {
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";
158 }
159 /* NOTREACHED */
160 abort ();
161 }
162
163 static long
164 vax_operandlength (modep)
165 unsigned char *modep;
166 {
167
168 switch (vax_operandmode (modep))
169 {
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);
196 }
197 /* NOTREACHED */
198 abort ();
199 }
200
201 static bfd_signed_vma
202 vax_offset (modep)
203 unsigned char *modep;
204 {
205 operandenum mode = vax_operandmode (modep);
206
207 ++modep; /* skip over the mode */
208 switch (mode)
209 {
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);
219 }
220 }
221
222
223 void
224 vax_find_call (parent, p_lowpc, p_highpc)
225 Sym *parent;
226 bfd_vma p_lowpc;
227 bfd_vma p_highpc;
228 {
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;
236
237 if (!inited)
238 {
239 inited = true;
240 sym_init (&indirectchild);
241 indirectchild.cg.prop.fract = 1.0;
242 indirectchild.cg.cyc.head = &indirectchild;
243 }
244
245 if (core_text_space == 0)
246 {
247 return;
248 }
249 if (p_lowpc < s_lowpc)
250 {
251 p_lowpc = s_lowpc;
252 }
253 if (p_highpc > s_highpc)
254 {
255 p_highpc = s_highpc;
256 }
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)
261 {
262 length = 1;
263 instructp = ((unsigned char *) core_text_space
264 + pc - core_text_sect->vma);
265 if ((*instructp & 0xff) == CALLS)
266 {
267 /*
268 * maybe a calls, better check it out.
269 * skip the count of the number of arguments.
270 */
271 DBG (CALLDEBUG,
272 printf ("[findcall]\t0x%lx:calls", (unsigned long) pc));
273 firstmode = vax_operandmode (instructp + length);
274 switch (firstmode)
275 {
276 case literal:
277 case immediate:
278 break;
279 default:
280 goto botched;
281 }
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)
288 {
289 case regdef:
290 case bytedispdef:
291 case worddispdef:
292 case longdispdef:
293 case bytereldef:
294 case wordreldef:
295 case longreldef:
296 /*
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???]
303 */
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:
310 /*
311 * regular pc relative addressing
312 * check that this is the address of
313 * a function.
314 */
315 destpc = pc + vax_offset (instructp + length);
316 if (destpc >= s_lowpc && destpc <= s_highpc)
317 {
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);
325 );
326 if (child->addr == destpc)
327 {
328 /*
329 * a hit
330 */
331 arc_add (parent, child, (unsigned long) 0);
332 length += vax_operandlength (instructp + length);
333 continue;
334 }
335 goto botched;
336 }
337 /*
338 * else:
339 * it looked like a calls,
340 * but it wasn't to anywhere.
341 */
342 goto botched;
343 default:
344 botched:
345 /*
346 * something funny going on.
347 */
348 DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
349 length = 1;
350 continue;
351 }
352 }
353 }
354 }
This page took 0.039141 seconds and 4 git commands to generate.