Files
seta75D 2e8a93c394 Init
2021-10-11 18:20:23 -03:00

298 lines
6.7 KiB
C

#ifndef lint
static char sccsid[] = "@(#)calls.m68k.c 1.1 92/07/30 SMI"; /* from UCB 1.1 02/16/83 */
#endif
#include "gprof.h"
#define TORIGIN N_TXTADDR( xbuf )
struct instruct {
unsigned short opcode:10,
modefield:3,
regfield:3;
};
/*
* a namelist entry to be the child of indirect calls
*/
nltype indirectchild = {
"(*)" , /* the name */
(unsigned long) 0 , /* the pc entry point */
(unsigned long) 0 , /* aligned entry point */
(double) 0.0 , /* ticks in this routine */
(double) 0.0 , /* cumulative ticks in children */
(long) 0 , /* how many times called */
(long) 0 , /* how many calls to self */
(double) 1.0 , /* propagation fraction */
(double) 0.0 , /* self propagation time */
(double) 0.0 , /* child propagation time */
(bool) 0 , /* print flag */
(int) 0 , /* index in the graph list */
(int) 0 , /* graph call chain top-sort order */
(int) 0 , /* internal number of cycle on */
(struct nl *) &indirectchild , /* pointer to head of cycle */
(struct nl *) 0 , /* pointer to next member of cycle */
(arctype *) 0 , /* list of caller arcs */
(arctype *) 0 /* list of callee arcs */
};
operandenum
operandmode( modep )
struct instruct *modep;
{
long usesreg = modep -> regfield;
switch ( modep -> modefield ) {
case 0:
return datareg;
case 1:
return addrreg;
case 2:
return defer;
case 3:
return postinc;
case 4:
return predec;
case 5:
return displ;
case 6:
return indexed;
case 7:
switch ( usesreg ) {
case 0:
return shortabsolute;
case 1:
return longabsolute;
case 2:
return pcrel;
case 3:
return pcindexed;
case 4:
return immediate;
}
}
return ((operandenum)-1);
}
char *
operandname( mode )
operandenum mode;
{
switch ( mode ) {
case datareg:
return "data register";
case addrreg:
return "address register";
case defer:
return "register indirect";
case postinc:
return "postincrement";
case predec:
return "predecrement";
case displ:
return "register+displacement";
case indexed:
return "indexed";
case shortabsolute:
return "short absolute";
case longabsolute:
return "long absolute";
case pcrel:
return "pc relative";
case pcindexed:
return "pc indexed";
case immediate:
return "immediate";
}
return "unknown";
}
long
operandlength( modep )
struct instruct *modep;
{
if (*(char *)modep == BSR) {
if (*((char *)modep+1) == 0)
return 0;
return 2;
}
switch ( operandmode( modep ) ) {
case datareg:
case addrreg:
case defer:
case postinc:
case predec:
return 0;
case displ:
case indexed:
case shortabsolute:
case pcrel:
case pcindexed:
return 2;
case longabsolute:
return 4;
case immediate:
return 4;
}
/* NOTREACHED */
}
unsigned long
reladdr( modep )
struct instruct *modep;
{
operandenum mode = operandmode( modep );
short *sp;
long *lp;
sp = (short *) modep;
sp += (sizeof modep)/(sizeof *sp); /* skip over the instruction */
switch ( mode ) {
default:
fprintf( stderr , "[reladdr] not relative address\n" );
return (unsigned long) modep;
case pcrel:
return (unsigned long)sp + *sp + TORIGIN + 2 ;
}
}
findcalls( parentp , p_lowpc , p_highpc )
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 & CALLSDEBUG ) {
printf( "[findcalls] %s: 0x%x to 0x%x\n" ,
parentp -> name , p_lowpc , p_highpc );
}
# endif DEBUG
for ( instructp = textspace + p_lowpc - TORIGIN;
instructp < textspace + p_highpc - TORIGIN;
instructp += length ) {
length = 2;
if ( ((struct instruct *)instructp)->opcode == JSR ) {
/*
* may be a call, better check it out.
* skip the count of the number of arguments.
*/
# ifdef DEBUG
if ( debug & CALLSDEBUG ) {
printf( "[findcalls]\t0x%x:jsr" , instructp - textspace );
}
# endif DEBUG
mode = operandmode( (struct instruct *) instructp );
# ifdef DEBUG
if ( debug & CALLSDEBUG ) {
printf( "\toperand is %s\n" , operandname( mode ) );
}
# endif DEBUG
switch ( mode ) {
case defer:
case displ:
case indexed:
case pcindexed:
/*
* 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( (struct instruct *) instructp );
continue;
case shortabsolute:
destpc = *(short *)(instructp +2);
goto callinstruction;
case longabsolute:
destpc = *(long *)(instructp +2);
goto callinstruction;
case pcrel:
/*
* regular pc relative addressing
* check that this is the address of
* a function.
*/
destpc = reladdr( (struct instruct *) instructp )
- (unsigned long) textspace;
callinstruction:
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 DEBUG
if ( childp -> value == destpc ) {
/*
* a hit
*/
addarc( parentp , childp , (long) 0 );
length += operandlength( (struct instruct *)
instructp );
continue;
}
goto botched;
}
/*
* else:
* it looked like a calls,
* but it wasn't to anywhere.
*/
goto botched;
default:
botched:
/*
* something funny going on.
*/
# ifdef DEBUG
if ( debug & CALLSDEBUG ) {
printf( "[findcalls]\tbut it's a botch\n" );
}
# endif DEBUG
length = 2;
continue;
}
} else if ( *instructp == BSR ) {
/*
* bsr's have fewer choices, but are more easily confused
* with other random bit patterns.
*/
destpc = *(instructp+1);
if ( destpc == 0 )
destpc = *(short *)(instructp + 2);
destpc += (unsigned long)instructp + TORIGIN + 2
- (unsigned long)textspace;
# ifdef DEBUG
if ( debug & CALLSDEBUG ) {
printf( "[findcalls]\t0x%x:bsr\n" , instructp - textspace );
}
# endif DEBUG
goto callinstruction;
}
}
}