#include "gprof.h"
#ifdef vax
#include "vax.h"
#endif
#ifdef m68k
#include "m68k.h"
#endif
static nltype indirectchild = {
"(*)" ,
(uint64_t) 0 ,
(uint64_t) 0 ,
(double) 0.0 ,
(double) 0.0 ,
(uint32_t) 0 ,
(int32_t) 0 ,
(int32_t) 0 ,
(double) 1.0 ,
(double) 0.0 ,
(double) 0.0 ,
(enum bool) 0 ,
(int) 0 ,
(int) 0 ,
(int) 0 ,
(struct nl *) &indirectchild ,
(struct nl *) 0 ,
(arctype *) 0 ,
(arctype *) 0
};
#ifdef vax
operandenum
operandmode( modep )
struct modebyte *modep;
{
uint32_t usesreg = modep -> regfield;
switch ( modep -> modefield ) {
case 0:
case 1:
case 2:
case 3:
return literal;
case 4:
return indexed;
case 5:
return reg;
case 6:
return regdef;
case 7:
return autodec;
case 8:
return ( usesreg != PC ? autoinc : immediate );
case 9:
return ( usesreg != PC ? autoincdef : absolute );
case 10:
return ( usesreg != PC ? bytedisp : byterel );
case 11:
return ( usesreg != PC ? bytedispdef : bytereldef );
case 12:
return ( usesreg != PC ? worddisp : wordrel );
case 13:
return ( usesreg != PC ? worddispdef : wordreldef );
case 14:
return ( usesreg != PC ? longdisp : longrel );
case 15:
return ( usesreg != PC ? longdispdef : longreldef );
}
}
static
char *
operandname( mode )
operandenum mode;
{
switch ( mode ) {
case literal:
return "literal";
case indexed:
return "indexed";
case reg:
return "register";
case regdef:
return "register deferred";
case autodec:
return "autodecrement";
case autoinc:
return "autoincrement";
case autoincdef:
return "autoincrement deferred";
case bytedisp:
return "byte displacement";
case bytedispdef:
return "byte displacement deferred";
case byterel:
return "byte relative";
case bytereldef:
return "byte relative deferred";
case worddisp:
return "word displacement";
case worddispdef:
return "word displacement deferred";
case wordrel:
return "word relative";
case wordreldef:
return "word relative deferred";
case immediate:
return "immediate";
case absolute:
return "absolute";
case longdisp:
return "long displacement";
case longdispdef:
return "long displacement deferred";
case longrel:
return "long relative";
case longreldef:
return "long relative deferred";
}
}
static
uint32_t
operandlength( modep )
struct modebyte *modep;
{
switch ( operandmode( modep ) ) {
case literal:
case reg:
case regdef:
case autodec:
case autoinc:
case autoincdef:
return 1;
case bytedisp:
case bytedispdef:
case byterel:
case bytereldef:
return 2;
case worddisp:
case worddispdef:
case wordrel:
case wordreldef:
return 3;
case immediate:
case absolute:
case longdisp:
case longdispdef:
case longrel:
case longreldef:
return 5;
case indexed:
return 1+operandlength( (struct modebyte *) ((char *) modep) + 1 );
}
}
static
uint32_t
reladdr( modep )
struct modebyte *modep;
{
operandenum mode = operandmode( modep );
char *cp;
short *sp;
int32_t *lp;
cp = (char *) modep;
cp += 1;
switch ( mode ) {
default:
fprintf( stderr , "[reladdr] not relative address\n" );
return (uint32_t) modep;
case byterel:
return (uint32_t) ( cp + sizeof *cp + *cp );
case wordrel:
sp = (short *) cp;
return (uint32_t) ( cp + sizeof *sp + *sp );
case longrel:
lp = (int32_t *) cp;
return (uint32_t) ( cp + sizeof *lp + *lp );
}
}
findcalls( parentp , p_lowpc , p_highpc )
nltype *parentp;
uint32_t p_lowpc;
uint32_t p_highpc;
{
unsigned char *instructp;
int32_t length;
nltype *childp;
operandenum mode;
operandenum firstmode;
uint32_t 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 & CALLSDEBUG ) {
printf( "[findcalls] %s: 0x%x to 0x%x\n" ,
parentp -> name , p_lowpc , p_highpc );
}
# endif
for ( instructp = textspace + p_lowpc ;
instructp < textspace + p_highpc ;
instructp += length ) {
length = 1;
if ( *instructp == CALLS ) {
# ifdef DEBUG
if ( debug & CALLSDEBUG ) {
printf( "[findcalls]\t0x%x:calls" , instructp - textspace );
}
# endif
firstmode = operandmode( (struct modebyte *) (instructp+length) );
switch ( firstmode ) {
case literal:
case immediate:
break;
default:
goto botched;
}
length += operandlength( (struct modebyte *) (instructp+length) );
mode = operandmode( (struct modebyte *) ( instructp + length ) );
# ifdef DEBUG
if ( debug & CALLSDEBUG ) {
printf( "\tfirst operand is %s", operandname( firstmode ) );
printf( "\tsecond operand is %s\n" , operandname( mode ) );
}
# endif
switch ( mode ) {
case regdef:
case bytedispdef:
case worddispdef:
case longdispdef:
case bytereldef:
case wordreldef:
case longreldef:
addarc( parentp , &indirectchild , (uint32_t) 0 , 0);
length += operandlength(
(struct modebyte *) ( instructp + length ) );
continue;
case byterel:
case wordrel:
case longrel:
destpc = reladdr( (struct modebyte *) (instructp+length) )
- (uint32_t) textspace;
if ( destpc >= s_lowpc && destpc <= s_highpc ) {
childp = nllookup( destpc );
# ifdef DEBUG
if ( debug & CALLSDEBUG ) {
printf( "[findcalls]\tdestpc 0x%x" , destpc );
printf( " childp->name %s" , childp -> name );
printf( " childp->value 0x%x\n" ,
childp -> value );
}
# endif
if ( childp -> value == destpc ) {
addarc( parentp , childp , (uint32_t) 0 , 0);
length += operandlength( (struct modebyte *)
( instructp + length ) );
continue;
}
goto botched;
}
goto botched;
default:
botched:
# ifdef DEBUG
if ( debug & CALLSDEBUG ) {
printf( "[findcalls]\tbut it's a botch\n" );
}
# endif
length = 1;
continue;
}
}
}
}
#endif
#ifdef m68k
void
findcalls(
nltype *parentp,
uint32_t p_lowpc,
uint32_t p_highpc)
{
unsigned short *instructp;
int32_t length;
nltype *childp;
uint32_t destpc;
if(textspace == NULL){
return;
}
if(p_lowpc < sample_sets->s_lowpc){
p_lowpc = sample_sets->s_lowpc;
}
if(p_highpc > sample_sets->s_highpc){
p_highpc = sample_sets->s_highpc;
}
#ifdef DEBUG
if(debug & CALLSDEBUG){
printf("[findcalls] %s: 0x%x to 0x%x\n", parentp->name,
(unsigned int)p_lowpc, (unsigned int)p_highpc);
}
#endif
for(instructp = (unsigned short *)(textspace + p_lowpc);
instructp < (unsigned short *)(textspace + p_highpc);
instructp += length){
length = 1;
if((*instructp & BSR_MASK) == BSR_OP){
short disp;
if(*instructp & 0xff)
disp = (char)(*instructp & 0xff);
else{
length = 2;
disp = instructp[1];
}
destpc = (uint32_t)instructp + disp + 2 -
(uint32_t)textspace;
gotdestpc:
if(destpc >= sample_sets->s_lowpc &&
destpc <= sample_sets->s_highpc){
childp = nllookup(destpc);
#ifdef DEBUG
if(debug & CALLSDEBUG){
printf("[findcalls]\tdestpc 0x%x",
(unsigned int)destpc);
printf("childp->name %s", childp->name);
printf("childp->value 0x%x\n",
(unsigned int)childp->value );
}
#endif
if(childp->value == destpc){
addarc(parentp, childp, 0, 0);
continue;
}
goto botched;
}
}
else if((*instructp & JBSR_MASK) == JBSR_OP){
if((*instructp & 0x38) != 0x38) {
indirect:
addarc(parentp, &indirectchild, 0, 0);
continue;
}
switch(*instructp & 7) {
case 0:
destpc = instructp[1];
length = 2;
goto gotdestpc;
case 1:
destpc = (instructp[1] << 16) + (instructp[2] & 0xffff);
length = 3;
goto gotdestpc;
default:
goto indirect;
}
}
else
continue;
botched:
#ifdef DEBUG
if(debug & CALLSDEBUG){
printf("[findcalls]\tbut it's a botch\n");
}
#endif
length = 1;
}
}
#endif