134199Sbostic /* 234199Sbostic * Copyright (c) 1983 Regents of the University of California. 334199Sbostic * All rights reserved. 434199Sbostic * 5*42683Sbostic * %sccs.include.redist.c% 634199Sbostic */ 734199Sbostic 825712Ssam #ifndef lint 9*42683Sbostic static char sccsid[] = "@(#)tahoe.c 1.5 (Berkeley) 06/01/90"; 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 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 * 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 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 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 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