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