#include "gprof.h"
nltype indirectchild = {
"(*)",
&modules,
(pctype)0,
(pctype)0,
(unsigned long)0,
(unsigned char)0,
(size_t)0,
(double)0.0,
(double)0.0,
(long)0,
(long)0,
(double)1.0,
(double)0.0,
(double)0.0,
(bool)0,
(int)0,
(int)0,
(int)0,
(struct nl *)&indirectchild,
(struct nl *)0,
(arctype *)0,
(arctype *)0,
(unsigned long)0
};
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
length = 4;
for (instructp = (uintptr_t)textspace + p_lowpc - TORIGIN;
instructp < (uintptr_t)textspace + p_highpc - TORIGIN;
instructp += length) {
switch (OP(instructp)) {
case CALL:
#ifdef DEBUG
if (debug & CALLSDEBUG) {
printf("[findcalls]\t0x%x:call\n",
PC_VAL(instructp));
}
#endif
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
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
continue;
}
#ifdef DEBUG
if (debug & CALLSDEBUG) {
printf("\toperands are DST = R%d,\tSRC = R%d",
RD(instructp), RS1(instructp));
}
#endif
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
switch (RS1(instructp)) {
case R_G0:
destpc = SIMM13(instructp);
break;
default:
addarc(parentp, &indirectchild, 0);
continue;
}
} else {
#ifdef DEBUG
if (debug & CALLSDEBUG) {
printf(" + R%d\n", RS2(instructp));
}
#endif
addarc(parentp, &indirectchild, 0);
continue;
}
break;
default:
continue;
}
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
if (childp->value == destpc) {
addarc(parentp, childp, 0);
continue;
}
}
#ifdef DEBUG
if (debug & CALLSDEBUG) {
printf("[findcalls]\tbut it's a switch or a botch\n");
}
#endif
continue;
}
}