#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * As of 1.4T, which is what we emulate, filesystem info comes from * statfs(), for which we need to include . As of 4.0.1 * and 5.2, we need to call statvfs(), from . Neither * has compatability with the other. Hence this dance. :-þ */ #include #if __NetBSD_Version__ >= 400000003 // 4.0.1 and later #define STATFS_VIA_STATVFS #elif __NetBSD_Version__ <= 104200000 // 1.4T and earlier #undef STATFS_VIA_STATVFS #else #error "Figure out whether STATFS_VIS_STATVFS should be defined" #endif #ifdef STATFS_VIA_STATVFS #include #else #include #endif /* * The revs I use that don't have WNOREAP have WNOWAIT, with the same * functionality. It's not documented, but it's there, apparently for * compatability with other OSes but usable natively. */ #if defined(WNOWAIT) && !defined(WNOREAP) #define WNOREAP WNOWAIT #endif /* * I see no clean way to implement __getcwd as a wrapper around getcwd, * and __getcwd has no declaration visible outside libc. So, this. * * Ugh. */ extern int __getcwd(char *, size_t); extern const char *__progname; #include "em-const.h" // PAGE_SIZE must be a power of two #define PAGE_SIZE 4096 #define USRSTACK 0xf0000000 #define MAXSSIZE (1U<<24) #define MAXDSIZE 0x04000000 #define MAXFDS 4096 #define STACKGAPLEN 400 // Second arg must be a power of two #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; typedef struct sig SIG; typedef struct nulterm_status NULTERM_STATUS; typedef struct sysent SYSENT; /* * In the args/rv strings: * * d 32-bit value, printed as signed decimal. * p 32-bit pointer, printed as hex. * b 32-bit value, printed in hex and decimal. * s (Pointer to) a string, printed as a string. * o 32-bit value, printed as unsigned octal. * D Two 32-bit values, printed in 64-bit signed decimal. * x A 32-bit pointer to a nil-terminated list of string * pointers (execve's argv and envp). * m Two 32-bit values, a pointer-and-length describing a * list of 32-bit values (sysctl's MIB args). * - The argument is ignored. * O Special-case hack for open(): if the second arg has * O_CREAT set, this turns into o, otherwise it is not * referenced and prints as "...". * f(...) Flags bitfield. The string in the parens is broken at * semicolons to describe the bits: * n:STRING * n in decimal, STRING terminated by ; or ) * Bit 1< 0) { skip --; continue; } if (**av != '-') { exe = *av; break; } 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; } nargs = ac - 1; args = av + 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 void destroy_vm(MEMSEG *vm) { MEMSEG *ms; while ((ms = vm)) { vm = ms->link; (*ms->ops->done)(ms); free(ms); } } 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 int read_exe(int fd, void *buf, int len, off_t off, const char *path, const char *what) { int rv; rv = pread(fd,buf,len,off); if (rv < 0) { printf("%s: %s: read: %s\n",path,what,strerror(errno)); return(-1); } if (rv == 0) { printf("%s: %s: read EOF\n",path,what); return(-1); } if (rv != len) { printf("%s: %s: read wanted %d, got %d\n",path,what,len,rv); return(-1); } return(0); } /* 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[PRINT_REGS__N]; int nr; int r; int n; int i; mask &= PRINT_REGS_ALL; nix = 0; for (i=0;mask;i++) { if (mask & 1) ixv[nix++] = i; mask >>= 1; } if (nix < 1) return; nr = (nix + 4) / 5; for (r=0;r= nr) fprintf(to," "); fprintf(to,"%-3s = ",regnames[i]); switch (i) { case PRINT_REGS_Y: fprintf(to,"%08lx",(ULI)s.y); break; case PRINT_REGS_PC: fprintf(to,"%08lx",(ULI)s.pc); break; case PRINT_REGS_NPC: fprintf(to,"%08lx",(ULI)s.npc); break; case PRINT_REGS_CC: 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,PRINT_REGS_ALL); } #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 (nomemacc) return; 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; } #if 0 static void stack_push_4(uint32_t v) { s.regs[R_SP] -= 4; mem_set_4(s.regs[R_SP],v); } #endif #if 0 static void stack_push_1(uint8_t v) { s.regs[R_SP] --; mem_set_1(s.regs[R_SP],v); } #endif #if 0 static void stack_push_str(const char *s) { int l; for (l=strlen(s);l>=0;l--) stack_push_1(s[l]); } #endif static void setup(void) { int i; for (i=32-1;i>=0;i--) s.regs[i] = 0; s.cc = 0; s.flags = 0; s.pc = 0; s.npc = s.pc + 4; vm = 0; s.wdepth = 0; s.instrs = 0; noninteractive = 0; mypid = getpid(); } static void copyout(const void *osbuf, uint32_t embuf, uint32_t n, const char *what, void (*prefail)(void)) { uint32_t part; MEMSEG *ms; int left; uint32_t bp; left = n; bp = embuf; while (left > 0) { ms = memseg_find(bp,0,"read"); if (! (ms->prot & P_W)) { if (prefail) (*prefail)(); printf("%s: %08lx: not accessible\n",what,(ULI)bp); top(); } part = ms->end - bp; if (part > left) part = left; bcopy((bp-embuf)+(const char *)osbuf,ms->data+(bp-ms->base),part); bp += part; left -= part; } } static int do_execve(const char *path, const char **argvstrs, const char **envpstrs) { __label__ enoexec_; int efd; Elf32_Ehdr eh; Elf32_Phdr *ph; int nph; int i; int l; MEMSEG *ms; int narg; int nenv; uint32_t argv; uint32_t envp; uint32_t *argvv; uint32_t *envpv; uint32_t ps_strings; int stacklen; uint32_t sfp; void enoexec(void) { goto enoexec_; } void memfail(void) { free(argvv); free(envpv); } for (narg=0;argvstrs[narg];narg++) ; for (nenv=0;envpstrs[nenv];nenv++) ; efd = open(path,O_RDONLY,0); if (efd < 0) { i = errno; printf("execve: open %s: %s\n",path,strerror(i)); return(os2em_errno(i)); } if (0) { enoexec_:; close(efd); return(em_ENOEXEC); } if (read_exe(efd,&eh,sizeof(eh),0,path,"bad ELF file (can't read header)") < 0) enoexec(); 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",path); enoexec(); } if (eh.e_ident[EI_CLASS] != ELFCLASS32) { printf("%s: bad ELF file (class isn't 32-bit)\n",path); enoexec(); } if (ELF_HALF_TO_NATIVE(eh.e_machine) != EM_SPARC) { printf("%s: bad ELF file (machine isn't SPARC)\n",path); enoexec(); } if (ELF_HALF_TO_NATIVE(eh.e_type) != ET_EXEC) { printf("%s: bad ELF file (type isn't EXEC)\n",path); enoexec(); } if (ELF_HALF_TO_NATIVE(eh.e_phentsize) != sizeof(Elf32_Phdr)) { printf("%s: bad ELF file (phentsize isn't sizeof(Elf32_Phdr))\n",path); enoexec(); } nph = ELF_HALF_TO_NATIVE(eh.e_phnum); s.pc = ELF_ADDR_TO_NATIVE(eh.e_entry); s.npc = s.pc + 4; dbrk = 0; ph = malloc(nph*sizeof(Elf32_Phdr)); if (read_exe(efd,ph,nph*sizeof(Elf32_Phdr),ELF_ADDR_TO_NATIVE(eh.e_phoff),path,"bad ELF file (can't read program headers)") < 0) enoexec(); 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",path); enoexec(); 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); if (!align || (align & (align-1))) { printf("%s: p_align (%#lx) isn't a power of two\n",path,(ULI)align); enoexec(); } 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)); if (read_exe(efd,ms->data,fsz,fo,path,"bad ELF file (can't read program segment)") < 0) enoexec(); 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); /* * For dynamically-linked executables, we need Aux32Info structs as * well. The stack has to be laid out with sp pointing to argc, * followed by argc+1 pointers to arg strings (and a trailing nil), * then envp pointers (terminated by a trailing nil), then Aux32Info * structs (terminated by one with a_type set to AT_NULL). After * that comes whatever else - which here means the argv and envp * strings, the stack gap, the signal-delivery trampoline, and * ps_strings. * * For the sake of comparisons, we want our stack layout to exactly * match the kernel's. In aid of this, we do things in a slightly * strange order, so as to exactly match the kernel's computations. */ stacklen = 0; for (i=nenv-1;i>=0;i--) stacklen += strlen(envpstrs[i]) + 1; for (i=narg-1;i>=0;i--) stacklen += strlen(argvstrs[i]) + 1; stacklen = ROUND_UP(stacklen,8); stacklen = ((narg+nenv+2)*4) + // argv/envp pointers (16 * 4) + // Aux32Info structs 4 + // not sure stacklen + // argv/envp strings STACKGAPLEN + // stack gap SZSIGCODE + // signal trampoline 16; // ps_strings stacklen = ROUND_UP(stacklen,8); sfp = USRSTACK - stacklen; s.regs[R_SP] = sfp; // argc mem_set_4(sfp,narg); // argv/envp strings argvv = malloc(narg*sizeof(uint32_t)); argvv[narg] = 0; envpv = malloc(nenv*sizeof(uint32_t)); envpv[nenv] = 0; sfp = s.regs[R_SP] + (1 + narg + nenv + 2 + 16) * 4; for (i=0;i0;i--) { mem_set_4(sfp,0); sfp += 4; } // ps_strings ps_strings = USRSTACK - 16; mem_set_4(ps_strings,argv); mem_set_4(ps_strings+4,narg); mem_set_4(ps_strings+8,envp); mem_set_4(ps_strings+12,nenv); // signal-delivery trampoline sigtramp = ps_strings - SZSIGCODE; l = SZSIGCODE / 4; for (i=0;i=0;i--) argv[i] = args[i]; envp = 0; e = do_execve(exe,argv,&envp); if (e) { printf("Initial exec failed %d\n",e); free(argv); top(); } free(argv); } static int new_fd(int osfd, int minfd, unsigned int rw) { int d; FD *fd; int i; for (d=minfd;(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,0,P_R); new_fd(1,1,P_W); new_fd(2,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; } s.wdepth ++; } 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)); } s.wdepth --; } 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 uint32_t andncc(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 const char *nulterm_scarg(uint32_t ptr, NULTERM_STATUS *nts) { 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); nts->tofree = s; return(s); } static void nulterm_done(NULTERM_STATUS *nts) { free(nts->tofree); } static uint32_t scarg(SCARGS *args, int n) { if (n < 0) panic("impossible scarg"); if (n < args->nreg) return(args->regs[n]); if (! args->sp) panic("scarg overrun"); return(mem_get_4(args->sp+((23+n-args->nreg)*4))); } static void print_decoded_ioctl(FILE *to, uint32_t ioc) { switch (ioc & em_IOC_DIRMASK) { case em_IOC_VOID: if (em_IOC_LEN(ioc) == 0) { fprintf(to,"_IO('%c',%d)",em_IOC_GROUP(ioc),em_IOC_NUM(ioc)); } else { fprintf(to,"_IOC(IOC_VOID,'%c',%d,%d)",em_IOC_GROUP(ioc),em_IOC_NUM(ioc),em_IOC_LEN(ioc)); } break; case em_IOC_OUT: fprintf(to,"_IOR('%c',%d,%d)",em_IOC_GROUP(ioc),em_IOC_NUM(ioc),em_IOC_LEN(ioc)); break; case em_IOC_IN: fprintf(to,"_IOW('%c',%d,%d)",em_IOC_GROUP(ioc),em_IOC_NUM(ioc),em_IOC_LEN(ioc)); break; case em_IOC_INOUT: fprintf(to,"_IOWR('%c',%d,%d)",em_IOC_GROUP(ioc),em_IOC_NUM(ioc),em_IOC_LEN(ioc)); break; default: fprintf(to,"unknown"); break; } } static void copy_or_nulpad(const void *from, int fromlen, uint32_t to, int tolen, const char *what, void (*prefail)(void)) { int o; int n; if (fromlen < tolen) { copyout(from,to,fromlen,what,prefail); o = fromlen; while (o < tolen) { n = sizeof(nulbuf); if (n > tolen-o) n = tolen - o; copyout(&nulbuf[0],to+o,n,what,prefail); o += n; } } else { copyout(from,to,tolen,what,prefail); } } static void set_sig_handler(int ossig, uint32_t emsig, uint32_t handler) { if ((ossig < 0) || (ossig > 65536)) panic("impossible set_sig_handler"); if (ossig >= asigh) { int newa; newa = ossig + 8; sigh = realloc(sigh,newa*sizeof(*sigh)); while (asigh < newa) sigh[asigh++].emsig = 0; } sigh[ossig].emsig = emsig; sigh[ossig].handler = handler; } static void lookup_sig_handler(int ossig, uint32_t *emsigp, uint32_t *handlerp) { if ((ossig < 0) || (ossig > 65536)) panic("impossible lookup_sig_handler"); if (ossig >= asigh) { *emsigp = 0; return; } *emsigp = sigh[ossig].emsig; *handlerp = sigh[ossig].handler; } static void handle_signal(int sig) { uint32_t emsig; uint32_t handler; lookup_sig_handler(sig,&emsig,&handler); if (emsig) { printf("signal delivery not implemented"); top(); } else { printf("unhandled signal"); top(); } } 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 void store_rusage(uint32_t buf, const struct rusage *ru) { 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); } static void store_stat(uint32_t stp, const struct stat *stb) { 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 } #ifdef STATFS_VIA_STATVFS static void store_statfs(uint32_t buf, const struct statvfs *sf, const char *what, void (*prefail)(void)) { uint32_t emflags; emflags = ((sf->f_flag & MNT_RDONLY) ? em_MNT_RDONLY : 0) | ((sf->f_flag & MNT_SYNCHRONOUS) ? em_MNT_SYNCHRONOUS : 0) | ((sf->f_flag & MNT_NOEXEC) ? em_MNT_NOEXEC : 0) | ((sf->f_flag & MNT_NOSUID) ? em_MNT_NOSUID : 0) | ((sf->f_flag & MNT_NODEV) ? em_MNT_NODEV : 0) | ((sf->f_flag & MNT_UNION) ? em_MNT_UNION : 0) | ((sf->f_flag & MNT_ASYNC) ? em_MNT_ASYNC : 0) | ((sf->f_flag & MNT_EXRDONLY) ? em_MNT_EXRDONLY : 0) | ((sf->f_flag & MNT_EXPORTED) ? em_MNT_EXPORTED : 0) | ((sf->f_flag & MNT_DEFEXPORTED) ? em_MNT_DEFEXPORTED : 0) | ((sf->f_flag & MNT_EXPORTANON) ? em_MNT_EXPORTANON : 0) | ((sf->f_flag & MNT_EXKERB) ? em_MNT_EXKERB : 0) | ((sf->f_flag & MNT_LOCAL) ? em_MNT_LOCAL : 0) | ((sf->f_flag & MNT_QUOTA) ? em_MNT_QUOTA : 0) | ((sf->f_flag & MNT_ROOTFS) ? em_MNT_ROOTFS : 0) | ((sf->f_flag & MNT_NOCOREDUMP) ? em_MNT_NOCOREDUMP : 0) | ((sf->f_flag & MNT_NOATIME) ? em_MNT_NOATIME : 0) | ((sf->f_flag & MNT_EXNORESPORT) ? em_MNT_EXNORESPORT : 0) | ((sf->f_flag & MNT_EXPUBLIC) ? em_MNT_EXPUBLIC : 0) | ((sf->f_flag & MNT_SYMPERM) ? em_MNT_SYMPERM : 0) | ((sf->f_flag & MNT_NODEVMTIME) ? em_MNT_NODEVMTIME : 0) | ((sf->f_flag & MNT_SOFTDEP) ? em_MNT_SOFTDEP : 0); mem_set_2(buf,0); mem_set_2(buf+2,emflags&0xffff); mem_set_4(buf+4,sf->f_bsize); mem_set_4(buf+8,sf->f_iosize); mem_set_4(buf+12,sf->f_blocks); mem_set_4(buf+16,sf->f_bfree); mem_set_4(buf+20,sf->f_bavail); mem_set_4(buf+24,sf->f_files); mem_set_4(buf+28,sf->f_ffree); mem_set_4(buf+32,sf->f_fsidx.__fsid_val[0]); mem_set_4(buf+36,sf->f_fsidx.__fsid_val[1]); mem_set_4(buf+40,sf->f_owner); mem_set_4(buf+44,emflags); mem_set_4(buf+48,sf->f_syncwrites); mem_set_4(buf+52,sf->f_asyncwrites); mem_set_4(buf+56,0); copy_or_nulpad(&sf->f_fstypename[0],sizeof(sf->f_fstypename),buf+60,em_MFSNAMELEN,what,prefail); copy_or_nulpad(&sf->f_mntonname[0],sizeof(sf->f_mntonname),buf+76,em_MNAMELEN,what,prefail); copy_or_nulpad(&sf->f_mntfromname[0],sizeof(sf->f_mntfromname),buf+166,em_MNAMELEN,what,prefail); } #else static void store_statfs(uint32_t buf, const struct statfs *sf, const char *what, void (*prefail)(void)) { uint32_t emflags; emflags = ((sf->f_flags & MNT_RDONLY) ? em_MNT_RDONLY : 0) | ((sf->f_flags & MNT_SYNCHRONOUS) ? em_MNT_SYNCHRONOUS : 0) | ((sf->f_flags & MNT_NOEXEC) ? em_MNT_NOEXEC : 0) | ((sf->f_flags & MNT_NOSUID) ? em_MNT_NOSUID : 0) | ((sf->f_flags & MNT_NODEV) ? em_MNT_NODEV : 0) | ((sf->f_flags & MNT_UNION) ? em_MNT_UNION : 0) | ((sf->f_flags & MNT_ASYNC) ? em_MNT_ASYNC : 0) | ((sf->f_flags & MNT_EXRDONLY) ? em_MNT_EXRDONLY : 0) | ((sf->f_flags & MNT_EXPORTED) ? em_MNT_EXPORTED : 0) | ((sf->f_flags & MNT_DEFEXPORTED) ? em_MNT_DEFEXPORTED : 0) | ((sf->f_flags & MNT_EXPORTANON) ? em_MNT_EXPORTANON : 0) | ((sf->f_flags & MNT_EXKERB) ? em_MNT_EXKERB : 0) | ((sf->f_flags & MNT_LOCAL) ? em_MNT_LOCAL : 0) | ((sf->f_flags & MNT_QUOTA) ? em_MNT_QUOTA : 0) | ((sf->f_flags & MNT_ROOTFS) ? em_MNT_ROOTFS : 0) | ((sf->f_flags & MNT_NOCOREDUMP) ? em_MNT_NOCOREDUMP : 0) | ((sf->f_flags & MNT_NOATIME) ? em_MNT_NOATIME : 0) | ((sf->f_flags & MNT_EXNORESPORT) ? em_MNT_EXNORESPORT : 0) | ((sf->f_flags & MNT_EXPUBLIC) ? em_MNT_EXPUBLIC : 0) | ((sf->f_flags & MNT_SYMPERM) ? em_MNT_SYMPERM : 0) | ((sf->f_flags & MNT_NODEVMTIME) ? em_MNT_NODEVMTIME : 0) | ((sf->f_flags & MNT_SOFTDEP) ? em_MNT_SOFTDEP : 0); mem_set_2(buf,0); mem_set_2(buf+2,emflags&0xffff); mem_set_4(buf+4,sf->f_bsize); mem_set_4(buf+8,sf->f_iosize); mem_set_4(buf+12,sf->f_blocks); mem_set_4(buf+16,sf->f_bfree); mem_set_4(buf+20,sf->f_bavail); mem_set_4(buf+24,sf->f_files); mem_set_4(buf+28,sf->f_ffree); mem_set_4(buf+32,sf->f_fsid.val[0]); mem_set_4(buf+36,sf->f_fsid.val[1]); mem_set_4(buf+40,sf->f_owner); mem_set_4(buf+44,emflags); mem_set_4(buf+48,sf->f_syncwrites); mem_set_4(buf+52,sf->f_asyncwrites); mem_set_4(buf+56,0); copy_or_nulpad(&sf->f_fstypename[0],sizeof(sf->f_fstypename),buf+60,em_MFSNAMELEN,what,prefail); copy_or_nulpad(&sf->f_mntonname[0],sizeof(sf->f_mntonname),buf+76,em_MNAMELEN,what,prefail); copy_or_nulpad(&sf->f_mntfromname[0],sizeof(sf->f_mntfromname),buf+166,em_MNAMELEN,what,prefail); } #endif static FD *descriptor_arg(uint32_t arg, unsigned int prot, const char *call) { FD *fd; if (arg > nfds) { trc(TRC_SYSCALL,"%s fd %lu out of range -> EBADF\n",call,(ULI)arg); return(0); } fd = fds[arg]; if (! fd) { trc(TRC_SYSCALL,"%s fd %lu not open -> EBADF\n",call,(ULI)arg); return(0); } if (prot && !(fd->prot & prot)) { const char *pkind; switch (prot) { case P_R: pkind = "readable"; break; case P_W: pkind = "writable"; break; default: panic("bad prot to descriptor_arg"); break; } trc(TRC_SYSCALL,"%s fd %lu not %s -> EBADF\n",call,(ULI)arg,pkind); return(0); } return(fd); } static SYSCALL_IMPL(sc_getpid) { SYSCALL_RET2(getpid(),getppid()); } 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; nulterm_done(&nts); SYSCALL_ERR(os2em_errno(i)); } nulterm_done(&nts); trc(TRC_SYSCALL,"%d: readlink result %.*s\n",mypid,n,&buf[0]); 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); fd = descriptor_arg(d,P_W,"write"); if (! fd) 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(os2em_errno(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"); store_rusage(buf,&ru); 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); fd = descriptor_arg(d,0,"__fstat13"); if (! fd) SYSCALL_ERR(em_EBADF); if (fstat(fd->fd,&stb) < 0) panic("impossible fstat failure"); store_stat(stp,&stb); SYSCALL_RET(0); } static SYSCALL_IMPL(sc_ioctl) { uint32_t d; uint32_t ioc; uint32_t arg; FD *fd; int e; d = scarg(args,0); ioc = scarg(args,1); arg = scarg(args,2); fd = descriptor_arg(d,0,"ioctl"); if (! fd) SYSCALL_ERR(em_EBADF); switch (ioc) { case em_TIOCGETA: { struct termios tio; e = ioctl(fd->fd,TIOCGETA,&tio); if (e < 0) SYSCALL_ERR(os2em_errno(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; case em_TIOCGPGRP: { int iv; e = ioctl(fd->fd,TIOCGPGRP,&iv); if (e < 0) SYSCALL_ERR(os2em_errno(e)); mem_set_4(arg,iv); SYSCALL_RET(0); } break; case em_TIOCSPGRP: { int iv; iv = mem_get_4(arg); e = ioctl(fd->fd,TIOCSPGRP,&iv); if (e < 0) SYSCALL_ERR(os2em_errno(e)); SYSCALL_RET(0); } break; case em_TIOCGWINSZ: { struct winsize wsz; e = ioctl(fd->fd,TIOCGWINSZ,&wsz); if (e < 0) SYSCALL_ERR(os2em_errno(e)); mem_set_2(arg,wsz.ws_row); mem_set_2(arg+2,wsz.ws_col); mem_set_2(arg+4,wsz.ws_xpixel); mem_set_2(arg+6,wsz.ws_ypixel); 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) { const char *path; uint32_t how; int oshow; int e; NULTERM_STATUS nts; path = nulterm_scarg(scarg(args,0),&nts); 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; nulterm_done(&nts); SYSCALL_ERR(os2em_errno(e)); } nulterm_done(&nts); SYSCALL_RET(0); } static SYSCALL_IMPL(sc_open) { const char *path; uint32_t how; uint32_t perm; int oshow; int osfd; int e; int fdp; NULTERM_STATUS nts; uint32_t d; path = nulterm_scarg(scarg(args,0),&nts); how = scarg(args,1); 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; } #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 perm = (how & em_O_CREAT) ? scarg(args,2) : 0; osfd = open(path,oshow,perm); if (osfd < 0) { e = errno; nulterm_done(&nts); SYSCALL_ERR(os2em_errno(e)); } d = new_fd(osfd,0,fdp); nulterm_done(&nts); SYSCALL_RET(d); } static SYSCALL_IMPL(sc_read) { uint32_t d; uint32_t buf; uint32_t len; char *osbuf; FD *fd; int n; void fail(void) { free(osbuf); } d = scarg(args,0); buf = scarg(args,1); len = scarg(args,2); fd = descriptor_arg(d,P_R,"read"); if (! fd) 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(os2em_errno(n)); } copyout(osbuf,buf,n,"read",&fail); free(osbuf); SYSCALL_RET(n); } static SYSCALL_IMPL(sc_close) { uint32_t d; FD *fd; int e; d = scarg(args,0); fd = descriptor_arg(d,0,"close"); if (! fd) SYSCALL_ERR(em_EBADF); e = close(fd->fd); if (e < 0) SYSCALL_ERR(os2em_errno(errno)); fds[d] = 0; free(fd); SYSCALL_RET(0); } static SYSCALL_IMPL(sc_geteuid) { SYSCALL_RET(geteuid()); } static SYSCALL_IMPL(sc_getegid) { SYSCALL_RET(getegid()); } static SYSCALL_IMPL(sc_getuid) { SYSCALL_RET(getuid()); } static SYSCALL_IMPL(sc_getgid) { SYSCALL_RET(getgid()); } static SYSCALL_IMPL(sc___sigaction14) { uint32_t sig; uint32_t act; uint32_t oact; uint32_t v; uint32_t handler; int i; int j; int ossig; struct sigaction sa; struct sigaction *sap; struct sigaction osa; struct sigaction *osap; sigset_t mask; sigset_t omask; sig = scarg(args,0); act = scarg(args,1); oact = scarg(args,2); ossig = em2os_signal(sig); if (ossig == 0) SYSCALL_ERR(em_EINVAL); if (act) { sap = &sa; handler = mem_get_4(act); switch (handler) { case em_SIG_DFL: sa.sa_handler = SIG_DFL; break; case em_SIG_IGN: sa.sa_handler = SIG_IGN; break; default: sa.sa_handler = &handle_signal; break; } sigemptyset(&sa.sa_mask); for (i=0;i<4;i++) { v = mem_get_4(act+4+(i<<2)); for (j=0;j<32;j++) if ((v >> j) & 1) sigaddset(&sa.sa_mask,(i<<5)+j); } v = mem_get_4(act+20); sa.sa_flags = ((v & em_SA_ONSTACK) ? SA_ONSTACK : 0) | ((v & em_SA_RESTART) ? SA_RESTART : 0) | ((v & em_SA_RESETHAND) ? SA_RESETHAND : 0) | ((v & em_SA_NOCLDSTOP) ? SA_NOCLDSTOP : 0) | ((v & em_SA_NODEFER) ? SA_NODEFER : 0) | ((v & em_SA_SIGINFO) ? SA_SIGINFO : 0) | ((v & em_SA_NOCLDWAIT) ? SA_NOCLDWAIT : 0); } else { sap = 0; } if (oact) { sigemptyset(&osa.sa_mask); osap = &osa; } else { osap = 0; } sigfillset(&mask); sigemptyset(&omask); sigprocmask(SIG_BLOCK,&mask,&omask); if (sa.sa_handler == &handle_signal) { set_sig_handler(ossig,sig,handler); } else { set_sig_handler(ossig,0,handler); } i = sigaction(ossig,sap,osap); j = errno; sigprocmask(SIG_SETMASK,&omask,0); if (i < 0) SYSCALL_ERR(os2em_errno(j)); SYSCALL_RET(0); } static SYSCALL_IMPL(sc_getpgrp) { SYSCALL_RET(getpgrp()); } static SYSCALL_IMPL(sc_setpgid) { int e; e = setpgid(scarg(args,0),scarg(args,1)); if (e < 0) SYSCALL_ERR(os2em_errno(errno)); SYSCALL_RET(e); } static SYSCALL_IMPL(sc_wait4) { uint32_t wpid; uint32_t statusp; uint32_t options; uint32_t rusagep; int e; int st; struct rusage ru; wpid = scarg(args,0); statusp = scarg(args,1); options = scarg(args,2); rusagep = scarg(args,3); e = wait4( (wpid & 0x80000000) ? -(int)(int32_t)(uint32_t)-wpid : (int)wpid, &st, ((options & em_WUNTRACED) ? WUNTRACED : 0) | ((options & em_WNOHANG) ? WNOHANG : 0) | ((options & em_WALTSIG) ? WALTSIG : 0) | ((options & em_WNOREAP) ? WNOREAP : 0), &ru ); if (e < 0) SYSCALL_ERR(os2em_errno(errno)); if (e == 0) SYSCALL_RET(0); if (statusp) { if (em_WIFEXITED(st)) { mem_set_4(statusp,em_W_EXITCODE(WEXITSTATUS(st),0)); } else if (em_WIFSIGNALED(st)) { mem_set_4(statusp,em_W_DEADSIG(WTERMSIG(st),WCOREDUMP(st))); } else if (em_WIFSTOPPED(st)) { mem_set_4(statusp,em_W_STOPCODE(WSTOPSIG(st))); } else { printf("Undecipherable wait4 status %#x\n",st); top(); } } SYSCALL_RET(e); } static SYSCALL_IMPL(sc___getcwd) { uint32_t bufp; uint32_t len; char *osbuf; int e; void fail(void) { free(osbuf); } bufp = scarg(args,0); len = scarg(args,1); osbuf = malloc(len?:1); if (! osbuf) { printf("Out of memory allocating __getcwd() buffer\n"); top(); } e = __getcwd(osbuf,len); if (e < 0) { e = errno; free(osbuf); SYSCALL_ERR(os2em_errno(e)); } if (e > len) panic("impossible __getcwd return"); copyout(osbuf,bufp,e,"__getcwd",&fail); free(osbuf); SYSCALL_RET(e); } static SYSCALL_IMPL(sc_madvise) { // madvise() is advisory; we always ignore it SYSCALL_RET(0); } static SYSCALL_IMPL(sc___stat13) { const char *path; uint32_t stp; struct stat stb; int e; NULTERM_STATUS nts; path = nulterm_scarg(scarg(args,0),&nts); stp = scarg(args,1); e = stat(path,&stb); if (e < 0) { e = errno; nulterm_done(&nts); SYSCALL_ERR(os2em_errno(e)); } nulterm_done(&nts); store_stat(stp,&stb); SYSCALL_RET(0); } /* * The return semantics of fork()-the-syscall are undocumented. * UTSLing reveals the below: child returns <0,1>; parent, . */ static SYSCALL_IMPL(sc_fork) { pid_t kid; fflush(0); kid = fork(); if (kid < 0) SYSCALL_ERR(os2em_errno(errno)); if (kid == 0) { noninteractive = 1; mypid = getpid(); SYSCALL_RET2(0,1); } else { SYSCALL_RET2(kid,0); } } static SYSCALL_IMPL(sc_execve) { const char *path; uint32_t emargv; uint32_t emenvp; NULTERM_STATUS nts_path; MEMSEG *oldvm; STATE oldstate; const char **argv; int nargv; const char **envp; int nenvp; int i; int e; NULTERM_STATUS *nts_argv; NULTERM_STATUS *nts_envp; path = nulterm_scarg(scarg(args,0),&nts_path); emargv = scarg(args,1); emenvp = scarg(args,2); for (nargv=0;mem_get_4(emargv+(nargv<<2));nargv++) ; for (nenvp=0;mem_get_4(emenvp+(nenvp<<2));nenvp++) ; argv = malloc((nargv+1)*sizeof(char *)); envp = malloc((nenvp+1)*sizeof(char *)); nts_argv = malloc(nargv*sizeof(NULTERM_STATUS)); nts_envp = malloc(nenvp*sizeof(NULTERM_STATUS)); argv[nargv] = 0; for (i=nargv-1;i>=0;i--) argv[i] = nulterm_scarg(emargv+(i<<2),&nts_argv[i]); for (i=nenvp-1;i>=0;i--) envp[i] = nulterm_scarg(emenvp+(i<<2),&nts_envp[i]); oldstate = s; oldvm = vm; vm = 0; e = do_execve(path,argv,envp); if (! e) { for (i=nargv-1;i>=0;i--) nulterm_done(&nts_argv[i]); for (i=nenvp-1;i>=0;i--) nulterm_done(&nts_envp[i]); nulterm_done(&nts_path); destroy_vm(oldvm); rv->grflags = 0; SYSCALL_RET(0); } else { for (i=nargv-1;i>=0;i--) nulterm_done(&nts_argv[i]); for (i=nenvp-1;i>=0;i--) nulterm_done(&nts_envp[i]); nulterm_done(&nts_path); destroy_vm(vm); vm = oldvm; s = oldstate; SYSCALL_ERR(e); } } static SYSCALL_IMPL(sc_nanosleep) { uint32_t rqp; uint32_t rmp; struct timespec rq; struct timespec rm; int e; rqp = scarg(args,0); rmp = scarg(args,1); rq.tv_sec = mem_get_4(rqp); rq.tv_nsec = mem_get_4(rqp+4); e = nanosleep(&rq,rmp?&rm:0); if (e == 0) { SYSCALL_RET(0); } else if (e == -1) { e = os2em_errno(errno); if (rmp) { mem_set_4(rmp,rm.tv_sec); mem_set_4(rmp+4,rm.tv_nsec); } SYSCALL_ERR(e); } panic("impossible nanosleep return %d",e); } static SYSCALL_IMPL(sc_fchdir) { uint32_t d; FD *fd; d = scarg(args,0); fd = descriptor_arg(d,0,"fchdir"); if (! fd) SYSCALL_ERR(em_EBADF); if (fchdir(fd->fd) < 0) SYSCALL_ERR(os2em_errno(errno)); SYSCALL_RET(0); } static SYSCALL_IMPL(sc_fcntl) { uint32_t d; uint32_t cmd; FD *fd; int e; d = scarg(args,0); cmd = scarg(args,1); switch (cmd) { case em_F_DUPFD: case em_F_SETFD: fd = descriptor_arg(d,0,"fcntl"); if (! fd) SYSCALL_ERR(em_EBADF); break; default: printf("Unrecognized fcntl %lu\n",(ULI)cmd); top(); break; } switch (cmd) { case em_F_DUPFD: { int newos; newos = dup(fd->fd); if (newos < 0) SYSCALL_ERR(os2em_errno(errno)); e = new_fd(newos,scarg(args,2),fd->prot); } break; case em_F_SETFD: e = fcntl(fd->fd,F_SETFD,(int)(scarg(args,2)&1)); break; default: panic("impossible fcntl"); break; } if (e < 0) SYSCALL_ERR(os2em_errno(e)); SYSCALL_RET(e); } static SYSCALL_IMPL(sc_fstatfs) { uint32_t d; uint32_t bufp; #ifdef STATFS_VIA_STATVFS struct statvfs sf; #else struct statfs sf; #endif FD *fd; int e; d = scarg(args,0); bufp = scarg(args,1); fd = descriptor_arg(d,0,"fstatfs"); if (! fd) SYSCALL_ERR(em_EBADF); #ifdef STATFS_VIA_STATVFS e = fstatvfs(fd->fd,&sf); #else e = fstatfs(fd->fd,&sf); #endif if (e < 0) SYSCALL_ERR(os2em_errno(errno)); store_statfs(bufp,&sf,"statfs",0); SYSCALL_RET(0); } static SYSCALL_IMPL(sc_lseek) { uint32_t d; uint64_t off; uint32_t whence; FD *fd; off_t e; int oswhence; d = scarg(args,0); // args[1] is unused padding off = (((uint64_t)scarg(args,2)) << 32) | scarg(args,3); whence = scarg(args,4); fd = descriptor_arg(d,0,"lseek"); if (! fd) SYSCALL_ERR(em_EBADF); switch (whence) { case em_SEEK_SET: oswhence = SEEK_SET; break; case em_SEEK_CUR: oswhence = SEEK_CUR; break; case em_SEEK_END: oswhence = SEEK_END; break; default: SYSCALL_ERR(em_EINVAL); break; } e = lseek(fd->fd,off,oswhence); if (e < 0) SYSCALL_ERR(os2em_errno(errno)); SYSCALL_RET2((e>>16)>>16,e); } /* * This is a hard case. * * getdents()'s API (a) is defined (by the 1.4T manpage) in terms of a * struct containing unsigned long and unsigned short, but actually * defined by the implementation in terms of uint32_t, uint16_t, and * uint8_t - and provides d_type, which is not in the manpage. * * Worse, we can't really tell whether the implementation we're running * on has a larger or smaller struct dirent than 1.4T/sparc, and/or * has weaker alignment requirements. This means that we may get more * entries than can fit into the buffer provided. * * However, no known version has such problems, so we panic if we run * into them. * * We really should copy structs dirent out of osbuf into a struct * dirent. But we don't have any good way to know how much to copy. * So we do what the API is apparently designed for and overlay the * struct onto the buffer - which means we have to malloc the buffer, * since we have no other way of ensuring it's suitably aligned (we * could allocate it as an array of structs dirent, but that has its * own problems). */ static SYSCALL_IMPL(sc_getdents) { uint32_t d; uint32_t buf; uint32_t size; FD *fd; char *osbuf; int e; int oso; int emo; uint32_t left; struct dirent *osde; uint8_t dt; int l; void fail(void) { free(osbuf); } d = scarg(args,0); buf = scarg(args,1); size = scarg(args,2); fd = descriptor_arg(d,P_R,"getdents"); if (! fd) SYSCALL_ERR(em_EBADF); osbuf = malloc(size); if (! osbuf) { printf("Out of memory allocating __getcwd() buffer\n"); top(); } e = getdents(fd->fd,osbuf,size); if (e < 0) SYSCALL_ERR(os2em_errno(errno)); oso = 0; emo = 0; left = size; while (oso < e) { if (oso+_DIRENT_MINSIZE(osde) > e) panic("getdents() partial (min)"); osde = (void *)(osbuf+oso); if (oso+osde->d_namlen > e) panic("getdents() partial (actual)"); if (osde->d_namlen > 255) { printf("getdents: d_namlen %d > 255, skipping entry\n",(int)osde->d_namlen); } else { l = 8 + ROUND_UP(osde->d_namlen+1,4); if (left < l) panic("getdents() overrun"); mem_set_4(buf+emo,osde->d_fileno); mem_set_2(buf+emo+4,l); switch (osde->d_type) { case DT_UNKNOWN: dt = em_DT_UNKNOWN; break; case DT_FIFO: dt = em_DT_FIFO; break; case DT_CHR: dt = em_DT_CHR; break; case DT_DIR: dt = em_DT_DIR; break; case DT_BLK: dt = em_DT_BLK; break; case DT_REG: dt = em_DT_REG; break; case DT_LNK: dt = em_DT_LNK; break; case DT_SOCK: dt = em_DT_SOCK; break; case DT_WHT: dt = em_DT_WHT; break; default: dt = em_DT_UNKNOWN; break; } mem_set_1(buf+emo+6,dt); mem_set_1(buf+emo+7,osde->d_namlen); copyout(&osde->d_name[0],buf+emo+8,osde->d_namlen,"getdents",&fail); copyout(&nulbuf[0],buf+emo+8+osde->d_namlen,l-(8+osde->d_namlen),"getdents",&fail); emo += l; } oso += osde->d_reclen; } SYSCALL_RET(emo); } static SYSENT sysent[] = { SYSINIT(exit,"V","d"), // 1 SYSINIT(fork,"d",""), // 2 SYSINIT(read,"d","dpd"), // 3 SYSINIT(write,"d","dpd"), // 4 SYSINIT(open,"d","sf(" // 5 "2@0:0=O_RDONLY,1=O_WRONLY,2=O_RDWR,3=O_NOACCESS;" "2:O_NONBLOCK;" "3:O_APPEND;" "4:O_SHLOCK;" "5:O_EXLOCK;" "6:O_ASYNC;" "7:O_SYNC;" "9:O_CREAT;" "10:O_TRUNC;" "11:O_EXCL;" "15:O_NOCTTY;" "16:O_DSYNC;" "18:O_ALT_IO;" "20:O_DIRECTORY;" "21:O_PLAIN)" "O"), SYSINIT(close,"V","d"), // 6 SYSINIT(wait4,"d","dpf(" // 7 "0:WNOHANG;" "1:WUNTRACED;" "2:WALTSIG;" "3:WNOREAP)" "p"), SYSINIT(fchdir,"V","d"), // 13 SYSINIT(break,"V","p"), // 17 SYSINIT(getpid,"dd",""), // 20 SYSINIT(getuid,"d",""), // 24 SYSINIT(geteuid,"d",""), // 25 SYSINIT(access,"V","sf(" // 33 "0:X_OK;" "1:W_OK;" "2:R_OK)"), SYSINIT(getegid,"d",""), // 43 SYSINIT(getgid,"d",""), // 47 SYSINIT(ioctl,"d","dv(IOCTL)p"), // 54 SYSINIT(readlink,"d","spd"), // 58 SYSINIT(execve,"V","sxx"), // 59 SYSINIT(madvise,"V","pdv(MADV)"), // 75 SYSINIT(getpgrp,"d",""), // 81 SYSINIT(setpgid,"V","dd"), // 82 SYSINIT(fcntl,"d","dv(FCNTL)b"), // 92 SYSINIT(gettimeofday,"V","pp"), // 116 SYSINIT(getrusage,"V","v(RUSAGE)p"), // 117 SYSINIT(fstatfs,"V","dp"), // 158 SYSINIT(mmap,"p","pdf(" // 197 "0:PROT_READ;" "1:PROT_WRITE;" "2:PROT_EXEC)" "f(" "0:MAP_SHARED;" "1:MAP_PRIVATE;" "2:MAP_COPY;" "4:MAP_FIXED;" "5:MAP_RENAME;" "6:MAP_NORESERVE;" "7:MAP_INHERIT;" "8:MAP_NOEXTEND;" "9:MAP_HASSEMAPHORE;" "1@12:0=MAP_FILE,1=MAP_ANON)" "dD"), SYSINIT(lseek,"D","d-Dv(LSEEK)"), // 199 SYSINIT(__sysctl,"d","mpppd"), // 202 SYSINIT(nanosleep,"V","pp"), // 240 SYSINIT(getdents,"d","dpd"), // 272 SYSINIT(__stat13,"V","sp"), // 278 SYSINIT(__fstat13,"V","dp"), // 279 SYSINIT(__sigaction14,"V","v(SIG)pp"), // 291 SYSINIT(__getcwd,"d","pd"), // 296 [0] = { 0, 0 } }; static const int nsysent = sizeof(sysent) / sizeof(sysent[0]); static const char *print_f_bits(FILE *f, const char *str, uint32_t val) { char *ep; long int n; long int m; uint32_t c; uint32_t mask; unsigned long int v; int i; int any; int found; if (*str++ != '(') panic("print_syscall_values: invalid f, no ("); any = 0; while (1) { n = strtol(str,&ep,10); if (ep == str) panic("print_syscall_values: invalid f, bad first #"); str = ep; switch (*str++) { default: panic("print_syscall_values: invalid f, bad number terminator"); break; case ':': if ((n < 0) || (n > 31)) panic("print_syscall_values: invalid f, bit # out of range"); for (i=0;str[i]&&(str[i]!=';')&&(str[i]!=')');i++) ; if (! str[i]) panic("print_syscall_values: invalid f, bad string terminator"); if (val & (((uint32_t)1) << n)) { fprintf(f,"%s%.*s",any?"|":"",i,str); val &= ~(((uint32_t)1) << n); any = 1; } str += i; break; case '@': m = strtol(str,&ep,10); if (ep == str) panic("print_syscall_values: invalid f, bad second #"); str = ep; if (*str++ != ':') panic("print_syscall_values: invalid f, bad second terminator"); if ((n < 1) || (m < 0) || (n > 32) || (m > 31) || (n+m > 32)) panic("print_syscall_values: invalid f, bad n@m"); c = val >> m; mask = (n < 32) ? (((uint32_t)1) << n) - 1 : ~(uint32_t)0; c &= mask; val &= ~(mask << m); found = 0; while (1) { v = strtoul(str,&ep,0); if (ep == str) panic("print_syscall_values: invalid f, bad test value"); if (*ep != '=') panic("print_syscall_values: invalid f, bad test terminator"); str = ep + 1; if (v & ~(unsigned long int)mask) panic("print_syscall_values: invalid f, impossible test value"); for (i=0;str[i]&&(str[i]!=',')&&(str[i]!=';')&&(str[i]!=')');i++) ; if (! str[i]) panic("print_syscall_values: invalid f, bad test string terminator"); if (c == v) { if (found) panic("print_syscall_values: invalid f, value %lu found twice",(ULI)c); fprintf(f,"%s%.*s",any?"|":"",i,str); any = 1; found = 1; } str += i; if (*str != ',') break; str ++; } if (! found) panic("print_syscall_values: invalid f, value %lu not found\n",(ULI)c); break; } if (*str != ';') break; str ++; } if (*str != ')') panic("print_syscall_values: invalid f, no )"); if (val) fprintf(f,"%s%08lx",any?"|":"",(ULI)val); return(str+1); } static const char *print_v_value(FILE *f, const char *str, uint32_t val) { const char *close; const char *pv; if (*str++ != '(') panic("print_syscall_values: invalid v, no ("); close = index(str,')'); if (! close) panic("print_syscall_values: invalid v, no )"); pv = 0; do <"printed"> { do <"good"> { switch (close-str) { case 3: if (!bcmp(str,"SIG",3)) { switch (val) { case em_SIGHUP: pv = "SIGHUP"; break; case em_SIGINT: pv = "SIGINT"; break; case em_SIGQUIT: pv = "SIGQUIT"; break; case em_SIGILL: pv = "SIGILL"; break; case em_SIGTRAP: pv = "SIGTRAP"; break; case em_SIGABRT: pv = "SIGABRT"; break; case em_SIGEMT: pv = "SIGEMT"; break; case em_SIGFPE: pv = "SIGFPE"; break; case em_SIGKILL: pv = "SIGKILL"; break; case em_SIGBUS: pv = "SIGBUS"; break; case em_SIGSEGV: pv = "SIGSEGV"; break; case em_SIGSYS: pv = "SIGSYS"; break; case em_SIGPIPE: pv = "SIGPIPE"; break; case em_SIGALRM: pv = "SIGALRM"; break; case em_SIGTERM: pv = "SIGTERM"; break; case em_SIGURG: pv = "SIGURG"; break; case em_SIGSTOP: pv = "SIGSTOP"; break; case em_SIGTSTP: pv = "SIGTSTP"; break; case em_SIGCONT: pv = "SIGCONT"; break; case em_SIGCHLD: pv = "SIGCHLD"; break; case em_SIGTTIN: pv = "SIGTTIN"; break; case em_SIGTTOU: pv = "SIGTTOU"; break; case em_SIGIO: pv = "SIGIO"; break; case em_SIGXCPU: pv = "SIGXCPU"; break; case em_SIGXFSZ: pv = "SIGXFSZ"; break; case em_SIGVTALRM: pv = "SIGVTALRM"; break; case em_SIGPROF: pv = "SIGPROF"; break; case em_SIGWINCH: pv = "SIGWINCH"; break; case em_SIGINFO: pv = "SIGINFO"; break; case em_SIGUSR1: pv = "SIGUSR1"; break; case em_SIGUSR2: pv = "SIGUSR2"; break; case em_SIGPWR: pv = "SIGPWR"; break; } break <"good">; } break; case 4: if (!bcmp(str,"MADV",4)) { switch (val) { case em_MADV_NORMAL: pv = "NORMAL"; break; case em_MADV_RANDOM: pv = "RANDOM"; break; case em_MADV_SEQUENTIAL: pv = "SEQUENTIAL"; break; case em_MADV_WILLNEED: pv = "WILLNEED"; break; case em_MADV_DONTNEED: pv = "DONTNEED"; break; case em_MADV_SPACEAVAIL: pv = "SPACEAVAIL"; break; case em_MADV_FREE: pv = "FREE"; break; } break <"good">; } break; case 5: switch (str[0]) { case 'I': if (!bcmp(str,"IOCTL",5)) { switch (val) { case em_TIOCGETA: pv = "TIOCGETA"; break; case em_TIOCGWINSZ: pv = "TIOCGWINSZ"; break; case em_TIOCSPGRP: pv = "TIOCSPGRP"; break; case em_TIOCGPGRP: pv = "TIOCGPGRP"; break; default: fprintf(f,"%08lx=",(ULI)val); print_decoded_ioctl(f,val); break <"printed">; } break <"good">; } break; case 'F': if (!bcmp(str,"FCNTL",5)) { switch (val) { case em_F_DUPFD: pv = "F_DUPFD"; break; case em_F_GETFD: pv = "F_GETFD"; break; case em_F_SETFD: pv = "F_SETFD"; break; case em_F_GETFL: pv = "F_GETFL"; break; case em_F_SETFL: pv = "F_SETFL"; break; case em_F_GETOWN: pv = "F_GETOWN"; break; case em_F_SETOWN: pv = "F_SETOWN"; break; case em_F_GETLK: pv = "F_GETLK"; break; case em_F_SETLK: pv = "F_SETLK"; break; case em_F_SETLKW: pv = "F_SETLKW"; break; case em_F_CLOSEM: pv = "F_CLOSEM"; break; } break <"good">; } break; case 'L': if (!bcmp(str,"LSEEK",5)) { switch (val) { case em_SEEK_SET: pv = "SEEK_SET"; break; case em_SEEK_CUR: pv = "SEEK_CUR"; break; case em_SEEK_END: pv = "SEEK_END"; break; } break <"good">; } break; } break; case 6: if (!bcmp(str,"RUSAGE",6)) { switch (val) { case em_RUSAGE_SELF: pv = "RUSAGE_SELF"; break; case em_RUSAGE_CHILDREN: pv = "RUSAGE_CHILDREN"; break; } break <"good">; } break; } panic("print_syscall_values: invalid v, string unrecognized"); } while (0); if (pv) { fprintf(f,"%s",pv); } else { fprintf(f,"%lu=unrecognized",(ULI)val); } } while (0); return(close+1); } static void print_syscall_values(FILE *f, const char *str, SCARGS *vals) { int vx; uint32_t v; vx = 0; nomemacc ++; while <"loop"> (*str) { if (vx) fprintf(f,", "); switch (*str++) { case 'd': fprintf(f,"%ld",(LI)(int32_t)scarg(vals,vx++)); break; case 'p': case 'x': // same as p for the moment v = scarg(vals,vx++); if (v) fprintf(f,"%08lx",(ULI)v); else fprintf(f,"0"); break; case 'b': v = scarg(vals,vx++); fprintf(f,"%#lx=%ld",(ULI)v,(LI)(int32_t)v); break; case 's': { uint8_t c; int defer; v = scarg(vals,vx++); fprintf(f,"%08lx=\"",(ULI)v); defer = -1; while (1) { c = mem_get_1(v++); if (defer >= 0) { if ((c >= '0') && (c <= '9')) { fprintf(f,"\\%03o",defer); } else { fprintf(f,"\\%o",defer); } defer = -1; } if (! c) break; switch (c) { case '\a': fprintf(f,"\\a"); break; case '\b': fprintf(f,"\\b"); break; case '\e': fprintf(f,"\\e"); break; case '\f': fprintf(f,"\\f"); break; case '\n': fprintf(f,"\\n"); break; case '\r': fprintf(f,"\\r"); break; case '\t': fprintf(f,"\\t"); break; case '\v': fprintf(f,"\\v"); break; case '\\': fprintf(f,"\\\\"); break; default: if (c < 31) { defer = c; } else if ((c >= 127) && (c < 160)) { fprintf(f,"\\%o",c); } else { fprintf(f,"%c",c); } break; } } fprintf(f,"\""); } break; case 'o': fprintf(f,"%#lo",(ULI)scarg(vals,vx++)); break; case '-': fprintf(f,"pad"); vx ++; break; case 'O': if (scarg(vals,1) & em_O_CREAT) { fprintf(f,"%#lo",(ULI)scarg(vals,vx++)); } else { fprintf(f,"..."); vx ++; } break; case 'D': { uint64_t v64; v64 = scarg(vals,vx++); v64 = (v64 << 32) | scarg(vals,vx++); fprintf(f,"%lld",(ULLI)(int64_t)v64); } break; case 'm': { uint32_t v2; uint32_t elt; int first; v = scarg(vals,vx++); v2 = scarg(vals,vx++); fprintf(f,"%08lx/%ld=",(ULI)v,(ULI)v2); first = 1; while (v2) { elt = mem_get_4(v); v += 4; v2 --; fprintf(f,"%s%ld",first?"":".",(LI)(int32_t)elt); first = 0; } } break; case 'f': str = print_f_bits(f,str,scarg(vals,vx++)); break; case 'v': str = print_v_value(f,str,scarg(vals,vx++)); break; default: panic("print_syscall_values: invalid key char %02x\n",(unsigned char)str[-1]); break; } } nomemacc --; } static void dosyscall(uint32_t id) { SCARGS args; uint32_t callno; SCRV rv; uint32_t g2; uint32_t g7; void (*fn)(SCARGS *, SCRV *); FILE *f; 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 & ~(em_SYSCALL_G2RFLAG | em_SYSCALL_G7RFLAG); trc(TRC_SYSCALL,"%d: (%llu) syscall CALL %d (",mypid,s.instrs,callno); 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; trc(TRC_SYSCALL,"__syscall -> %d (",callno); if ((callno >= nsysent) || !sysent[callno].name) { trc(TRC_SYSCALL,"?)"); } else { trc(TRC_SYSCALL,"%s)",sysent[callno].name); } } else { if ((callno >= nsysent) || !sysent[callno].name) { trc(TRC_SYSCALL,"?"); } else { trc(TRC_SYSCALL,"%s",sysent[callno].name); } } f = trc_f(TRC_SYSCALL); if (f) { fprintf(f,") ("); print_syscall_values(f,sysent[callno].args,&args); fprintf(f,")\n"); } rv.err = 0; rv.rv = 0; rv.rv2 = s.regs[R_O1]; rv.grflags = id & (em_SYSCALL_G2RFLAG | em_SYSCALL_G7RFLAG); if (callno >= nsysent) { printf("Unknown syscall %08lx\n",(ULI)callno); top(); } fn = sysent[callno].impl; if (! fn) { printf("Unknown syscall %08lx\n",(ULI)callno); top(); } (*fn)(&args,&rv); trc(TRC_SYSCALL,"%d: (%llu) syscall RET ",mypid,s.instrs); if (rv.err == 0) { f = trc_f(TRC_SYSCALL); if (f) { fprintf(f,"success"); if (sysent[callno].rv[0] != 'V') { SCARGS a; a.regs[0] = rv.rv; a.regs[1] = rv.rv2; a.sp = 0; a.nreg = 2; fprintf(f," "); print_syscall_values(f,sysent[callno].rv,&a); } fprintf(f,", returning to "); } if (rv.grflags & em_SYSCALL_G2RFLAG) { s.pc = g2; s.npc = s.pc + 4; trc(TRC_SYSCALL,"%%g2\n"); } else if (rv.grflags & em_SYSCALL_G7RFLAG) { s.pc = g7; s.npc = s.pc + 4; trc(TRC_SYSCALL,"%%g7\n"); } else { s.cc &= ~CC_C; trc(TRC_SYSCALL,"pc/npc\n"); } s.regs[R_O0] = rv.rv; s.regs[R_O1] = rv.rv2; } else { s.regs[R_O0] = rv.err; trc(TRC_SYSCALL,"error %lu (%s)\n",(ULI)rv.err,em_strerror(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 mulscc(int dr, int sr1, uint32_t v) { uint32_t t; uint32_t t2; t2 = s.regs[sr1] & 1; t = s.regs[sr1] >> 1; switch (s.cc & (CC_N | CC_V)) { case 0: case CC_N | CC_V: break; case CC_N: case CC_V: t |= 0x80000000; break; } s.regs[dr] = addcc(t,(s.y&1)?v:0); s.y = (s.y >> 1) | (t2 << 31); } static void instr_(void) { uint32_t xa; uint32_t inst; uint32_t a; uint32_t v; uint32_t v2; 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; } s.instrs ++; 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 21: // andncc s.regs[DREG(inst)] = andncc(s.regs[SREG1(inst)],I(inst)?SIMM13(inst):s.regs[SREG2(inst)]); break; case 36: // mulscc mulscc(DREG(inst),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 40: // rd %y s.regs[DREG(inst)] = s.y; break; case 48: // wr %y s.y = s.regs[SREG1(inst)] ^ (I(inst) ? SIMM13(inst) : s.regs[SREG2(inst)]); 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,"%d: (%llu) pc %08lx, code %08lx",mypid,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 (postexec) { if (trc_if(TRC_STACK)) { if (s.regs[R_SP] & 3) panic("post-exec stack (%08lx) misaligned\n",(ULI)s.regs[R_SP]); if (trc_if(TRC_STACK)) { FILE *f; uint32_t a; uint32_t v; f = trc_f(TRC_STACK); nomemacc ++; a = s.regs[R_SP]; fprintf(f,"sp = %08lx\n",(ULI)a); if (a & 0xf) fprintf(f,"%08lx: %*s",(ULI)(a&~(uint32_t)0xf),(int)(((a&0xf)>>2)*9),""); for (;a<(uint32_t)USRSTACK;a+=4) { v = mem_get_4(a); if ((a & 0xf) == 0) fprintf(f,"%08lx: ",(ULI)a); fprintf(f," %08lx",(ULI)v); if ((a & 0xf) == 0xc) fprintf(f,"\n"); } #if USRSTACK & 0xf fprintf(f,"\n"); #endif nomemacc --; fflush(f); } } postexec = 0; } if (trc_if(TRC_INSTR)) { nomemacc ++; do_instr_trc(); nomemacc --; } 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|O_TRUNC,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 init_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,"%d: chg: ",mypid); 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; if (s.wdepth != prevstate->wdepth) { pref(); trc(TRC_CHG," wd=%u",s.wdepth); } 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.y != prevstate->y) { pref(); trc(TRC_CHG," y=%08lx",(ULI)s.y); } 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 |= 1ULL << PRINT_REGS_NPC; cp = ep; } else if ((ep-cp == 2) && !strncmp(cp,"pc",2)) { mask |= 1ULL << PRINT_REGS_PC; cp = ep; } else if ((ep-cp == 2) && !strncmp(cp,"cc",2)) { mask |= 1ULL << PRINT_REGS_CC; cp = ep; } else if ((ep-cp == 1) && !strncmp(cp,"y",1)) { mask |= 1ULL << PRINT_REGS_Y; cp = ep; } else { badregname:; printf("unknown register name `%.*s'\n",(int)(ep-cp),cp); mask |= 1ULL << PRINT_REGS_BAD; } } } } if (mask == 0) mask = PRINT_REGS_ALL; if (! (mask & (1ULL << PRINT_REGS_BAD))) 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 (noninteractive) { printf("\n(exiting, non-interactive)\n"); fflush(0); exit(1); } 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); init_trc(); init_fds(); setup(); initial_exec(); run(); return(0); }