7491f6d51f84b780c57b7a47459169e632a3a965
[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  * @(#)tahoe.c  8.1 (Berkeley) 6/6/93
34  */
35
36 #include        "gprof.h"
37
38     /*
39      *  a namelist entry to be the child of indirect callf
40      */
41 nltype  indirectchild = {
42         "(*)" ,                         /* the name */
43         (unsigned long) 0 ,             /* the pc entry point */
44         (unsigned long) 0 ,             /* entry point aligned to histogram */
45         (double) 0.0 ,                  /* ticks in this routine */
46         (double) 0.0 ,                  /* cumulative ticks in children */
47         (long) 0 ,                      /* how many times called */
48         (long) 0 ,                      /* how many calls to self */
49         (double) 1.0 ,                  /* propagation fraction */
50         (double) 0.0 ,                  /* self propagation time */
51         (double) 0.0 ,                  /* child propagation time */
52         (bool) 0 ,                      /* print flag */
53         (int) 0 ,                       /* index in the graph list */
54         (int) 0 ,                       /* graph call chain top-sort order */
55         (int) 0 ,                       /* internal number of cycle on */
56         (struct nl *) &indirectchild ,  /* pointer to head of cycle */
57         (struct nl *) 0 ,               /* pointer to next member of cycle */
58         (arctype *) 0 ,                 /* list of caller arcs */
59         (arctype *) 0                   /* list of callee arcs */
60     };
61
62 operandenum
63 operandmode( modep )
64     unsigned char       *modep;
65 {
66     long        usesreg = ((long)*modep) & 0xf;
67
68     switch ( ((long)*modep) >> 4 ) {
69         case 0:
70         case 1:
71         case 2:
72         case 3:
73             return literal;
74         case 4:
75             return indexed;
76         case 5:
77             return reg;
78         case 6:
79             return regdef;
80         case 7:
81             return autodec;
82         case 8:
83             return ( usesreg != 0xe ? autoinc : immediate );
84         case 9:
85             return ( usesreg != PC ? autoincdef : absolute );
86         case 10:
87             return ( usesreg != PC ? bytedisp : byterel );
88         case 11:
89             return ( usesreg != PC ? bytedispdef : bytereldef );
90         case 12:
91             return ( usesreg != PC ? worddisp : wordrel );
92         case 13:
93             return ( usesreg != PC ? worddispdef : wordreldef );
94         case 14:
95             return ( usesreg != PC ? longdisp : longrel );
96         case 15:
97             return ( usesreg != PC ? longdispdef : longreldef );
98     }
99     /* NOTREACHED */
100 }
101
102 char *
103 operandname( mode )
104     operandenum mode;
105 {
106
107     switch ( mode ) {
108         case literal:
109             return "literal";
110         case indexed:
111             return "indexed";
112         case reg:
113             return "register";
114         case regdef:
115             return "register deferred";
116         case autodec:
117             return "autodecrement";
118         case autoinc:
119             return "autoincrement";
120         case autoincdef:
121             return "autoincrement deferred";
122         case bytedisp:
123             return "byte displacement";
124         case bytedispdef:
125             return "byte displacement deferred";
126         case byterel:
127             return "byte relative";
128         case bytereldef:
129             return "byte relative deferred";
130         case worddisp:
131             return "word displacement";
132         case worddispdef:
133             return "word displacement deferred";
134         case wordrel:
135             return "word relative";
136         case wordreldef:
137             return "word relative deferred";
138         case immediate:
139             return "immediate";
140         case absolute:
141             return "absolute";
142         case longdisp:
143             return "long displacement";
144         case longdispdef:
145             return "long displacement deferred";
146         case longrel:
147             return "long relative";
148         case longreldef:
149             return "long relative deferred";
150     }
151     /* NOTREACHED */
152 }
153
154 long
155 operandlength( modep )
156     unsigned char       *modep;
157 {
158
159     switch ( operandmode( modep ) ) {
160         case literal:
161         case reg:
162         case regdef:
163         case autodec:
164         case autoinc:
165         case autoincdef:
166             return 1;
167         case bytedisp:
168         case bytedispdef:
169         case byterel:
170         case bytereldef:
171             return 2;
172         case worddisp:
173         case worddispdef:
174         case wordrel:
175         case wordreldef:
176             return 3;
177         case immediate:
178         case absolute:
179         case longdisp:
180         case longdispdef:
181         case longrel:
182         case longreldef:
183             return 5;
184         case indexed:
185             return 1+operandlength( modep + 1 );
186     }
187     /* NOTREACHED */
188 }
189
190 unsigned long
191 reladdr( modep )
192     char        *modep;
193 {
194     operandenum mode = operandmode( modep );
195     char        *cp;
196     short       *sp;
197     long        *lp;
198     int         i;
199     long        value = 0;
200
201     cp = modep;
202     cp += 1;                    /* skip over the mode */
203     switch ( mode ) {
204         default:
205             fprintf( stderr , "[reladdr] not relative address\n" );
206             return (unsigned long) modep;
207         case byterel:
208             return (unsigned long) ( cp + sizeof *cp + *cp );
209         case wordrel:
210             for (i = 0; i < sizeof *sp; i++)
211                 value = (value << 8) + (cp[i] & 0xff);
212             return (unsigned long) ( cp + sizeof *sp + value );
213         case longrel:
214             for (i = 0; i < sizeof *lp; i++)
215                 value = (value << 8) + (cp[i] & 0xff);
216             return (unsigned long) ( cp + sizeof *lp + value );
217     }
218 }
219
220 findcall( parentp , p_lowpc , p_highpc )
221     nltype              *parentp;
222     unsigned long       p_lowpc;
223     unsigned long       p_highpc;
224 {
225     unsigned char       *instructp;
226     long                length;
227     nltype              *childp;
228     operandenum         mode;
229     operandenum         firstmode;
230     unsigned long       destpc;
231
232     if ( textspace == 0 ) {
233         return;
234     }
235     if ( p_lowpc < s_lowpc ) {
236         p_lowpc = s_lowpc;
237     }
238     if ( p_highpc > s_highpc ) {
239         p_highpc = s_highpc;
240     }
241 #   ifdef DEBUG
242         if ( debug & CALLDEBUG ) {
243             printf( "[findcall] %s: 0x%x to 0x%x\n" ,
244                     parentp -> name , p_lowpc , p_highpc );
245         }
246 #   endif DEBUG
247     for (   instructp = textspace + p_lowpc ;
248             instructp < textspace + p_highpc ;
249             instructp += length ) {
250         length = 1;
251         if ( *instructp == CALLF ) {
252                 /*
253                  *      maybe a callf, better check it out.
254                  *      skip the count of the number of arguments.
255                  */
256 #           ifdef DEBUG
257                 if ( debug & CALLDEBUG ) {
258                     printf( "[findcall]\t0x%x:callf" , instructp - textspace );
259                 }
260 #           endif DEBUG
261             firstmode = operandmode( instructp+length );
262             switch ( firstmode ) {
263                 case literal:
264                 case immediate:
265                     break;
266                 default:
267                     goto botched;
268             }
269             length += operandlength( instructp+length );
270             mode = operandmode( instructp + length );
271 #           ifdef DEBUG
272                 if ( debug & CALLDEBUG ) {
273                     printf( "\tfirst operand is %s", operandname( firstmode ) );
274                     printf( "\tsecond operand is %s\n" , operandname( mode ) );
275                 }
276 #           endif DEBUG
277             switch ( mode ) {
278                 case regdef:
279                 case bytedispdef:
280                 case worddispdef:
281                 case longdispdef:
282                 case bytereldef:
283                 case wordreldef:
284                 case longreldef:
285                         /*
286                          *      indirect call: call through pointer
287                          *      either  *d(r)   as a parameter or local
288                          *              (r)     as a return value
289                          *              *f      as a global pointer
290                          *      [are there others that we miss?,
291                          *       e.g. arrays of pointers to functions???]
292                          */
293                     addarc( parentp , &indirectchild , (long) 0 );
294                     length += operandlength( instructp + length );
295                     continue;
296                 case byterel:
297                 case wordrel:
298                 case longrel:
299                         /*
300                          *      regular pc relative addressing
301                          *      check that this is the address of
302                          *      a function.
303                          */
304                     destpc = reladdr( instructp+length )
305                                 - (unsigned long) textspace;
306                     if ( destpc >= s_lowpc && destpc <= s_highpc ) {
307                         childp = nllookup( destpc );
308 #                       ifdef DEBUG
309                             if ( debug & CALLDEBUG ) {
310                                 printf( "[findcall]\tdestpc 0x%x" , destpc );
311                                 printf( " childp->name %s" , childp -> name );
312                                 printf( " childp->value 0x%x\n" ,
313                                         childp -> value );
314                             }
315 #                       endif DEBUG
316                         if ( childp -> value == destpc ) {
317                                 /*
318                                  *      a hit
319                                  */
320                             addarc( parentp , childp , (long) 0 );
321                             length += operandlength( instructp + length );
322                             continue;
323                         }
324                         goto botched;
325                     }
326                         /*
327                          *      else:
328                          *      it looked like a callf,
329                          *      but it wasn't to anywhere.
330                          */
331                     goto botched;
332                 default:
333                 botched:
334                         /*
335                          *      something funny going on.
336                          */
337 #                   ifdef DEBUG
338                         if ( debug & CALLDEBUG ) {
339                             printf( "[findcall]\tbut it's a botch\n" );
340                         }
341 #                   endif DEBUG
342                     length = 1;
343                     continue;
344             }
345         }
346     }
347 }