| /* |
| * 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 |