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