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