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