blob: e08b733993b51617518bd56812efbaedd4237971 [file] [log] [blame]
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) Hewlett-Packard (Paul Bame) paul_bame@hp.com
*/
#include <stdio.h>
#define GET_REG(reg) ({ \
unsigned long r; \
__asm__ __volatile__( \
"copy " #reg ",%0" : "=r" (r) \
); \
r; \
})
#define GET_SP() GET_REG(30)
#define GET_RP() GET_REG(2)
#define GET_PC() ({ \
unsigned long r; \
__asm__ __volatile__( \
"ldil L%%(.+8), %0\n\t" \
"ldo R%%(.+4)(%0), %0" : "=r" (r) \
); \
r; \
})
/* These two would be MUCH easier with a quick asm() instruction! */
/* extract some bits, least-sig bit is numbered 0, unsigned */
#define GETBITSLSB0(i, start, length) \
(((i) >> (start)) & ((1 << (length)) - 1))
/* extract some bits, least-sig bit is numbered 0, signed */
#define GETBITSLSB0S(i, start, length) \
(((signed)((i) << (32 - (start + length)))) >> (32 - length))
/* bl xxx,%r2 */
#define BL2_BITS 0xe8400000
#define BL2_MASK 0xffe0e000
#define IS_BL2(i) (((i) & BL2_MASK) == BL2_BITS)
/********** Not finished ************/
#define BLR_BITS 0xe8004
#define BLR_MASK 0xfc00e
union bl
{
unsigned instr;
struct
{
unsigned opcode:6;
unsigned t:5;
unsigned w1:5;
unsigned dummy:3;
unsigned w2_0_9:10;
unsigned w2_10:1;
unsigned n:1;
unsigned w:1;
} bits;
};
static int
assemble_17(unsigned instr)
{
union bl bl;
int x;
int sx;
bl.instr = instr;
x = bl.bits.w2_0_9;
x |= bl.bits.w2_10 << 10;
x |= bl.bits.w1 << 11;
x |= bl.bits.w << (5 + 11);
sx = x << (32 - 17);
sx >>= (32 - 17 - 2);
#if 0
printf("op %x t %x w1 %x w20 %x n %x w %x x %x 4x %x sx %d\n",
bl.bits.opcode,
bl.bits.t,
bl.bits.w1,
bl.bits.w2_0_9,
bl.bits.n,
bl.bits.w, x, x << 2, sx);
#endif
return sx;
}
static unsigned *
find_rp(unsigned *sp, unsigned *dot, unsigned **btargetp)
{
unsigned *lim = sp - 1024;
extern unsigned _etext, __text_start;
while(sp > lim)
{
unsigned *maybe_rp = (unsigned *)*sp;
if (0) printf("%p: %p\n", sp, maybe_rp);
if (((unsigned)maybe_rp & 0x3) == 0x3
&& maybe_rp < &_etext
&& maybe_rp >= &__text_start)
{
unsigned instr;
unsigned *btarget;
maybe_rp = (unsigned *)((unsigned)maybe_rp & ~0x3);
/* check if instr - 2 is a bl ..., %r2 */
instr = maybe_rp[-2];
if (IS_BL2(instr))
{
btarget = (unsigned *)((unsigned)maybe_rp + assemble_17(instr));
printf("%p: %p: bl %p, %%r2\n",
sp,
maybe_rp - 2,
btarget
);
if (btarget > dot)
{
printf("unlikely bl, .+0x%x\n",
(unsigned)btarget - (unsigned)maybe_rp);
}
else
{
*btargetp = btarget;
return sp;
}
}
}
sp--;
}
return 0;
}
void unwind()
{
unsigned *rp = (unsigned *)(GET_RP() & ~0x3);
unsigned *sp = (unsigned *)GET_SP();
/* lie about these data types... _end could be 1-byte aligned */
extern unsigned _end;
extern unsigned _etext;
extern unsigned __text_start;
unsigned *lastrpsp = sp;
extern unsigned dotlabel;
unsigned *dot;
unsigned *our_entry;
unsigned *lim;
unsigned *btarget;
asm("\ndotlabel:");
dot = &dotlabel;
printf("Initial rp: %p\tsp: %p\tetext: %p\t.: %p\n", rp, sp, &_etext, dot);
/* find where my RP is stored, hence my caller's stack frame */
for ( ; *sp != rp; sp--)
{
}
printf("Found my RP on stack at %p\n", sp);
/* stack frames are 16 words minimum, rp is stored in word -5 relative */
/* to stack pointer on entry to a routine, so we can calculate the sp */
/* on entry to the current routine */
sp += 5;
printf("My entry SP was %p\n", sp);
/* by disassembling the target of the branch which brought us here, */
/* we can learn our entry point address */
our_entry = (unsigned *)(assemble_17(rp[-2]) + (unsigned)rp);
printf("Entry point to this routine is %p\n", our_entry);
/* can't be sure about args, but some may be on stack... */
printf("%p: %p(%08x, %08x, %08x, %08x)\n",
rp - 2,
our_entry,
sp[-9],
sp[-10],
sp[-11],
sp[-12]);
/* become the previous procedure */
dot = rp;
/* this is the minimum stack frame size -- skip over it */
sp -= 16;
sp = find_rp(sp, dot, &btarget);
if (sp != 0)
{
rp = (unsigned *)((unsigned)*sp & ~0x3);
printf("Found my RP (%p) on stack at %p\n", rp, sp);
/* stack frames are 16 words minimum, rp is stored in word -5 relative */
/* to stack pointer on entry to a routine, so we can calculate the sp */
/* on entry to the current routine */
sp += 5;
printf("My entry SP was %p\n", sp);
/* by disassembling the target of the branch which brought us here, */
/* we can learn our entry point address */
if (0) our_entry = (unsigned *)(assemble_17(rp[-2]) + (unsigned)rp);
printf("Entry point to this routine is %p\n", btarget);
/* can't be sure about args, but some may be on stack... */
printf("%p: %p()\n", rp - 2, our_entry);
/* become the previous procedure */
dot = rp;
}
}
#if 0
void ounwind()
{
unsigned *sp = (unsigned *)GET_SP();
unsigned *rp = (unsigned *)GET_RP();
/* lie about these data types... _end could be 1-byte aligned */
extern unsigned _end;
extern unsigned _etext;
extern unsigned __text_start;
unsigned *lim = sp - 1024*4;
unsigned *lastrpsp = sp;
extern unsigned dotlabel;
unsigned *dot;
asm("\ndotlabel:");
dot = &dotlabel;
printf("Initial rp: %p\tsp: %p\tetext: %p\t.: %p\n", rp, sp, &_etext, dot);
/* walk backwards in stack looking for likely RPs */
while(sp > lim)
{
unsigned *maybe_rp = (unsigned *)*sp;
if (0) printf("%p: %p\n", sp, maybe_rp);
if (((unsigned)maybe_rp & 0x3) == 0x3
&& maybe_rp < &_etext
&& maybe_rp >= &__text_start)
{
unsigned instr;
unsigned *btarget;
maybe_rp = (unsigned *)((unsigned)maybe_rp & ~0x3);
/* check if instr - 2 is a bl ..., %r2 */
instr = maybe_rp[-2];
if (IS_BL2(instr))
{
btarget = (unsigned)maybe_rp + assemble_17(instr);
printf("%p: %p: bl %p, %%r2, stack delta 0x%x\n",
sp,
maybe_rp - 2,
btarget,
(unsigned)lastrpsp - (unsigned)sp
);
if (btarget > dot)
{
printf("unlikely bl, .+0x%x\n",
(unsigned)btarget - (unsigned)maybe_rp);
}
lastrpsp = sp;
}
}
sp--;
}
exit(77);
}
#endif