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