2001-05-28 Philip Blundell <philb@gnu.org>
[binutils.git] / gprof / tahoe.c
blob5981bc5278bbca9fde1d7f17f2d3048861e826fb
1 /*
2 * Copyright (c) 1983 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 "cg_arcs.h"
21 #include "corefile.h"
22 #include "hist.h"
23 #include "symtab.h"
26 * opcode of the `callf' instruction
28 #define CALLF 0xfe
31 * register for pc relative addressing
33 #define PC 0xf
35 enum tahoe_opermodes
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
42 typedef enum tahoe_opermodes tahoe_operandenum;
45 * A symbol to be the child of indirect callf:
47 Sym indirectchild;
50 tahoe_operandenum
51 tahoe_operandmode (modep)
52 unsigned char *modep;
54 long usesreg = ((long) *modep) & 0xf;
56 switch (((long) *modep) >> 4)
58 case 0:
59 case 1:
60 case 2:
61 case 3:
62 return literal;
63 case 4:
64 return indexed;
65 case 5:
66 return reg;
67 case 6:
68 return regdef;
69 case 7:
70 return autodec;
71 case 8:
72 return usesreg != 0xe ? autoinc : immediate;
73 case 9:
74 return usesreg != PC ? autoincdef : absolute;
75 case 10:
76 return usesreg != PC ? bytedisp : byterel;
77 case 11:
78 return usesreg != PC ? bytedispdef : bytereldef;
79 case 12:
80 return usesreg != PC ? worddisp : wordrel;
81 case 13:
82 return usesreg != PC ? worddispdef : wordreldef;
83 case 14:
84 return usesreg != PC ? longdisp : longrel;
85 case 15:
86 return usesreg != PC ? longdispdef : longreldef;
88 /* NOTREACHED */
89 abort ();
92 char *
93 tahoe_operandname (mode)
94 tahoe_operandenum mode;
97 switch (mode)
99 case literal:
100 return "literal";
101 case indexed:
102 return "indexed";
103 case reg:
104 return "register";
105 case regdef:
106 return "register deferred";
107 case autodec:
108 return "autodecrement";
109 case autoinc:
110 return "autoincrement";
111 case autoincdef:
112 return "autoincrement deferred";
113 case bytedisp:
114 return "byte displacement";
115 case bytedispdef:
116 return "byte displacement deferred";
117 case byterel:
118 return "byte relative";
119 case bytereldef:
120 return "byte relative deferred";
121 case worddisp:
122 return "word displacement";
123 case worddispdef:
124 return "word displacement deferred";
125 case wordrel:
126 return "word relative";
127 case wordreldef:
128 return "word relative deferred";
129 case immediate:
130 return "immediate";
131 case absolute:
132 return "absolute";
133 case longdisp:
134 return "long displacement";
135 case longdispdef:
136 return "long displacement deferred";
137 case longrel:
138 return "long relative";
139 case longreldef:
140 return "long relative deferred";
142 /* NOTREACHED */
143 abort ();
146 long
147 tahoe_operandlength (modep)
148 unsigned char *modep;
151 switch (tahoe_operandmode (modep))
153 case literal:
154 case reg:
155 case regdef:
156 case autodec:
157 case autoinc:
158 case autoincdef:
159 return 1;
160 case bytedisp:
161 case bytedispdef:
162 case byterel:
163 case bytereldef:
164 return 2;
165 case worddisp:
166 case worddispdef:
167 case wordrel:
168 case wordreldef:
169 return 3;
170 case immediate:
171 case absolute:
172 case longdisp:
173 case longdispdef:
174 case longrel:
175 case longreldef:
176 return 5;
177 case indexed:
178 return 1 + tahoe_operandlength (modep + 1);
180 /* NOTREACHED */
181 abort ();
184 bfd_vma
185 tahoe_reladdr (modep)
186 char *modep;
188 tahoe_operandenum mode = tahoe_operandmode (modep);
189 char *cp;
190 short *sp;
191 long *lp;
192 int i;
193 long value = 0;
195 cp = modep;
196 ++cp; /* skip over the mode */
197 switch (mode)
199 default:
200 fprintf (stderr, "[reladdr] not relative address\n");
201 return (bfd_vma) modep;
202 case byterel:
203 return (bfd_vma) (cp + sizeof *cp + *cp);
204 case wordrel:
205 for (i = 0; (size_t) i < sizeof *sp; i++)
206 value = (value << 8) + (cp[i] & 0xff);
207 return (bfd_vma) (cp + sizeof *sp + value);
208 case longrel:
209 for (i = 0; (size_t) i < sizeof *lp; i++)
210 value = (value << 8) + (cp[i] & 0xff);
211 return (bfd_vma) (cp + sizeof *lp + value);
215 void
216 tahoe_find_call (parent, p_lowpc, p_highpc)
217 Sym *parent;
218 bfd_vma p_lowpc;
219 bfd_vma p_highpc;
221 unsigned char *instructp;
222 long length;
223 Sym *child;
224 tahoe_operandenum mode;
225 tahoe_operandenum firstmode;
226 bfd_vma destpc;
227 static bool inited = FALSE;
229 if (!inited)
231 inited = TRUE;
232 sym_init (&indirectchild);
233 indirectchild.cg.prop.fract = 1.0;
234 indirectchild.cg.cyc.head = &indirectchild;
237 if (core_text_space == 0)
239 return;
241 if (p_lowpc < s_lowpc)
243 p_lowpc = s_lowpc;
245 if (p_highpc > s_highpc)
247 p_highpc = s_highpc;
249 DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
250 parent->name, (unsigned long) p_lowpc,
251 (unsigned long) p_highpc));
252 for (instructp = (unsigned char *) core_text_space + p_lowpc;
253 instructp < (unsigned char *) core_text_space + p_highpc;
254 instructp += length)
256 length = 1;
257 if (*instructp == CALLF)
260 * maybe a callf, better check it out.
261 * skip the count of the number of arguments.
263 DBG (CALLDEBUG, printf ("[findcall]\t0x%lx:callf",
264 ((unsigned long)
265 (instructp
266 - (unsigned char *) core_text_space))));
267 firstmode = tahoe_operandmode (instructp + length);
268 switch (firstmode)
270 case literal:
271 case immediate:
272 break;
273 default:
274 goto botched;
276 length += tahoe_operandlength (instructp + length);
277 mode = tahoe_operandmode (instructp + length);
278 DBG (CALLDEBUG,
279 printf ("\tfirst operand is %s", tahoe_operandname (firstmode));
280 printf ("\tsecond operand is %s\n", tahoe_operandname (mode));
282 switch (mode)
284 case regdef:
285 case bytedispdef:
286 case worddispdef:
287 case longdispdef:
288 case bytereldef:
289 case wordreldef:
290 case longreldef:
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???]
299 arc_add (parent, &indirectchild, (unsigned long) 0);
300 length += tahoe_operandlength (instructp + length);
301 continue;
302 case byterel:
303 case wordrel:
304 case longrel:
306 * regular pc relative addressing
307 * check that this is the address of
308 * a function.
310 destpc = tahoe_reladdr (instructp + length)
311 - (bfd_vma) core_text_space;
312 if (destpc >= s_lowpc && destpc <= s_highpc)
314 child = sym_lookup (&symtab, destpc);
315 DBG (CALLDEBUG,
316 printf ("[findcall]\tdestpc 0x%lx",
317 (unsigned long) destpc);
318 printf (" child->name %s", child->name);
319 printf (" child->addr 0x%lx\n",
320 (unsigned long) child->addr);
322 if (child->addr == destpc)
325 * a hit
327 arc_add (parent, child, (unsigned long) 0);
328 length += tahoe_operandlength (instructp + length);
329 continue;
331 goto botched;
334 * else:
335 * it looked like a callf,
336 * but it wasn't to anywhere.
338 goto botched;
339 default:
340 botched:
342 * something funny going on.
344 DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
345 length = 1;
346 continue;