134199Sbostic /*
2*62017Sbostic * Copyright (c) 1983, 1993
3*62017Sbostic * The Regents of the University of California. All rights reserved.
434199Sbostic *
542683Sbostic * %sccs.include.redist.c%
634199Sbostic */
734199Sbostic
825712Ssam #ifndef lint
9*62017Sbostic static char sccsid[] = "@(#)tahoe.c 8.1 (Berkeley) 06/06/93";
1034199Sbostic #endif /* not lint */
1125712Ssam
1225712Ssam #include "gprof.h"
1325712Ssam
1425712Ssam /*
1525712Ssam * a namelist entry to be the child of indirect callf
1625712Ssam */
1725712Ssam nltype indirectchild = {
1825712Ssam "(*)" , /* the name */
1925712Ssam (unsigned long) 0 , /* the pc entry point */
2025712Ssam (unsigned long) 0 , /* entry point aligned to histogram */
2125712Ssam (double) 0.0 , /* ticks in this routine */
2225712Ssam (double) 0.0 , /* cumulative ticks in children */
2325712Ssam (long) 0 , /* how many times called */
2425712Ssam (long) 0 , /* how many calls to self */
2525712Ssam (double) 1.0 , /* propagation fraction */
2625712Ssam (double) 0.0 , /* self propagation time */
2725712Ssam (double) 0.0 , /* child propagation time */
2825712Ssam (bool) 0 , /* print flag */
2925712Ssam (int) 0 , /* index in the graph list */
3025712Ssam (int) 0 , /* graph call chain top-sort order */
3125712Ssam (int) 0 , /* internal number of cycle on */
3225712Ssam (struct nl *) &indirectchild , /* pointer to head of cycle */
3325712Ssam (struct nl *) 0 , /* pointer to next member of cycle */
3425712Ssam (arctype *) 0 , /* list of caller arcs */
3525712Ssam (arctype *) 0 /* list of callee arcs */
3625712Ssam };
3725712Ssam
3825712Ssam operandenum
operandmode(modep)3925712Ssam operandmode( modep )
4025712Ssam unsigned char *modep;
4125712Ssam {
4225712Ssam long usesreg = ((long)*modep) & 0xf;
4325712Ssam
4425712Ssam switch ( ((long)*modep) >> 4 ) {
4525712Ssam case 0:
4625712Ssam case 1:
4725712Ssam case 2:
4825712Ssam case 3:
4925712Ssam return literal;
5025712Ssam case 4:
5125712Ssam return indexed;
5225712Ssam case 5:
5325712Ssam return reg;
5425712Ssam case 6:
5525712Ssam return regdef;
5625712Ssam case 7:
5725712Ssam return autodec;
5825712Ssam case 8:
5925712Ssam return ( usesreg != 0xe ? autoinc : immediate );
6025712Ssam case 9:
6125712Ssam return ( usesreg != PC ? autoincdef : absolute );
6225712Ssam case 10:
6325712Ssam return ( usesreg != PC ? bytedisp : byterel );
6425712Ssam case 11:
6525712Ssam return ( usesreg != PC ? bytedispdef : bytereldef );
6625712Ssam case 12:
6725712Ssam return ( usesreg != PC ? worddisp : wordrel );
6825712Ssam case 13:
6925712Ssam return ( usesreg != PC ? worddispdef : wordreldef );
7025712Ssam case 14:
7125712Ssam return ( usesreg != PC ? longdisp : longrel );
7225712Ssam case 15:
7325712Ssam return ( usesreg != PC ? longdispdef : longreldef );
7425712Ssam }
7525712Ssam /* NOTREACHED */
7625712Ssam }
7725712Ssam
7825712Ssam char *
operandname(mode)7925712Ssam operandname( mode )
8025712Ssam operandenum mode;
8125712Ssam {
8225712Ssam
8325712Ssam switch ( mode ) {
8425712Ssam case literal:
8525712Ssam return "literal";
8625712Ssam case indexed:
8725712Ssam return "indexed";
8825712Ssam case reg:
8925712Ssam return "register";
9025712Ssam case regdef:
9125712Ssam return "register deferred";
9225712Ssam case autodec:
9325712Ssam return "autodecrement";
9425712Ssam case autoinc:
9525712Ssam return "autoincrement";
9625712Ssam case autoincdef:
9725712Ssam return "autoincrement deferred";
9825712Ssam case bytedisp:
9925712Ssam return "byte displacement";
10025712Ssam case bytedispdef:
10125712Ssam return "byte displacement deferred";
10225712Ssam case byterel:
10325712Ssam return "byte relative";
10425712Ssam case bytereldef:
10525712Ssam return "byte relative deferred";
10625712Ssam case worddisp:
10725712Ssam return "word displacement";
10825712Ssam case worddispdef:
10925712Ssam return "word displacement deferred";
11025712Ssam case wordrel:
11125712Ssam return "word relative";
11225712Ssam case wordreldef:
11325712Ssam return "word relative deferred";
11425712Ssam case immediate:
11525712Ssam return "immediate";
11625712Ssam case absolute:
11725712Ssam return "absolute";
11825712Ssam case longdisp:
11925712Ssam return "long displacement";
12025712Ssam case longdispdef:
12125712Ssam return "long displacement deferred";
12225712Ssam case longrel:
12325712Ssam return "long relative";
12425712Ssam case longreldef:
12525712Ssam return "long relative deferred";
12625712Ssam }
12725712Ssam /* NOTREACHED */
12825712Ssam }
12925712Ssam
13025712Ssam long
operandlength(modep)13125712Ssam operandlength( modep )
13225712Ssam unsigned char *modep;
13325712Ssam {
13425712Ssam
13525712Ssam switch ( operandmode( modep ) ) {
13625712Ssam case literal:
13725712Ssam case reg:
13825712Ssam case regdef:
13925712Ssam case autodec:
14025712Ssam case autoinc:
14125712Ssam case autoincdef:
14225712Ssam return 1;
14325712Ssam case bytedisp:
14425712Ssam case bytedispdef:
14525712Ssam case byterel:
14625712Ssam case bytereldef:
14725712Ssam return 2;
14825712Ssam case worddisp:
14925712Ssam case worddispdef:
15025712Ssam case wordrel:
15125712Ssam case wordreldef:
15225712Ssam return 3;
15325712Ssam case immediate:
15425712Ssam case absolute:
15525712Ssam case longdisp:
15625712Ssam case longdispdef:
15725712Ssam case longrel:
15825712Ssam case longreldef:
15925712Ssam return 5;
16025712Ssam case indexed:
16125712Ssam return 1+operandlength( modep + 1 );
16225712Ssam }
16325712Ssam /* NOTREACHED */
16425712Ssam }
16525712Ssam
16625712Ssam unsigned long
reladdr(modep)16725712Ssam reladdr( modep )
16825712Ssam char *modep;
16925712Ssam {
17025712Ssam operandenum mode = operandmode( modep );
17125712Ssam char *cp;
17225712Ssam short *sp;
17325712Ssam long *lp;
17425712Ssam int i;
17525712Ssam long value = 0;
17625712Ssam
17725712Ssam cp = modep;
17825712Ssam cp += 1; /* skip over the mode */
17925712Ssam switch ( mode ) {
18025712Ssam default:
18125712Ssam fprintf( stderr , "[reladdr] not relative address\n" );
18225712Ssam return (unsigned long) modep;
18325712Ssam case byterel:
18425712Ssam return (unsigned long) ( cp + sizeof *cp + *cp );
18525712Ssam case wordrel:
18625712Ssam for (i = 0; i < sizeof *sp; i++)
18725712Ssam value = (value << 8) + (cp[i] & 0xff);
18825712Ssam return (unsigned long) ( cp + sizeof *sp + value );
18925712Ssam case longrel:
19025712Ssam for (i = 0; i < sizeof *lp; i++)
19125712Ssam value = (value << 8) + (cp[i] & 0xff);
19225712Ssam return (unsigned long) ( cp + sizeof *lp + value );
19325712Ssam }
19425712Ssam }
19525712Ssam
findcall(parentp,p_lowpc,p_highpc)19625713Ssam findcall( parentp , p_lowpc , p_highpc )
19725712Ssam nltype *parentp;
19825712Ssam unsigned long p_lowpc;
19925712Ssam unsigned long p_highpc;
20025712Ssam {
20125712Ssam unsigned char *instructp;
20225712Ssam long length;
20325712Ssam nltype *childp;
20425712Ssam operandenum mode;
20525712Ssam operandenum firstmode;
20625712Ssam unsigned long destpc;
20725712Ssam
20825712Ssam if ( textspace == 0 ) {
20925712Ssam return;
21025712Ssam }
21125712Ssam if ( p_lowpc < s_lowpc ) {
21225712Ssam p_lowpc = s_lowpc;
21325712Ssam }
21425712Ssam if ( p_highpc > s_highpc ) {
21525712Ssam p_highpc = s_highpc;
21625712Ssam }
21725712Ssam # ifdef DEBUG
21825712Ssam if ( debug & CALLDEBUG ) {
21925713Ssam printf( "[findcall] %s: 0x%x to 0x%x\n" ,
22025712Ssam parentp -> name , p_lowpc , p_highpc );
22125712Ssam }
22225712Ssam # endif DEBUG
22325712Ssam for ( instructp = textspace + p_lowpc ;
22425712Ssam instructp < textspace + p_highpc ;
22525712Ssam instructp += length ) {
22625712Ssam length = 1;
22725712Ssam if ( *instructp == CALLF ) {
22825712Ssam /*
22925712Ssam * maybe a callf, better check it out.
23025712Ssam * skip the count of the number of arguments.
23125712Ssam */
23225712Ssam # ifdef DEBUG
23325712Ssam if ( debug & CALLDEBUG ) {
23425713Ssam printf( "[findcall]\t0x%x:callf" , instructp - textspace );
23525712Ssam }
23625712Ssam # endif DEBUG
23725712Ssam firstmode = operandmode( instructp+length );
23825712Ssam switch ( firstmode ) {
23925712Ssam case literal:
24025712Ssam case immediate:
24125712Ssam break;
24225712Ssam default:
24325712Ssam goto botched;
24425712Ssam }
24525712Ssam length += operandlength( instructp+length );
24625712Ssam mode = operandmode( instructp + length );
24725712Ssam # ifdef DEBUG
24825712Ssam if ( debug & CALLDEBUG ) {
24925712Ssam printf( "\tfirst operand is %s", operandname( firstmode ) );
25025712Ssam printf( "\tsecond operand is %s\n" , operandname( mode ) );
25125712Ssam }
25225712Ssam # endif DEBUG
25325712Ssam switch ( mode ) {
25425712Ssam case regdef:
25525712Ssam case bytedispdef:
25625712Ssam case worddispdef:
25725712Ssam case longdispdef:
25825712Ssam case bytereldef:
25925712Ssam case wordreldef:
26025712Ssam case longreldef:
26125712Ssam /*
26225712Ssam * indirect call: call through pointer
26325712Ssam * either *d(r) as a parameter or local
26425712Ssam * (r) as a return value
26525712Ssam * *f as a global pointer
26625712Ssam * [are there others that we miss?,
26725712Ssam * e.g. arrays of pointers to functions???]
26825712Ssam */
26925712Ssam addarc( parentp , &indirectchild , (long) 0 );
27025712Ssam length += operandlength( instructp + length );
27125712Ssam continue;
27225712Ssam case byterel:
27325712Ssam case wordrel:
27425712Ssam case longrel:
27525712Ssam /*
27625712Ssam * regular pc relative addressing
27725712Ssam * check that this is the address of
27825712Ssam * a function.
27925712Ssam */
28025712Ssam destpc = reladdr( instructp+length )
28125712Ssam - (unsigned long) textspace;
28225712Ssam if ( destpc >= s_lowpc && destpc <= s_highpc ) {
28325712Ssam childp = nllookup( destpc );
28425712Ssam # ifdef DEBUG
28525712Ssam if ( debug & CALLDEBUG ) {
28625713Ssam printf( "[findcall]\tdestpc 0x%x" , destpc );
28725712Ssam printf( " childp->name %s" , childp -> name );
28825712Ssam printf( " childp->value 0x%x\n" ,
28925712Ssam childp -> value );
29025712Ssam }
29125712Ssam # endif DEBUG
29225712Ssam if ( childp -> value == destpc ) {
29325712Ssam /*
29425712Ssam * a hit
29525712Ssam */
29625712Ssam addarc( parentp , childp , (long) 0 );
29725712Ssam length += operandlength( instructp + length );
29825712Ssam continue;
29925712Ssam }
30025712Ssam goto botched;
30125712Ssam }
30225712Ssam /*
30325712Ssam * else:
30425712Ssam * it looked like a callf,
30525712Ssam * but it wasn't to anywhere.
30625712Ssam */
30725712Ssam goto botched;
30825712Ssam default:
30925712Ssam botched:
31025712Ssam /*
31125712Ssam * something funny going on.
31225712Ssam */
31325712Ssam # ifdef DEBUG
31425712Ssam if ( debug & CALLDEBUG ) {
31525713Ssam printf( "[findcall]\tbut it's a botch\n" );
31625712Ssam }
31725712Ssam # endif DEBUG
31825712Ssam length = 1;
31925712Ssam continue;
32025712Ssam }
32125712Ssam }
32225712Ssam }
32325712Ssam }
324