libmach support for sparc64 .u and elf boot images. - mkfile,obj.c,setmach.c - glue - elf.h,executable.c - boot image support - u.c,udb.c,uobj.c - new bits, borrowed heavily from kobj.c et al Reference: /n/sources/patch/applied/libmach-uobj Date: Sun Apr 24 06:08:49 CES 2005 --- /sys/src/libmach/elf.h Sun Apr 24 06:03:18 2005 +++ /sys/src/libmach/elf.h Sun Apr 24 06:03:14 2005 @@ -79,6 +79,7 @@ I860 = 7, /* Intel i860 */ MIPS = 8, /* Mips R2000 */ S370 = 9, /* Amdhal */ + SPARC64 = 18, /* Sun SPARC v9 */ POWER = 20, /* PowerPC */ NO_VERSION = 0, /* version, ident[VERSION] */ --- /sys/src/libmach/executable.c Sun Apr 24 06:03:37 2005 +++ /sys/src/libmach/executable.c Sun Apr 24 06:03:32 2005 @@ -57,6 +57,7 @@ extern Mach mmips2le; extern Mach mmips2be; extern Mach msparc; +extern Mach msparc64; extern Mach m68020; extern Mach mi386; extern Mach marm; @@ -121,6 +122,14 @@ sizeof(struct sparcexec), beswal, sparcboot }, + { U_MAGIC, /* Sparc64 u.out */ + "sparc64 plan 9 executable", + "sparc64 plan 9 dlm", + FSPARC64, + &msparc64, + sizeof(Exec), + beswal, + adotout }, { A_MAGIC, /* 68020 2.out & boot image */ "68020 plan 9 executable", "68020 plan 9 dlm", @@ -506,6 +515,10 @@ mach = &mmips; fp->type = FMIPS; break; + case SPARC64: + mach = &msparc64; + fp->type = FSPARC64; + break; case POWER: mach = &mpower; fp->type = FPOWER; @@ -542,6 +555,29 @@ is = i; } if(it == -1 || id == -1) { + /* + * The SPARC64 boot image is something of an ELF hack. + * Text+Data+BSS are represented by ph[0]. Symbols + * are represented by ph[1]: + * + * filesz, memsz, vaddr, paddr, off + * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff + * ph[1] : symsz, lcsz, 0, 0, symoff + */ + if(ep->machine == SPARC64 && ep->phnum == 2) { + ulong txtaddr, txtsz, dataddr, bsssz; + + txtaddr = ph[0].vaddr | 0x80000000; + txtsz = ph[0].filesz - ph[0].paddr; + dataddr = txtaddr + txtsz; + bsssz = ph[0].memsz - ph[0].filesz; + settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset); + setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz); + setsym(fp, ph[1].filesz, 0, ph[1].memsz, ph[1].offset); + free(ph); + return 1; + } + werrstr("No TEXT or DATA sections"); free(ph); return 0; --- /sys/src/libmach/mkfile Sun Apr 24 06:03:59 2005 +++ /sys/src/libmach/mkfile Sun Apr 24 06:03:56 2005 @@ -11,6 +11,7 @@ setmach\ v\ k\ + u\ q\ 0\ 2\ @@ -19,6 +20,7 @@ 7\ vdb\ kdb\ + udb\ qdb\ 2db\ 8db\ @@ -26,6 +28,7 @@ 7db\ vobj\ kobj\ + uobj\ 2obj\ 8obj\ 5obj\ --- /sys/src/libmach/obj.c Sun Apr 24 06:04:25 2005 +++ /sys/src/libmach/obj.c Sun Apr 24 06:04:21 2005 @@ -27,13 +27,15 @@ _isk(char*), _isq(char*), _isv(char*), + _isu(char*), _read2(Biobuf*, Prog*), _read5(Biobuf*, Prog*), _read7(Biobuf*, Prog*), _read8(Biobuf*, Prog*), _readk(Biobuf*, Prog*), _readq(Biobuf*, Prog*), - _readv(Biobuf*, Prog*); + _readv(Biobuf*, Prog*), + _readu(Biobuf*, Prog*); typedef struct Obj Obj; typedef struct Symtab Symtab; @@ -54,6 +56,7 @@ [ObjSparc] "sparc .k", _isk, _readk, [ObjPower] "power .q", _isq, _readq, [ObjMips] "mips .v", _isv, _readv, + [ObjSparc64] "sparc64 .u", _isu, _readu, [Maxobjtype] 0, 0 }; --- /sys/src/libmach/setmach.c Sun Apr 24 06:04:53 2005 +++ /sys/src/libmach/setmach.c Sun Apr 24 06:04:50 2005 @@ -17,9 +17,9 @@ }; extern Mach mmips, msparc, m68020, mi386, - marm, mmips2be, mmips2le, mpower, malpha; + marm, mmips2be, mmips2le, mpower, malpha, msparc64; extern Machdata mipsmach, sparcmach, m68020mach, i386mach, - armmach, mipsmach2le, powermach, alphamach; + armmach, mipsmach2le, powermach, alphamach, sparc64mach; /* * machine selection table. machines with native disassemblers should @@ -106,6 +106,12 @@ AALPHA, &malpha, &alphamach, }, + { "sparc64", /*plan 9 sparc64 */ + FSPARC64, + FSPARCB, /* XXX? */ + ASPARC64, + &msparc64, + &sparc64mach, }, { 0 }, /*the terminator*/ }; --- /sys/src/libmach/u.c Thu Jan 1 00:00:00 1970 +++ /sys/src/libmach/u.c Sun Apr 24 06:05:23 2005 @@ -0,0 +1,118 @@ +/* + * sparc64 definition + */ +#include +#include +#include "/sparc64/include/ureg.h" +#include + +#define REGOFF(x) (ulong)(&((struct Ureg *) 0)->x) + +#define R1 REGOFF(r1) +#define R7 REGOFF(r7) +#define PC REGOFF(pc) +#define R15 REGOFF(r15) + +#define REGSIZE sizeof(struct Ureg) +#define FP_REG(x) (REGSIZE+4*(x)) +#define FPREGSIZE (33*4) + +Reglist sparc64reglist[] = { + {"Y", REGOFF(y), RINT|RRDONLY, 'X'}, + {"TT", REGOFF(tt), RINT|RRDONLY, 'X'}, + {"PSTATE", REGOFF(pstate), RINT|RRDONLY, 'X'}, + {"PC", REGOFF(pc), RINT, 'X'}, + {"SP", REGOFF(sp), RINT, 'X'}, /* also R1 */ + {"R2", REGOFF(r2), RINT, 'X'}, + {"R3", REGOFF(r3), RINT, 'X'}, + {"R4", REGOFF(r4), RINT, 'X'}, + {"R5", REGOFF(r5), RINT, 'X'}, + {"R6", REGOFF(r6), RINT, 'X'}, + {"R7", REGOFF(r7), RINT, 'X'}, + {"R8", REGOFF(r8), RINT, 'X'}, + {"R9", REGOFF(r9), RINT, 'X'}, + {"R10", REGOFF(r10), RINT, 'X'}, + {"R11", REGOFF(r11), RINT, 'X'}, + {"R12", REGOFF(r12), RINT, 'X'}, + {"R13", REGOFF(r13), RINT, 'X'}, + {"R14", REGOFF(r14), RINT, 'X'}, + {"R15", REGOFF(r15), RINT, 'X'}, + {"R16", REGOFF(r16), RINT, 'X'}, + {"R17", REGOFF(r17), RINT, 'X'}, + {"R18", REGOFF(r18), RINT, 'X'}, + {"R19", REGOFF(r19), RINT, 'X'}, + {"R20", REGOFF(r20), RINT, 'X'}, + {"R21", REGOFF(r21), RINT, 'X'}, + {"R22", REGOFF(r22), RINT, 'X'}, + {"R23", REGOFF(r23), RINT, 'X'}, + {"R24", REGOFF(r24), RINT, 'X'}, + {"R25", REGOFF(r25), RINT, 'X'}, + {"R26", REGOFF(r26), RINT, 'X'}, + {"R27", REGOFF(r27), RINT, 'X'}, + {"R28", REGOFF(r28), RINT, 'X'}, + {"R29", REGOFF(r29), RINT, 'X'}, + {"R30", REGOFF(r30), RINT, 'X'}, + {"R31", REGOFF(r31), RINT, 'X'}, + {"NPC", REGOFF(npc), RINT, 'X'}, + + {"F0", FP_REG(0), RFLT, 'F'}, + {"F1", FP_REG(1), RFLT, 'f'}, + {"F2", FP_REG(2), RFLT, 'F'}, + {"F3", FP_REG(3), RFLT, 'f'}, + {"F4", FP_REG(4), RFLT, 'F'}, + {"F5", FP_REG(5), RFLT, 'f'}, + {"F6", FP_REG(6), RFLT, 'F'}, + {"F7", FP_REG(7), RFLT, 'f'}, + {"F8", FP_REG(8), RFLT, 'F'}, + {"F9", FP_REG(9), RFLT, 'f'}, + {"F10", FP_REG(10), RFLT, 'F'}, + {"F11", FP_REG(11), RFLT, 'f'}, + {"F12", FP_REG(12), RFLT, 'F'}, + {"F13", FP_REG(13), RFLT, 'f'}, + {"F14", FP_REG(14), RFLT, 'F'}, + {"F15", FP_REG(15), RFLT, 'f'}, + {"F16", FP_REG(16), RFLT, 'F'}, + {"F17", FP_REG(17), RFLT, 'f'}, + {"F18", FP_REG(18), RFLT, 'F'}, + {"F19", FP_REG(19), RFLT, 'f'}, + {"F20", FP_REG(20), RFLT, 'F'}, + {"F21", FP_REG(21), RFLT, 'f'}, + {"F22", FP_REG(22), RFLT, 'F'}, + {"F23", FP_REG(23), RFLT, 'f'}, + {"F24", FP_REG(24), RFLT, 'F'}, + {"F25", FP_REG(25), RFLT, 'f'}, + {"F26", FP_REG(26), RFLT, 'F'}, + {"F27", FP_REG(27), RFLT, 'f'}, + {"F28", FP_REG(28), RFLT, 'F'}, + {"F29", FP_REG(29), RFLT, 'f'}, + {"F30", FP_REG(30), RFLT, 'F'}, + {"F31", FP_REG(31), RFLT, 'f'}, + {"FSR", FP_REG(32), RINT, 'X'}, + {"FPRS", FP_REG(33), RINT, 'X'}, + { 0 } +}; + +/* + * sparc64 has same stack format as mips + */ +Mach msparc64 = +{ + "sparc64", + MSPARC64, /* machine type */ + sparc64reglist, /* register list */ + REGSIZE, /* register set size in bytes */ + FPREGSIZE, /* floating point register size in bytes */ + "PC", /* name of PC */ + "R1", /* name of SP */ + "R15", /* name of link register */ + "setSB", /* static base register name */ + 0, /* value */ + 0x2000, /* page size */ + 0x80000000, /* kernel base */ + 0, /* kernel text mask */ + 4, /* quantization of pc */ + 4, /* szaddr */ + 4, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; --- /sys/src/libmach/udb.c Thu Jan 1 00:00:00 1970 +++ /sys/src/libmach/udb.c Sun Apr 24 06:05:55 2005 @@ -0,0 +1,1075 @@ +#include +#include +#include +#include + +/* + * Sparc64-specific debugger interface + */ + +static char *sparc64excep(Map*, Rgetter); +static int sparc64foll(Map*, ulong, Rgetter, ulong*); +static int sparc64inst(Map*, ulong, char, char*, int); +static int sparc64das(Map*, ulong, char*, int); +static int sparc64instlen(Map*, ulong); + +Machdata sparc64mach = +{ + {0x91, 0xd0, 0x20, 0x01}, /* breakpoint: TA $1 */ + 4, /* break point size */ + + beswab, /* convert short to local byte order */ + beswal, /* convert long to local byte order */ + beswav, /* convert vlong to local byte order */ + risctrace, /* C traceback */ + riscframe, /* frame finder */ + sparc64excep, /* print exception */ + 0, /* breakpoint fixup */ + beieeesftos, /* single precision float printer */ + beieeedftos, /* double precision float printer */ + sparc64foll, /* following addresses */ + sparc64inst, /* print instruction */ + sparc64das, /* dissembler */ + sparc64instlen, /* instruction size */ +}; + +static char *trapname[] = +{ + 0, + "power on reset", + "watchdog reset", + "external reset", + "software reset", + "RED", + 0, 0, + "instruction access exception", + "instruction access MMU miss", + "instruction access error", + 0, 0, 0, 0, 0, + "illegal instruction", + "privileged opcode", + "unimplemented LDD", + "unimplemented STD", + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + "fp disabled", + "fp exception ieee 754", + "fp exception other", + 0, 0, 0, 0, + "division by zero", + "internal processor error", + 0, 0, 0, 0, 0, 0, + "data access exception", + "data access MMU miss", + "data access error", + "data access protection", + "mem address not aligned", + "LDDF mem address not aligned", + "STDF mem address not aligned", + "privileged action", + "LDQF mem address nto aligned", + "STQF mem address not aligned", +}; + +static char* +excname(ulong tt) +{ + static char buf[32]; + + if(tt < sizeof trapname/sizeof(char*) && trapname[tt]) + return trapname[tt]; + if(tt >= 258) + sprint(buf, "trap instruction %ld", tt-128); + else if(65<=tt && tt<=79) + sprint(buf, "interrupt level %ld", tt-64); + else switch(tt){ + case 64: + return "async data error"; + case 96: + return "mondo interrupt"; + case 100: + return "instruction access MMU miss"; + case 104: + return "data access MMU miss"; + case 108: + return "data access protection"; + case 256: + return "syscall"; + case 257: + return "breakpoint"; + default: + sprint(buf, "unknown trap %ld", tt); + } + return buf; +} + +static char* +sparc64excep(Map *map, Rgetter rget) +{ + long tt; + + tt = (*rget)(map, "TT"); + return excname(tt); +} + + /* Sparc disassembler and related functions */ + +struct opcode { + char *mnemonic; + void (*f)(struct instr*, char*); + int flag; +}; + +static char FRAMENAME[] = ".frame"; + +typedef struct instr Instr; + +struct instr { + uchar op; /* bits 31-30 */ + uchar rd; /* bits 29-25 */ + uchar op2; /* bits 24-22 */ + uchar a; /* bit 29 */ + uchar cond; /* bits 28-25 */ + uchar op3; /* bits 24-19 */ + uchar rs1; /* bits 18-14 */ + uchar i; /* bit 13 */ + uchar asi; /* bits 12-05 */ + uchar rs2; /* bits 04-00 */ + short simm13; /* bits 12-00, signed */ + ushort opf; /* bits 13-05 */ + ulong immdisp22; /* bits 21-00 */ + ulong simmdisp22; /* bits 21-00, signed */ + ulong disp30; /* bits 30-00 */ + ulong imm32; /* SETHI+ADD constant */ + int target; /* SETHI+ADD dest reg */ + long w0; + long w1; + ulong addr; /* pc of instruction */ + char *curr; /* current fill level in output buffer */ + char *end; /* end of buffer */ + int size; /* number of longs in instr */ + char *err; /* errmsg */ +}; + +static Map *mymap; /* disassembler context */ +static int dascase; + +static int mkinstr(ulong, Instr*); +static void bra1(Instr*, char*, char*[]); +static void bra(Instr*, char*); +static void fbra(Instr*, char*); +static void cbra(Instr*, char*); +static void unimp(Instr*, char*); +static void fpop(Instr*, char*); +static void shift(Instr*, char*); +static void sethi(Instr*, char*); +static void load(Instr*, char*); +static void loada(Instr*, char*); +static void store(Instr*, char*); +static void storea(Instr*, char*); +static void add(Instr*, char*); +static void cmp(Instr*, char*); +static void wr(Instr*, char*); +static void jmpl(Instr*, char*); +static void rd(Instr*, char*); +static void loadf(Instr*, char*); +static void storef(Instr*, char*); +static void loadc(Instr*, char*); +static void loadcsr(Instr*, char*); +static void trap(Instr*, char*); + +static struct opcode sparc64op0[8] = { + [0] "UNIMP", unimp, 0, /* page 137 */ + [2] "B", bra, 0, /* page 119 */ + [4] "SETHI", sethi, 0, /* page 104 */ + [6] "FB", fbra, 0, /* page 121 */ + [7] "CB", cbra, 0, /* page 123 */ +}; + +static struct opcode sparc64op2[64] = { + [0x00] "ADD", add, 0, /* page 108 */ + [0x10] "ADDCC", add, 0, + [0x08] "ADDX", add, 0, + [0x18] "ADDXCC", add, 0, + + [0x20] "TADD", add, 0, /* page 109 */ + [0x22] "TADDCCTV", add, 0, + + [0x04] "SUB", add, 0, /* page 110 */ + [0x14] "SUBCC", cmp, 0, + [0x0C] "SUBX", add, 0, + [0x1C] "SUBXCC", add, 0, + + [0x21] "TSUB", add, 0, /* page 111 */ + [0x23] "TSUBCCTV", add, 0, + + [0x24] "MULSCC", add, 0, /* page 112 */ + + [0x0A] "UMUL", add, 0, /* page 113 */ + [0x0B] "SMUL", add, 0, + [0x1A] "UMULCC", add, 0, + [0x1B] "SMULCC", add, 0, + + [0x0E] "UDIV", add, 0, /* page 115 */ + [0x0F] "SDIV", add, 0, + [0x1E] "UDIVCC", add, 0, + [0x1F] "SDIVCC", add, 0, + + [0x01] "AND", add, 0, /* page 106 */ + [0x11] "ANDCC", add, 0, + [0x05] "ANDN", add, 0, + [0x15] "ANDNCC", add, 0, + [0x02] "OR", add, 0, + [0x12] "ORCC", add, 0, + [0x06] "ORN", add, 0, + [0x16] "ORNCC", add, 0, + [0x03] "XOR", add, 0, + [0x13] "XORCC", add, 0, + [0x07] "XORN", add, 0, + [0x17] "XORNCC", add, 0, + + [0x25] "SLL", shift, 0, /* page 107 */ + [0x26] "SRL", shift, 0, + [0x27] "SRA", shift, 0, + + [0x3C] "SAVE", add, 0, /* page 117 */ + [0x3D] "RESTORE", add, 0, + + [0x38] "JMPL", jmpl, 0, /* page 126 */ + + [0x39] "RETT", add, 0, /* page 127 */ + + [0x3A] "T", trap, 0, /* page 129 */ + + [0x28] "rdy", rd, 0, /* page 131 */ + [0x29] "rdpsr", rd, 0, + [0x2A] "rdwim", rd, 0, + [0x2B] "rdtbr", rd, 0, + + [0x30] "wry", wr, 0, /* page 133 */ + [0x31] "wrpsr", wr, 0, + [0x32] "wrwim", wr, 0, + [0x33] "wrtbr", wr, 0, + + [0x3B] "flush", add, 0, /* page 138 */ + + [0x34] "FPOP", fpop, 0, /* page 140 */ + [0x35] "FPOP", fpop, 0, +}; + +static struct opcode sparc64op3[64]={ + [0x09] "ldsb", load, 0, /* page 90 */ + [0x19] "ldsba", loada, 0, + [0x0A] "ldsh", load, 0, + [0x1A] "ldsha", loada, 0, + [0x01] "ldub", load, 0, + [0x11] "lduba", loada, 0, + [0x02] "lduh", load, 0, + [0x12] "lduha", loada, 0, + [0x00] "ld", load, 0, + [0x10] "lda", loada, 0, + [0x03] "ldd", load, 0, + [0x13] "ldda", loada, 0, + + [0x20] "ldf", loadf, 0, /* page 92 */ + [0x23] "lddf", loadf, 0, + [0x21] "ldfsr", loadf,0, + + [0x30] "ldc", loadc, 0, /* page 94 */ + [0x33] "lddc", loadc, 0, + [0x31] "ldcsr", loadcsr,0, + + [0x05] "stb", store, 0, /* page 95 */ + [0x15] "stba", storea, 0, + [0x06] "sth", store, 0, + [0x16] "stha", storea, 0, + [0x04] "st", store, 0, + [0x14] "sta", storea, 0, + [0x07] "std", store, 0, + [0x17] "stda", storea, 0, + + [0x24] "stf", storef, 0, /* page 97 */ + [0x27] "stdf", storef, 0, + [0x25] "stfsr", storef,0, + [0x26] "stdfq", storef,0, + + [0x34] "stc", loadc, 0, /* page 99 */ + [0x37] "stdc", loadc, 0, + [0x35] "stcsr", loadcsr,0, + [0x36] "stdcq", loadcsr,0, + + [0x0D] "ldstub", store, 0, /* page 101 */ + [0x1D] "ldstuba", storea, 0, + + [0x0F] "swap", load, 0, /* page 102 */ + [0x1F] "swapa", loada, 0, +}; + +static void +bprint(Instr *i, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + i->curr = vseprint(i->curr, i->end, fmt, arg); + va_end(arg); +} + +static int +decode(ulong pc, Instr *i) +{ + long w; + + if (get4(mymap, pc, &w) < 0) { + werrstr("can't read instruction: %r"); + return -1; + } + i->op = (w >> 30) & 0x03; + i->rd = (w >> 25) & 0x1F; + i->op2 = (w >> 22) & 0x07; + i->a = (w >> 29) & 0x01; + i->cond = (w >> 25) & 0x0F; + i->op3 = (w >> 19) & 0x3F; + i->rs1 = (w >> 14) & 0x1F; + i->i = (w >> 13) & 0x01; + i->asi = (w >> 5) & 0xFF; + i->rs2 = (w >> 0) & 0x1F; + i->simm13 = (w >> 0) & 0x1FFF; + if(i->simm13 & (1<<12)) + i->simm13 |= ~((1<<13)-1); + i->opf = (w >> 5) & 0x1FF; + i->immdisp22 = (w >> 0) & 0x3FFFFF; + i->simmdisp22 = i->immdisp22; + if(i->simmdisp22 & (1<<21)) + i->simmdisp22 |= ~((1<<22)-1); + i->disp30 = (w >> 0) & 0x3FFFFFFF; + i->w0 = w; + i->target = -1; + i->addr = pc; + i->size = 1; + return 1; +} + +static int +mkinstr(ulong pc, Instr *i) +{ + Instr xi; + + if (decode(pc, i) < 0) + return -1; + if(i->op==0 && i->op2==4 && !dascase){ /* SETHI */ + if (decode(pc+4, &xi) < 0) + return -1; + if(xi.op==2 && xi.op3==0) /* ADD */ + if(xi.i == 1 && xi.rs1 == i->rd){ /* immediate to same reg */ + i->imm32 = xi.simm13 + (i->immdisp22<<10); + i->target = xi.rd; + i->w1 = xi.w0; + i->size++; + return 1; + } + } + if(i->op==2 && i->opf==1 && !dascase){ /* FMOVS */ + if (decode(pc+4, &xi) < 0) + return -1; + if(i->op==2 && i->opf==1) /* FMOVS */ + if(xi.rd==i->rd+1 && xi.rs2==i->rs2+1){ /* next pair */ + i->w1 = xi.w0; + i->size++; + } + } + return 1; +} + +static int +printins(Map *map, ulong pc, char *buf, int n) +{ + Instr instr; + void (*f)(Instr*, char*); + + mymap = map; + memset(&instr, 0, sizeof(instr)); + instr.curr = buf; + instr.end = buf+n-1; + if (mkinstr(pc, &instr) < 0) + return -1; + switch(instr.op){ + case 0: + f = sparc64op0[instr.op2].f; + if(f) + (*f)(&instr, sparc64op0[instr.op2].mnemonic); + else + bprint(&instr, "unknown %lux", instr.w0); + break; + + case 1: + bprint(&instr, "%X", "CALL\t"); + instr.curr += symoff(instr.curr, instr.end-instr.curr, + pc+instr.disp30*4, CTEXT); + if (!dascase) + bprint(&instr, "(SB)"); + break; + + case 2: + f = sparc64op2[instr.op3].f; + if(f) + (*f)(&instr, sparc64op2[instr.op3].mnemonic); + else + bprint(&instr, "unknown %lux", instr.w0); + break; + + case 3: + f = sparc64op3[instr.op3].f; + if(f) + (*f)(&instr, sparc64op3[instr.op3].mnemonic); + else + bprint(&instr, "unknown %lux", instr.w0); + break; + } + if (instr.err) { + if (instr.curr != buf) + bprint(&instr, "\t\t;"); + bprint(&instr, instr.err); + } + return instr.size*4; +} + +/* convert to lower case from upper, according to dascase */ +static int +Xfmt(Fmt *f) +{ + char buf[128]; + char *s, *t, *oa; + + oa = va_arg(f->args, char*); + if(dascase){ + for(s=oa,t=buf; *t = *s; s++,t++) + if('A'<=*t && *t<='Z') + *t += 'a'-'A'; + return fmtstrcpy(f, buf); + } + return fmtstrcpy(f, oa); +} + +static int +sparc64inst(Map *map, ulong pc, char modifier, char *buf, int n) +{ + static int fmtinstalled = 0; + + /* a modifier of 'I' toggles the dissassembler type */ + if (!fmtinstalled) { + fmtinstalled = 1; + fmtinstall('X', Xfmt); + } + if ((asstype == ASUNSPARC && modifier == 'i') + || (asstype == ASPARC && modifier == 'I')) + dascase = 'a'-'A'; + else + dascase = 0; + return printins(map, pc, buf, n); +} + +static int +sparc64das(Map *map, ulong pc, char *buf, int n) +{ + Instr instr; + + mymap = map; + memset(&instr, 0, sizeof(instr)); + instr.curr = buf; + instr.end = buf+n-1; + if (mkinstr(pc, &instr) < 0) + return -1; + if (instr.end-instr.curr > 8) + instr.curr = _hexify(instr.curr, instr.w0, 7); + if (instr.end-instr.curr > 9 && instr.size == 2) { + *instr.curr++ = ' '; + instr.curr = _hexify(instr.curr, instr.w1, 7); + } + *instr.curr = 0; + return instr.size*4; +} + +static int +sparc64instlen(Map *map, ulong pc) +{ + Instr i; + + mymap = map; + if (mkinstr(pc, &i) < 0) + return -1; + return i.size*4; +} + +static int +plocal(Instr *i) +{ + int offset; + Symbol s; + + if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) + return -1; + if (s.value > i->simm13) { + if(getauto(&s, s.value-i->simm13, CAUTO, &s)) { + bprint(i, "%s+%d(SP)", s.name, s.value); + return 1; + } + } else { + offset = i->simm13-s.value; + if (getauto(&s, offset-4, CPARAM, &s)) { + bprint(i, "%s+%d(FP)", s.name, offset); + return 1; + } + } + return -1; +} + +static void +address(Instr *i) +{ + Symbol s, s2; + long off, off1; + + if (i->rs1 == 1 && plocal(i) >= 0) + return; + off = mach->sb+i->simm13; + if(i->rs1 == 2 && findsym(off, CANY, &s) + && s.value-off < 4096 + && (s.class == CDATA || s.class == CTEXT)) { + if(off==s.value && s.name[0]=='$'){ + off1 = 0; + get4(mymap, s.value, &off1); + if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){ + bprint(i, "$%s(SB)", s2.name); + return; + } + } + bprint(i, "%s", s.name); + if (s.value != off) + bprint(i, "+%lux", s.value-off); + bprint(i, "(SB)"); + return; + } + bprint(i, "%lux(R%d)", i->simm13, i->rs1); +} + +static void +unimp(Instr *i, char *m) +{ + bprint(i, "%X", m); +} + +static char *bratab[16] = { /* page 91 */ + [0X8] "A", + [0X0] "N", + [0X9] "NE", + [0X1] "E", + [0XA] "G", + [0X2] "LE", + [0XB] "GE", + [0X3] "L", + [0XC] "GU", + [0X4] "LEU", + [0XD] "CC", + [0X5] "CS", + [0XE] "POS", + [0X6] "NEG", + [0XF] "VC", + [0X7] "VS", +}; + +static char *fbratab[16] = { /* page 91 */ + [0X8] "A", + [0X0] "N", + [0X7] "U", + [0X6] "G", + [0X5] "UG", + [0X4] "L", + [0X3] "UL", + [0X2] "LG", + [0X1] "NE", + [0X9] "E", + [0XA] "UE", + [0XB] "GE", + [0XC] "UGE", + [0XD] "LE", + [0XE] "ULE", + [0XF] "O", +}; + +static char *cbratab[16] = { /* page 91 */ + [0X8] "A", + [0X0] "N", + [0X7] "3", + [0X6] "2", + [0X5] "23", + [0X4] "1", + [0X3] "13", + [0X2] "12", + [0X1] "123", + [0X9] "0", + [0XA] "03", + [0XB] "02", + [0XC] "023", + [0XD] "01", + [0XE] "013", + [0XF] "012", +}; + +static void +bra1(Instr *i, char *m, char *tab[]) +{ + long imm; + + imm = i->simmdisp22; + if(i->a) + bprint(i, "%X%X.%c\t", m, tab[i->cond], 'A'+dascase); + else + bprint(i, "%X%X\t", m, tab[i->cond]); + i->curr += symoff(i->curr, i->end-i->curr, i->addr+4*imm, CTEXT); + if (!dascase) + bprint(i, "(SB)"); +} + +static void +bra(Instr *i, char *m) /* page 91 */ +{ + bra1(i, m, bratab); +} + +static void +fbra(Instr *i, char *m) /* page 93 */ +{ + bra1(i, m, fbratab); +} + +static void +cbra(Instr *i, char *m) /* page 95 */ +{ + bra1(i, m, cbratab); +} + +static void +trap(Instr *i, char *m) /* page 101 */ +{ + if(i->i == 0) + bprint(i, "%X%X\tR%d+R%d", m, bratab[i->cond], i->rs2, i->rs1); + else + bprint(i, "%X%X\t$%lux+R%d", m, bratab[i->cond], i->simm13, i->rs1); +} + +static void +sethi(Instr *i, char *m) /* page 89 */ +{ + ulong imm; + + imm = i->immdisp22<<10; + if(dascase){ + bprint(i, "%X\t%lux, R%d", m, imm, i->rd); + return; + } + if(imm==0 && i->rd==0){ + bprint(i, "NOP"); + return; + } + if(i->target < 0){ + bprint(i, "MOVW\t$%lux, R%d", imm, i->rd); + return; + } + bprint(i, "MOVW\t$%lux, R%d", i->imm32, i->target); +} + +static char ldtab[] = { + 'W', + 'B', + 'H', + 'D', +}; + +static char* +moveinstr(int op3, char *m) +{ + char *s; + int c; + static char buf[8]; + + if(!dascase){ + /* batshit cases */ + if(op3 == 0xF || op3 == 0x1F) + return "SWAP"; + if(op3 == 0xD || op3 == 0x1D) + return "TAS"; /* really LDSTUB */ + c = ldtab[op3&3]; + s = ""; + if((op3&11)==1 || (op3&11)==2) + s="U"; + sprint(buf, "MOV%c%s", c, s); + return buf; + } + return m; +} + +static void +load(Instr *i, char *m) /* page 68 */ +{ + m = moveinstr(i->op3, m); + if(i->i == 0) + bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs1, i->rs2, i->rd); + else{ + bprint(i, "%s\t", m); + address(i); + bprint(i, ", R%d", i->rd); + } +} + +static void +loada(Instr *i, char *m) /* page 68 */ +{ + m = moveinstr(i->op3, m); + if(i->i == 0) + bprint(i, "%s\t(R%d+R%d, %d), R%d", m, i->rs1, i->rs2, i->asi, i->rd); + else + bprint(i, "unknown ld asi %lux", i->w0); +} + +static void +store(Instr *i, char *m) /* page 74 */ +{ + m = moveinstr(i->op3, m); + if(i->i == 0) + bprint(i, "%s\tR%d, (R%d+R%d)", + m, i->rd, i->rs1, i->rs2); + else{ + bprint(i, "%s\tR%d, ", m, i->rd); + address(i); + } +} + +static void +storea(Instr *i, char *m) /* page 74 */ +{ + m = moveinstr(i->op3, m); + if(i->i == 0) + bprint(i, "%s\tR%d, (R%d+R%d, %d)", m, i->rd, i->rs1, i->rs2, i->asi); + else + bprint(i, "%s\tR%d, %d(R%d, %d), ???", m, i->rd, i->simm13, i->rs1, i->asi); +} + +static void +shift(Instr *i, char *m) /* page 88 */ +{ + if(i->i == 0){ + if(i->rs1 == i->rd) + if(dascase) + bprint(i, "%X\tR%d, R%d", m, i->rs1, i->rs2); + else + bprint(i, "%X\tR%d, R%d", m, i->rs2, i->rs1); + else + if(dascase) + bprint(i, "%X\tR%d, R%d, R%d", m, i->rs1, i->rs2, i->rd); + else + bprint(i, "%X\tR%d, R%d, R%d", m, i->rs2, i->rs1, i->rd); + }else{ + if(i->rs1 == i->rd) + if(dascase) + bprint(i, "%X\t$%d,R%d", m, i->simm13&0x1F, i->rs1); + else + bprint(i, "%X\tR%d, $%d", m, i->rs1, i->simm13&0x1F); + else + if(dascase) + bprint(i, "%X\tR%d, $%d, R%d",m,i->rs1,i->simm13&0x1F,i->rd); + else + bprint(i, "%X\t$%d, R%d, R%d",m,i->simm13&0x1F,i->rs1,i->rd); + } +} + +static void +add(Instr *i, char *m) /* page 82 */ +{ + if(i->i == 0){ + if(dascase) + bprint(i, "%X\tR%d, R%d", m, i->rs1, i->rs2); + else + if(i->op3==2 && i->rs1==0 && i->rd) /* OR R2, R0, R1 */ + bprint(i, "MOVW\tR%d", i->rs2); + else + bprint(i, "%X\tR%d, R%d", m, i->rs2, i->rs1); + }else{ + if(dascase) + bprint(i, "%X\tR%d, $%lux", m, i->rs1, i->simm13); + else + if(i->op3==0 && i->rd && i->rs1==0) /* ADD $x, R0, R1 */ + bprint(i, "MOVW\t$%lux", i->simm13); + else if(i->op3==0 && i->rd && i->rs1==2){ + /* ADD $x, R2, R1 -> MOVW $x(SB), R1 */ + bprint(i, "MOVW\t$"); + address(i); + } else + bprint(i, "%X\t$%lux, R%d", m, i->simm13, i->rs1); + } + if(i->rs1 != i->rd) + bprint(i, ", R%d", i->rd); +} + +static void +cmp(Instr *i, char *m) +{ + if(dascase || i->rd){ + add(i, m); + return; + } + if(i->i == 0) + bprint(i, "CMP\tR%d, R%d", i->rs1, i->rs2); + else + bprint(i, "CMP\tR%d, $%lux", i->rs1, i->simm13); +} + +static char *regtab[4] = { + "Y", + "PSTATE", + "WIM", /* XXX not any more */ + "TT", +}; + +static void +wr(Instr *i, char *m) /* page 82 */ +{ + if(dascase){ + if(i->i == 0) + bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2); + else + bprint(i, "%s\tR%d, $%lux", m, i->rs1, i->simm13); + }else{ + if(i->i && i->simm13==0) + bprint(i, "MOVW\tR%d", i->rs1); + else if(i->i == 0) + bprint(i, "wr\tR%d, R%d", i->rs2, i->rs1); + else + bprint(i, "wr\t$%lux, R%d", i->simm13, i->rs1); + } + bprint(i, ", %s", regtab[i->op3&3]); +} + +static void +rd(Instr *i, char *m) /* page 103 */ +{ + if(i->rs1==15 && i->rd==0){ + m = "stbar"; + if(!dascase) + m = "STBAR"; + bprint(i, "%s", m); + }else{ + if(!dascase) + m = "MOVW"; + bprint(i, "%s\t%s, R%d", m, regtab[i->op3&3], i->rd); + } +} + +static void +jmpl(Instr *i, char *m) /* page 82 */ +{ + if(i->i == 0){ + if(i->rd == 15) + bprint(i, "%X\t(R%d+R%d)", "CALL", i->rs2, i->rs1); + else + bprint(i, "%X\t(R%d+R%d), R%d", m, i->rs2, i->rs1, i->rd); + }else{ + if(!dascase && i->simm13==8 && i->rs1==15 && i->rd==0) + bprint(i, "RETURN"); + else{ + bprint(i, "%X\t", m); + address(i); + bprint(i, ", R%d", i->rd); + } + } +} + +static void +loadf(Instr *i, char *m) /* page 70 */ +{ + if(!dascase){ + m = "FMOVD"; + if(i->op3 == 0x20) + m = "FMOVF"; + else if(i->op3 == 0x21) + m = "MOVW"; + } + if(i->i == 0) + bprint(i, "%s\t(R%d+R%d)", m, i->rs1, i->rs2); + else{ + bprint(i, "%s\t", m); + address(i); + } + if(i->op3 == 0x21) + bprint(i, ", FSR"); + else + bprint(i, ", R%d", i->rd); +} + +static +void storef(Instr *i, char *m) /* page 70 */ +{ + if(!dascase){ + m = "FMOVD"; + if(i->op3 == 0x25 || i->op3 == 0x26) + m = "MOVW"; + else if(i->op3 == 0x20) + m = "FMOVF"; + } + bprint(i, "%s\t", m); + if(i->op3 == 0x25) + bprint(i, "FSR, "); + else if(i->op3 == 0x26) + bprint(i, "FQ, "); + else + bprint(i, "R%d, ", i->rd); + if(i->i == 0) + bprint(i, "(R%d+R%d)", i->rs1, i->rs2); + else + address(i); +} + +static +void loadc(Instr *i, char *m) /* page 72 */ +{ + if(i->i == 0) + bprint(i, "%s\t(R%d+R%d), C%d", m, i->rs1, i->rs2, i->rd); + else{ + bprint(i, "%s\t", m); + address(i); + bprint(i, ", C%d", i->rd); + } +} + +static +void loadcsr(Instr *i, char *m) /* page 72 */ +{ + if(i->i == 0) + bprint(i, "%s\t(R%d+R%d), CSR", m, i->rs1, i->rs2); + else{ + bprint(i, "%s\t", m); + address(i); + bprint(i, ", CSR"); + } +} + +static struct{ + int opf; + char *name; +} fptab1[] = { /* ignores rs1 */ + 0xC4, "FITOS", /* page 109 */ + 0xC8, "FITOD", + 0xCC, "FITOX", + + 0xD1, "FSTOI", /* page 110 */ + 0xD2, "FDTOI", + 0xD3, "FXTOI", + + 0xC9, "FSTOD", /* page 111 */ + 0xCD, "FSTOX", + 0xC6, "FDTOS", + 0xCE, "FDTOX", + 0xC7, "FXTOS", + 0xCB, "FXTOD", + + 0x01, "FMOVS", /* page 112 */ + 0x05, "FNEGS", + 0x09, "FABSS", + + 0x29, "FSQRTS", /* page 113 */ + 0x2A, "FSQRTD", + 0x2B, "FSQRTX", + + 0, 0, +}; + +static struct{ + int opf; + char *name; +} fptab2[] = { /* uses rs1 */ + + 0x41, "FADDS", /* page 114 */ + 0x42, "FADDD", + 0x43, "FADDX", + 0x45, "FSUBS", + 0x46, "FSUBD", + 0x47, "FSUBX", + + 0x49, "FMULS", /* page 115 */ + 0x4A, "FMULD", + 0x4B, "FMULX", + 0x4D, "FDIVS", + 0x4E, "FDIVD", + 0x4F, "FDIVX", + + 0x51, "FCMPS", /* page 116 */ + 0x52, "FCMPD", + 0x53, "FCMPX", + 0x55, "FCMPES", + 0x56, "FCMPED", + 0x57, "FCMPEX", + + 0, 0 +}; + +static void +fpop(Instr *i, char *m) /* page 108-116 */ +{ + int j; + + if(dascase==0 && i->size==2){ + bprint(i, "FMOVD\tF%d, F%d", i->rs2, i->rd); + return; + } + for(j=0; fptab1[j].name; j++) + if(fptab1[j].opf == i->opf){ + bprint(i, "%X\tF%d, F%d", fptab1[j].name, i->rs2, i->rd); + return; + } + for(j=0; fptab2[j].name; j++) + if(fptab2[j].opf == i->opf){ + bprint(i, "%X\tF%d, F%d, F%d", fptab2[j].name, i->rs1, i->rs2, i->rd); + return; + } + bprint(i, "%X%ux\tF%d, F%d, F%d", m, i->opf, i->rs1, i->rs2, i->rd); +} + +static int +sparc64foll(Map *map, ulong pc, Rgetter rget, ulong *foll) +{ + ulong w, r1, r2; + char buf[8]; + Instr i; + + mymap = map; + if (mkinstr(pc, &i) < 0) + return -1; + w = i.w0; + switch(w & 0xC1C00000){ + case 0x00800000: /* branch on int cond */ + case 0x01800000: /* branch on fp cond */ + case 0x01C00000: /* branch on copr cond */ + foll[0] = pc+8; + foll[1] = pc + (i.simmdisp22<<2); + return 2; + } + + if((w&0xC0000000) == 0x40000000){ /* CALL */ + foll[0] = pc + (i.disp30<<2); + return 1; + } + + if((w&0xC1F80000) == 0x81C00000){ /* JMPL */ + sprint(buf, "R%ld", (w>>14)&0xF); + r1 = (*rget)(map, buf); + if(w & 0x2000) /* JMPL R1+simm13 */ + r2 = i.simm13; + else{ /* JMPL R1+R2 */ + sprint(buf, "R%ld", w&0xF); + r2 = (*rget)(map, buf); + } + foll[0] = r1 + r2; + return 1; + } + foll[0] = pc+i.size*4; + return 1; +} --- /sys/src/libmach/uobj.c Thu Jan 1 00:00:00 1970 +++ /sys/src/libmach/uobj.c Sun Apr 24 06:06:28 2005 @@ -0,0 +1,133 @@ +/* + * uobj.c - identify and parse a sparc64 object file + */ +#include +#include +#include +#include "uc/u.out.h" +#include "obj.h" + +typedef struct Addr Addr; +struct Addr +{ + char type; + char sym; + char name; +}; +static Addr addr(Biobuf*); +static char type2char(int); +static void skip(Biobuf*, int); + + +int +_isu(char *s) +{ + return s[0] == ANAME /* ANAME */ + && s[1] == D_FILE /* type */ + && s[2] == 1 /* sym */ + && s[3] == '<'; /* name of file */ +} + + +int +_readu(Biobuf *bp, Prog *p) +{ + int as, n; + Addr a; + + as = Bgetc(bp); /* as */ + if(as < 0) + return 0; + p->kind = aNone; + if(as == ANAME || as == ASIGNAME){ + if(as == ASIGNAME) + skip(bp, 4); /* signature */ + p->kind = aName; + p->type = type2char(Bgetc(bp)); /* type */ + p->sym = Bgetc(bp); /* sym */ + n = 0; + for(;;) { + as = Bgetc(bp); + if(as < 0) + return 0; + n++; + if(as == 0) + break; + } + p->id = malloc(n); + if(p->id == 0) + return 0; + Bseek(bp, -n, 1); + if(Bread(bp, p->id, n) != n) + return 0; + return 1; + } + if(as == ATEXT) + p->kind = aText; + else if(as == AGLOBL) + p->kind = aData; + skip(bp, 5); /* reg (1 byte); lineno (4 bytes) */ + a = addr(bp); + addr(bp); + if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN) + p->kind = aNone; + p->sym = a.sym; + return 1; +} + +static Addr +addr(Biobuf *bp) +{ + Addr a; + long off; + + a.type = Bgetc(bp); /* a.type */ + skip(bp, 1); /* reg */ + a.sym = Bgetc(bp); /* sym index */ + a.name = Bgetc(bp); /* sym type */ + switch(a.type) { + default: + case D_NONE: case D_REG: case D_FREG: case D_CREG: case D_PREG: + break; + case D_BRANCH: + case D_OREG: + case D_ASI: + case D_CONST: + off = Bgetc(bp); + off |= Bgetc(bp) << 8; + off |= Bgetc(bp) << 16; + off |= Bgetc(bp) << 24; + if(off < 0) + off = -off; + if(a.sym!=0 && (a.name==D_PARAM || a.name==D_AUTO)) + _offset(a.sym, off); + break; + case D_SCONST: + skip(bp, NSNAME); + break; + case D_FCONST: + skip(bp, 8); + break; + } + return a; +} + + +static char +type2char(int t) +{ + switch(t){ + case D_EXTERN: return 'U'; + case D_STATIC: return 'b'; + case D_AUTO: return 'a'; + case D_PARAM: return 'p'; + default: return UNKNOWN; + } +} + +static void +skip(Biobuf *bp, int n) +{ + while (n-- > 0) + Bgetc(bp); +}