Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.bin / gprof / tahoe.c
1 /*
2  * Copyright (c) 1983, 1993
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. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 static char sccsid[] = "@(#)tahoe.c     8.1 (Berkeley) 6/6/93";
36 #endif /* not lint */
37
38 #include        "gprof.h"
39
40     /*
41      *  a namelist entry to be the child of indirect callf
42      */
43 nltype  indirectchild = {
44         "(*)" ,                         /* the name */
45         (unsigned long) 0 ,             /* the pc entry point */
46         (unsigned long) 0 ,             /* entry point aligned to histogram */
47         (double) 0.0 ,                  /* ticks in this routine */
48         (double) 0.0 ,                  /* cumulative ticks in children */
49         (long) 0 ,                      /* how many times called */
50         (long) 0 ,                      /* how many calls to self */
51         (double) 1.0 ,                  /* propagation fraction */
52         (double) 0.0 ,                  /* self propagation time */
53         (double) 0.0 ,                  /* child propagation time */
54         (bool) 0 ,                      /* print flag */
55         (int) 0 ,                       /* index in the graph list */
56         (int) 0 ,                       /* graph call chain top-sort order */
57         (int) 0 ,                       /* internal number of cycle on */
58         (struct nl *) &indirectchild ,  /* pointer to head of cycle */
59         (struct nl *) 0 ,               /* pointer to next member of cycle */
60         (arctype *) 0 ,                 /* list of caller arcs */
61         (arctype *) 0                   /* list of callee arcs */
62     };
63
64 operandenum
65 operandmode( modep )
66     unsigned char       *modep;
67 {
68     long        usesreg = ((long)*modep) & 0xf;
69
70     switch ( ((long)*modep) >> 4 ) {
71         case 0:
72         case 1:
73         case 2:
74         case 3:
75             return literal;
76         case 4:
77             return indexed;
78         case 5:
79             return reg;
80         case 6:
81             return regdef;
82         case 7:
83             return autodec;
84         case 8:
85             return ( usesreg != 0xe ? autoinc : immediate );
86         case 9:
87             return ( usesreg != PC ? autoincdef : absolute );
88         case 10:
89             return ( usesreg != PC ? bytedisp : byterel );
90         case 11:
91             return ( usesreg != PC ? bytedispdef : bytereldef );
92         case 12:
93             return ( usesreg != PC ? worddisp : wordrel );
94         case 13:
95             return ( usesreg != PC ? worddispdef : wordreldef );
96         case 14:
97             return ( usesreg != PC ? longdisp : longrel );
98         case 15:
99             return ( usesreg != PC ? longdispdef : longreldef );
100     }
101     /* NOTREACHED */
102 }
103
104 char *
105 operandname( mode )
106     operandenum mode;
107 {
108
109     switch ( mode ) {
110         case literal:
111             return "literal";
112         case indexed:
113             return "indexed";
114         case reg:
115             return "register";
116         case regdef:
117             return "register deferred";
118         case autodec:
119             return "autodecrement";
120         case autoinc:
121             return "autoincrement";
122         case autoincdef:
123             return "autoincrement deferred";
124         case bytedisp:
125             return "byte displacement";
126         case bytedispdef:
127             return "byte displacement deferred";
128         case byterel:
129             return "byte relative";
130         case bytereldef:
131             return "byte relative deferred";
132         case worddisp:
133             return "word displacement";
134         case worddispdef:
135             return "word displacement deferred";
136         case wordrel:
137             return "word relative";
138         case wordreldef:
139             return "word relative deferred";
140         case immediate:
141             return "immediate";
142         case absolute:
143             return "absolute";
144         case longdisp:
145             return "long displacement";
146         case longdispdef:
147             return "long displacement deferred";
148         case longrel:
149             return "long relative";
150         case longreldef:
151             return "long relative deferred";
152     }
153     /* NOTREACHED */
154 }
155
156 long
157 operandlength( modep )
158     unsigned char       *modep;
159 {
160
161     switch ( operandmode( modep ) ) {
162         case literal:
163         case reg:
164         case regdef:
165         case autodec:
166         case autoinc:
167         case autoincdef:
168             return 1;
169         case bytedisp:
170         case bytedispdef:
171         case byterel:
172         case bytereldef:
173             return 2;
174         case worddisp:
175         case worddispdef:
176         case wordrel:
177         case wordreldef:
178             return 3;
179         case immediate:
180         case absolute:
181         case longdisp:
182         case longdispdef:
183         case longrel:
184         case longreldef:
185             return 5;
186         case indexed:
187             return 1+operandlength( modep + 1 );
188     }
189     /* NOTREACHED */
190 }
191
192 unsigned long
193 reladdr( modep )
194     char        *modep;
195 {
196     operandenum mode = operandmode( modep );
197     char        *cp;
198     short       *sp;
199     long        *lp;
200     int         i;
201     long        value = 0;
202
203     cp = modep;
204     cp += 1;                    /* skip over the mode */
205     switch ( mode ) {
206         default:
207             fprintf( stderr , "[reladdr] not relative address\n" );
208             return (unsigned long) modep;
209         case byterel:
210             return (unsigned long) ( cp + sizeof *cp + *cp );
211         case wordrel:
212             for (i = 0; i < sizeof *sp; i++)
213                 value = (value << 8) + (cp[i] & 0xff);
214             return (unsigned long) ( cp + sizeof *sp + value );
215         case longrel:
216             for (i = 0; i < sizeof *lp; i++)
217                 value = (value << 8) + (cp[i] & 0xff);
218             return (unsigned long) ( cp + sizeof *lp + value );
219     }
220 }
221
222 findcall( parentp , p_lowpc , p_highpc )
223     nltype              *parentp;
224     unsigned long       p_lowpc;
225     unsigned long       p_highpc;
226 {
227     unsigned char       *instructp;
228     long                length;
229     nltype              *childp;
230     operandenum         mode;
231     operandenum         firstmode;
232     unsigned long       destpc;
233
234     if ( textspace == 0 ) {
235         return;
236     }
237     if ( p_lowpc < s_lowpc ) {
238         p_lowpc = s_lowpc;
239     }
240     if ( p_highpc > s_highpc ) {
241         p_highpc = s_highpc;
242     }
243 #   ifdef DEBUG
244         if ( debug & CALLDEBUG ) {
245             printf( "[findcall] %s: 0x%x to 0x%x\n" ,
246                     parentp -> name , p_lowpc , p_highpc );
247         }
248 #   endif DEBUG
249     for (   instructp = textspace + p_lowpc ;
250             instructp < textspace + p_highpc ;
251             instructp += length ) {
252         length = 1;
253         if ( *instructp == CALLF ) {
254                 /*
255                  *      maybe a callf, better check it out.
256                  *      skip the count of the number of arguments.
257                  */
258 #           ifdef DEBUG
259                 if ( debug & CALLDEBUG ) {
260                     printf( "[findcall]\t0x%x:callf" , instructp - textspace );
261                 }
262 #           endif DEBUG
263             firstmode = operandmode( instructp+length );
264             switch ( firstmode ) {
265                 case literal:
266                 case immediate:
267                     break;
268                 default:
269                     goto botched;
270             }
271             length += operandlength( instructp+length );
272             mode = operandmode( instructp + length );
273 #           ifdef DEBUG
274                 if ( debug & CALLDEBUG ) {
275                     printf( "\tfirst operand is %s", operandname( firstmode ) );
276                     printf( "\tsecond operand is %s\n" , operandname( mode ) );
277                 }
278 #           endif DEBUG
279             switch ( mode ) {
280                 case regdef:
281                 case bytedispdef:
282                 case worddispdef:
283                 case longdispdef:
284                 case bytereldef:
285                 case wordreldef:
286                 case longreldef:
287                         /*
288                          *      indirect call: call through pointer
289                          *      either  *d(r)   as a parameter or local
290                          *              (r)     as a return value
291                          *              *f      as a global pointer
292                          *      [are there others that we miss?,
293                          *       e.g. arrays of pointers to functions???]
294                          */
295                     addarc( parentp , &indirectchild , (long) 0 );
296                     length += operandlength( instructp + length );
297                     continue;
298                 case byterel:
299                 case wordrel:
300                 case longrel:
301                         /*
302                          *      regular pc relative addressing
303                          *      check that this is the address of
304                          *      a function.
305                          */
306                     destpc = reladdr( instructp+length )
307                                 - (unsigned long) textspace;
308                     if ( destpc >= s_lowpc && destpc <= s_highpc ) {
309                         childp = nllookup( destpc );
310 #                       ifdef DEBUG
311                             if ( debug & CALLDEBUG ) {
312                                 printf( "[findcall]\tdestpc 0x%x" , destpc );
313                                 printf( " childp->name %s" , childp -> name );
314                                 printf( " childp->value 0x%x\n" ,
315                                         childp -> value );
316                             }
317 #                       endif DEBUG
318                         if ( childp -> value == destpc ) {
319                                 /*
320                                  *      a hit
321                                  */
322                             addarc( parentp , childp , (long) 0 );
323                             length += operandlength( instructp + length );
324                             continue;
325                         }
326                         goto botched;
327                     }
328                         /*
329                          *      else:
330                          *      it looked like a callf,
331                          *      but it wasn't to anywhere.
332                          */
333                     goto botched;
334                 default:
335                 botched:
336                         /*
337                          *      something funny going on.
338                          */
339 #                   ifdef DEBUG
340                         if ( debug & CALLDEBUG ) {
341                             printf( "[findcall]\tbut it's a botch\n" );
342                         }
343 #                   endif DEBUG
344                     length = 1;
345                     continue;
346             }
347         }
348     }
349 }