Subversion Repositories planix.SVN

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Debugger utilities shared by at least two architectures
 */

#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>

#define STARTSYM        "_main"
#define PROFSYM         "_mainp"
#define FRAMENAME       ".frame"

extern  Machdata        mipsmach;

int     asstype = AMIPS;                /* disassembler type */
Machdata *machdata;             /* machine-dependent functions */

int
localaddr(Map *map, char *fn, char *var, uvlong *r, Rgetter rget)
{
        Symbol s;
        uvlong fp, pc, sp, link;

        if (!lookup(fn, 0, &s)) {
                werrstr("function not found");
                return -1;
        }
        pc = rget(map, mach->pc);
        sp = rget(map, mach->sp);
        if(mach->link)
                link = rget(map, mach->link);
        else
                link = 0;
        fp = machdata->findframe(map, s.value, pc, sp, link);
        if (fp == 0) {
                werrstr("stack frame not found");
                return -1;
        }

        if (!var || !var[0]) {
                *r = fp;
                return 1;
        }

        if (findlocal(&s, var, &s) == 0) {
                werrstr("local variable not found");
                return -1;
        }

        switch (s.class) {
        case CAUTO:
                *r = fp - s.value;
                break;
        case CPARAM:            /* assume address size is stack width */
                *r = fp + s.value + mach->szaddr;
                break;
        default:
                werrstr("local variable not found: %d", s.class);
                return -1;
        }
        return 1;
}

/*
 * Print value v as s.name[+offset] if possible, or just v.
 */
int
symoff(char *buf, int n, uvlong v, int space)
{
        Symbol s;
        int r;
        long delta;

        r = delta = 0;          /* to shut compiler up */
        if (v) {
                r = findsym(v, space, &s);
                if (r)
                        delta = v-s.value;
                if (delta < 0)
                        delta = -delta;
        }
        if (v == 0 || r == 0)
                return snprint(buf, n, "%llux", v);
        if (s.type != 't' && s.type != 'T' && delta >= 4096)
                return snprint(buf, n, "%llux", v);
        else if (delta)
                return snprint(buf, n, "%s+%lux", s.name, delta);
        else
                return snprint(buf, n, "%s", s.name);
}

/*
 *      Format floating point registers
 *
 *      Register codes in format field:
 *      'X' - print as 32-bit hexadecimal value
 *      'F' - 64-bit double register when modif == 'F'; else 32-bit single reg
 *      'f' - 32-bit ieee float
 *      '8' - big endian 80-bit ieee extended float
 *      '3' - little endian 80-bit ieee extended float with hole in bytes 8&9
 */
int
fpformat(Map *map, Reglist *rp, char *buf, int n, int modif)
{
        char reg[12];
        ulong r;

        switch(rp->rformat)
        {
        case 'X':
                if (get4(map, rp->roffs, &r) < 0)
                        return -1;
                snprint(buf, n, "%lux", r);
                break;
        case 'F':       /* first reg of double reg pair */
                if (modif == 'F')
                if ((rp->rformat=='F') || (((rp+1)->rflags&RFLT) && (rp+1)->rformat == 'f')) {
                        if (get1(map, rp->roffs, (uchar *)reg, 8) < 0)
                                return -1;
                        machdata->dftos(buf, n, reg);
                        if (rp->rformat == 'F')
                                return 1;
                        return 2;
                }       
                        /* treat it like 'f' */
                if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
                        return -1;
                machdata->sftos(buf, n, reg);
                break;
        case 'f':       /* 32 bit float */
                if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
                        return -1;
                machdata->sftos(buf, n, reg);
                break;
        case '3':       /* little endian ieee 80 with hole in bytes 8&9 */
                if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
                        return -1;
                memmove(reg+10, reg+8, 2);      /* open hole */
                memset(reg+8, 0, 2);            /* fill it */
                leieee80ftos(buf, n, reg);
                break;
        case '8':       /* big-endian ieee 80 */
                if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
                        return -1;
                beieee80ftos(buf, n, reg);
                break;
        default:        /* unknown */
                break;
        }
        return 1;
}

char *
_hexify(char *buf, ulong p, int zeros)
{
        ulong d;

        d = p/16;
        if(d)
                buf = _hexify(buf, d, zeros-1);
        else
                while(zeros--)
                        *buf++ = '0';
        *buf++ = "0123456789abcdef"[p&0x0f];
        return buf;
}

/*
 * These routines assume that if the number is representable
 * in IEEE floating point, it will be representable in the native
 * double format.  Naive but workable, probably.
 */
int
ieeedftos(char *buf, int n, ulong h, ulong l)
{
        double fr;
        int exp;

        if (n <= 0)
                return 0;


        if(h & (1L<<31)){
                *buf++ = '-';
                h &= ~(1L<<31);
        }else
                *buf++ = ' ';
        n--;
        if(l == 0 && h == 0)
                return snprint(buf, n, "0.");
        exp = (h>>20) & ((1L<<11)-1L);
        if(exp == 0)
                return snprint(buf, n, "DeN(%.8lux%.8lux)", h, l);
        if(exp == ((1L<<11)-1L)){
                if(l==0 && (h&((1L<<20)-1L)) == 0)
                        return snprint(buf, n, "Inf");
                else
                        return snprint(buf, n, "NaN(%.8lux%.8lux)", h&((1L<<20)-1L), l);
        }
        exp -= (1L<<10) - 2L;
        fr = l & ((1L<<16)-1L);
        fr /= 1L<<16;
        fr += (l>>16) & ((1L<<16)-1L);
        fr /= 1L<<16;
        fr += (h & (1L<<20)-1L) | (1L<<20);
        fr /= 1L<<21;
        fr = ldexp(fr, exp);
        return snprint(buf, n, "%.18g", fr);
}

int
ieeesftos(char *buf, int n, ulong h)
{
        double fr;
        int exp;

        if (n <= 0)
                return 0;

        if(h & (1L<<31)){
                *buf++ = '-';
                h &= ~(1L<<31);
        }else
                *buf++ = ' ';
        n--;
        if(h == 0)
                return snprint(buf, n, "0.");
        exp = (h>>23) & ((1L<<8)-1L);
        if(exp == 0)
                return snprint(buf, n, "DeN(%.8lux)", h);
        if(exp == ((1L<<8)-1L)){
                if((h&((1L<<23)-1L)) == 0)
                        return snprint(buf, n, "Inf");
                else
                        return snprint(buf, n, "NaN(%.8lux)", h&((1L<<23)-1L));
        }
        exp -= (1L<<7) - 2L;
        fr = (h & ((1L<<23)-1L)) | (1L<<23);
        fr /= 1L<<24;
        fr = ldexp(fr, exp);
        return snprint(buf, n, "%.9g", fr);
}

int
beieeesftos(char *buf, int n, void *s)
{
        return ieeesftos(buf, n, beswal(*(ulong*)s));
}

int
beieeedftos(char *buf, int n, void *s)
{
        return ieeedftos(buf, n, beswal(*(ulong*)s), beswal(((ulong*)(s))[1]));
}

int
leieeesftos(char *buf, int n, void *s)
{
        return ieeesftos(buf, n, leswal(*(ulong*)s));
}

int
leieeedftos(char *buf, int n, void *s)
{
        return ieeedftos(buf, n, leswal(((ulong*)(s))[1]), leswal(*(ulong*)s));
}

/* packed in 12 bytes, with s[2]==s[3]==0; mantissa starts at s[4]*/
int
beieee80ftos(char *buf, int n, void *s)
{
        uchar *reg = (uchar*)s;
        int i;
        ulong x;
        uchar ieee[8+8];        /* room for slop */
        uchar *p, *q;

        memset(ieee, 0, sizeof(ieee));
        /* sign */
        if(reg[0] & 0x80)
                ieee[0] |= 0x80;

        /* exponent */
        x = ((reg[0]&0x7F)<<8) | reg[1];
        if(x == 0)              /* number is ±0 */
                goto done;
        if(x == 0x7FFF){
                if(memcmp(reg+4, ieee+1, 8) == 0){ /* infinity */
                        x = 2047;
                }else{                          /* NaN */
                        x = 2047;
                        ieee[7] = 0x1;          /* make sure */
                }
                ieee[0] |= x>>4;
                ieee[1] |= (x&0xF)<<4;
                goto done;
        }
        x -= 0x3FFF;            /* exponent bias */
        x += 1023;
        if(x >= (1<<11) || ((reg[4]&0x80)==0 && x!=0))
                return snprint(buf, n, "not in range");
        ieee[0] |= x>>4;
        ieee[1] |= (x&0xF)<<4;

        /* mantissa */
        p = reg+4;
        q = ieee+1;
        for(i=0; i<56; i+=8, p++, q++){ /* move one byte */
                x = (p[0]&0x7F) << 1;
                if(p[1] & 0x80)
                        x |= 1;
                q[0] |= x>>4;
                q[1] |= (x&0xF)<<4;
        }
    done:
        return beieeedftos(buf, n, (void*)ieee);
}

int
leieee80ftos(char *buf, int n, void *s)
{
        int i;
        char *cp;
        char b[12];

        cp = (char*) s;
        for(i=0; i<12; i++)
                b[11-i] = *cp++;
        return beieee80ftos(buf, n, b);
}

int
cisctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
{
        Symbol s;
        int found, i;
        uvlong opc, moved;

        USED(link);
        i = 0;
        opc = 0;
        while(pc && opc != pc) {
                moved = pc2sp(pc);
                if (moved == ~0)
                        break;
                found = findsym(pc, CTEXT, &s);
                if (!found)
                        break;
                if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
                        break;

                sp += moved;
                opc = pc;
                if (geta(map, sp, &pc) < 0)
                        break;
                (*trace)(map, pc, sp, &s);
                sp += mach->szaddr;     /*assumes address size = stack width*/
                if(++i > 40)
                        break;
        }
        return i;
}

int
risctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
{
        int i;
        Symbol s, f;
        uvlong oldpc;

        i = 0;
        while(findsym(pc, CTEXT, &s)) {
                if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
                        break;

                if(pc == s.value)       /* at first instruction */
                        f.value = 0;
                else if(findlocal(&s, FRAMENAME, &f) == 0)
                        break;

                oldpc = pc;
                if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant)
                        pc = link;
                else
                        if (geta(map, sp, &pc) < 0)
                                break;

                if(pc == 0 || (pc == oldpc && f.value == 0))
                        break;

                sp += f.value;
                (*trace)(map, pc-8, sp, &s);

                if(++i > 40)
                        break;
        }
        return i;
}

uvlong
ciscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
{
        Symbol s;
        uvlong moved;

        USED(link);
        for(;;) {
                moved = pc2sp(pc);
                if (moved  == ~0)
                        break;
                sp += moved;
                findsym(pc, CTEXT, &s);
                if (addr == s.value)
                        return sp;
                if (geta(map, sp, &pc) < 0)
                        break;
                sp += mach->szaddr;     /*assumes sizeof(addr) = stack width*/
        }
        return 0;
}

uvlong
riscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
{
        Symbol s, f;

        while (findsym(pc, CTEXT, &s)) {
                if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
                        break;

                if(pc == s.value)       /* at first instruction */
                        f.value = 0;
                else
                if(findlocal(&s, FRAMENAME, &f) == 0)
                        break;

                sp += f.value;
                if (s.value == addr)
                        return sp;

                if (s.type == 'L' || s.type == 'l' || pc-s.value <= mach->szaddr*2)
                        pc = link;
                else
                if (geta(map, sp-f.value, &pc) < 0)
                        break;
        }
        return 0;
}