* alpha.c (alpha_Instruction): Don't use.
[external/binutils.git] / gprof / tahoe.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 `callf' instruction
29      */
30 #define CALLF   0xfe
31
32     /*
33      *        register for pc relative addressing
34      */
35 #define PC      0xf
36
37 enum tahoe_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 tahoe_opermodes tahoe_operandenum;
45
46 /*
47  * A symbol to be the child of indirect callf:
48  */
49 static Sym indirectchild;
50
51 static tahoe_operandenum tahoe_operandmode PARAMS ((unsigned char *));
52 static char *tahoe_operandname PARAMS ((tahoe_operandenum));
53 static long tahoe_operandlength PARAMS ((unsigned char *));
54 static bfd_signed_vma tahoe_offset PARAMS ((unsigned char *));
55 void tahoe_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
56
57 static tahoe_operandenum
58 tahoe_operandmode (modep)
59      unsigned char *modep;
60 {
61   long usesreg = *modep & 0xf;
62
63   switch ((*modep >> 4) & 0xf)
64     {
65     case 0:
66     case 1:
67     case 2:
68     case 3:
69       return literal;
70     case 4:
71       return indexed;
72     case 5:
73       return reg;
74     case 6:
75       return regdef;
76     case 7:
77       return autodec;
78     case 8:
79       return usesreg != 0xe ? autoinc : immediate;
80     case 9:
81       return usesreg != PC ? autoincdef : absolute;
82     case 10:
83       return usesreg != PC ? bytedisp : byterel;
84     case 11:
85       return usesreg != PC ? bytedispdef : bytereldef;
86     case 12:
87       return usesreg != PC ? worddisp : wordrel;
88     case 13:
89       return usesreg != PC ? worddispdef : wordreldef;
90     case 14:
91       return usesreg != PC ? longdisp : longrel;
92     case 15:
93       return usesreg != PC ? longdispdef : longreldef;
94     }
95   /* NOTREACHED */
96   abort ();
97 }
98
99 static char *
100 tahoe_operandname (mode)
101      tahoe_operandenum mode;
102 {
103
104   switch (mode)
105     {
106     case literal:
107       return "literal";
108     case indexed:
109       return "indexed";
110     case reg:
111       return "register";
112     case regdef:
113       return "register deferred";
114     case autodec:
115       return "autodecrement";
116     case autoinc:
117       return "autoincrement";
118     case autoincdef:
119       return "autoincrement deferred";
120     case bytedisp:
121       return "byte displacement";
122     case bytedispdef:
123       return "byte displacement deferred";
124     case byterel:
125       return "byte relative";
126     case bytereldef:
127       return "byte relative deferred";
128     case worddisp:
129       return "word displacement";
130     case worddispdef:
131       return "word displacement deferred";
132     case wordrel:
133       return "word relative";
134     case wordreldef:
135       return "word relative deferred";
136     case immediate:
137       return "immediate";
138     case absolute:
139       return "absolute";
140     case longdisp:
141       return "long displacement";
142     case longdispdef:
143       return "long displacement deferred";
144     case longrel:
145       return "long relative";
146     case longreldef:
147       return "long relative deferred";
148     }
149   /* NOTREACHED */
150   abort ();
151 }
152
153 static long
154 tahoe_operandlength (modep)
155      unsigned char *modep;
156 {
157
158   switch (tahoe_operandmode (modep))
159     {
160     case literal:
161     case reg:
162     case regdef:
163     case autodec:
164     case autoinc:
165     case autoincdef:
166       return 1;
167     case bytedisp:
168     case bytedispdef:
169     case byterel:
170     case bytereldef:
171       return 2;
172     case worddisp:
173     case worddispdef:
174     case wordrel:
175     case wordreldef:
176       return 3;
177     case immediate:
178     case absolute:
179     case longdisp:
180     case longdispdef:
181     case longrel:
182     case longreldef:
183       return 5;
184     case indexed:
185       return 1 + tahoe_operandlength (modep + 1);
186     }
187   /* NOTREACHED */
188   abort ();
189 }
190
191 static bfd_signed_vma
192 tahoe_offset (modep)
193      unsigned char *modep;
194 {
195   tahoe_operandenum mode = tahoe_operandmode (modep);
196
197   ++modep;                              /* skip over the mode */
198   switch (mode)
199     {
200     default:
201       fprintf (stderr, "[reladdr] not relative address\n");
202       return 0;
203     case byterel:
204       return 1 + bfd_get_signed_8 (core_bfd, modep);
205     case wordrel:
206       return 2 + bfd_get_signed_16 (core_bfd, modep);
207     case longrel:
208       return 4 + bfd_get_signed_32 (core_bfd, modep);
209     }
210 }
211
212 void
213 tahoe_find_call (parent, p_lowpc, p_highpc)
214      Sym *parent;
215      bfd_vma p_lowpc;
216      bfd_vma p_highpc;
217 {
218   unsigned char *instructp;
219   long length;
220   Sym *child;
221   tahoe_operandenum mode;
222   tahoe_operandenum firstmode;
223   bfd_vma pc, destpc;
224   static bool inited = FALSE;
225
226   if (!inited)
227     {
228       inited = TRUE;
229       sym_init (&indirectchild);
230       indirectchild.cg.prop.fract = 1.0;
231       indirectchild.cg.cyc.head = &indirectchild;
232     }
233
234   if (core_text_space == 0)
235     {
236       return;
237     }
238   if (p_lowpc < s_lowpc)
239     {
240       p_lowpc = s_lowpc;
241     }
242   if (p_highpc > s_highpc)
243     {
244       p_highpc = s_highpc;
245     }
246   DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
247                           parent->name, (unsigned long) p_lowpc,
248                           (unsigned long) p_highpc));
249   for (pc = p_lowpc; pc < p_highpc; pc += length)
250     {
251       length = 1;
252       instructp = ((unsigned char *) core_text_space
253                    + pc - core_text_sect->vma);
254       if ((*instructp & 0xff) == CALLF)
255         {
256           /*
257            *    maybe a callf, better check it out.
258            *      skip the count of the number of arguments.
259            */
260           DBG (CALLDEBUG, printf ("[findcall]\t0x%lx:callf",
261                                   (unsigned long) pc));
262           firstmode = tahoe_operandmode (instructp + length);
263           switch (firstmode)
264             {
265             case literal:
266             case immediate:
267               break;
268             default:
269               goto botched;
270             }
271           length += tahoe_operandlength (instructp + length);
272           mode = tahoe_operandmode (instructp + length);
273           DBG (CALLDEBUG,
274                printf ("\tfirst operand is %s", tahoe_operandname (firstmode));
275                printf ("\tsecond operand is %s\n", tahoe_operandname (mode));
276             );
277           switch (mode)
278             {
279             case regdef:
280             case bytedispdef:
281             case worddispdef:
282             case longdispdef:
283             case bytereldef:
284             case wordreldef:
285             case longreldef:
286               /*
287                *    indirect call: call through pointer
288                *      either  *d(r)   as a parameter or local
289                *              (r)     as a return value
290                *              *f      as a global pointer
291                *      [are there others that we miss?,
292                *       e.g. arrays of pointers to functions???]
293                */
294               arc_add (parent, &indirectchild, (unsigned long) 0);
295               length += tahoe_operandlength (instructp + length);
296               continue;
297             case byterel:
298             case wordrel:
299             case longrel:
300               /*
301                *    regular pc relative addressing
302                *      check that this is the address of
303                *      a function.
304                */
305               destpc = pc + tahoe_offset (instructp + length);
306               if (destpc >= s_lowpc && destpc <= s_highpc)
307                 {
308                   child = sym_lookup (&symtab, destpc);
309                   DBG (CALLDEBUG,
310                        printf ("[findcall]\tdestpc 0x%lx",
311                                (unsigned long) destpc);
312                        printf (" child->name %s", child->name);
313                        printf (" child->addr 0x%lx\n",
314                                (unsigned long) child->addr);
315                     );
316                   if (child->addr == destpc)
317                     {
318                       /*
319                        *    a hit
320                        */
321                       arc_add (parent, child, (unsigned long) 0);
322                       length += tahoe_operandlength (instructp + length);
323                       continue;
324                     }
325                   goto botched;
326                 }
327               /*
328                *    else:
329                *      it looked like a callf,
330                *      but it wasn't to anywhere.
331                */
332               goto botched;
333             default:
334             botched:
335               /*
336                *    something funny going on.
337                */
338               DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
339               length = 1;
340               continue;
341             }
342         }
343     }
344 }