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