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