xref: /openbsd-src/gnu/usr.bin/binutils/gprof/vax.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*
2  * Copyright (c) 1983, 1993, 2001
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 #include "gprof.h"
30 #include "cg_arcs.h"
31 #include "corefile.h"
32 #include "hist.h"
33 #include "symtab.h"
34 
35     /*
36      *        opcode of the `calls' instruction
37      */
38 #define	CALLS	0xfb
39 
40     /*
41      *        register for pc relative addressing
42      */
43 #define	PC	0xf
44 
45 enum opermodes
46   {
47     literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
48     bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef,
49     immediate, absolute, byterel, bytereldef, wordrel, wordreldef,
50     longrel, longreldef
51   };
52 typedef enum opermodes operandenum;
53 
54 struct modebyte
55   {
56     unsigned int regfield:4;
57     unsigned int modefield:4;
58   };
59 
60 /*
61  * A symbol to be the child of indirect calls:
62  */
63 Sym indirectchild;
64 
65 
66 static operandenum
67 vax_operandmode (modep)
68      struct modebyte *modep;
69 {
70   long usesreg = modep->regfield;
71 
72   switch (modep->modefield)
73     {
74     case 0:
75     case 1:
76     case 2:
77     case 3:
78       return literal;
79     case 4:
80       return indexed;
81     case 5:
82       return reg;
83     case 6:
84       return regdef;
85     case 7:
86       return autodec;
87     case 8:
88       return usesreg != PC ? autoinc : immediate;
89     case 9:
90       return usesreg != PC ? autoincdef : absolute;
91     case 10:
92       return usesreg != PC ? bytedisp : byterel;
93     case 11:
94       return usesreg != PC ? bytedispdef : bytereldef;
95     case 12:
96       return usesreg != PC ? worddisp : wordrel;
97     case 13:
98       return usesreg != PC ? worddispdef : wordreldef;
99     case 14:
100       return usesreg != PC ? longdisp : longrel;
101     case 15:
102       return usesreg != PC ? longdispdef : longreldef;
103     }
104   /* NOTREACHED */
105   abort ();
106 }
107 
108 static char *
109 vax_operandname (mode)
110      operandenum mode;
111 {
112 
113   switch (mode)
114     {
115     case literal:
116       return "literal";
117     case indexed:
118       return "indexed";
119     case reg:
120       return "register";
121     case regdef:
122       return "register deferred";
123     case autodec:
124       return "autodecrement";
125     case autoinc:
126       return "autoincrement";
127     case autoincdef:
128       return "autoincrement deferred";
129     case bytedisp:
130       return "byte displacement";
131     case bytedispdef:
132       return "byte displacement deferred";
133     case byterel:
134       return "byte relative";
135     case bytereldef:
136       return "byte relative deferred";
137     case worddisp:
138       return "word displacement";
139     case worddispdef:
140       return "word displacement deferred";
141     case wordrel:
142       return "word relative";
143     case wordreldef:
144       return "word relative deferred";
145     case immediate:
146       return "immediate";
147     case absolute:
148       return "absolute";
149     case longdisp:
150       return "long displacement";
151     case longdispdef:
152       return "long displacement deferred";
153     case longrel:
154       return "long relative";
155     case longreldef:
156       return "long relative deferred";
157     }
158   /* NOTREACHED */
159   abort ();
160 }
161 
162 static long
163 vax_operandlength (modep)
164      struct modebyte *modep;
165 {
166 
167   switch (vax_operandmode (modep))
168     {
169     case literal:
170     case reg:
171     case regdef:
172     case autodec:
173     case autoinc:
174     case autoincdef:
175       return 1;
176     case bytedisp:
177     case bytedispdef:
178     case byterel:
179     case bytereldef:
180       return 2;
181     case worddisp:
182     case worddispdef:
183     case wordrel:
184     case wordreldef:
185       return 3;
186     case immediate:
187     case absolute:
188     case longdisp:
189     case longdispdef:
190     case longrel:
191     case longreldef:
192       return 5;
193     case indexed:
194       return 1 + vax_operandlength ((struct modebyte *) ((char *) modep) + 1);
195     }
196   /* NOTREACHED */
197   abort ();
198 }
199 
200 static bfd_vma
201 vax_reladdr (modep)
202      struct modebyte *modep;
203 {
204   operandenum mode = vax_operandmode (modep);
205   char *cp;
206   short *sp;
207   long *lp;
208 
209   cp = (char *) modep;
210   ++cp;				/* skip over the mode */
211   switch (mode)
212     {
213     default:
214       fprintf (stderr, "[reladdr] not relative address\n");
215       return (bfd_vma) modep;
216     case byterel:
217       return (bfd_vma) (cp + sizeof *cp + *cp);
218     case wordrel:
219       sp = (short *) cp;
220       return (bfd_vma) (cp + sizeof *sp + *sp);
221     case longrel:
222       lp = (long *) cp;
223       return (bfd_vma) (cp + sizeof *lp + *lp);
224     }
225 }
226 
227 
228 void
229 vax_find_call (parent, p_lowpc, p_highpc)
230      Sym *parent;
231      bfd_vma p_lowpc;
232      bfd_vma p_highpc;
233 {
234   unsigned char *instructp;
235   long length;
236   Sym *child;
237   operandenum mode;
238   operandenum firstmode;
239   bfd_vma destpc;
240   static bool inited = FALSE;
241 
242   if (!inited)
243     {
244       inited = TRUE;
245       sym_init (&indirectchild);
246       indirectchild.cg.prop.fract = 1.0;
247       indirectchild.cg.cyc.head = &indirectchild;
248     }
249 
250   if (core_text_space == 0)
251     {
252       return;
253     }
254   if (p_lowpc < s_lowpc)
255     {
256       p_lowpc = s_lowpc;
257     }
258   if (p_highpc > s_highpc)
259     {
260       p_highpc = s_highpc;
261     }
262   DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
263 			  parent->name, (unsigned long) p_lowpc,
264 			  (unsigned long) p_highpc));
265   for (instructp = (unsigned char *) core_text_space + p_lowpc;
266        instructp < (unsigned char *) core_text_space + p_highpc;
267        instructp += length)
268     {
269       length = 1;
270       if (*instructp == CALLS)
271 	{
272 	  /*
273 	   *    maybe a calls, better check it out.
274 	   *      skip the count of the number of arguments.
275 	   */
276 	  DBG (CALLDEBUG,
277 	       printf ("[findcall]\t0x%lx:calls",
278 		       ((unsigned long)
279 			(instructp - (unsigned char *) core_text_space))));
280 	  firstmode = vax_operandmode ((struct modebyte *) (instructp + length));
281 	  switch (firstmode)
282 	    {
283 	    case literal:
284 	    case immediate:
285 	      break;
286 	    default:
287 	      goto botched;
288 	    }
289 	  length += vax_operandlength ((struct modebyte *) (instructp + length));
290 	  mode = vax_operandmode ((struct modebyte *) (instructp + length));
291 	  DBG (CALLDEBUG,
292 	       printf ("\tfirst operand is %s", vax_operandname (firstmode));
293 	       printf ("\tsecond operand is %s\n", vax_operandname (mode)));
294 	  switch (mode)
295 	    {
296 	    case regdef:
297 	    case bytedispdef:
298 	    case worddispdef:
299 	    case longdispdef:
300 	    case bytereldef:
301 	    case wordreldef:
302 	    case longreldef:
303 	      /*
304 	       *    indirect call: call through pointer
305 	       *      either  *d(r)   as a parameter or local
306 	       *              (r)     as a return value
307 	       *              *f      as a global pointer
308 	       *      [are there others that we miss?,
309 	       *       e.g. arrays of pointers to functions???]
310 	       */
311 	      arc_add (parent, &indirectchild, (unsigned long) 0);
312 	      length += vax_operandlength (
313 				  (struct modebyte *) (instructp + length));
314 	      continue;
315 	    case byterel:
316 	    case wordrel:
317 	    case longrel:
318 	      /*
319 	       *    regular pc relative addressing
320 	       *      check that this is the address of
321 	       *      a function.
322 	       */
323 	      destpc = vax_reladdr ((struct modebyte *) (instructp + length))
324 		- (bfd_vma) core_text_space;
325 	      if (destpc >= s_lowpc && destpc <= s_highpc)
326 		{
327 		  child = sym_lookup (&symtab, destpc);
328 		  DBG (CALLDEBUG,
329 		       printf ("[findcall]\tdestpc 0x%lx",
330 			       (unsigned long) destpc);
331 		       printf (" child->name %s", child->name);
332 		       printf (" child->addr 0x%lx\n",
333 			       (unsigned long) child->addr);
334 		    );
335 		  if (child->addr == destpc)
336 		    {
337 		      /*
338 		       *    a hit
339 		       */
340 		      arc_add (parent, child, (unsigned long) 0);
341 		      length += vax_operandlength ((struct modebyte *)
342 						   (instructp + length));
343 		      continue;
344 		    }
345 		  goto botched;
346 		}
347 	      /*
348 	       *    else:
349 	       *      it looked like a calls,
350 	       *      but it wasn't to anywhere.
351 	       */
352 	      goto botched;
353 	    default:
354 	    botched:
355 	      /*
356 	       *    something funny going on.
357 	       */
358 	      DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
359 	      length = 1;
360 	      continue;
361 	    }
362 	}
363     }
364 }
365