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