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