#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern const char *__progname; #include "em-const.h" #define PAGE_SIZE 4096 #define USRSTACK 0xf0000000 #define MAXSSIZE (1U<<24) #define MAXDSIZE 0x04000000 #define MAXFDS 4096 #define ROUND_UP(a,b) (((a)+(b)-1) & ~((b)-1)) #define ROUND_DOWN(a,b) ((a) & ~((b)-1)) #define REP4(x) x, x, x, x #define REP8(x) REP4(x), REP4(x) #define REP16(x) REP8(x), REP8(x) #define REP32(x) REP16(x), REP16(x) #define REP64(x) REP32(x), REP32(x) #define REP128(x) REP64(x), REP64(x) #define REP256(x) REP128(x), REP128(x) #define REP2b(x) REP4(x) #define REP3b(x) REP8(x) #define REP4b(x) REP16(x) #define REP5b(x) REP32(x) #define REP6b(x) REP64(x) #define REP7b(x) REP128(x) #define REP8b(x) REP256(x) #define OPC(opc) (((opc)>>30)&3) /* format select bits */ #define OP2(opc) (((opc)>>22)&7) /* opcode bits, format 2 */ #define DREG(opc) (((opc)>>25)&31) /* dest reg bits, formats 2 and 3 */ #define A(opc) (((opc)>>29)&1) /* annul bit, format 2 */ #define COND(opc) (((opc)>>25)&15) /* condition code bits, format 2 */ #define IMM22(opc) ((opc)&0x003fffff) /* immediate data, format 2 */ #define DISP22(opc) signextend(IMM22(opc),22) /* displacement, format 2 */ #define OP3(opc) (((opc)>>19)&0x3f) /* opcode bits, format 3 */ #define SREG1(opc) (((opc)>>14)&31) /* source reg 1 bits, format 3 */ #define SREG2(opc) ((opc)&31) /* source reg 2 bits, format 3 */ #define I(opc) (((opc)>>13)&1) /* immediate bit, format 3 */ #define ASI(opc) (((opc)>>5)&0xff) /* alternative space bits, format 3 */ #define SIMM13(opc) signextend((opc)&0x1fff,13) /* immediate data, format 3 */ #define OPF(opc) (((opc)>>5)&0x1ff) /* FPU opcode bits, format 3 */ #define P_R 0x01 #define P_W 0x02 #define P_X 0x04 #define SYSCALL_IMPL(fn) void fn(SCARGS *args __attribute__((__unused__)), SCRV *rv __attribute__((__unused__))) #define SYSCALL_SETERR(e) do { rv->err = (e); } while (0) #define SYSCALL_ERR(e) do { SYSCALL_SETERR((e)); return; } while (0) #define SYSCALL_SETRET(v) do { rv->rv = (v); } while (0) #define SYSCALL_RET(v) do { SYSCALL_SETRET((v)); return; } while (0) #define SYSCALL_RET2(v1,v2) do { rv->rv = (v1); rv->rv2 = (v2); return; } while (0) typedef struct memseg MEMSEG; typedef struct memsegops MEMSEGOPS; typedef struct state STATE; typedef struct scargs SCARGS; typedef struct fd FD; typedef struct memseg_priv_malloc MEMSEG_PRIV_MALLOC; typedef struct memseg_priv_mmap MEMSEG_PRIV_MMAP; typedef struct trc TRC; typedef struct trcfile TRCFILE; typedef struct memacc MEMACC; typedef struct mfblk MFBLK; typedef struct scrv SCRV; struct scrv { uint32_t err; uint32_t rv; uint32_t rv2; } ; struct mfblk { char *buf; int alloc; int len; char **strptr; int *allocptr; } ; struct memacc { uint32_t a1; uint32_t a2; uint8_t *vp; int a; int n; char rw; } ; struct trc { const char *name; TRCFILE *out; TRCFILE *file; } ; struct trcfile { int filerefs; int outrefs; FILE *f; char *name; } ; struct memseg_priv_malloc { void *tofree; } ; struct memseg_priv_mmap { int refcnt; char *mapped; uint32_t size; } ; struct fd { int fd; unsigned int prot; // P_R and/or P_W } ; struct scargs { int nreg; uint32_t regs[6]; uint32_t sp; } ; struct memsegops { void (*done)(MEMSEG *); void (*curtail)(MEMSEG *, uint32_t); void (*behead)(MEMSEG *, uint32_t); MEMSEG *(*split)(MEMSEG *, uint32_t, uint32_t); } ; #define MEMSEGOPS_INIT(name) {\ &memseg_done_##name, \ &memseg_curtail_##name, \ &memseg_behead_##name, \ &memseg_split_##name, \ } struct memseg { MEMSEG *link; uint32_t base; uint32_t size; uint32_t end; unsigned char prot; // zero or more of P_[RWX] uint8_t *data; void *priv; MEMSEGOPS *ops; } ; struct state { unsigned int cc; #define CC_N 8 #define CC_Z 4 #define CC_V 2 #define CC_C 1 unsigned int flags; #define SF_ANNUL 0x00000001 uint32_t pc; uint32_t npc; uint32_t regs[32]; #define R_G0 0 #define R_G1 1 #define R_G2 2 #define R_G3 3 #define R_G4 4 #define R_G5 5 #define R_G6 6 #define R_G7 7 #define R_O0 8 #define R_O1 9 #define R_O2 10 #define R_O3 11 #define R_O4 12 #define R_O5 13 #define R_O6 14 #define R_O7 15 #define R_L0 16 #define R_L1 17 #define R_L2 18 #define R_L3 19 #define R_L4 20 #define R_L5 21 #define R_L6 22 #define R_L7 23 #define R_I0 24 #define R_I1 25 #define R_I2 26 #define R_I3 27 #define R_I4 28 #define R_I5 29 #define R_I6 30 #define R_I7 31 #define R_SP R_O6 #define R_FP R_I6 unsigned long long int instrs; } ; typedef unsigned long int ULI; typedef long int LI; typedef unsigned long long int ULLI; static const char *exe = 0; static char **args = 0; static int nargs = 0; static STATE s; static MEMSEG *vm; static FD **fds; static int nfds; static uint32_t dbrk; static int verbose; static void (*err_jmp)(void) = 0; static TRC trace[] = { { "instr" }, #define TRC_INSTR 0 { "chg" }, #define TRC_CHG 1 { "mem" }, #define TRC_MEM 2 { 0 } }; #define TRC__N 3 static TRCFILE trcfile_stdout; static MEMACC *memacc; static int amemacc; static int nmemacc; #define ELF_HALF_TO_NATIVE(x) ntohs((x)) #define ELF_WORD_TO_NATIVE(x) ntohl((x)) #define ELF_ADDR_TO_NATIVE(x) ntohl((x)) #define ELF_OFFSET_TO_NATIVE(x) ntohl((x)) // Extra three at end for benefit of print_regs() static const char * const regnames[35] = { "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7", "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7", "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7", "pc", "npc", "cc" }; static const char *icc[] = { "n", "e", "le", "l", "leu", "lu/cs", "neg", "vs", "a", "ne", "g", "ge", "gu", "geu/cc", "pos", "vc" }; static const char *fcc[] = { "n", "ne", "lg", "ul", "l", "ug", "g", "u", "a", "e", "ue", "ge", "uge", "le", "ule", "o" }; static const char *ccc[] = { "n", "123", "12", "13", "1", "23", "2", "3", "a", "0", "03", "02", "023", "01", "013", "012" }; /* The CMASK_* defines assume these */ #if (CC_N != 8) || (CC_Z != 4) || (CC_V != 2) || (CC_C != 1) #error "conds[] assumptions invalid" #endif // Would _like_ to somehow generate these from CC_* // But I think the preprocessor isn't that smart #define CMASK_N 0xff00 #define CMASK_Z 0xf0f0 #define CMASK_V 0xcccc #define CMASK_C 0xaaaa static const uint16_t conds[16] = { 0, // never CMASK_Z, // eq CMASK_Z | (CMASK_N ^ CMASK_V), // le CMASK_N ^ CMASK_V, // lt CMASK_C | CMASK_Z, // leu CMASK_C, // ltu, cs CMASK_N, // neg CMASK_V, // vs 0xffff, // always 0xffff ^ CMASK_Z, // ne 0xffff ^ (CMASK_Z | (CMASK_N ^ CMASK_V)), // gt 0xffff ^ CMASK_N ^ CMASK_V, // ge 0xffff ^ (CMASK_C | CMASK_Z), // gtu 0xffff ^ CMASK_C, // geu, cc 0xffff ^ CMASK_N, // pos 0xffff ^ CMASK_V }; // vc #undef CMASK_N #undef CMASK_Z #undef CMASK_V #undef CMASK_C #define Cisspace(x) isspace((unsigned char)(x)) #define Cisdigit(x) isdigit((unsigned char)(x)) static void panic(int, const char *, ...) __attribute__((__format__(__printf__,2,3),__noreturn__)); static void panic(int lno, const char *fmt, ...) #define panic(...) (panic)(__LINE__, __VA_ARGS__) { va_list ap; fprintf(stderr,"%s: panic (line %d): ",__progname,lno); va_start(ap,fmt); vfprintf(stderr,fmt,ap); va_end(ap); fprintf(stderr,"\n"); exit(1); } static void top(void) __attribute__((__noreturn__)); static void top(void) { if (! err_jmp) exit(1); (*err_jmp)(); panic("err_jmp returned"); } static uint32_t errno_map(int err) { switch (errno) { #ifdef EPERM case EPERM: return(em_EPERM); break; #endif #ifdef ENOENT case ENOENT: return(em_ENOENT); break; #endif #ifdef ESRCH case ESRCH: return(em_ESRCH); break; #endif #ifdef EINTR case EINTR: return(em_EINTR); break; #endif #ifdef EIO case EIO: return(em_EIO); break; #endif #ifdef ENXIO case ENXIO: return(em_ENXIO); break; #endif #ifdef E2BIG case E2BIG: return(em_E2BIG); break; #endif #ifdef ENOEXEC case ENOEXEC: return(em_ENOEXEC); break; #endif #ifdef EBADF case EBADF: return(em_EBADF); break; #endif #ifdef ECHILD case ECHILD: return(em_ECHILD); break; #endif #ifdef EDEADLK case EDEADLK: return(em_EDEADLK); break; #endif #ifdef ENOMEM case ENOMEM: return(em_ENOMEM); break; #endif #ifdef EACCES case EACCES: return(em_EACCES); break; #endif #ifdef EFAULT case EFAULT: return(em_EFAULT); break; #endif #ifdef ENOTBLK case ENOTBLK: return(em_ENOTBLK); break; #endif #ifdef EBUSY case EBUSY: return(em_EBUSY); break; #endif #ifdef EEXIST case EEXIST: return(em_EEXIST); break; #endif #ifdef EXDEV case EXDEV: return(em_EXDEV); break; #endif #ifdef ENODEV case ENODEV: return(em_ENODEV); break; #endif #ifdef ENOTDIR case ENOTDIR: return(em_ENOTDIR); break; #endif #ifdef EISDIR case EISDIR: return(em_EISDIR); break; #endif #ifdef EINVAL case EINVAL: return(em_EINVAL); break; #endif #ifdef ENFILE case ENFILE: return(em_ENFILE); break; #endif #ifdef EMFILE case EMFILE: return(em_EMFILE); break; #endif #ifdef ENOTTY case ENOTTY: return(em_ENOTTY); break; #endif #ifdef ETXTBSY case ETXTBSY: return(em_ETXTBSY); break; #endif #ifdef EFBIG case EFBIG: return(em_EFBIG); break; #endif #ifdef ENOSPC case ENOSPC: return(em_ENOSPC); break; #endif #ifdef ESPIPE case ESPIPE: return(em_ESPIPE); break; #endif #ifdef EROFS case EROFS: return(em_EROFS); break; #endif #ifdef EMLINK case EMLINK: return(em_EMLINK); break; #endif #ifdef EPIPE case EPIPE: return(em_EPIPE); break; #endif #ifdef EDOM case EDOM: return(em_EDOM); break; #endif #ifdef ERANGE case ERANGE: return(em_ERANGE); break; #endif #ifdef EAGAIN case EAGAIN: return(em_EAGAIN); break; #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EAGAIN != EWOULDBLOCK)) case EWOUDBLOCK: return(em_EWOULDBLOCK); break; #endif #ifdef EINPROGRESS case EINPROGRESS: return(em_EINPROGRESS); break; #endif #ifdef EALREADY case EALREADY: return(em_EALREADY); break; #endif #ifdef ENOTSOCK case ENOTSOCK: return(em_ENOTSOCK); break; #endif #ifdef EDESTADDRREQ case EDESTADDRREQ: return(em_EDESTADDRREQ); break; #endif #ifdef EMSGSIZE case EMSGSIZE: return(em_EMSGSIZE); break; #endif #ifdef EPROTOTYPE case EPROTOTYPE: return(em_EPROTOTYPE); break; #endif #ifdef ENOPROTOOPT case ENOPROTOOPT: return(em_ENOPROTOOPT); break; #endif #ifdef EPROTONOSUPPORT case EPROTONOSUPPORT: return(em_EPROTONOSUPPORT); break; #endif #ifdef ESOCKTNOSUPPORT case ESOCKTNOSUPPORT: return(em_ESOCKTNOSUPPORT); break; #endif #ifdef EOPNOTSUPP case EOPNOTSUPP: return(em_EOPNOTSUPP); break; #endif #ifdef EPFNOSUPPORT case EPFNOSUPPORT: return(em_EPFNOSUPPORT); break; #endif #ifdef EAFNOSUPPORT case EAFNOSUPPORT: return(em_EAFNOSUPPORT); break; #endif #ifdef EADDRINUSE case EADDRINUSE: return(em_EADDRINUSE); break; #endif #ifdef EADDRNOTAVAIL case EADDRNOTAVAIL: return(em_EADDRNOTAVAIL); break; #endif #ifdef ENETDOWN case ENETDOWN: return(em_ENETDOWN); break; #endif #ifdef ENETUNREACH case ENETUNREACH: return(em_ENETUNREACH); break; #endif #ifdef ENETRESET case ENETRESET: return(em_ENETRESET); break; #endif #ifdef ECONNABORTED case ECONNABORTED: return(em_ECONNABORTED); break; #endif #ifdef ECONNRESET case ECONNRESET: return(em_ECONNRESET); break; #endif #ifdef ENOBUFS case ENOBUFS: return(em_ENOBUFS); break; #endif #ifdef EISCONN case EISCONN: return(em_EISCONN); break; #endif #ifdef ENOTCONN case ENOTCONN: return(em_ENOTCONN); break; #endif #ifdef ESHUTDOWN case ESHUTDOWN: return(em_ESHUTDOWN); break; #endif #ifdef ETOOMANYREFS case ETOOMANYREFS: return(em_ETOOMANYREFS); break; #endif #ifdef ETIMEDOUT case ETIMEDOUT: return(em_ETIMEDOUT); break; #endif #ifdef ECONNREFUSED case ECONNREFUSED: return(em_ECONNREFUSED); break; #endif #ifdef ELOOP case ELOOP: return(em_ELOOP); break; #endif #ifdef ENAMETOOLONG case ENAMETOOLONG: return(em_ENAMETOOLONG); break; #endif #ifdef EHOSTDOWN case EHOSTDOWN: return(em_EHOSTDOWN); break; #endif #ifdef EHOSTUNREACH case EHOSTUNREACH: return(em_EHOSTUNREACH); break; #endif #ifdef ENOTEMPTY case ENOTEMPTY: return(em_ENOTEMPTY); break; #endif #ifdef EPROCLIM case EPROCLIM: return(em_EPROCLIM); break; #endif #ifdef EUSERS case EUSERS: return(em_EUSERS); break; #endif #ifdef EDQUOT case EDQUOT: return(em_EDQUOT); break; #endif #ifdef ESTALE case ESTALE: return(em_ESTALE); break; #endif #ifdef EREMOTE case EREMOTE: return(em_EREMOTE); break; #endif #ifdef EBADRPC case EBADRPC: return(em_EBADRPC); break; #endif #ifdef ERPCMISMATCH case ERPCMISMATCH: return(em_ERPCMISMATCH); break; #endif #ifdef EPROGUNAVAIL case EPROGUNAVAIL: return(em_EPROGUNAVAIL); break; #endif #ifdef EPROGMISMATCH case EPROGMISMATCH: return(em_EPROGMISMATCH); break; #endif #ifdef EPROCUNAVAIL case EPROCUNAVAIL: return(em_EPROCUNAVAIL); break; #endif #ifdef ENOLCK case ENOLCK: return(em_ENOLCK); break; #endif #ifdef ENOSYS case ENOSYS: return(em_ENOSYS); break; #endif #ifdef EFTYPE case EFTYPE: return(em_EFTYPE); break; #endif #ifdef EAUTH case EAUTH: return(em_EAUTH); break; #endif #ifdef ENEEDAUTH case ENEEDAUTH: return(em_ENEEDAUTH); break; #endif #ifdef EIDRM case EIDRM: return(em_EIDRM); break; #endif #ifdef ENOMSG case ENOMSG: return(em_ENOMSG); break; #endif #ifdef EOVERFLOW case EOVERFLOW: return(em_EOVERFLOW); break; #endif #ifdef ENOTPLAIN case ENOTPLAIN: return(em_ENOTPLAIN); break; #endif } printf("Unmappable errno %d\n",err); top(); } static void save_arg(const char *arg) { args = realloc(args,(nargs+1)+sizeof(char *)); args[nargs++] = strdup(arg); } static void handleargs(int ac, char **av) { int skip; int errs; skip = 0; errs = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av != '-') { if (! exe) { exe = *av; } else { save_arg(*av); } continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs = 1; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-dummy")) { WANTARG(); (void)av[skip]; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs = 1; } if (! exe) { fprintf(stderr,"%s: need executable filename\n",__progname); errs = 1; } if (errs) exit(1); } #if 0 static int mf_write(void *mv, const char *buf, int len) { MFBLK *m; m = mv; if (m->len+len > m->alloc) { m->alloc = m->len + len; m->buf = realloc(m->buf,m->alloc); } bcopy(buf,m->buf+m->len,len); m->len += len; return(len); } static int mf_close(void *mv) { MFBLK *m; mf_write(mv,"",1); m = mv; *m->strptr = m->buf; *m->allocptr = m->alloc; free(m); return(0); } static FILE *mfopen(char **sp, int *ap) { MFBLK *m; FILE *f; m = malloc(sizeof(MFBLK)); m->strptr = sp; m->allocptr = ap; m->buf = *sp; m->alloc = *ap; m->len = 0; f = funopen(m,0,mf_write,0,mf_close); if (f == 0) free(m); return(f); } #endif static MEMSEGOPS memseg_ops_malloc; // forward static MEMSEG *memseg_new_malloc(uint32_t base, uint32_t size, unsigned char prot) { MEMSEG *n; MEMSEG_PRIV_MALLOC *p; n = malloc(sizeof(MEMSEG)); p = malloc(sizeof(MEMSEG_PRIV_MALLOC)); n->base = base; n->size = size; n->end = base + size; n->prot = prot; p->tofree = malloc(size); n->data = p->tofree; n->ops = &memseg_ops_malloc; n->priv = p; n->link = vm; vm = n; return(n); } static void memseg_done_malloc(MEMSEG *ms) { free(((MEMSEG_PRIV_MALLOC *)ms->priv)->tofree); free(ms->priv); } static void memseg_curtail_malloc(MEMSEG *ms, uint32_t by) { if (by >= ms->size) panic("impossible malloc curtail"); ms->size -= by; ms->end -= by; } static void memseg_behead_malloc(MEMSEG *ms, uint32_t by) { if (by >= ms->size) panic("impossible malloc behead"); ms->size -= by; ms->base += by; ms->data += by; } static MEMSEG *memseg_split_malloc(MEMSEG *ms, uint32_t part1, uint32_t part2) { MEMSEG *n; if ((part1 > ms->size) || (part2 > ms->size) || (part1+part2 > ms->size)) panic("impossible malloc split"); n = memseg_new_malloc(ms->end-part2,part2,ms->prot); bcopy(ms->data+(ms->size-part2),n->data,part2); ms->size = part1; ms->end = ms->base + part1; return(n); } static MEMSEGOPS memseg_ops_malloc = MEMSEGOPS_INIT(malloc); static MEMSEGOPS memseg_ops_mmap; // forward static MEMSEG *memseg_new_mmap(uint32_t base, uint32_t size, unsigned char prot, void *mapped) { MEMSEG *n; MEMSEG_PRIV_MMAP *p; n = malloc(sizeof(MEMSEG)); p = malloc(sizeof(MEMSEG_PRIV_MMAP)); n->base = base; n->size = size; n->end = base + size; n->prot = prot; p->refcnt = 1; p->mapped = mapped; p->size = size; n->data = mapped; n->ops = &memseg_ops_mmap; n->priv = p; n->link = vm; vm = n; return(n); } static void memseg_done_mmap(MEMSEG *ms) { MEMSEG_PRIV_MMAP *p; p = ms->priv; p->refcnt --; if (p->refcnt < 1) { munmap(p->mapped,p->size); free(p); } } static void memseg_curtail_mmap(MEMSEG *ms, uint32_t by) { if (by >= ms->size) panic("impossible malloc curtail"); ms->size -= by; ms->end -= by; } static void memseg_behead_mmap(MEMSEG *ms, uint32_t by) { if (by >= ms->size) panic("impossible malloc behead"); ms->size -= by; ms->base += by; ms->data += by; } static MEMSEG *memseg_split_mmap(MEMSEG *ms, uint32_t part1, uint32_t part2) { MEMSEG *n; MEMSEG_PRIV_MMAP *p; if ((part1 > ms->size) || (part2 > ms->size) || (part1+part2 > ms->size)) panic("impossible mmap split"); p = ms->priv; n = malloc(sizeof(MEMSEG)); n->base = ms->base + ms->size - part2; n->size = part2; n->end = ms->end; n->prot = ms->prot; p->refcnt ++; n->data = ms->data + (ms->size - part2); n->ops = ms->ops; n->priv = p; n->link = vm; vm = n; return(n); } static MEMSEGOPS memseg_ops_mmap = MEMSEGOPS_INIT(mmap); static void memseg_clear_conflict(uint32_t newbase, uint32_t newsize, MEMSEG *ignore) { uint32_t newend; MEMSEG *ms; MEMSEG **msp; newend = newbase + newsize; if (newsize < 1) panic("empty memseg"); if ((newbase & (PAGE_SIZE-1)) || (newsize & (PAGE_SIZE-1))) panic("misaligned memseg"); if (newend < newbase) panic("va wraparound"); msp = &vm; while ((ms = *msp)) { if (ms != ignore) { /* * Each existing memseg may relate to the new memseg in N ways * (nnn=new, ooo=old, ***=both): * * (a) ...ooo...nnn... * (b) ...ooonnn... * (c) ...ooo***nnn... * (d) ...ooo***... * (e) ...ooo***ooo... * (f) ...***nnn... * (g) ...******... * (h) ...******ooo... * (i) ...nnn***nnn... * (j) ...nnn***... * (k) ...nnn***ooo... * (l) ...nnnooo... * (m) ...nnn...ooo... */ if ((ms->base >= newbase) && (ms->end <= newend)) { // Cases f, g, i, j: destroy old entirely *msp = ms->link; (*ms->ops->done)(ms); free(ms); continue; } else if ((ms->end <= newbase) || (ms->base >= newend)) { // Cases a, b, l, m: do nothing } else if (ms->end < newend) { // Cases c, d: curtail old (*ms->ops->curtail)(ms,ms->end-newbase); } else if (ms->base >= newbase) { // Cases h, k: behead old (*ms->ops->behead)(ms,newend-ms->base); } else { // Case e: split old (*ms->ops->split)(ms,newbase-ms->base,ms->end-newend); } } msp = &ms->link; } } static MEMSEG *memseg_mem(uint32_t va, uint32_t size, unsigned int prot) { MEMSEG *n; n = memseg_new_malloc(va,size,prot); memseg_clear_conflict(n->base,n->size,n); return(n); } static void sort_vm(void) { MEMSEG *sort(MEMSEG *list) { MEMSEG *a; MEMSEG *b; MEMSEG *t; MEMSEG **lp; if (!list || !list->link) return(list); a = 0; b = 0; while (list) { t = list; list = t->link; t->link = b; b = a; a = t; } a = sort(a); b = sort(b); lp = &list; while (a || b) { if (a && (!b || (a->base < b->base))) { t = a; a = a->link; } else { t = b; b = b->link; } *lp = t; lp = &t->link; } *lp = 0; return(list); } vm = sort(vm); } static uint32_t find_space(uint32_t base, uint32_t size, uint32_t max) { MEMSEG *ms; uint32_t lastend; uint32_t rv; if (size & 0x80000000) panic("impossible find_space (size)"); if ((uint32_t)(base+size) < base) panic("impossible find_space (wrap)"); if (base+size > max) panic("impossible find_space (max)"); if (verbose) printf("find_space: base %08lx size %08lx max %08lx\n",(ULI)base,(ULI)size,(ULI)max); do <"found"> { sort_vm(); lastend = PAGE_SIZE; for (ms=vm;ms;ms=ms->link) { if (verbose) printf("find_space: memseg base %08lx size %08lx end %08lx\n",(ULI)ms->base,(ULI)ms->size,(ULI)ms->end); if ((ms->base >= base+size) && (ms->base-lastend >= size)) { rv = (lastend < base) ? base : lastend; break <"found">; } lastend = ms->end; if (lastend+size > max) break; } if (lastend+size <= max) { rv = (lastend < base) ? base : lastend; break <"found">; } panic("can't find space: base %08lx size %08lx max %08lx",(ULI)base,(ULI)size,(ULI)max); } while( 0); if (verbose) printf("find_space: returning %08lx\n",(ULI)rv); return(rv); } static void read_exe(int fd, void *buf, int len, off_t off, const char *what) { int rv; rv = pread(fd,buf,len,off); if (rv < 0) { printf("%s: %s: read: %s\n",exe,what,strerror(errno)); top(); } if (rv == 0) { printf("%s: %s: read EOF\n",exe,what); top(); } if (rv != len) { printf("%s: %s: read wanted %d, got %d\n",exe,what,len,rv); top(); } } /* The output generated doesn't really make sense otherwise... */ #if (CC_N != 8) || (CC_Z != 4) || (CC_V != 2) || (CC_C != 1) #error "print_cc assumptions invalid" #endif static void print_cc(FILE *to, unsigned int cc) { fprintf(to,"%c%c%c%c", (cc & CC_N) ? 'N' : '.', (cc & CC_Z) ? 'Z' : '.', (cc & CC_V) ? 'V' : '.', (cc & CC_C) ? 'C' : '.' ); } static void print_regs(FILE *to, uint64_t mask) { int nix; int ixv[35]; int nr; int r; int n; int i; mask &= 0x00000007ffffffffULL; nix = 0; for (i=0;i<35;i++) if ((mask >> i) & 1) ixv[nix++] = i; if (nix < 1) return; nr = (nix + 4) / 5; for (r=0;r= nr) fprintf(to," "); fprintf(to,"%-3s = ",regnames[i]); switch (i) { case 32: fprintf(to,"%08lx",(ULI)s.pc); break; case 33: fprintf(to,"%08lx",(ULI)s.npc); break; case 34: print_cc(to,s.cc); break; default: fprintf(to,"%08lx",(ULI)s.regs[i]); break; } } fprintf(to,"\n"); } } #if 0 static void dumpregs(FILE *to) { print_regs(to,0x00000007ffffffffULL); } #endif static FILE *trc_f(int which) { if ((which < 0) || (which >= TRC__N)) abort(); return(trace[which].out?trace[which].out->f:0); } static int trc_if(int which) { if ((which < 0) || (which >= TRC__N)) abort(); return(!!trace[which].out); } static void trc(int, const char *, ...) __attribute__((__format__(__printf__,2,3))); static void trc(int which, const char *fmt, ...) { FILE *f; va_list ap; f = trc_f(which); if (f == 0) return; va_start(ap,fmt); vfprintf(f,fmt,ap); va_end(ap); } static void mem_rw(char rw, uint32_t a, uint8_t v) { MEMACC *m; if (nmemacc >= amemacc) { int i; i = amemacc; memacc = realloc(memacc,(amemacc=nmemacc+16)*sizeof(*memacc)); for (;ivp = malloc((m->a=8)*sizeof(uint8_t)); } } if ( (nmemacc > 0) && (a == (m=&memacc[nmemacc-1])->a2) && (rw == m->rw) ) { if (m->n >= m->a) m->vp = realloc(m->vp,(m->a=m->n+8)*sizeof(uint8_t)); m->vp[m->n++] = v; m->a2 ++; return; } m = &memacc[nmemacc++]; m->a1 = a; m->a2 = a + 1; m->n = 1; m->vp[0] = v; m->rw = rw; } static MEMSEG *memseg_find(uint32_t addr, uint32_t align, const char *op) { MEMSEG *ms; MEMSEG **msp; if (addr & align) { printf("%s %08lx: not aligned\n",op,(ULI)addr); top(); } msp = &vm; while ((ms = *msp)) { if ((addr >= ms->base) && (addr < ms->end)) { *msp = ms->link; ms->link = vm; vm = ms; return(ms); } else { msp = &ms->link; } } printf("%s %08lx: not mapped\n",op,(ULI)addr); top(); } static uint8_t *mem_find(uint32_t addr, uint32_t align, const char *op, unsigned int prot) { MEMSEG *ms; ms = memseg_find(addr,align,op); if (ms->prot & prot) return(ms->data+(addr-ms->base)); printf("%s %08lx: not accessible\n",op,(ULI)addr); top(); } static uint32_t mem_get_4(uint32_t addr) { uint8_t *p; p = mem_find(addr,3,"get_4",P_R); if (verbose) { printf("get_4: %08lx -> %02x %02x %02x %02x\n", (ULI)addr,p[0],p[1],p[2],p[3]); } if (trc_if(TRC_MEM)) { mem_rw('r',addr,p[0]); mem_rw('r',addr+1,p[1]); mem_rw('r',addr+2,p[2]); mem_rw('r',addr+3,p[3]); } return((p[0]*0x01000000)|(p[1]*0x00010000)|(p[2]*0x00000100)|p[3]); } static uint32_t mem_exe_4(uint32_t addr) { uint8_t *p; p = mem_find(addr,3,"exe_4",P_X); if (verbose) { printf("exe_4: %08lx -> %02x %02x %02x %02x\n", (ULI)addr,p[0],p[1],p[2],p[3]); } if (trc_if(TRC_MEM)) { mem_rw('x',addr,p[0]); mem_rw('x',addr+1,p[1]); mem_rw('x',addr+2,p[2]); mem_rw('x',addr+3,p[3]); } return((p[0]*0x01000000)|(p[1]*0x00010000)|(p[2]*0x00000100)|p[3]); } static void mem_set_4(uint32_t addr, uint32_t v) { uint8_t *p; p = mem_find(addr,3,"set_4",P_W); if (verbose) { printf("set_4: %08lx <- %02x %02x %02x %02x\n", (ULI)addr, (int)((v>>24)&0xff), (int)((v>>16)&0xff), (int)((v>>8)&0xff), (int)(v&0xff)); } p[0] = v >> 24; p[1] = v >> 16; p[2] = v >> 8; p[3] = v; if (trc_if(TRC_MEM)) { mem_rw('w',addr,p[0]); mem_rw('w',addr+1,p[1]); mem_rw('w',addr+2,p[2]); mem_rw('w',addr+3,p[3]); } } static uint16_t mem_get_2(uint32_t addr) { uint8_t *p; p = mem_find(addr,1,"get_2",P_R); if (verbose) { printf("get_2: %08lx -> %02x %02x\n", (ULI)addr,p[0],p[1]); } if (trc_if(TRC_MEM)) { mem_rw('r',addr,p[0]); mem_rw('r',addr+1,p[1]); } return((p[0]*0x0100)|p[1]); } static void mem_set_2(uint32_t addr, uint16_t v) { uint8_t *p; p = mem_find(addr,1,"set_2",P_W); if (verbose) { printf("set_2: %08lx <- %02x %02x\n",(ULI)addr,(int)((v>>8)&0xff),(int)(v&0xff)); } p[0] = v >> 8; p[1] = v; if (trc_if(TRC_MEM)) { mem_rw('w',addr,p[0]); mem_rw('w',addr+1,p[1]); } } static uint8_t mem_get_1(uint32_t addr) { uint8_t *p; p = mem_find(addr,0,"get_1",P_R); if (verbose) printf("get_1: %08lx -> %02x\n",(ULI)addr,p[0]); if (trc_if(TRC_MEM)) mem_rw('r',addr,*p); return(*p); } static void mem_set_1(uint32_t addr, uint8_t v) { uint8_t *p; p = mem_find(addr,0,"set_1",P_W); if (verbose) printf("set_1: %08lx <- %02x\n",(ULI)addr,v); if (trc_if(TRC_MEM)) mem_rw('w',addr,v); *p = v; } static void stack_push_4(uint32_t v) { s.regs[R_SP] -= 4; mem_set_4(s.regs[R_SP],v); } static void stack_push_1(uint8_t v) { s.regs[R_SP] --; mem_set_1(s.regs[R_SP],v); } static void stack_push_str(const char *s) { int l; for (l=strlen(s);l>=0;l--) stack_push_1(s[l]); } static void setup(void) { int efd; Elf32_Ehdr eh; Elf32_Phdr *ph; int nph; int i; MEMSEG *ms; uint32_t argv; uint32_t envp; uint32_t *argvv; uint32_t ps_strings; efd = open(exe,O_RDONLY,0); read_exe(efd,&eh,sizeof(eh),0,"bad ELF file (can't read header)"); if ( (eh.e_ident[EI_MAG0] != ELFMAG0) || (eh.e_ident[EI_MAG1] != ELFMAG1) || (eh.e_ident[EI_MAG2] != ELFMAG2) || (eh.e_ident[EI_MAG3] != ELFMAG3) ) { printf("%s: bad ELF file (bad magic number)\n",exe); top(); } if (eh.e_ident[EI_CLASS] != ELFCLASS32) { printf("%s: bad ELF file (class isn't 32-bit)\n",exe); top(); } if (ELF_HALF_TO_NATIVE(eh.e_machine) != EM_SPARC) { printf("%s: bad ELF file (machine isn't SPARC)\n",exe); top(); } if (ELF_HALF_TO_NATIVE(eh.e_type) != ET_EXEC) { printf("%s: bad ELF file (type isn't EXEC)\n",exe); top(); } if (ELF_HALF_TO_NATIVE(eh.e_phentsize) != sizeof(Elf32_Phdr)) { printf("%s: bad ELF file (phentsize isn't sizeof(Elf32_Phdr))\n",exe); top(); } nph = ELF_HALF_TO_NATIVE(eh.e_phnum); for (i=32-1;i>=0;i--) s.regs[i] = 0; s.cc = 0; s.flags = 0; s.pc = ELF_ADDR_TO_NATIVE(eh.e_entry); s.npc = s.pc + 4; vm = 0; dbrk = 0; ph = malloc(nph*sizeof(Elf32_Phdr)); read_exe(efd,ph,nph*sizeof(Elf32_Phdr),ELF_ADDR_TO_NATIVE(eh.e_phoff),"bad ELF file (can't read program headers)"); for (i=nph-1;i>=0;i--) { unsigned int t; unsigned long int flags; t = ELF_WORD_TO_NATIVE(ph[i].p_type); switch (t) { case PT_INTERP: printf("%s: PT_INTERP executables not supported\n",exe); top(); break; case PT_LOAD: { uint32_t align; uint32_t va; uint32_t fa; uint32_t diff; uint32_t fo; uint32_t fsz; uint32_t msz; uint32_t psz; flags = ELF_WORD_TO_NATIVE(ph[i].p_flags); fa = ELF_ADDR_TO_NATIVE(ph[i].p_vaddr); align = ELF_WORD_TO_NATIVE(ph[i].p_align); va = fa; if (align > 1) va = ROUND_DOWN(va,align); diff = fa - va; fo = ELF_OFFSET_TO_NATIVE(ph[i].p_offset) - diff; fsz = ELF_WORD_TO_NATIVE(ph[i].p_filesz) + diff; msz = ELF_WORD_TO_NATIVE(ph[i].p_memsz) + diff; psz = ROUND_UP(msz,PAGE_SIZE); if (verbose) { printf(" PT_LOAD section: offset %lx vaddr %lx paddr %lx filesz %lx memsz %lx flags %lx<", (ULI)ELF_OFFSET_TO_NATIVE(ph[i].p_offset), (ULI)fa, (ULI)ELF_ADDR_TO_NATIVE(ph[i].p_paddr), (ULI)ELF_WORD_TO_NATIVE(ph[i].p_filesz), (ULI)ELF_WORD_TO_NATIVE(ph[i].p_memsz), flags); printf("%c%c%c",(flags&PF_R)?'R':'-',(flags&PF_W)?'W':'-',(flags&PF_X)?'X':'-'); if (flags & ~(PF_R|PF_W|PF_X)) printf("+%lx",flags&~(PF_R|PF_W|PF_X)); printf("> align %lx\n",(ULI)align); printf(" Load va %lx from %lx fsz %lx msz %lx psz %lx\n", (ULI)va, (ULI)fo, (ULI)fsz, (ULI)msz, (ULI)psz); } ms = memseg_mem(va,psz,((flags&PF_R)?P_R:0)|((flags&PF_W)?P_W:0)|((flags&PF_X)?P_X:0)); read_exe(efd,ms->data,fsz,fo,"bad ELF file (can't read program segment)"); if (fsz < psz) bzero(ms->data+fsz,psz-fsz); if (va+psz > dbrk) dbrk = va + psz; } break; } } close(efd); ms = memseg_mem(USRSTACK-MAXSSIZE,MAXSSIZE,P_R|P_W|P_X); bzero(ms->data,MAXSSIZE); s.regs[R_SP] = USRSTACK; // ps_strings space s.regs[R_SP] -= 16; ps_strings = s.regs[R_SP]; // argv strings argvv = malloc(nargs*sizeof(uint32_t)); argvv[nargs] = 0; for (i=nargs-1;i>=0;i--) { stack_push_str(args[i]); argvv[i] = s.regs[R_SP]; } while (s.regs[R_SP] & 3) stack_push_1(0); // no environment, just a terminating nil pointer, at present stack_push_4(0); envp = s.regs[R_SP]; stack_push_4(0); for (i=nargs-1;i>=0;i--) stack_push_4(argvv[i]); argv = s.regs[R_SP]; stack_push_4(nargs); free(argvv); mem_set_4(ps_strings,0); mem_set_4(ps_strings+4,envp); mem_set_4(ps_strings+8,nargs); mem_set_4(ps_strings+12,argv); s.regs[R_G1] = ps_strings; s.regs[R_SP] -= 64; // rwindow space s.instrs = 0; } static int new_fd(int osfd, unsigned int rw) { int d; FD *fd; int i; for (d=0;(d MAXFDS) { printf("Out of fds\n"); top(); } if (d >= nfds) { i = nfds; nfds = d + 8; fds = realloc(fds,nfds*sizeof(*fds)); for (;ifd = osfd; fd->prot = rw & (P_R | P_W); return(d); } static void init_fds(void) { nfds = 0; fds = 0; new_fd(0,P_R); new_fd(1,P_W); new_fd(2,P_W); } static uint32_t signextend(uint32_t v, int bits) { if ((v >> (bits-1)) & 1) { v |= (~(uint32_t)0) << bits; } else { v &= ~((~(uint32_t)0) << bits); } return(v); } static void unimp(uint32_t xa, uint32_t inst) { printf("Unimplemented: at %08lx inst=%08lx\n",(ULI)xa,(ULI)inst); printf(" OPC=%d OP2=%d DREG=%d A=%d COND=%d IMM22=%d, DISP22=%d\n", (int)OPC(inst), (int)OP2(inst), (int)DREG(inst), (int)A(inst), (int)COND(inst), (int)IMM22(inst), (int)DISP22(inst)); printf(" OP3=%d SREG1=%d SREG2=%d I=%d ASI=%d SIMM13=%d OPF=%d\n", (int)OP3(inst), (int)SREG1(inst), (int)SREG2(inst), (int)I(inst), (int)ASI(inst), (int)SIMM13(inst), OPF(inst)); top(); } static void window_save(void) { uint32_t sp; int i; sp = s.regs[R_SP]; for (i=8-1;i>=0;i--) { mem_set_4(sp+(i*4),s.regs[R_L0+i]); mem_set_4(sp+32+(i*4),s.regs[R_I0+i]); s.regs[R_I0+i] = s.regs[R_O0+i]; s.regs[R_O0+i] = 0; s.regs[R_L0+i] = 0; } } static void window_restore(void) { uint32_t fp; int i; fp = s.regs[R_FP]; for (i=8-1;i>=0;i--) { s.regs[R_O0+i] = s.regs[R_I0+i]; s.regs[R_L0+i] = mem_get_4(fp+(i*4)); s.regs[R_I0+i] = mem_get_4(fp+32+(i*4)); } } static uint32_t addcc(uint32_t a, uint32_t b) { uint64_t v; v = (uint64_t)a + (uint64_t)b; s.cc = ((v & 0x80000000) ? CC_N : 0) | (((uint32_t)v == 0) ? CC_Z : 0) | ((0x80000000&(a^v)&~(a^b)) ? CC_V : 0) | ((v & 0x100000000ULL) ? CC_C : 0); return(v); } static uint32_t subcc(uint32_t a, uint32_t b) { uint64_t v; v = (uint64_t)a - (uint64_t)b; s.cc = ((v & 0x80000000) ? CC_N : 0) | (((uint32_t)v == 0) ? CC_Z : 0) | (((a^b)&(v^a)&0x80000000) ? CC_V : 0) | ((v & 0x100000000ULL) ? CC_C : 0); return(v); } static uint32_t sra(uint32_t v, uint32_t n) { n &= 31; if (v & 0x80000000) { v = ~((~v) >> n); } else { v >>= n; } return(v); } static uint32_t andcc(uint32_t a, uint32_t b) { uint32_t v; v = a & b; s.cc = ((v & 0x80000000) ? CC_N : 0) | ((v == 0) ? CC_Z : 0); return(v); } static uint32_t orcc(uint32_t a, uint32_t b) { uint32_t v; v = a | b; s.cc = ((v & 0x80000000) ? CC_N : 0) | ((v == 0) ? CC_Z : 0); return(v); } static void cbranch(int cond, int annul, uint32_t to) { switch (cond) { case 8: s.npc = to; /* fall through */ case 0: if (annul) s.flags |= SF_ANNUL; break; default: if ((conds[cond&15] >> (s.cc & 15)) & 1) { s.npc = to; } else { if (annul) s.flags |= SF_ANNUL; } break; } } static void scarg_nulterm(uint32_t ptr, char **sp) { int l; unsigned char *s; int i; l = 0; while (mem_get_1(ptr+l)) l ++; s = malloc(l+1); for (i=0;i<=l;i++) s[i] = mem_get_1(ptr+i); *sp = s; } static uint32_t scarg(SCARGS *args, int n) { if (n < 0) panic("impossible scarg"); if (n < args->nreg) return(args->regs[n]); return(mem_get_4(args->sp+((23+n-args->nreg)*4))); } static SYSCALL_IMPL(sc_getpid) { SYSCALL_RET2(getpid(),getppid()); } static int em_sc_int(uint32_t valp, uint32_t lenp, uint32_t val, SCRV *rv) { uint32_t len; int i; if (valp == 0) { mem_set_4(lenp,4); SYSCALL_SETRET(4); return(1); } len = mem_get_4(lenp); if (len < 4) { for (i=0;i>24); val <<= 8; } SYSCALL_SETERR(em_ENOMEM); } else { for (i=0;i<4;i++) { mem_set_1(valp+i,val>>24); val <<= 8; } mem_set_4(lenp,4); SYSCALL_SETRET(4); } return(1); } static int em_sysctl_hw(uint32_t *mib, int miblen, uint32_t valp, uint32_t lenp, SCRV *rv) { if (miblen != 1) return(0); switch (mib[0]) { case em_HW_PAGESIZE: return(em_sc_int(valp,lenp,PAGE_SIZE,rv)); break; } return(0); } static SYSCALL_IMPL(sc___sysctl) { uint32_t mibp; uint32_t v; int nmib; uint32_t mib[16]; int i; // MIB length in range? v = scarg(args,1); if ((v < 2) || (v > 16)) SYSCALL_ERR(em_EINVAL); nmib = v; // We don't support setting (yet) if (scarg(args,4)) SYSCALL_ERR(em_EPERM); // Read MIB mibp = scarg(args,0); for (i=nmib-1;i>=0;i--) { mib[i] = mem_get_4(mibp+(i<<2)); } // Do it! switch (mib[0]) { case em_CTL_HW: if (em_sysctl_hw(mib+1,nmib-1,scarg(args,2),scarg(args,3),rv)) return; break; } printf("Unsupported sysctl "); for (i=0;i 65536) l = 65536; n = readlink(path,&buf[0],l); if (n < 0) { i = errno; free(path); SYSCALL_ERR(errno_map(i)); } free(path); bufp = scarg(args,1); for (i=0;i= USRSTACK) SYSCALL_ERR(em_EINVAL); end = addr + len; if (end < addr) SYSCALL_ERR(em_EINVAL); printf("MAP_FIXED mmap not yet implemented\n"); printf("addr %08lx len %08lx prot %08lx flags %08lx fd %08lx offset %016llx\n", (ULI)addr, (ULI)len, (ULI)prot, (ULI)flags, (ULI)fd, (ULLI)offset); top(); } else { addr = find_space(MAXDSIZE,len,USRSTACK); } if (flags & em_MAP_ANON) { void *mmrv; if (fd != (uint32_t)-1) SYSCALL_ERR(em_EINVAL); mmrv = mmap( 0, len, ((prot&em_PROT_READ)?PROT_READ:0) | ((prot&em_PROT_WRITE)?PROT_WRITE:0) | ((prot&em_PROT_EXEC)?PROT_EXEC:0), MAP_ANON | ((flags & em_MAP_SHARED) ? MAP_SHARED : 0) | ((flags & em_MAP_PRIVATE) ? MAP_PRIVATE : 0), -1, 0 ); if (mmrv == MAP_FAILED) { printf("Anonymous mmap failed: %s\n",strerror(errno)); top(); } memseg_new_mmap(addr,len,((prot&em_PROT_READ)?P_R:0)|((prot&em_PROT_WRITE)?P_W:0)|((prot&em_PROT_EXEC)?P_X:0),mmrv); SYSCALL_RET(addr); } else { printf("Non-anonymous mmap not yet implemented\n"); printf("addr %08lx len %08lx prot %08lx flags %08lx fd %08lx offset %016llx\n", (ULI)addr, (ULI)len, (ULI)prot, (ULI)flags, (ULI)fd, (ULLI)offset); top(); } } static SYSCALL_IMPL(sc_break) { uint32_t newbrk; MEMSEG *ms; newbrk = scarg(args,0); if (verbose) printf("brk: %08lx\n",(ULI)newbrk); newbrk = ROUND_UP(newbrk,PAGE_SIZE); if (newbrk > MAXDSIZE) { printf("break: %08lx exceeds data size limit\n",(ULI)newbrk); top(); } if (newbrk > dbrk) { ms = memseg_new_malloc(dbrk,newbrk-dbrk,P_R|P_W); memseg_clear_conflict(ms->base,ms->size,ms); dbrk = newbrk; } else if (newbrk < dbrk) { memseg_clear_conflict(newbrk,dbrk-newbrk,0); } SYSCALL_RET(0); } static SYSCALL_IMPL(sc_write) { uint32_t d; uint32_t buf; uint32_t len; uint32_t part; FD *fd; int niov; static int aiov = 0; static struct iovec *iov = 0; MEMSEG *ms; int n; d = scarg(args,0); buf = scarg(args,1); len = scarg(args,2); if (d > nfds) SYSCALL_ERR(em_EBADF); fd = fds[d]; if (!fd || !(fd->prot & P_W)) SYSCALL_ERR(em_EBADF); if (len < 1) SYSCALL_RET(0); niov = 0; while (len > 0) { ms = memseg_find(buf,0,"write"); if (! (ms->prot & P_R)) { printf("write %08lx: not accessible\n",(ULI)buf); top(); } part = ms->end - buf; if (part > len) part = len; if (niov >= aiov) iov = realloc(iov,(aiov=niov+8)*sizeof(*iov)); iov[niov++] = (struct iovec){.iov_base=ms->data+(buf-ms->base),.iov_len=part}; buf += part; len -= part; } n = writev(fd->fd,iov,niov); if (n < 0) SYSCALL_ERR(errno_map(errno)); SYSCALL_RET(n); } static SYSCALL_IMPL(sc_exit) { uint32_t ec; ec = scarg(args,0); exit(ec); } static SYSCALL_IMPL(sc_getrusage) { uint32_t who; uint32_t buf; struct rusage ru; int oswho; who = scarg(args,0); buf = scarg(args,1); switch (who) { default: SYSCALL_ERR(em_EINVAL); break; case em_RUSAGE_SELF: oswho = RUSAGE_SELF; break; case em_RUSAGE_CHILDREN: oswho = RUSAGE_CHILDREN; break; } if (getrusage(oswho,&ru) < 0) panic("impossible getrusage failure"); mem_set_4(buf,ru.ru_utime.tv_sec); mem_set_4(buf+4,ru.ru_utime.tv_usec); mem_set_4(buf+8,ru.ru_stime.tv_sec); mem_set_4(buf+12,ru.ru_stime.tv_usec); mem_set_4(buf+16,ru.ru_maxrss); mem_set_4(buf+20,ru.ru_ixrss); mem_set_4(buf+24,ru.ru_idrss); mem_set_4(buf+28,ru.ru_isrss); mem_set_4(buf+32,ru.ru_minflt); mem_set_4(buf+36,ru.ru_majflt); mem_set_4(buf+40,ru.ru_nswap); mem_set_4(buf+44,ru.ru_inblock); mem_set_4(buf+48,ru.ru_oublock); mem_set_4(buf+52,ru.ru_msgsnd); mem_set_4(buf+56,ru.ru_msgrcv); mem_set_4(buf+60,ru.ru_nsignals); mem_set_4(buf+64,ru.ru_nvcsw); mem_set_4(buf+68,ru.ru_nivcsw); SYSCALL_RET(0); } static SYSCALL_IMPL(sc___fstat13) { uint32_t d; uint32_t stp; struct stat stb; FD *fd; d = scarg(args,0); stp = scarg(args,1); if (d > nfds) SYSCALL_ERR(em_EBADF); fd = fds[d]; if (! fd) SYSCALL_ERR(em_EBADF); if (fstat(fd->fd,&stb) < 0) panic("impossible fstat failure"); mem_set_4(stp,stb.st_dev); mem_set_4(stp+4,stb.st_ino); mem_set_4(stp+8,stb.st_mode); mem_set_4(stp+12,stb.st_nlink); mem_set_4(stp+16,stb.st_uid); mem_set_4(stp+20,stb.st_gid); mem_set_4(stp+24,stb.st_rdev); mem_set_4(stp+28,stb.st_atimespec.tv_sec); mem_set_4(stp+32,stb.st_atimespec.tv_nsec); mem_set_4(stp+36,stb.st_mtimespec.tv_sec); mem_set_4(stp+40,stb.st_mtimespec.tv_nsec); mem_set_4(stp+44,stb.st_ctimespec.tv_sec); mem_set_4(stp+48,stb.st_ctimespec.tv_nsec); mem_set_4(stp+52,0); // struct padding mem_set_4(stp+56,(stb.st_size>>16)>>16); mem_set_4(stp+60,stb.st_size); mem_set_4(stp+64,(stb.st_blocks>>16)>>16); mem_set_4(stp+68,stb.st_blocks); mem_set_4(stp+72,stb.st_blksize); mem_set_4(stp+76,0); // XXX should be st_flags mem_set_4(stp+80,stb.st_gen); mem_set_4(stp+84,0); // struct padding mem_set_4(stp+88,0); // st_qspare, word 0 mem_set_4(stp+92,0); // st_qspare, word 1 mem_set_4(stp+96,0); // st_qspare, word 2 mem_set_4(stp+100,0); // st_qspare, word 3 SYSCALL_RET(0); } static SYSCALL_IMPL(sc_ioctl) { uint32_t d; uint32_t ioc; uint32_t arg; FD *fd; struct termios tio; int e; d = scarg(args,0); ioc = scarg(args,1); arg = scarg(args,2); if (d > nfds) SYSCALL_ERR(em_EBADF); fd = fds[d]; if (! fd) SYSCALL_ERR(em_EBADF); switch (ioc) { case em_TIOCGETA: e = ioctl(fd->fd,TIOCGETA,&tio); if (e < 0) SYSCALL_ERR(errno_map(e)); mem_set_1(arg+16+em_VEOF,tio.c_cc[VEOF]); mem_set_1(arg+16+em_VEOL,tio.c_cc[VEOL]); mem_set_1(arg+16+em_VEOL2,tio.c_cc[VEOL2]); mem_set_1(arg+16+em_VERASE,tio.c_cc[VERASE]); mem_set_1(arg+16+em_VWERASE,tio.c_cc[VWERASE]); mem_set_1(arg+16+em_VKILL,tio.c_cc[VKILL]); mem_set_1(arg+16+em_VREPRINT,tio.c_cc[VREPRINT]); mem_set_1(arg+16+em_VINTR,tio.c_cc[VINTR]); mem_set_1(arg+16+em_VQUIT,tio.c_cc[VQUIT]); mem_set_1(arg+16+em_VSUSP,tio.c_cc[VSUSP]); mem_set_1(arg+16+em_VDSUSP,tio.c_cc[VDSUSP]); mem_set_1(arg+16+em_VSTART,tio.c_cc[VSTART]); mem_set_1(arg+16+em_VSTOP,tio.c_cc[VSTOP]); mem_set_1(arg+16+em_VLNEXT,tio.c_cc[VLNEXT]); mem_set_1(arg+16+em_VDISCARD,tio.c_cc[VDISCARD]); mem_set_1(arg+16+em_VMIN,tio.c_cc[VMIN]); mem_set_1(arg+16+em_VTIME,tio.c_cc[VTIME]); mem_set_1(arg+16+em_VSTATUS,tio.c_cc[VSTATUS]); mem_set_4(arg, ((tio.c_iflag & IGNBRK) ? em_IGNBRK : 0) | ((tio.c_iflag & BRKINT) ? em_BRKINT : 0) | ((tio.c_iflag & IGNPAR) ? em_IGNPAR : 0) | ((tio.c_iflag & PARMRK) ? em_PARMRK : 0) | ((tio.c_iflag & INPCK) ? em_INPCK : 0) | ((tio.c_iflag & ISTRIP) ? em_ISTRIP : 0) | ((tio.c_iflag & INLCR) ? em_INLCR : 0) | ((tio.c_iflag & IGNCR) ? em_IGNCR : 0) | ((tio.c_iflag & ICRNL) ? em_ICRNL : 0) | ((tio.c_iflag & IXON) ? em_IXON : 0) | ((tio.c_iflag & IXOFF) ? em_IXOFF : 0) | ((tio.c_iflag & IXANY) ? em_IXANY : 0) | ((tio.c_iflag & IMAXBEL) ? em_IMAXBEL : 0) ); mem_set_4(arg+4, ((tio.c_oflag & OPOST) ? em_OPOST : 0) | ((tio.c_oflag & ONLCR) ? em_ONLCR : 0) | ((tio.c_oflag & OXTABS) ? em_OXTABS : 0) | ((tio.c_oflag & ONOEOT) ? em_ONOEOT : 0) | ((tio.c_oflag & OCRNL) ? em_OCRNL : 0) | ((tio.c_oflag & ONOCR) ? em_ONOCR : 0) | ((tio.c_oflag & ONLRET) ? em_ONLRET : 0) ); mem_set_4(arg+8, ((tio.c_cflag & CIGNORE) ? em_CIGNORE : 0) | (((tio.c_cflag & CSIZE) == CS5) ? em_CS5 : 0) | (((tio.c_cflag & CSIZE) == CS6) ? em_CS6 : 0) | (((tio.c_cflag & CSIZE) == CS7) ? em_CS7 : 0) | (((tio.c_cflag & CSIZE) == CS8) ? em_CS8 : 0) | ((tio.c_cflag & CSTOPB) ? em_CSTOPB : 0) | ((tio.c_cflag & CREAD) ? em_CREAD : 0) | ((tio.c_cflag & PARENB) ? em_PARENB : 0) | ((tio.c_cflag & PARODD) ? em_PARODD : 0) | ((tio.c_cflag & HUPCL) ? em_HUPCL : 0) | ((tio.c_cflag & CLOCAL) ? em_CLOCAL : 0) | ((tio.c_cflag & CRTSCTS) ? em_CRTSCTS : 0) | ((tio.c_cflag & CDTRCTS) ? em_CDTRCTS : 0) | ((tio.c_cflag & MDMBUF) ? em_MDMBUF : 0) ); mem_set_4(arg+12, ((tio.c_lflag & ECHOKE) ? em_ECHOKE : 0) | ((tio.c_lflag & ECHOE) ? em_ECHOE : 0) | ((tio.c_lflag & ECHOK) ? em_ECHOK : 0) | ((tio.c_lflag & ECHO) ? em_ECHO : 0) | ((tio.c_lflag & ECHONL) ? em_ECHONL : 0) | ((tio.c_lflag & ECHOPRT) ? em_ECHOPRT : 0) | ((tio.c_lflag & ECHOCTL) ? em_ECHOCTL : 0) | ((tio.c_lflag & ISIG) ? em_ISIG : 0) | ((tio.c_lflag & ALTWERASE) ? em_ALTWERASE : 0) | ((tio.c_lflag & IEXTEN) ? em_IEXTEN : 0) | ((tio.c_lflag & EXTPROC) ? em_EXTPROC : 0) | ((tio.c_lflag & TOSTOP) ? em_TOSTOP : 0) | ((tio.c_lflag & FLUSHO) ? em_FLUSHO : 0) | ((tio.c_lflag & NOKERNINFO) ? em_NOKERNINFO : 0) | ((tio.c_lflag & PENDIN) ? em_PENDIN : 0) | ((tio.c_lflag & NOFLSH) ? em_NOFLSH : 0) ); mem_set_4(arg+36,tio.c_ispeed); mem_set_4(arg+40,tio.c_ospeed); SYSCALL_RET(0); break; } printf("Unimplemented ioctl %08lx = ",(ULI)ioc); switch (ioc & em_IOC_DIRMASK) { case em_IOC_VOID: if (em_IOC_LEN(ioc) == 0) { printf("_IO('%c',%d)",em_IOC_GROUP(ioc),em_IOC_NUM(ioc)); } else { printf("_IOC(IOC_VOID,'%c',%d,%d)",em_IOC_GROUP(ioc),em_IOC_NUM(ioc),em_IOC_LEN(ioc)); } break; case em_IOC_OUT: printf("_IOR('%c',%d,%d)",em_IOC_GROUP(ioc),em_IOC_NUM(ioc),em_IOC_LEN(ioc)); break; case em_IOC_IN: printf("_IOW('%c',%d,%d)",em_IOC_GROUP(ioc),em_IOC_NUM(ioc),em_IOC_LEN(ioc)); break; case em_IOC_INOUT: printf("_IOWR('%c',%d,%d)",em_IOC_GROUP(ioc),em_IOC_NUM(ioc),em_IOC_LEN(ioc)); break; default: printf("unknown"); break; } printf("\n"); top(); } static SYSCALL_IMPL(sc_gettimeofday) { uint32_t tvp; uint32_t tzp; struct timeval tv; tvp = scarg(args,0); tzp = scarg(args,1); gettimeofday(&tv,0); if (tvp) { mem_set_4(tvp,tv.tv_sec); mem_set_4(tvp+4,tv.tv_usec); } if (tzp) { mem_set_4(tzp,0); mem_set_4(tzp+4,0); } SYSCALL_RET(0); } static SYSCALL_IMPL(sc_access) { char *path; uint32_t how; int oshow; int e; scarg_nulterm(scarg(args,0),&path); if (verbose) printf("access: path = %s\n",path); how = scarg(args,1); oshow = ((how & em_R_OK) ? R_OK : 0) | ((how & em_W_OK) ? W_OK : 0) | ((how & em_X_OK) ? X_OK : 0); e = access(path,oshow); if (e < 0) { e = errno; free(path); SYSCALL_ERR(errno_map(e)); } free(path); SYSCALL_RET(0); } static SYSCALL_IMPL(sc_open) { char *path; uint32_t how; uint32_t perm; int oshow; int osfd; int e; int fdp; scarg_nulterm(scarg(args,0),&path); if (verbose) printf("open: path = %s\n",path); how = scarg(args,1); perm = scarg(args,2); switch (how & em_O_ACCMODE) { case em_O_RDONLY: oshow = O_RDONLY; fdp = P_R; break; case em_O_WRONLY: oshow = O_WRONLY; fdp = P_W; break; case em_O_RDWR: oshow = O_RDWR; fdp = P_R|P_W; break; case em_O_NOACCESS: oshow = O_NOACCESS; fdp = 0; break; } if (how & em_O_NONBLOCK) oshow |= O_NONBLOCK; #define F(x) do { if (how & em_##x) oshow |= x; } while (0) F(O_NONBLOCK); F(O_APPEND); F(O_SHLOCK); F(O_EXLOCK); F(O_ASYNC); F(O_SYNC); F(O_CREAT); F(O_TRUNC); F(O_EXCL); F(O_DSYNC); F(O_RSYNC); F(O_ALT_IO); F(O_NOCTTY); F(O_DIRECTORY); F(O_PLAIN); #undef F osfd = open(path,oshow,perm); if (osfd < 0) { e = errno; free(path); SYSCALL_ERR(errno_map(e)); } free(path); SYSCALL_RET(new_fd(osfd,fdp)); } static SYSCALL_IMPL(sc_read) { uint32_t d; uint32_t buf; uint32_t len; uint32_t part; char *osbuf; FD *fd; MEMSEG *ms; int n; int left; uint32_t bp; d = scarg(args,0); buf = scarg(args,1); len = scarg(args,2); if (d > nfds) SYSCALL_ERR(em_EBADF); fd = fds[d]; if (!fd || !(fd->prot & P_R)) SYSCALL_ERR(em_EBADF); if (len < 1) SYSCALL_RET(0); osbuf = malloc(len); if (! osbuf) { printf("Out of memory allocating read() buffer\n"); top(); } n = read(fd->fd,osbuf,len); if (n < 0) { n = errno; free(osbuf); SYSCALL_ERR(errno_map(n)); } left = n; bp = buf; while (left > 0) { ms = memseg_find(bp,0,"read"); if (! (ms->prot & P_W)) { free(osbuf); printf("read %08lx: not accessible\n",(ULI)bp); top(); } part = ms->end - bp; if (part > left) part = left; bcopy(osbuf+(bp-buf),ms->data+(bp-ms->base),part); bp += part; left -= part; } free(osbuf); SYSCALL_RET(n); } static SYSCALL_IMPL(sc_close) { uint32_t d; FD *fd; int e; d = scarg(args,0); if (d > nfds) SYSCALL_ERR(em_EBADF); fd = fds[d]; if (! fd) SYSCALL_ERR(em_EBADF); e = close(fd->fd); if (e < 0) SYSCALL_ERR(errno_map(errno)); fds[d] = 0; free(fd); SYSCALL_RET(0); } void (*sysent[])(SCARGS *, SCRV *) = { [em_SYS_exit] = &sc_exit, // 1 [em_SYS_read] = &sc_read, // 3 [em_SYS_write] = &sc_write, // 4 [em_SYS_open] = &sc_open, // 5 [em_SYS_close] = &sc_close, // 6 [em_SYS_break] = &sc_break, // 17 [em_SYS_getpid] = &sc_getpid, // 20 [em_SYS_access] = &sc_access, // 33 [em_SYS_ioctl] = &sc_ioctl, // 54 [em_SYS_readlink] = &sc_readlink, // 58 [em_SYS_gettimeofday] = &sc_gettimeofday, // 116 [em_SYS_getrusage] = &sc_getrusage, // 117 [em_SYS_mmap] = &sc_mmap, // 197 [em_SYS___sysctl] = &sc___sysctl, // 202 [em_SYS___fstat13] = &sc___fstat13, // 279 [0] = 0 }; static void dosyscall(uint32_t id) { SCARGS args; uint32_t callno; SCRV rv; uint32_t g2; uint32_t g7; void (*fn)(SCARGS *, SCRV *); g2 = s.regs[R_G2]; g7 = s.regs[R_G7]; args.nreg = 6; args.regs[0] = s.regs[R_O0]; args.regs[1] = s.regs[R_O1]; args.regs[2] = s.regs[R_O2]; args.regs[3] = s.regs[R_O3]; args.regs[4] = s.regs[R_O4]; args.regs[5] = s.regs[R_O5]; args.sp = s.regs[R_SP]; callno = id & ~0xc00; if (callno == em_SYS___syscall) { callno = args.regs[1]; args.regs[0] = args.regs[2]; args.regs[1] = args.regs[3]; args.regs[2] = args.regs[4]; args.regs[3] = args.regs[5]; args.nreg = 4; } rv.err = 0; rv.rv = 0; rv.rv2 = s.regs[R_O1]; if (callno >= (sizeof(sysent)/sizeof(sysent[0]))) { printf("Unknown syscall %08lx\n",(ULI)callno); top(); } fn = sysent[callno]; if (! fn) { printf("Unknown syscall %08lx\n",(ULI)callno); top(); } (*fn)(&args,&rv); if (rv.err == 0) { if (id & 0x400) // SYSCALL_G2RFLAG { s.pc = g2; s.npc = s.pc + 4; } else if (id & 0x800) // SYSCALL_G7RFLAG { s.pc = g7; s.npc = s.pc + 4; } else { s.cc &= ~CC_C; } s.regs[R_O0] = rv.rv; s.regs[R_O1] = rv.rv2; } else { s.regs[R_O0] = rv.err; s.cc |= CC_C; } } static void trap(uint32_t arg) { switch (arg) { case 0: // syscall dosyscall(s.regs[R_G1]); break; default: printf("Unknown trap code %08lx\n",(ULI)arg); top(); break; } } static void ctrap(int cond, uint32_t arg) { int doit; doit = (conds[cond&15] >> (s.cc & 15)) & 1; if (doit) trap(arg); } static void instr_(void) { uint32_t xa; uint32_t inst; uint32_t a; uint32_t v; uint32_t v2; s.instrs ++; xa = s.pc; if (xa & 3) { printf("Misaligned instruction at %08lx\n",(ULI)xa); top(); } s.pc = s.npc; s.npc += 4; if (s.flags & SF_ANNUL) { s.flags &= ~SF_ANNUL; return; } inst = mem_exe_4(xa); #define UNIMP() unimp(xa,inst) switch (OPC(inst)) { case 1: // format 1 // 01oo oooo oooo oooo oooo oooo oooo oooo // o = offset, in longword units s.regs[R_O7] = xa; s.npc = xa + (inst << 2); break; case 0: // format 2 // 00rr rrro ooii iiii iiii iiii iiii iiii // 00ac ccco oodd dddd dddd dddd dddd dddd // r = dreg, a = annul, c = cond, o = opcode // i = immediate data, d = displacement switch (OP2(inst)) { case 0: UNIMP(); break; case 1: UNIMP(); break; case 2: // bCC cbranch(COND(inst),A(inst),xa+(DISP22(inst)<<2)); break; case 3: UNIMP(); break; case 4: // sethi s.regs[DREG(inst)] = IMM22(inst) << 10; break; case 5: UNIMP(); break; case 6: UNIMP(); break; case 7: UNIMP(); break; } break; case 2: // format 3 switch (OP3(inst)) { case 0: // add s.regs[DREG(inst)] = s.regs[SREG1(inst)] + (I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]); break; case 1: // and s.regs[DREG(inst)] = s.regs[SREG1(inst)] & (I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]); break; case 2: // or s.regs[DREG(inst)] = s.regs[SREG1(inst)] | (I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]); break; case 3: // xor s.regs[DREG(inst)] = s.regs[SREG1(inst)] ^ (I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]); break; case 4: // sub s.regs[DREG(inst)] = s.regs[SREG1(inst)] - (I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]); break; case 5: // andn s.regs[DREG(inst)] = s.regs[SREG1(inst)] & ~(I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]); break; case 7: // xnor s.regs[DREG(inst)] = ~(s.regs[SREG1(inst)] ^ (I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)])); break; case 8: // addx s.regs[DREG(inst)] = s.regs[SREG1(inst)] + (I(inst)?SIMM13(inst):s.regs[SREG2(inst)]) + ((s.cc&CC_C)?1:0); break; case 12: // subx s.regs[DREG(inst)] = s.regs[SREG1(inst)] - (I(inst)?SIMM13(inst):s.regs[SREG2(inst)]) - ((s.cc&CC_C)?1:0); break; case 16: // addcc s.regs[DREG(inst)] = addcc(s.regs[SREG1(inst)],I(inst)?SIMM13(inst):s.regs[SREG2(inst)]); break; case 17: // andcc s.regs[DREG(inst)] = andcc(s.regs[SREG1(inst)],I(inst)?SIMM13(inst):s.regs[SREG2(inst)]); break; case 18: // orcc s.regs[DREG(inst)] = orcc(s.regs[SREG1(inst)],I(inst)?SIMM13(inst):s.regs[SREG2(inst)]); break; case 20: // subcc s.regs[DREG(inst)] = subcc(s.regs[SREG1(inst)],I(inst)?SIMM13(inst):s.regs[SREG2(inst)]); break; case 37: // sll s.regs[DREG(inst)] = s.regs[SREG1(inst)] << ((I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]) & 31); break; case 38: // srl s.regs[DREG(inst)] = s.regs[SREG1(inst)] >> ((I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]) & 31); break; case 39: // sra s.regs[DREG(inst)] = sra(s.regs[SREG1(inst)],(I(inst)?SIMM13(inst):s.regs[SREG2(inst)])&31); break; case 56: // jmpl s.npc = s.regs[SREG1(inst)] + (I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]); s.regs[DREG(inst)] = xa; break; case 58: // tCC ctrap(DREG(inst)&15,s.regs[SREG1(inst)]+(I(inst)?SIMM13(inst):s.regs[SREG2(inst)])); break; case 60: // save v = s.regs[SREG1(inst)] + (I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]); window_save(); s.regs[DREG(inst)] = v; break; case 61: // restore v = s.regs[SREG1(inst)] + (I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]); window_restore(); s.regs[DREG(inst)] = v; break; default: UNIMP(); break; } break; case 3: // format 3 switch (OP3(inst)) { case 0: // ld s.regs[DREG(inst)] = mem_get_4((I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]) + s.regs[SREG1(inst)]); break; case 1: // ldub s.regs[DREG(inst)] = mem_get_1((I(inst)?SIMM13(inst):s.regs[SREG2(inst)])+s.regs[SREG1(inst)]); break; case 2: // lduh s.regs[DREG(inst)] = mem_get_2((I(inst)?SIMM13(inst):s.regs[SREG2(inst)])+s.regs[SREG1(inst)]); break; case 3: // ldd a = (I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]) + s.regs[SREG1(inst)]; if (a & 7) { printf("ldd: %08lx: not aligned\n",(ULI)a); top(); } v = mem_get_4(a); v2 = mem_get_4(a+4); s.regs[DREG(inst)] = v; s.regs[DREG(inst)+1] = v2; break; case 4: // st mem_set_4( (I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]) + s.regs[SREG1(inst)], s.regs[DREG(inst)] ); break; case 5: // stb mem_set_1( (I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]) + s.regs[SREG1(inst)], s.regs[DREG(inst)] ); break; case 6: // sth mem_set_2( (I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]) + s.regs[SREG1(inst)], s.regs[DREG(inst)] ); break; case 7: // std a = (I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]) + s.regs[SREG1(inst)]; if (a & 7) { printf("std: %08lx: not aligned\n",(ULI)a); top(); } mem_set_4(a,s.regs[DREG(inst)]); mem_set_4(a+4,s.regs[DREG(inst)+1]); break; case 9: // ldsb s.regs[DREG(inst)] = signextend(mem_get_1((I(inst)?SIMM13(inst):s.regs[SREG2(inst)])+s.regs[SREG1(inst)]),8); break; case 10: // ldsh s.regs[DREG(inst)] = signextend(mem_get_2((I(inst)?SIMM13(inst):s.regs[SREG2(inst)])+s.regs[SREG1(inst)]),16); break; default: UNIMP(); break; } break; } } static void print_address(FILE *mf, uint32_t opc) { int anything; anything = 0; if (SREG1(opc) != 0) { fprintf(mf,"%s",regnames[SREG1(opc)]); anything = 1; } if (I(opc)) { int32_t off; off = SIMM13(opc); if (off || !anything) { if (off < 0) fprintf(mf,"-%#lx",(ULI)-off); else fprintf(mf,"%s%#lx",anything?"+":"",(ULI)off); } } else { if (SREG2(opc) || !anything) { fprintf(mf,"%s%s",anything?"+":"",regnames[SREG2(opc)]); } } } static void do_instr_trc(void) { uint32_t inst; FILE *mf; inst = mem_get_4(s.pc); mf = trc_f(TRC_INSTR); fprintf(mf,"(%llu) pc %08lx, code %08lx",s.instrs,(ULI)s.pc,(ULI)inst); if (s.flags & SF_ANNUL) fprintf(mf," (annulled)"); fprintf(mf,": "); switch (OPC(inst)) { case 1: /* format 1 */ /* 01oo oooo oooo oooo oooo oooo oooo oooo */ /* o = offset, in longword units */ fprintf(mf,"call %#lx",(ULI)(s.pc+((inst&0x3fffffff)<<2))); break; case 0: /* format 2 */ /* 00rr rrro ooii iiii iiii iiii iiii iiii */ /* 00ac ccco oodd dddd dddd dddd dddd dddd */ /* r = dreg, a = annul, c = cond, o = opcode */ /* i = immediate data, d = displacement */ switch (OP2(inst)) { case 0: fprintf(mf,"unimp 0x%lx",(ULI)IMM22(inst)); break; case 4: if (inst == 0x01000000) { fprintf(mf,"nop"); } else { fprintf(mf,"sethi %%hi(0x%08lx), %s",(ULI)(IMM22(inst)<<10),regnames[DREG(inst)]); } break; { int n; const char **ccvec; const char *pref; case 2: ccvec = &icc[0]; pref = "b"; if (0) { case 6: ccvec = &fcc[0]; pref = "fb"; } if (0) { case 7: ccvec = &ccc[0]; pref = "cb"; } fprintf(mf,"%s%s",pref,ccvec[COND(inst)]); n = strlen(pref) + strlen(ccvec[COND(inst)]); if (A(inst)) { fprintf(mf,",a"); n += 2; } fprintf(mf,"%*s%#lx",12-n,"",(ULI)(s.pc+(DISP22(inst)<<2))); } break; case 1: case 3: case 5: fprintf(mf,"",(ULI)OP2(inst),(ULI)DREG(inst),(ULI)IMM22(inst)); break; } break; case 2: /* format 3 */ { static const char *rs1_ri_rd_opc[] = { "Dadd", "Xand", "Xor", "Xxor", /* 0000xx */ "Dsub", "Xandn", "Xorn", "Xxnor", /* 0001xx */ "Daddx", 0, 0, 0, "Dsubx", 0, 0, 0, /* 001xxx */ "Daddcc", "Xandcc", "Xorcc", "Xxorcc", /* 0100xx */ "Dsubcc", "Xandncc", "Xorncc", "Xxnorcc", /* 0101xx */ "Daddxcc", 0, 0, 0, "Dsubxcc", 0, 0, 0, /* 011xxx */ "Dtaddcc", "Dtsubcc", "Dtaddcctv", "Dtsubcctv", /* 1000xx */ "Dmulscc", "5sll", "5srl", "5sra", /* 1001xx */ REP3b(0), /* 101xxx */ REP3b(0), /* 110xxx */ 0, 0, 0, 0, "Dsave", "Drestore", 0, 0 }; /* 111xxx */ static const char *rdreg[] = { REP5b(0), /* 0xxxxx */ REP3b(0), /* 100xxx */ "y", "psr", "wim", "tbr", 0, 0, 0, 0, /* 101xxx */ REP4b(0) }; /* 11xxxx */ static const char *wrreg[] = { REP5b(0), /* 0xxxxx */ REP4b(0), /* 10xxxx */ "y", "psr", "wim", "tbr", 0, 0, 0, 0, /* 110xxx */ REP3b(0) }; /* 111xxx */ const char *os; int op3; int opf; op3 = OP3(inst); if ((os = rs1_ri_rd_opc[op3])) { if (inst == 0x81e80000) { /* restore %g0, %g0, %g0 -> restore */ fprintf(mf,"restore"); } else if (inst == 0x81e00000) { /* save %g0, %g0, %g0 -> save */ fprintf(mf,"save"); } else if ((op3 == 20) && (DREG(inst) == 0)) { /* subcc x, y, %g0 -> cmp x, y */ fprintf(mf,"cmp %s, ",regnames[SREG1(inst)]); if (I(inst)) fprintf(mf,"%ld",(LI)(int32_t)SIMM13(inst)); else fprintf(mf,"%s",regnames[SREG2(inst)]); } else if ( (op3 == 18) && !I(inst) && (SREG2(inst) == 0) && (DREG(inst) == 0) ) { /* orcc x, %g0, %g0 -> tst x */ fprintf(mf,"tst %s",regnames[SREG1(inst)]); } else if ( (op3 == 18) && !I(inst) && (SREG1(inst) == 0) && (DREG(inst) == 0) ) { /* orcc %g0, x, %g0 -> tst x */ fprintf(mf,"tst %s",regnames[SREG2(inst)]); } else if ((op3 == 7) && !I(inst) && (SREG2(inst) == 0)) { /* xnor x, %g0, y -> not x, y */ /* xnor x, %g0, x -> not x */ fprintf(mf,"not %s",regnames[SREG1(inst)]); if (DREG(inst) != SREG1(inst)) fprintf(mf,", %s",regnames[DREG(inst)]); } else if ((op3 == 4) && !I(inst) && (SREG1(inst) == 0)) { /* sub %g0, x, y -> neg x, y */ /* sub %g0, x, x -> neg x */ fprintf(mf,"neg %s",regnames[SREG2(inst)]); if (DREG(inst) != SREG2(inst)) fprintf(mf,", %s",regnames[DREG(inst)]); } else if ((op3 == 0) && I(inst) && (SREG1(inst) == DREG(inst))) { /* add x, y, x -> inc y, x */ /* add x, 1, x -> inc x */ fprintf(mf,"inc "); if (SIMM13(inst) != 1) fprintf(mf,"%ld, ",(LI)(int32_t)SIMM13(inst)); fprintf(mf,"%s",regnames[SREG1(inst)]); } else if ((op3 == 4) && I(inst) && (SREG1(inst) == DREG(inst))) { /* sub x, y, x -> dec y, x */ /* sub x, 1, x -> dec x */ fprintf(mf,"dec "); if (SIMM13(inst) != 1) fprintf(mf,"%ld, ",(LI)(int32_t)SIMM13(inst)); fprintf(mf,"%s",regnames[SREG1(inst)]); } else if ( (op3 == 16) && I(inst) && (SREG1(inst) == DREG(inst)) && (SIMM13(inst) == 1) ) { /* addcc x, 1, x -> inccc x */ fprintf(mf,"inccc %s",regnames[SREG1(inst)]); } else if ( (op3 == 20) && I(inst) && (SREG1(inst) == DREG(inst)) && (SIMM13(inst) == 1) ) { /* subcc x, 1, x -> deccc x */ fprintf(mf,"deccc %s",regnames[SREG1(inst)]); } else if ((op3 == 17) && (DREG(inst) == 0)) { /* andcc x, y, %g0 -> btst y, x */ fprintf(mf,"btst "); if (I(inst)) fprintf(mf,"%#lx",(ULI)SIMM13(inst)); else fprintf(mf,"%s",regnames[SREG2(inst)]); fprintf(mf,", %s",regnames[SREG1(inst)]); } else if ( (op3 == 2) && !I(inst) && (SREG1(inst) == 0) && (SREG2(inst) == 0) ) { /* or %g0, %g0, x -> clr x */ fprintf(mf,"clr %s",regnames[DREG(inst)]); } else if ( (op3 == 2) && (SREG1(inst) == 0) ) { /* or %g0, x, y -> mov x, y */ fprintf(mf,"mov "); if (I(inst)) fprintf(mf,"%#lx",(ULI)SIMM13(inst)); else fprintf(mf,"%s",regnames[SREG2(inst)]); fprintf(mf,", %s",regnames[DREG(inst)]); } else { fprintf(mf,"%s%*s%s, ",os+1,12-(int)strlen(os+1),"",regnames[SREG1(inst)]); if (I(inst)) { switch (os[0]) { case 'D': fprintf(mf,"%ld",(LI)(int32_t)SIMM13(inst)); break; case 'X': fprintf(mf,"0x%lx",(ULI)SIMM13(inst)); break; case '5': fprintf(mf,"%d",(int)(SIMM13(inst)&31)); break; } } else { fprintf(mf,"%s",regnames[SREG2(inst)]); } fprintf(mf,", %s",regnames[DREG(inst)]); } } else if ((os = rdreg[op3])) { fprintf(mf,"rd %%%s, %s",os,regnames[DREG(inst)]); } else if ((os = wrreg[op3])) { fprintf(mf,"wr %s, ",regnames[SREG1(inst)]); if (I(inst)) fprintf(mf,"0x%lx",(ULI)SIMM13(inst)); else fprintf(mf,"%s",regnames[SREG2(inst)]); fprintf(mf,", %%%s",os); } else { switch (op3) { case 52: /* 110100 - fpop1 */ { static const char *fs1_fs2_fd[] = { REP6b(0), /*000xxxxxx*/ REP3b(0), /*001000xxx*/ 0, "fmuls", "fmuld", "fmulx", /*0010010xx*/ 0, "fdivs", "fdivd", "fdivx", /*0010011xx*/ REP4b(0), /*00101xxxx*/ REP5b(0), /*0011xxxxx*/ REP7b(0), /*01xxxxxxx*/ REP8b(0) }; /*1xxxxxxxx*/ static const char *fs2_fd[] = { 0, "fmovs", 0, 0, /*0000000xx*/ 0, "fnegs", 0, 0, /*0000001xx*/ 0, "fabss", 0, 0, /*0000010xx*/ REP2b(0), /*0000011xx*/ REP4b(0), /*00001xxxx*/ REP3b(0), /*000100xxx*/ 0, "fsqrts", "fsqrtd", "fsqrtx", /*0001010xx*/ REP2b(0), /*0001011xx*/ REP4b(0), /*00011xxxx*/ REP6b(0), /*001xxxxxx*/ REP6b(0), /*010xxxxxx*/ 0, "fstoir", "fdtoir", "fxtoir", /*0110000xx*/ "fitos", 0, "fdtos", "fxtos", /*0110001xx*/ "fitod", "fstod", 0, "fxtod", /*0110010xx*/ "fitox", "fstox", "fdtox", 0, /*0110011xx*/ 0, "fstoi", "fdtoi", "fxtoi", /*0110100xx*/ REP2b(0), /*0110101xx*/ REP3b(0), /*011011xxx*/ REP5b(0), /*0111xxxxx*/ REP8b(0) }; /*1xxxxxxxx*/ opf = OPF(inst); if ((os = fs1_fs2_fd[opf])) { fprintf(mf,"%s%*s%%f%d, %%f%d, %%f%d",os,12-(int)strlen(os),"",(int)SREG1(inst),(int)SREG2(inst),(int)DREG(inst)); } else if ((os = fs2_fd[opf])) { fprintf(mf,"%s%*s%%f%d, %%f%d",os,12-(int)strlen(os),"",(int)SREG2(inst),(int)DREG(inst)); } else { fprintf(mf,"",(int)OPF(inst),(int)SREG1(inst),(int)SREG2(inst),(int)DREG(inst)); } } break; case 53: /* 110101 - fpop2 */ { static const char *cmps[] = { REP6b(0), /*000xxxxxx*/ REP4b(0), /*00100xxxx*/ 0, "fcmps", "fcmpd", "fcmpx", /*0010100xx*/ 0, "fcmpes", "fcmped", "fcmpex", /*0010101xx*/ REP3b(0), /*001011xxx*/ REP5b(0), /*0011xxxxx*/ REP7b(0), /*01xxxxxxx*/ REP8b(0) }; /*1xxxxxxxx*/ opf = OPF(inst); if ((os = cmps[opf])) { fprintf(mf,"%s%*s%%f%d, %%f%d",os,12-(int)strlen(os),"",(int)SREG1(inst),(int)SREG2(inst)); } else { fprintf(mf,"",(int)OPF(inst),(int)SREG1(inst),(int)SREG2(inst),(int)DREG(inst)); } } break; case 54: /* 110110 - cpop1 */ fprintf(mf,"",(int)OPF(inst),(int)SREG1(inst),(int)SREG2(inst),(int)DREG(inst)); break; case 55: /* 110111 - cpop2 */ fprintf(mf,"",(int)OPF(inst),(int)SREG1(inst),(int)SREG2(inst),(int)DREG(inst)); break; case 56: /* 111000 */ if (inst == 0x81c7e008) /* jmpl %i7+8, %g0 */ { fprintf(mf,"ret"); } else if (inst == 0x81c3e008) /* jmpl %o7+8, %g0 */ { fprintf(mf,"retl"); } else if (DREG(inst) == 0) /* jmpl x, %g0 */ { fprintf(mf,"jmp "); print_address(mf,inst); } else if (DREG(inst) == 15) /* jmpl x, %o7 */ { fprintf(mf,"call "); print_address(mf,inst); } else { fprintf(mf,"jmpl "); print_address(mf,inst); fprintf(mf,", %s",regnames[DREG(inst)]); } break; case 57: /* 111001 */ fprintf(mf,"rett "); print_address(mf,inst); break; case 58: /* 111010 */ os = icc[DREG(inst)&15]; fprintf(mf,"t%s%*s",os,11-(int)strlen(os),""); print_address(mf,inst); break; case 59: /* 111011 */ fprintf(mf,"iflush "); print_address(mf,inst); break; default: fprintf(mf,"",(int)OP3(inst),(int)DREG(inst),(int)SREG1(inst),(int)I(inst),(int)ASI(inst),(int)OPF(inst),(int)SIMM13(inst),(int)SREG2(inst)); break; } } } break; case 3: /* format 3 */ { static const char *addr_rd[] = { "ld", "ldub", "lduh", "ldd", 0, 0, 0, 0, /* 000xxx */ 0, "ldsb", "ldsh", 0, 0, "ldstub", 0, "swap", /* 001xxx */ REP4b(0), /* 01xxxx */ REP5b(0) }; /* 1xxxxx */ static const char *addr_asi_rd[] = { REP4b(0), /* 00xxxx */ "lda", "lduba", "lduha", "ldda", 0, 0, 0, 0, /* 010xxx */ 0, "ldsba", "ldsha", 0, 0, "ldstuba", 0, "swapa", /* 011xxx */ REP5b(0) }; /* 1xxxxx */ static const char *rd_addr[] = { 0, 0, 0, 0, "st", "stb", "sth", "std", /* 000xxx */ REP3b(0), /* 001xxx */ REP4b(0), /* 01xxxx */ REP5b(0) }; /* 1xxxxx */ static const char *rd_addr_asi[] = { REP4b(0), /* 00xxxx */ 0, 0, 0, 0, "sta", "stba", "stha", "stda", /* 010xxx */ REP3b(0), /* 011xxx */ REP5b(0) }; /* 1xxxxx */ static const char *ld[] = { REP5b(0), /* 0xxxxx */ "frld", "fsld", 0, "frldd", 0, 0, 0, 0, /* 100xxx */ REP3b(0), /* 101xxx */ "crld", "csld", 0, "crldd", 0, 0, 0, 0, /* 110xxx */ REP3b(0) }; /* 111xxx */ static const char *st[] = { REP5b(0), /* 0xxxxx */ 0, 0, 0, 0, "frst", "fsst", "fqst", "frstd", /* 100xxx */ REP3b(0), /* 101xxx */ 0, 0, 0, 0, "crst", "csst", "cqst", "crstd", /* 110xxx */ REP3b(0) }; /* 111xxx */ int op3; const char *os; op3 = OP3(inst); if ((os = addr_rd[op3])) { fprintf(mf,"%s%*s[",os,12-(int)strlen(os),""); print_address(mf,inst); fprintf(mf,"], %s",regnames[DREG(inst)]); } else if ((os = addr_asi_rd[op3]) && !I(inst)) { fprintf(mf,"%s%*s[%s+%s], %s",os,12-(int)strlen(os),"",regnames[SREG1(inst)],regnames[SREG2(inst)],regnames[DREG(inst)]); } else if ((os = rd_addr[op3])) { if (DREG(inst) == 0) { fprintf(mf,"clr%s%*s[",os+2,9-(int)strlen(os+2),""); } else { fprintf(mf,"%s%*s%s, [",os,12-(int)strlen(os),"",regnames[DREG(inst)]); } print_address(mf,inst); fprintf(mf,"]"); } else if ((os = rd_addr_asi[op3]) && !I(inst)) { fprintf(mf,"%s%*s%s, [%s+%s]",os,12-(int)strlen(os),"",regnames[DREG(inst)],regnames[SREG1(inst)],regnames[SREG2(inst)]); } else if ((os = ld[op3])) { fprintf(mf,"%s%*s[",os+2,12-(int)strlen(os+2),""); print_address(mf,inst); switch (os[1]) { case 'r': fprintf(mf,"], %%%c%d",os[0],(int)DREG(inst)); break; case 's': fprintf(mf,"], %%%csr",os[0]); break; } } else if ((os = st[op3])) { fprintf(mf,"%s%*s",os+2,12-(int)strlen(os+2),""); switch (os[1]) { case 'r': fprintf(mf,"%%%c%d",os[0],(int)DREG(inst)); break; case 's': fprintf(mf,"%%%csr",os[0]); break; case 'q': fprintf(mf,"%%%cq",os[0]); break; } fprintf(mf,", ["); print_address(mf,inst); fprintf(mf,"]"); } else { fprintf(mf,"",(int)OP3(inst),(int)DREG(inst),(int)SREG1(inst),(int)I(inst),(int)ASI(inst),(int)OPF(inst),(int)SIMM13(inst),(int)SREG2(inst)); } } break; } fprintf(mf,"\n"); } static void instr(void) { if (trc_if(TRC_INSTR)) { int n; n = nmemacc; do_instr_trc(); nmemacc = n; } instr_(); s.regs[0] = 0; } static void dump_vm(void) { MEMSEG *ms; printf("base size end prot\n"); sort_vm(); for (ms=vm;ms;ms=ms->link) { printf("%08lx %08lx %08lx %c%c%c\n", (ULI)ms->base, (ULI)ms->size, (ULI)ms->end, (ms->prot&P_R)?'R':'-', (ms->prot&P_W)?'W':'-', (ms->prot&P_X)?'X':'-'); } } static char *trace_onoff(char *cp, void (*fn)(int), const char *tag) { char *ep; int i; for (ep=cp;*ep&&!Cisspace(*ep);ep++) ; if ((ep-cp == 1) && (*cp == '*')) { for (i=0;ioutrefs || tf->filerefs) return; fclose(tf->f); free(tf->name); free(tf); } static void trace_close(int kind) { if (trace[kind].out) { trace[kind].out->outrefs --; trcfile_free0(trace[kind].out); trace[kind].out = 0; } } static void trace_open(int kind) { trace_close(kind); trace[kind].out = trace[kind].file; trace[kind].out->outrefs ++; } static TRCFILE *setup_trcfile(char *n, int nlen) { TRCFILE *tf; int fd; if ((nlen == 1) && (n[0] == '-')) return(&trcfile_stdout); tf = malloc(sizeof(TRCFILE)); tf->filerefs = 0; tf->outrefs = 0; tf->name = malloc(nlen+1); bcopy(n,tf->name,nlen); tf->name[nlen] = '\0'; fd = open(tf->name,O_WRONLY|O_APPEND|O_CREAT,0644); if (fd < 0) { tf->f = 0; } else { tf->f = fdopen(fd,"a"); if (! tf->f) close(fd); } if (! tf->f) { printf("can't open %s: %s\n",tf->name,strerror(errno)); free(tf->name); free(tf); return(0); } setlinebuf(tf->f); return(tf); } static void trace_setfile(int kind, TRCFILE *tf) { int on; tf->filerefs ++; on = !!trace[kind].out; trace_close(kind); if (trace[kind].file) { trace[kind].file->filerefs --; trcfile_free0(trace[kind].file); } trace[kind].file = tf; if (on) trace_open(kind); } static char *trace_on(char *cp) { return(trace_onoff(cp,&trace_open,"on")); } static char *trace_off(char *cp) { return(trace_onoff(cp,&trace_close,"off")); } static char *trace_out(char *cp) { char *ep; char *colon; TRCFILE *tf; int i; #if TRC__N > 32 #error Update trace_out for this many types of tracing #endif uint32_t kinds; char *kp; colon = 0; for (ep=cp;*ep&&!Cisspace(*ep);ep++) if (!colon && (*ep == ':')) colon = ep; if (! colon) { tf = setup_trcfile(cp,ep-cp); if (tf) { for (i=0;i= TRC__N) { printf("bad trace name %.*s in t > command\n",(int)(cp-kp),kp); return(0); } cp ++; if (cp[-1] == ':') break; } tf = setup_trcfile(cp,ep-cp); if (tf) { for (i=0;i>i) & 1) trace_setfile(i,tf); trcfile_free0(tf); } } return(ep); } static void setup_trc(void) { int i; for (i=0;i maxl) maxl = l; } for (i=0;i %s\n",maxl,trace[i].name,trace[i].out->name); } else { printf("%*s off\n",maxl,trace[i].name); } } return; } break; case '?': printf("tracing names:"); for (i=0;i)\n",*cp); return; break; case '+': cp = trace_on(cp+1); break; case '-': cp = trace_off(cp+1); break; case '>': cp = trace_out(cp+1); break; } if (cp) while (*cp && Cisspace(*cp)) cp ++; } } static void log_chg(STATE *prevstate) { int i; int any; void pref(void) { if (! any) trc(TRC_CHG,"chg: "); any ++; } if (trc_if(TRC_MEM)) { if (nmemacc) { for (i=0;irw,(ULI)m->a1); for (j=0;jn;j++) trc(TRC_CHG," %02x",m->vp[j]); trc(TRC_CHG,"\n"); } nmemacc = 0; } } if (trc_if(TRC_CHG)) { any = 0; for (i=0;i<32;i++) { if (s.regs[i] != prevstate->regs[i]) { pref(); trc(TRC_CHG," %s=%08lx",regnames[i],(ULI)s.regs[i]); } } if (s.cc != prevstate->cc) { pref(); trc(TRC_CHG," cc="); print_cc(trc_f(TRC_CHG),s.cc); } if (any) trc(TRC_CHG,"\n"); } *prevstate = s; } static void show_regs(const char *cp) { uint64_t mask; char *ep; const char *t; int n; int i; mask = 0; while (1) { for (cp++;*cp&&Cisspace(*cp);cp++) ; if (! *cp) break; if (Cisdigit(*cp)) { n = strtol(cp,&ep,10); if ((n < 0) || (n > 31) || (cp == ep)) goto badregname; mask |= 1ULL << n; cp = ep; } else { for (t=cp;*t&&!Cisspace(*t);t++) ; for (i=0;i<32;i++) { n = strlen(regnames[i]); if ( (t-cp == n) && !strncmp(cp,regnames[i],n) ) { mask |= 1ULL << i; cp = t; break; } } if (i >= 32) { if ((ep-cp == 3) && !strncmp(cp,"npc",3)) { mask |= 0x200000000ULL; cp = ep; } else if ((ep-cp == 2) && !strncmp(cp,"pc",3)) { mask |= 0x100000000ULL; cp = ep; } else if ((ep-cp == 2) && !strncmp(cp,"cc",3)) { mask |= 0x400000000ULL; cp = ep; } else { badregname:; printf("unknown register name `%.*s'\n",(int)(ep-cp),cp); mask |= 0x8000000000000000; } } } } if (mask == 0) mask = 0x7ffffffffULL; if (! (mask & 0x8000000000000000)) print_regs(stdout,mask); } static void dump_mem(const char *cp) { unsigned long int v; uint32_t v1; uint32_t v2; uint32_t a; int len; char *ep; for (;*cp&&Cisspace(*cp);cp++) ; v = strtoul(cp,&ep,16); if (ep == cp) { printf("Bad starting address\n"); return; } v1 = v; if (v1 != v) { printf("Out-of-range starting address\n"); return; } for (cp=ep;*cp&&Cisspace(*cp);cp++) ; if (*cp == '\0') { len = 1; v2 = (v1 > 0xffffff80) ? (uint32_t)-v1 : 128; } else { if (*cp == '+') { len = 1; cp ++; } v = strtoul(cp,&ep,16); if (ep == cp) { printf("Bad %s\n",len?"size":"ending address"); return; } v2 = v; if (v2 != v) { printf("Out-of-range %s\n",len?"size":"ending address"); return; } for (cp=ep;*cp&&Cisspace(*cp);cp++) ; if (*cp) { printf("Junk after arguments\n"); return; } } if (len) { v2 += v1; if ((v2 > 0) && (v2 < v1)) { printf("Address range overflow\n"); return; } } else { if (v2 < v1) { printf("(Note: swapping arguments)\n"); v = v1; v1 = v2; v2 = v; } } if (v1 == v2) return; if (v1 & 15) printf("%08lx:%*s",(ULI)(v1&~(uint32_t)15),(3*(v1&15))+(((v1&15)>8)?3:2),""); for (a=v1;a!=v2;a++) { switch (a & 15) { case 0: printf("%08lx: ",(ULI)a); break; case 8: printf(" "); break; } printf(" %02x",mem_get_1(a)); if ((a & 15) == 15) printf("\n"); } if ((a & 15) != 0) printf("\n"); nmemacc = 0; } static void run(void) { __label__ err_throw; char *cp; int i; int n; STATE savestate; char cmd[512]; void throw_out(void) { goto err_throw; } err_jmp = &throw_out; if (0) { err_throw:; s = savestate; } while (1) { printf("sparc [pc=%08lx npc=%08lx ic=%llu]> ",(ULI)s.pc,(ULI)s.npc,s.instrs); fflush(0); if (fgets(&cmd[0],sizeof(cmd),stdin) == 0) exit(0); cp =&cmd[0]; i = strlen(cp); if ((i > 0) && (cp[i-1] == '\n')) cp[i-1] = '\0'; while (*cp && Cisspace(*cp)) cp ++; switch (*cp) { default: printf("`%c' not recognized (? for help)\n",*cp); continue; break; case '\0': continue; break; case '?': printf( "sN step N instructions\n" //"yN step N syscalls\n" "t show tracing state\n" "t +kind\n" " turn `kind' tracing on\n" "t -kind\n" " turn `kind' tracing off\n" "t >kind1,kind2,...:file\n" " send tracing output for kind1, kind2, etc to file\n" " note: does not also turn tracing on\n" "t >file\n" " like t >kind,kind,...:file for all possible kinds\n" "g go (like s with infinity as argument)\n" "r show all registers\n" "r reg [reg ...]\n" " show listed registers (number or name)\n" "M dump memory map\n" //"F dump file descriptor table\n" "m start\n" "m start end\n" "m start +bytes\n" " show memory contents (with one arg defaults to 128 bytes)\n" "Q quit\n" ); break; case 'g': savestate = s; while (1) { instr(); log_chg(&savestate); } break; case 'M': dump_vm(); break; case 'm': dump_mem(cp+1); break; case 'Q': exit(0); break; case 'r': show_regs(cp); break; case 's': n = atoi(cp+1); if (n < 1) n = 1; savestate = s; instr(); log_chg(&savestate); if (n > 1) { for (n--;n>0;n--) { instr(); log_chg(&savestate); } } break; case 't': do_tracing(cp+1); break; } } } int main(int, char **); int main(int ac, char **av) { handleargs(ac,av); setup_trc(); init_fds(); setup(); run(); return(0); }