tally(struct rawarc *rawp) { nltype *parentp; nltype *childp; parentp = nllookup( rawp -> raw_frompc ); childp = nllookup( rawp -> raw_selfpc ); if ( parentp == 0 || childp == 0 ) return; if ( kflag && onlist( kfromlist , parentp -> name ) && onlist( ktolist , childp -> name ) ) { return; } childp -> ncall += rawp -> raw_count; # ifdef DEBUG if ( debug & TALLYDEBUG ) { printf( "[tally] arc from %s to %s traversed %d times\n" , parentp -> name , childp -> name , rawp -> raw_count ); } # endif /* DEBUG */ addarc( parentp , childp , rawp -> raw_count ); }
void findcalls(nltype *parentp, pctype p_lowpc, pctype p_highpc) { unsigned long instructp; sztype length; nltype *childp; pctype destpc; if (textspace == 0) { return; } if (p_lowpc > s_highpc) return; if (p_highpc < s_lowpc) return; if (p_lowpc < s_lowpc) p_lowpc = s_lowpc; if (p_highpc > s_highpc) p_highpc = s_highpc; #ifdef DEBUG if (debug & CALLSDEBUG) { printf("[findcalls] %s: 0x%llx to 0x%llx\n", parentp->name, p_lowpc, p_highpc); } #endif /* DEBUG */ length = 4; for (instructp = (uintptr_t)textspace + p_lowpc - TORIGIN; instructp < (uintptr_t)textspace + p_highpc - TORIGIN; instructp += length) { switch (OP(instructp)) { case CALL: /* * May be a call, better check it out. */ #ifdef DEBUG if (debug & CALLSDEBUG) { printf("[findcalls]\t0x%x:call\n", PC_VAL(instructp)); } #endif /* DEBUG */ destpc = (DISP30(instructp) << 2) + PC_VAL(instructp); break; case FMT3_0x10: if (OP3(instructp) != JMPL) continue; #ifdef DEBUG if (debug & CALLSDEBUG) printf("[findcalls]\t0x%x:jmpl", PC_VAL(instructp)); #endif /* DEBUG */ if (RD(instructp) == R_G0) { #ifdef DEBUG if (debug & CALLSDEBUG) { switch (RS1(instructp)) { case R_O7: printf("\tprobably a RETL\n"); break; case R_I7: printf("\tprobably a RET\n"); break; default: printf(", but not a call: " "linked to g0\n"); } } #endif /* DEBUG */ continue; } #ifdef DEBUG if (debug & CALLSDEBUG) { printf("\toperands are DST = R%d,\tSRC = R%d", RD(instructp), RS1(instructp)); } #endif /* DEBUG */ if (IMMED(instructp)) { #ifdef DEBUG if (debug & CALLSDEBUG) { if (SIMM13(instructp) < 0) { printf(" - 0x%x\n", -(SIMM13(instructp))); } else { printf(" + 0x%x\n", SIMM13(instructp)); } } #endif /* DEBUG */ switch (RS1(instructp)) { case R_G0: /* * absolute address, simm 13 */ destpc = SIMM13(instructp); break; default: /* * indirect call */ addarc(parentp, &indirectchild, 0); continue; } } else { /* * two register sources, all cases are indirect */ #ifdef DEBUG if (debug & CALLSDEBUG) { printf(" + R%d\n", RS2(instructp)); } #endif /* DEBUG */ addarc(parentp, &indirectchild, 0); continue; } break; default: continue; } /* * Check that the destination is the address of * a function; this allows us to differentiate * real calls from someone trying to get the PC, * e.g. position independent switches. */ if (destpc >= s_lowpc && destpc <= s_highpc) { childp = nllookup(&modules, destpc, NULL); #ifdef DEBUG if (debug & CALLSDEBUG) { printf("[findcalls]\tdestpc 0x%llx", destpc); printf(" childp->name %s", childp->name); printf(" childp->value 0x%llx\n", childp->value); } #endif /* DEBUG */ if (childp->value == destpc) { /* * a hit */ addarc(parentp, childp, 0); continue; } } /* * else: * it looked like a call, * but it wasn't to anywhere. */ #ifdef DEBUG if (debug & CALLSDEBUG) { printf("[findcalls]\tbut it's a switch or a botch\n"); } #endif /* DEBUG */ continue; } }
void findcall(nltype *parentp, unsigned long p_lowpc, unsigned long p_highpc) { unsigned char *instructp; long length; nltype *childp; operandenum mode; operandenum firstmode; unsigned long destpc; if ( textspace == 0 ) { return; } if ( p_lowpc < s_lowpc ) { p_lowpc = s_lowpc; } if ( p_highpc > s_highpc ) { p_highpc = s_highpc; } # ifdef DEBUG if ( debug & CALLDEBUG ) { printf( "[findcall] %s: 0x%x to 0x%x\n" , parentp -> name , p_lowpc , p_highpc ); } # endif /* DEBUG */ for ( instructp = textspace + p_lowpc ; instructp < textspace + p_highpc ; instructp += length ) { length = 1; if ( *instructp == CALLF ) { /* * maybe a callf, better check it out. * skip the count of the number of arguments. */ # ifdef DEBUG if ( debug & CALLDEBUG ) { printf( "[findcall]\t0x%x:callf" , instructp - textspace ); } # endif /* DEBUG */ firstmode = operandmode( instructp+length ); switch ( firstmode ) { case literal: case immediate: break; default: goto botched; } length += operandlength( instructp+length ); mode = operandmode( instructp + length ); # ifdef DEBUG if ( debug & CALLDEBUG ) { printf( "\tfirst operand is %s", operandname( firstmode ) ); printf( "\tsecond operand is %s\n" , operandname( mode ) ); } # endif /* DEBUG */ switch ( mode ) { case regdef: case bytedispdef: case worddispdef: case longdispdef: case bytereldef: case wordreldef: case longreldef: /* * indirect call: call through pointer * either *d(r) as a parameter or local * (r) as a return value * *f as a global pointer * [are there others that we miss?, * e.g. arrays of pointers to functions???] */ addarc( parentp , &indirectchild , (long) 0 ); length += operandlength( instructp + length ); continue; case byterel: case wordrel: case longrel: /* * regular pc relative addressing * check that this is the address of * a function. */ destpc = reladdr( instructp+length ) - (unsigned long) textspace; if ( destpc >= s_lowpc && destpc <= s_highpc ) { childp = nllookup( destpc ); # ifdef DEBUG if ( debug & CALLDEBUG ) { printf( "[findcall]\tdestpc 0x%x" , destpc ); printf( " childp->name %s" , childp -> name ); printf( " childp->value 0x%x\n" , childp -> value ); } # endif /* DEBUG */ if ( childp -> value == destpc ) { /* * a hit */ addarc( parentp , childp , (long) 0 ); length += operandlength( instructp + length ); continue; } goto botched; } /* * else: * it looked like a callf, * but it wasn't to anywhere. */ goto botched; default: botched: /* * something funny going on. */ # ifdef DEBUG if ( debug & CALLDEBUG ) { printf( "[findcall]\tbut it's a botch\n" ); } # endif /* DEBUG */ length = 1; continue; } } } }