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