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