2004-02-10 Arnaud Charlet <charlet@act-europe.fr>,
[binutils.git] / gprof / tahoe.c
blob1e7da7df0ace31ce6e48e6c6537b0805be7edfad
1 /*
2 * Copyright (c) 1983, 1993, 2001
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
29 #include "gprof.h"
30 #include "search_list.h"
31 #include "source.h"
32 #include "symtab.h"
33 #include "cg_arcs.h"
34 #include "corefile.h"
35 #include "hist.h"
38 * opcode of the `callf' instruction
40 #define CALLF 0xfe
43 * register for pc relative addressing
45 #define PC 0xf
47 enum tahoe_opermodes
49 literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
50 bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef,
51 immediate, absolute, byterel, bytereldef, wordrel, wordreldef,
52 longrel, longreldef
54 typedef enum tahoe_opermodes tahoe_operandenum;
57 * A symbol to be the child of indirect callf:
59 static Sym indirectchild;
61 static tahoe_operandenum tahoe_operandmode PARAMS ((unsigned char *));
62 static char *tahoe_operandname PARAMS ((tahoe_operandenum));
63 static long tahoe_operandlength PARAMS ((unsigned char *));
64 static bfd_signed_vma tahoe_offset PARAMS ((unsigned char *));
65 void tahoe_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
67 static tahoe_operandenum
68 tahoe_operandmode (modep)
69 unsigned char *modep;
71 long usesreg = *modep & 0xf;
73 switch ((*modep >> 4) & 0xf)
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 != 0xe ? 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;
105 /* NOTREACHED */
106 abort ();
109 static char *
110 tahoe_operandname (mode)
111 tahoe_operandenum mode;
114 switch (mode)
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";
159 /* NOTREACHED */
160 abort ();
163 static long
164 tahoe_operandlength (modep)
165 unsigned char *modep;
168 switch (tahoe_operandmode (modep))
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 + tahoe_operandlength (modep + 1);
197 /* NOTREACHED */
198 abort ();
201 static bfd_signed_vma
202 tahoe_offset (modep)
203 unsigned char *modep;
205 tahoe_operandenum mode = tahoe_operandmode (modep);
207 ++modep; /* skip over the mode */
208 switch (mode)
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);
222 void
223 tahoe_find_call (parent, p_lowpc, p_highpc)
224 Sym *parent;
225 bfd_vma p_lowpc;
226 bfd_vma p_highpc;
228 unsigned char *instructp;
229 long length;
230 Sym *child;
231 tahoe_operandenum mode;
232 tahoe_operandenum firstmode;
233 bfd_vma pc, destpc;
234 static bfd_boolean inited = FALSE;
236 if (!inited)
238 inited = TRUE;
239 sym_init (&indirectchild);
240 indirectchild.cg.prop.fract = 1.0;
241 indirectchild.cg.cyc.head = &indirectchild;
244 if (core_text_space == 0)
246 return;
248 if (p_lowpc < s_lowpc)
250 p_lowpc = s_lowpc;
252 if (p_highpc > s_highpc)
254 p_highpc = s_highpc;
256 DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
257 parent->name, (unsigned long) p_lowpc,
258 (unsigned long) p_highpc));
259 for (pc = p_lowpc; pc < p_highpc; pc += length)
261 length = 1;
262 instructp = ((unsigned char *) core_text_space
263 + pc - core_text_sect->vma);
264 if ((*instructp & 0xff) == CALLF)
267 * maybe a callf, better check it out.
268 * skip the count of the number of arguments.
270 DBG (CALLDEBUG, printf ("[findcall]\t0x%lx:callf",
271 (unsigned long) pc));
272 firstmode = tahoe_operandmode (instructp + length);
273 switch (firstmode)
275 case literal:
276 case immediate:
277 break;
278 default:
279 goto botched;
281 length += tahoe_operandlength (instructp + length);
282 mode = tahoe_operandmode (instructp + length);
283 DBG (CALLDEBUG,
284 printf ("\tfirst operand is %s", tahoe_operandname (firstmode));
285 printf ("\tsecond operand is %s\n", tahoe_operandname (mode));
287 switch (mode)
289 case regdef:
290 case bytedispdef:
291 case worddispdef:
292 case longdispdef:
293 case bytereldef:
294 case wordreldef:
295 case longreldef:
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???]
304 arc_add (parent, &indirectchild, (unsigned long) 0);
305 length += tahoe_operandlength (instructp + length);
306 continue;
307 case byterel:
308 case wordrel:
309 case longrel:
311 * regular pc relative addressing
312 * check that this is the address of
313 * a function.
315 destpc = pc + tahoe_offset (instructp + length);
316 if (destpc >= s_lowpc && destpc <= s_highpc)
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);
326 if (child->addr == destpc)
329 * a hit
331 arc_add (parent, child, (unsigned long) 0);
332 length += tahoe_operandlength (instructp + length);
333 continue;
335 goto botched;
338 * else:
339 * it looked like a callf,
340 * but it wasn't to anywhere.
342 goto botched;
343 default:
344 botched:
346 * something funny going on.
348 DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
349 length = 1;
350 continue;