diff options
Diffstat (limited to 'gprof/tahoe.c')
-rw-r--r-- | gprof/tahoe.c | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/gprof/tahoe.c b/gprof/tahoe.c new file mode 100644 index 0000000..924d95d --- /dev/null +++ b/gprof/tahoe.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that: (1) source distributions retain this entire copyright + * notice and comment, and (2) distributions including binaries display + * the following acknowledgement: ``This product includes software + * developed by the University of California, Berkeley and its contributors'' + * in the documentation or other materials provided with the distribution + * and in all advertising materials mentioning features or use of this + * software. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char sccsid[] = "@(#)tahoe.c 1.5 (Berkeley) 6/1/90"; +#endif /* not lint */ + +#include "gprof.h" + + /* + * a namelist entry to be the child of indirect callf + */ +nltype indirectchild = { + "(*)" , /* the name */ + (unsigned long) 0 , /* the pc entry point */ + (unsigned long) 0 , /* entry point aligned to histogram */ + (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 ) + unsigned char *modep; +{ + long usesreg = ((long)*modep) & 0xf; + + switch ( ((long)*modep) >> 4 ) { + 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 != 0xe ? 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 ); + } + /* NOTREACHED */ +} + +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"; + } + /* NOTREACHED */ +} + +long +operandlength( modep ) + unsigned char *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( modep + 1 ); + } + /* NOTREACHED */ +} + +unsigned long +reladdr( modep ) + char *modep; +{ + operandenum mode = operandmode( modep ); + char *cp; + short *sp; + long *lp; + int i; + long value = 0; + + cp = modep; + cp += 1; /* skip over the mode */ + switch ( mode ) { + default: + fprintf( stderr , "[reladdr] not relative address\n" ); + return (unsigned long) modep; + case byterel: + return (unsigned long) ( cp + sizeof *cp + *cp ); + case wordrel: + for (i = 0; i < sizeof *sp; i++) + value = (value << 8) + (cp[i] & 0xff); + return (unsigned long) ( cp + sizeof *sp + value ); + case longrel: + for (i = 0; i < sizeof *lp; i++) + value = (value << 8) + (cp[i] & 0xff); + return (unsigned long) ( cp + sizeof *lp + value ); + } +} + +findcall( 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 & 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; + } + } + } +} |