Logo Search packages:      
Sourcecode: palo version File versions  Download package

unwind.c

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

Generated by  Doxygen 1.6.0   Back to index