* corefile.c: Rename from core.c.
[platform/upstream/binutils.git] / gprof / tahoe.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 `callf' instruction
27      */
28 #define CALLF   0xfe
29
30     /*
31      *        register for pc relative addressing
32      */
33 #define PC      0xf
34
35 enum tahoe_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 tahoe_opermodes tahoe_operandenum;
43
44 /*
45  * A symbol to be the child of indirect callf:
46  */
47 Sym indirectchild;
48
49
50 tahoe_operandenum
51 tahoe_operandmode (modep)
52      unsigned char *modep;
53 {
54   long usesreg = ((long) *modep) & 0xf;
55
56   switch (((long) *modep) >> 4)
57     {
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;
87     }
88   /* NOTREACHED */
89   abort ();
90 }
91
92 char *
93 tahoe_operandname (mode)
94      tahoe_operandenum mode;
95 {
96
97   switch (mode)
98     {
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";
141     }
142   /* NOTREACHED */
143   abort ();
144 }
145
146 long
147 tahoe_operandlength (modep)
148      unsigned char *modep;
149 {
150
151   switch (tahoe_operandmode (modep))
152     {
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);
179     }
180   /* NOTREACHED */
181   abort ();
182 }
183
184 bfd_vma
185 tahoe_reladdr (modep)
186      char *modep;
187 {
188   tahoe_operandenum mode = tahoe_operandmode (modep);
189   char *cp;
190   short *sp;
191   long *lp;
192   int i;
193   long value = 0;
194
195   cp = modep;
196   ++cp;                         /* skip over the mode */
197   switch (mode)
198     {
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);
212     }
213 }
214
215 void
216 tahoe_find_call (parent, p_lowpc, p_highpc)
217      Sym *parent;
218      bfd_vma p_lowpc;
219      bfd_vma p_highpc;
220 {
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;
228
229   if (!inited)
230     {
231       inited = TRUE;
232       sym_init (&indirectchild);
233       indirectchild.cg.prop.fract = 1.0;
234       indirectchild.cg.cyc.head = &indirectchild;
235     }
236
237   if (core_text_space == 0)
238     {
239       return;
240     }
241   if (p_lowpc < s_lowpc)
242     {
243       p_lowpc = s_lowpc;
244     }
245   if (p_highpc > s_highpc)
246     {
247       p_highpc = s_highpc;
248     }
249   DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
250                           parent->name, p_lowpc, p_highpc));
251   for (instructp = (unsigned char *) core_text_space + p_lowpc;
252        instructp < (unsigned char *) core_text_space + p_highpc;
253        instructp += length)
254     {
255       length = 1;
256       if (*instructp == CALLF)
257         {
258           /*
259            *    maybe a callf, better check it out.
260            *      skip the count of the number of arguments.
261            */
262           DBG (CALLDEBUG, printf ("[findcall]\t0x%x:callf",
263                                   instructp - (unsigned char *) core_text_space));
264           firstmode = tahoe_operandmode (instructp + length);
265           switch (firstmode)
266             {
267             case literal:
268             case immediate:
269               break;
270             default:
271               goto botched;
272             }
273           length += tahoe_operandlength (instructp + length);
274           mode = tahoe_operandmode (instructp + length);
275           DBG (CALLDEBUG,
276                printf ("\tfirst operand is %s", tahoe_operandname (firstmode));
277                printf ("\tsecond operand is %s\n", tahoe_operandname (mode));
278             );
279           switch (mode)
280             {
281             case regdef:
282             case bytedispdef:
283             case worddispdef:
284             case longdispdef:
285             case bytereldef:
286             case wordreldef:
287             case longreldef:
288               /*
289                *    indirect call: call through pointer
290                *      either  *d(r)   as a parameter or local
291                *              (r)     as a return value
292                *              *f      as a global pointer
293                *      [are there others that we miss?,
294                *       e.g. arrays of pointers to functions???]
295                */
296               arc_add (parent, &indirectchild, (long) 0);
297               length += tahoe_operandlength (instructp + length);
298               continue;
299             case byterel:
300             case wordrel:
301             case longrel:
302               /*
303                *    regular pc relative addressing
304                *      check that this is the address of 
305                *      a function.
306                */
307               destpc = tahoe_reladdr (instructp + length)
308                 - (bfd_vma) core_text_space;
309               if (destpc >= s_lowpc && destpc <= s_highpc)
310                 {
311                   child = sym_lookup (&symtab, destpc);
312                   DBG (CALLDEBUG,
313                        printf ("[findcall]\tdestpc 0x%lx", destpc);
314                        printf (" child->name %s", child->name);
315                        printf (" child->addr 0x%lx\n", child->addr);
316                     );
317                   if (child->addr == destpc)
318                     {
319                       /*
320                        *    a hit
321                        */
322                       arc_add (parent, child, (long) 0);
323                       length += tahoe_operandlength (instructp + length);
324                       continue;
325                     }
326                   goto botched;
327                 }
328               /*
329                *    else:
330                *      it looked like a callf,
331                *      but it wasn't to anywhere.
332                */
333               goto botched;
334             default:
335             botched:
336               /*
337                *    something funny going on.
338                */
339               DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
340               length = 1;
341               continue;
342             }
343         }
344     }
345 }