#define RESTORE_RETURNVAL 0x8fbf0000
#define RESTORE_RETURNVAL_MASK 0xffff0000
#define ADJUST_STACKP_C 0x27bd0000
#define ADJUST_STACKP_C_MASK 0xffff0000
#define ADJUST_STACKP_V 0x03a1e821
#define ADJUST_STACKP_V_MASK 0xffffffff
#define SET_UPPER_C 0x3c010000
#define SET_UPPER_C_MASK 0xffff0000
#define OR_LOWER_C 0x34210000
#define OR_LOWER_C_MASK 0xffff0000
#define SET_LOWER_C 0x34010000
#define SET_LOWER_C_MASK 0xffff0000
#define RETURN 0x03e00008
#define CALL(f) (0x0c000000 | (((int) (f)) >> 2))
#define HASH_SIZE 256
typedef struct _returnCache {
unsigned long *returnAddress;
long raOffset;
long spAdjust;
} ReturnCacheRec, *ReturnCachePtr;
static ReturnCacheRec returnCache[HASH_SIZE];
#define HASH(ra) ((((int) (ra)) >> 2) & (HASH_SIZE - 1))
typedef int Bool;
#define TRUE 1
#define FALSE 0
getStackTrace (results, max)
unsigned long *results;
int max;
{
extern unsigned long *getReturnAddress (), *getStackPointer ();
extern int main ();
unsigned long *ra, *ra_limit;
unsigned long *sp;
unsigned long inst;
unsigned long mainCall;
unsigned short const_upper;
unsigned short const_lower;
long ra_offset;
long sp_adjust;
Bool found_ra_offset, found_sp_adjust;
Bool found_const_upper, found_const_lower;
ReturnCachePtr rc;
ra = getReturnAddress ();
sp = getStackPointer ();
mainCall = CALL(main);
while (ra && max) {
rc = &returnCache[HASH(ra)];
if (rc->returnAddress != ra)
{
found_ra_offset = FALSE;
found_sp_adjust = FALSE;
found_const_upper = FALSE;
found_const_lower = FALSE;
const_upper = 0;
const_lower = 0;
rc->returnAddress = ra;
ra_limit = (unsigned long *) 0x10000000;
ra_offset = 0;
sp_adjust = -1;
while ((!found_ra_offset || !found_sp_adjust) && ra < ra_limit)
{
inst = *ra;
if ((inst & RESTORE_RETURNVAL_MASK) == RESTORE_RETURNVAL)
{
ra_offset = inst & ~RESTORE_RETURNVAL_MASK;
found_ra_offset = TRUE;
}
else if ((inst & ADJUST_STACKP_C_MASK) == ADJUST_STACKP_C)
{
sp_adjust = inst & ~ADJUST_STACKP_C_MASK;
found_sp_adjust = TRUE;
}
else if ((inst & ADJUST_STACKP_V_MASK) == ADJUST_STACKP_V)
{
sp_adjust = 0;
found_sp_adjust = TRUE;
}
else if ((inst & SET_UPPER_C_MASK) == SET_UPPER_C)
{
const_upper = inst & ~SET_UPPER_C_MASK;
const_lower = 0;
found_const_upper = TRUE;
}
else if ((inst & OR_LOWER_C_MASK) == OR_LOWER_C)
{
const_lower = inst & ~OR_LOWER_C_MASK;
found_const_lower = TRUE;
}
else if ((inst & SET_LOWER_C_MASK) == SET_LOWER_C)
{
const_lower = inst & ~SET_LOWER_C_MASK;
const_upper = 0;
found_const_lower = TRUE;
}
else if (inst == RETURN)
ra_limit = ra + 2;
ra++;
}
if (sp_adjust == 0 && (found_const_upper || found_const_lower))
sp_adjust = (const_upper << 16) | const_lower;
rc->raOffset = ra_offset;
rc->spAdjust = sp_adjust;
}
if (rc->spAdjust <= 0)
{
*results++ = 0;
break;
}
ra = (unsigned long *) sp[rc->raOffset>>2];
sp += rc->spAdjust >> 2;
*results++ = ((unsigned long) ra) - 8;
if (ra[-2] == mainCall)
{
*results++ = 0;
break;
}
max--;
}
}