/* This file is in the public domain. */ #if !defined(SUN_MMAP) && !defined(NeXT_MMAP) && !defined(NetBSD_MMAP) #if defined(__NetBSD__) #define NetBSD_MMAP #elif defined(sun) #define SUN_MMAP #elif defined(NeXT) #define NeXT_MMAP #else #define NO_MMAP #endif #endif #include #include #include #include #include #include #include #include #include #include #ifdef SUN_MMAP #include #include #endif #ifdef NeXT_MMAP #include #include #endif #ifdef NetBSD_MMAP #include #endif extern const char *__progname; #include "htable.h" #include "machine.h" #include "fnprintf.h" #define beep disas_beep /* damn it! curses.h has taken over beep()! */ #if defined(sun) extern void *sbrk(unsigned int); #endif typedef struct isrc ISRC; typedef struct astack ASTACK; struct astack { DPOS *stk; DPOS *wtop; int alloc; int depth; } ; struct isrc { ISRC *link; FILE *f; } ; static ISRC *istack; static int istack_chars; unsigned long int coresize; ADDR corebase; ADDR coreend; CFLAG *flags; DPOS loc; static const char *core; static void *symtbl_n; static void *symtbl_a; static void *annotations; static WIN Wroot; #define wroot (&Wroot) static int allredraw; static LINE *lines; static WIN *curwin; static int mustrecenter; static ASTACK stack; static int curline; static FILE *fileio_f; static char *datafile = 0; static char *basestr = 0; static MACHINE *machine = 0; static char *saved_S_file = 0; static char *saved_T_file = 0; static char *saved_Y_file = 0; static void cffill(CFLAG *ptr, int ncf, CFLAG v) { if (sizeof(CFLAG) == 1) { memset(ptr,v,ncf); } else { for (;ncf>0;ncf--) *ptr++ = v; } } static unsigned long int readcflags(FILE *f, CFLAG *fv, unsigned long int nf) { return(fread(fv,1,nf,f)); } static void writecflags(FILE *f, CFLAG *fv, unsigned long int nf) { fwrite(fv,1,nf,f); } static unsigned int symtbl_n_hash(const void *sym, int tblsiz) { return(string_hfxn(((const SYMBOL *)sym)->name,tblsiz)); } static int symtbl_n_cmp(const void *s1, const void *s2) { return(string_cmpfxn(((const SYMBOL *)s1)->name,((const SYMBOL *)s2)->name)); } static unsigned int symtbl_a_hash(const void *sym, int tblsiz) { return(((const SYMBOL *)sym)->addr % tblsiz); } static int symtbl_a_cmp(const void *s1, const void *s2) { int sa1; int sa2; sa1 = ((const SYMBOL *)s1)->addr; sa2 = ((const SYMBOL *)s2)->addr; if (sa1 < sa2) { return(-1); } else if (sa1 > sa2) { return(1); } return(0); } static unsigned int annotation_hash(const void *ann, int tblsiz) { return(((const ANNOTATION *)ann)->addr % tblsiz); } static int annotation_cmp(const void *a1, const void *a2) { int aa1; int aa2; aa1 = ((const ANNOTATION *)a1)->addr; aa2 = ((const ANNOTATION *)a2)->addr; if (aa1 < aa2) { return(-1); } else if (aa1 > aa2) { return(1); } return(0); } static void *alloc_once(unsigned int nb) { #if defined(sun) return(sbrk(nb)); #else return(malloc(nb)); #endif } static void *mmap_file(int fd, unsigned long int size) { #ifdef SUN_MMAP void *rv; rv = mmap(0,size,PROT_READ,MAP_SHARED,fd,0); if (rv == (void *)-1) { fprintf(stderr,"%s: can't mmap data file: %s\n",__progname,strerror(errno)); exit(1); } return(rv); #endif #ifdef NetBSD_MMAP void *rv; rv = mmap(0,size,PROT_READ,MAP_SHARED,fd,0); if (rv == (void *)-1) { fprintf(stderr,"%s: can't mmap data file: %s\n",__progname,strerror(errno)); exit(1); } return(rv); #endif #ifdef NeXT_MMAP vm_offset_t rv; kern_return_t krv; rv = 0; krv = map_fd(fd,0,&rv,1,size); if (krv != KERN_SUCCESS) { fprintf(stderr,"%s: can't mmap data file: %s\n",__progname,mach_error_string(krv)); exit(1); } return((void *)rv); #endif #ifdef NO_MMAP void *rv; int left; int did; char *bp; rv = malloc(size); if (rv == 0) { fprintf(stderr,"%s: can't allocate memory for data file\n",__progname); exit(1); } bp = rv; left = size; while (left > 0) { did = read(fd,bp,left); if (did < 0) { fprintf(stderr,"%s: read error on data file: %s\n",__progname,strerror(errno)); exit(1); } if (did == 0) { fprintf(stderr,"%s: unexpected EOF on data file\n",__progname); exit(1); } left -= did; bp += did; } return(rv); #endif } static void free_symbol(SYMBOL *s) { free(s->name); free(s); } static void free_symbol_v(void *svp) { free_symbol(svp); } static void free_note(NOTE *n) { int i; if (! n) return; for (i=n->nlines-1;i>=0;i--) free(n->text[i]); free(n->text); free(n); } static void free_annotation(ANNOTATION *a) { if (! a) return; free_note(a->before); free_note(a->on); free_note(a->after); free(a); } static void free_annotation_v(void *avp) { free_annotation(avp); } static void free_stack(ASTACK s) { free(s.stk); free(s.wtop); } static void delete_symbol(SYMBOL *s) { del_this_hentry(symtbl_n,s); del_this_hentry(symtbl_a,s); free_symbol(s); } static SYMBOL *symbol_for_name(char *name) { SYMBOL s; void *svp; s.name = name; svp = find_hentry(symtbl_n,&s); return(svp?(SYMBOL *)svp:0); } ANNOTATION *annotation_for_addr(ADDR addr) { ANNOTATION a; void *avp; a.addr = addr; avp = find_hentry(annotations,&a); return(avp?:0); } SYMBOL *symbol_for_addr(ADDR addr) { SYMBOL s; void *svp; s.addr = addr; svp = find_hentry(symtbl_a,&s); return(svp?:0); } #if 0 static ADDR sym_le_addr; static SYMBOL *sym_le_sym; static void symbol_le_chk(void *sv) { SYMBOL *s; s = sv; if (s->addr > sym_le_addr) return; if (sym_le_sym && (s->addr <= sym_le_sym->addr)) return; sym_le_sym = s; } static SYMBOL *symbol_le_addr(ADDR addr) { sym_le_addr = addr; sym_le_sym = 0; map_htable(symtbl_a,symbol_le_chk); return(sym_le_sym); } #endif static void istack_push(FILE *f) { ISRC *i; if (! istack) istack_chars = 0; i = malloc(sizeof(ISRC)); i->f = f; i->link = istack; istack = i; } static ISRC *istack_pop(void) { ISRC *t; t = istack; istack = t->link; return(t); } static int istack_get(void) { while (istack) { int c; c = getc(istack->f); if (c != EOF) { istack_chars ++; if (! (istack_chars % 10000)) { move(LINES-1,0); standout(); printw("[%d]",istack_chars); clrtoeol(); refresh(); } return(c); } fclose(istack->f); free(istack_pop()); } return(EOF); } static void istack_flush(void) { while (istack) { fclose(istack->f); free(istack_pop()); } } static void set_symbol(char *name, ADDR addr) { SYMBOL *s; s = symbol_for_name(name); if (s) { del_this_hentry(symtbl_a,s); s->addr = addr; add_new_hentry(symtbl_a,s); free(name); return; } s = malloc(sizeof(SYMBOL)); s->name = name; s->addr = addr; add_new_hentry(symtbl_n,s); add_new_hentry(symtbl_a,s); } int print_quoted_string(void (*fn)(char), ADDR *op, int maxcols, int len, unsigned int flg) #define o (*op) { unsigned int c; int col; int rv; int pnxt; if (! (flg & PQSF_NOQUOTES)) fnprintf(fn,"\""); col = 0; while (1) { if (len == 0) { rv = 0; break; } else if (len > 0) { len --; } if (o >= coresize) { rv = 0; break; } c = corefetchu(o++,1); if (o >= coresize) { pnxt = 0; } else { pnxt = 1; switch (len) { case PQS_TONUL: if (c == 0) pnxt = 0; break; case PQS_CFPREV: if (flags[o] != CF_PREV) pnxt = 0; break; default: if (len < 0) abort(); if (len == 0) pnxt = 0; break; } } if ((c < 32) || (c > 126)) { switch (c) { default: if (pnxt && isdigit(corefetchu(o,1))) { col += fnprintf(fn,"\\%03o",c); } else { col += fnprintf(fn,"\\%o",c); } break; case '\b': col += fnprintf(fn,"\\b"); break; case '\33':col += fnprintf(fn,"\\e"); break; case '\f': col += fnprintf(fn,"\\f"); break; case '\n': col += fnprintf(fn,"\\n"); break; case '\r': col += fnprintf(fn,"\\r"); break; case '\t': col += fnprintf(fn,"\\t"); break; } } else if ((c == '\\') || (c == '"')) { col += fnprintf(fn,"\\%c",c); } else { fnprintf(fn,"%c",c); col ++; } if (! pnxt) { rv = 0; break; } if ((maxcols > 0) && (col >= maxcols)) { rv = 1; break; } } if (! (flg & PQSF_NOQUOTES)) fnprintf(fn,"\""); return(rv); } #undef o void maybe_print_stringptr(void (*fn)(char), ADDR a) { if (fn && (a >= corebase) && (a < coreend)) { ADDR o; ADDR e; o = a - corebase; for (a=o;(flags[a]==CF_PREV)||(flags[a]==CF_CSTR);a--) ; switch (flags[a]) { case CF_STR: fnprintf(fn," <"); if (a != o) fnprintf(fn,"%ld+",o-a); if (print_quoted_string(fn,&a,20,PQS_TONUL,0)) fnprintf(fn,"..."); fnprintf(fn,">"); break; case CF_SBLK: for (e=o;(e"); break; } } } void print_symbol_or_hex(void (*fn)(char), ADDR a) { SYMBOL *s; s = symbol_for_addr(a); if (s) { fnprintf(fn,"%s",s->name); } else { fnprintf(fn,"%#lx",(unsigned long int)a); } maybe_print_stringptr(fn,a); } void maybe_print_ptrlit(void (*fn)(char), unsigned long int v) { SYMBOL *s; s = symbol_for_addr(v); if (s) fnprintf(fn,"<%s>",s->name); } static void create_htables(void) { symtbl_n = new_htable(symtbl_n_hash,symtbl_n_cmp); symtbl_a = new_htable(symtbl_a_hash,symtbl_a_cmp); annotations = new_htable(annotation_hash,annotation_cmp); } static void init_stack(void) { stack.stk = 0; stack.wtop = 0; stack.alloc = 0; stack.depth = 0; } static void startup(const char *fn, const char *basestr) { int fd; int i; struct stat stb; if (! machine) { fprintf(stderr,"%s: no machine type specified\n",__progname); exit(1); } corebase = basestr ? strtoul(basestr,0,0) : 0; fd = open(fn,O_RDONLY,0); if (fd < 0) { fprintf(stderr,"%s: can't open %s: %s\n",__progname,fn,strerror(errno)); exit(1); } fstat(fd,&stb); coresize = stb.st_size; coreend = corebase + coresize; core = mmap_file(fd,coresize); close(fd); flags = alloc_once(coresize); cffill(flags,coresize,CF_NULL); initscr(); lines = alloc_once(LINES*sizeof(LINE)); cbreak(); nonl(); noecho(); create_htables(); init_stack(); curwin = malloc(sizeof(WIN)); wroot->flink = curwin; wroot->blink = curwin; curwin->flink = wroot; curwin->blink = wroot; curwin->firstline = 0; curwin->lastline = LINES-2; curwin->top = locoff(0); allredraw = 1; loc = locoff(0); loc.type = DLT_ON; for (i=0;iinit)(); istack = 0; } DPOS locaddr(ADDR a) { ADDR o; if ((a < corebase) || (a >= coreend)) return((DPOS){.type=DLT_NOSUCH}); o = a - corebase; while ((o > 0) && ISPREV(flags[o])) o --; return((DPOS) { .type = DLT_ON, .laddr = o + corebase, .ann = annotation_for_addr(o+corebase), .u = { .on = { .addr = a, .aoff = a-corebase } } }); } DPOS loc_upline_nosuch(DPOS l) { ADDR o; switch (l.type) { default: abort(); break; case DLT_NOSUCH: return(l); break; case DLT_ON: if (l.ann && l.ann->before) { l.type = DLT_BEFORE; l.u.alno = l.ann->before->nlines - 1; return(l); } break; case DLT_BEFORE: if (l.u.alno > 0) { l.u.alno --; return(l); } break; case DLT_AFTER: if (l.u.alno > 0) { l.u.alno --; } else { l.type = DLT_ON; l.u.on.addr = l.laddr; l.u.on.aoff = l.laddr - corebase; } return(l); break; case DLT_LEGACY: return((DPOS){.type=DLT_NOSUCH}); break; } o = l.laddr - corebase; if (o < 1) return((DPOS){.type=DLT_NOSUCH}); do { o --; } while ((o > 0) && ISPREV(flags[o])); l = locoff(o); if (l.ann && l.ann->after) { l.type = DLT_AFTER; l.u.alno = l.ann->after->nlines - 1; } return(l); } DPOS loc_dnline_nosuch(DPOS l) { ADDR o; switch (l.type) { default: abort(); break; case DLT_NOSUCH: return(l); break; case DLT_ON: if (l.ann && l.ann->after) { l.type = DLT_AFTER; l.u.alno = 0; return(l); } break; case DLT_BEFORE: l.u.alno ++; if (l.u.alno >= l.ann->before->nlines) { l.type = DLT_ON; l.u.on.addr = l.laddr; l.u.on.aoff = l.laddr - corebase; } return(l); break; case DLT_AFTER: l.u.alno ++; if (l.u.alno < l.ann->after->nlines) return(l); break; case DLT_LEGACY: return((DPOS){.type=DLT_NOSUCH}); break; } o = (l.laddr - corebase) + 1; while ((o < coresize) && ISPREV(flags[o])) o ++; l = locoff(o); if (l.ann && l.ann->before) { l.type = DLT_BEFORE; l.u.alno = 0; } return(l); } DPOS loc_upline_stop(DPOS l) { DPOS l2; l2 = loc_upline_nosuch(l); return((l2.type == DLT_NOSUCH) ? l : l2); } DPOS loc_dnline_stop(DPOS l) { DPOS l2; l2 = loc_dnline_nosuch(l); return((l2.type == DLT_NOSUCH) ? l : l2); } static void recenterwin(void) { int i; DPOS l; l = loc; if (ISPREV(flags[loc.laddr-corebase])) loc = locaddr((l.type==DLT_ON)?loc.u.on.addr:loc.laddr); for (i=(curwin->lastline-curwin->firstline)/2;i>0;i--) { l = loc_upline_stop(l); } curwin->top = l; curwin->redraw = 1; } void beep(void) { write(1,"\7",1); istack_flush(); } void disas_redraw_cur(void) { curwin->redraw = 1; } int checkchange(int noisy) { if (loc.type == DLT_ON) return(0); if (noisy) { beep(); return(1); } return(0); } int changecur(int noisy) { ADDR o; if (checkchange(noisy)) return(1); o = loc.u.on.aoff; switch (flags[o]) { case CF_CSTR: flags[o] = CF_PREV; /* fall through */ case CF_PREV: for (;(flags[o]==CF_PREV)||(flags[o]==CF_CSTR);o--) ; switch (flags[o]) { case CF_SPC: break; case CF_STR: for (;oredraw = 1; return(0); } unsigned long int corefetchu(ADDR off, int size) { return((*machine->corefetch)(core+off,size)); } long int corefetchs(ADDR off, int size) { unsigned long int u; u = corefetchu(off,size); if (u & (1UL << ((8*size)-1))) u |= (~0xffUL) << (8*(size-1)); return(u); } static int do_dis_byte(ADDR addr, void (*fn)(char)) { fnprintf(fn,".byte %02lx",corefetchu(addr-corebase,1)); flags[addr-corebase] = CF_BYTE; return(1); } static int do_dis_word(ADDR addr, void (*fn)(char)) { if (addr+2 > coreend) return(-1); addr -= corebase; fnprintf(fn,".word %04lx",corefetchu(addr,2)); flags[addr++] = CF_WORD; flags[addr++] = CF_PREV; return(2); } static int do_dis_long(ADDR addr, void (*fn)(char)) { if (addr+4 > coreend) return(-1); addr -= corebase; fnprintf(fn,".long %08lx",corefetchu(addr,4)); flags[addr++] = CF_LONG; flags[addr++] = CF_PREV; flags[addr++] = CF_PREV; flags[addr++] = CF_PREV; return(4); } static int do_dis_char(ADDR addr, void (*fn)(char)) { unsigned int c; c = corefetchu(addr-corebase,1); if ((c < 32) || (c > 126)) { switch (c) { default: fnprintf(fn,".char '\\%o'",c); break; case '\b': fnprintf(fn,".char '\\b'"); break; case '\33': fnprintf(fn,".char '\\e'"); break; case '\f': fnprintf(fn,".char '\\f'"); break; case '\n': fnprintf(fn,".char '\\n'"); break; case '\r': fnprintf(fn,".char '\\r'"); break; case '\t': fnprintf(fn,".char '\\t'"); break; } } else if ((c == '\\') || (c == '\'')) { fnprintf(fn,".char '\\%c'",c); } else { fnprintf(fn,".char '%c'",c); } flags[addr-corebase] = CF_CHAR; return(1); } static int do_dis_string(ADDR addr, void (*fn)(char), int contd) { ADDR orig; ADDR i; int overlen; addr -= corebase; orig = addr; fnprintf(fn,".string "); overlen = print_quoted_string(fn,&addr,40,PQS_TONUL,0); flags[orig] = contd ? CF_CSTR : CF_STR; for (i=orig+1;iptrsize > coreend) return(-1); addr -= corebase; fnprintf(fn,".ptr "); print_symbol_or_hex(fn,corefetchu(addr,machine->ptrsize)); flags[addr++] = CF_PTR; for (i=machine->ptrsize;i>1;i--) flags[addr++] = CF_PREV; return(machine->ptrsize); } static int do_dis_chunk(ADDR addr, void (*fn)(char)) { ADDR a; int n; addr -= corebase; fnprintf(fn,".chunk "); for (a=addr+1,n=1;(a= coresize) return(-1); while (1) { switch (flags[o]) { default: rv = (*machine->dis)(addr,fn); break; case CF_PREV: { ADDR i; for (i=o-1;flags[i]==CF_PREV;i--) ; for (;idis)(addr,fn); if (rv < 0) { ADDR i; for (i=o;idis)(addr,fn); break; case CF_BYTE: rv = do_dis_byte(addr,fn); break; case CF_WORD: rv = do_dis_word(addr,fn); break; case CF_LONG: rv = do_dis_long(addr,fn); break; case CF_CHAR: rv = do_dis_char(addr,fn); break; case CF_STR: rv = do_dis_string(addr,fn,0); break; case CF_CSTR: rv = do_dis_string(addr,fn,1); break; case CF_SBLK: rv = do_dis_strblk(addr,fn); break; case CF_SPC: rv = do_dis_space(addr,fn); break; case CF_PTR: rv = do_dis_ptr(addr,fn); break; case CF_CPREV: flags[o] = CF_CHUNK; /* fall through */ case CF_CHUNK: rv = do_dis_chunk(addr,fn); break; } if (rv == 0) continue; return(rv); } } static int skip(ADDR addr) { return(do_dis(addr,0)); } static void window_write(char ch) { addch(ch); } static void disas(ADDR addr) { SYMBOL *sp; sp = symbol_for_addr(addr); if (sp) { printw("%12s: ",sp->name); } else { printw("%12lx: ",(unsigned long int)addr); } do_dis(addr,&window_write); } int getstr(const char *prompt, char **strp, char **savestrp) { char *buf; int len; int have; int c; have = 9; buf = malloc(have); len = 0; while (1) { if (! istack) { move(LINES-1,0); standout(); addstr(prompt); if (savestrp && *savestrp && (len == 0)) { addstr(*savestrp); clrtoeol(); move(LINES-1,strlen(prompt)); } else { buf[len] = '\0'; addstr(buf); clrtoeol(); } refresh(); c = getch(); } else { c = istack_get(); if (c == EOF) continue; } switch (c) { default: if (isprint(c)) { buf[len++] = c; if (len >= have) { buf = realloc(buf,have=len+10); } } break; case '\7': beep(); free(buf); return(-1); break; case '\r': case '\n': if (! istack) standend(); buf[len] = '\0'; if (savestrp) { if ((len == 0) && *savestrp) { free(buf); buf = strdup(*savestrp); } else { free(*savestrp); *savestrp = strdup(buf); } } *strp = buf; return(0); break; case '\177': case '\b': if (len < 1) { beep(); } else { len --; } break; } } } static int geta(const char *prompt, ADDR *ap) { char xnum[65]; int nchars; int c; nchars = 0; while (1) { if (! istack) { move(LINES-1,0); standout(); addstr(prompt); xnum[nchars] = '\0'; addstr(xnum); clrtoeol(); refresh(); c = getch(); } else { c = istack_get(); if (c == EOF) continue; } switch <"typedchar"> (c) { default: beep(); break; case '.': if (nchars == 0) { xnum[0] = '.'; nchars = 1; } else { beep(); } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'a': case 'A': case 'b': case 'B': case 'c': case 'C': case 'd': case 'D': case 'e': case 'E': case 'f': case 'F': if ((nchars > 0) && (xnum[0] == '.')) { beep(); break; } if ((nchars >= sizeof(xnum)-1) && (xnum[0] == '0')) { bcopy(&xnum[1],&xnum[0],sizeof(xnum)-1); nchars = sizeof(xnum) - 2; } if (nchars >= sizeof(xnum)-1) { beep(); } else { xnum[nchars++] = c; } break; case '\7': beep(); return(-1); break; case '\r': case '\n': if (nchars == 0) { beep(); } else { if (xnum[0] == '.') { switch (loc.type) { default: abort(); break; case DLT_NOSUCH: case DLT_LEGACY: beep(); break <"typedchar">; case DLT_ON: *ap = loc.u.on.addr; break; case DLT_BEFORE: case DLT_AFTER: *ap = loc.laddr; break; } } else { unsigned long int v; xnum[nchars] = '\0'; sscanf(xnum,"%lx",&v); *ap = v; } if (! istack) standend(); return(0); } break; case '\177': case '\b': if (nchars == 0) { beep(); } else { nchars --; } break; } } } static int to_ul(const char *s, unsigned long int *vp, int defbase) { int base; char *e; unsigned long int v; base = 0; if (s[0] == '0') { switch (s[1]) { case 'b': case 'B': base = 2; break; case 'o': case 'O': base = 8; break; case 't': case 'T': base = 10; break; case 'x': case 'X': base = 16; break; } } if (base == 0) base = defbase; else s += 2; v = strtoul(s,&e,base); if (*e || (s == e)) return(0); *vp = v; return(1); } static void a_command(void) { char *astr; SYMBOL *s; ADDR addr; if (getstr("Address ",&astr,0) < 0) return; s = symbol_for_name(astr); if (s) { addr = s->addr; } else { unsigned long int uli; if (! to_ul(astr,&uli,16)) { beep(); free(astr); return; } addr = uli; } if ((addr < corebase) || (addr >= coreend)) { beep(); } else { loc = locaddr(addr); recenterwin(); } free(astr); } static void A_command(void) { char *lstr; unsigned long int len; int over; ADDR o; ADDR a; ADDR orig; if (checkchange(1)) return; if (getstr("Length ",&lstr,0) < 0) return; if (! to_ul(lstr,&len,10)) { beep(); free(lstr); return; } a = loc.u.on.aoff; if ((len > coresize) || (a+len > coresize)) len = coresize - a; if (len < 1) return; if (changecur(1)) abort(); do { flags[a] = CF_SBLK; orig = a; over = print_quoted_string(0,&a,40,len,0); for (o=orig+1;o0)&&(flags[o]==CF_PREV);o--) ; if (flags[o] == CF_SPC) { flags[loc.u.on.aoff] = CF_PREV; loc = locoff(o); if (--curline < curwin->firstline) recenterwin(); } else { flags[loc.u.on.aoff] = CF_SPC; } curwin->redraw = 1; } o = loc.u.on.aoff + 1; while ( (o < coresize) && (core[o] == 0) && !symbol_for_addr(corebase+o) && ( (flags[o] == f) || (flags[o] == CF_PREV) || (flags[o] == CF_NULL) ) ) { flags[o++] = CF_PREV; } if ((o < coresize) && (flags[o] == CF_PREV)) flags[o] = CF_BYTE; } static void c_command(void) { if (changecur(1)) return; flags[loc.u.on.aoff] = CF_CHAR; } static void C_command(void) { char *nstr; int n; ADDR o; int inchunk; if (checkchange(1)) return; if (getstr("Chunk size ",&nstr,0) < 0) return; n = atoi(nstr); if (n < 1) { beep(); return; } if (n > coresize-loc.u.on.aoff) n = coresize - loc.u.on.aoff; if (changecur(1)) abort(); o = loc.u.on.aoff; inchunk = (flags[o] == CF_CHUNK); flags[o++] = CF_CHUNK; for (;n>1;n--) { inchunk = (flags[o] == CF_CHUNK) || (inchunk && (flags[o] == CF_CPREV)); flags[o++] = CF_CPREV; } if ((o < coresize) && inchunk && (flags[o] == CF_CPREV)) flags[o] = CF_NULL; } static void H_command(void) { LINE *l; l = &lines[curline]; l->type = LT_DIS; l->flags |= LF_REDRAW; curline = curwin->firstline; l = &lines[curline]; l->type = LT_CURDIS; l->flags |= LF_REDRAW; loc = l->loc; lines[curwin->lastline].flags |= LF_REDRAW; } static void i_command(void) { if (changecur(1)) return; if ((flags[loc.u.on.aoff] & ~CFF_INST) != CF_INST) { flags[loc.u.on.aoff] = CF_INST; } } static void I_command(void) { if (changecur(1)) return; if ((flags[loc.u.on.aoff] & ~CFF_INST) != CF_INST) { flags[loc.u.on.aoff] = CF_INST | CFF_INST_PTRLITS; } else { flags[loc.u.on.aoff] ^= CFF_INST_PTRLITS; } } static void j_command(void) { DPOS l; l = loc_dnline_nosuch(loc); if (l.type == DLT_NOSUCH) { beep(); return; } loc = l; if (++curline >= curwin->lastline) { recenterwin(); } else { register LINE *l; l = &lines[curline]; l->type = LT_CURDIS; l->flags |= LF_REDRAW; l --; l->type = LT_DIS; l->flags |= LF_REDRAW; lines[curwin->lastline].flags |= LF_REDRAW; } } static void k_command(void) { DPOS l; if ((loc.type == DLT_ON) && (loc.u.on.addr != loc.laddr)) { loc.u.on.addr = loc.laddr; loc.u.on.aoff = loc.laddr - corebase; lines[curline].type = LT_CURDIS; lines[curline].flags |= LF_REDRAW; return; } l = loc_upline_nosuch(loc); if (l.type == DLT_NOSUCH) { beep(); return; } if (flags[l.laddr-corebase] == CF_NULL) { beep(); return; } loc = l; if (--curline < curwin->firstline) { recenterwin(); } else { register LINE *l; l = &lines[curline]; l->type = LT_CURDIS; l->flags |= LF_REDRAW; l ++; l->type = LT_DIS; l->flags |= LF_REDRAW; lines[curwin->lastline].flags |= LF_REDRAW; } } static void l_command(void) { if (changecur(1)) return; flags[loc.u.on.aoff] = CF_LONG; } static void L_command(void) { LINE *l; l = &lines[curline]; l->type = LT_DIS; l->flags |= LF_REDRAW; curline = curwin->lastline - 1; while ((curline > 0) && (lines[curline].loc.type == DLT_NOSUCH)) curline --; l = &lines[curline]; l->type = LT_CURDIS; l->flags |= LF_REDRAW; loc = l->loc; lines[curwin->lastline].flags |= LF_REDRAW; } static void o_command(void) { char *name; ADDR value; SYMBOL *s; if (getstr("Overriding symbol name ",&name,0) < 0) return; if (geta("Overriding symbol value ",&value) < 0) return; while (1) { s = symbol_for_addr(value); if (!s) break; delete_symbol(s); } set_symbol(name,value); allredraw = 1; } static void p_command(void) { if (changecur(1)) return; flags[loc.u.on.aoff] = CF_PTR; } static void ensure_stack(void) { if (stack.depth >= stack.alloc) { stack.alloc = stack.depth + 8; stack.stk = realloc(stack.stk,stack.alloc*sizeof(*stack.stk)); stack.wtop = realloc(stack.wtop,stack.alloc*sizeof(*stack.wtop)); } } static void read_historic(FILE *f, void (*fail)(const char *)) { unsigned long int uli; int i; char *sn; ADDR curaddr; char mnfmt[32]; char machinename[256]; ADDR *stk; static void lose(const char *s) { free(stk); (*fail)(s); } stk = 0; sprintf(&mnfmt[0],"%%%lus",sizeof(machinename)-2UL); if (fscanf(f,&mnfmt[0],&machinename[0]) != 1) lose("can't read machine name"); if (strcmp(&machinename[0],machine->names[0])) lose("for another machine"); if (fscanf(f,"%lu",&uli) != 1) lose("can't read coresize"); if (uli != coresize) lose("coresize different"); if (fscanf(f,"%lu",&uli) != 1) lose("can't read corebase"); if (uli != corebase) lose("corebase different"); if (fscanf(f,"%lu",&uli) != 1) lose("can't get curaddr"); if ((uli < corebase) || (uli >= coreend)) lose("curaddr out of range"); curaddr = uli; if (fscanf(f,"%d",&i) != 1) lose("can't get stack depth"); if (i < 0) lose("negative stack depth"); stack.depth = i; ensure_stack(); stk = malloc(i*sizeof(ADDR)); for (i=0;i= coreend)) lose("stack element out of range"); stk[i] = uli; } do { i = getc(f); if (i == EOF) lose("EOF before flag vector"); } while (i != '.'); if (readcflags(f,flags,coresize) != coresize) lose("can't read flag vector"); while (1) { if (fscanf(f,"%d",&i) != 1) lose("can't read symbol length"); if (i == 0) break; sn = malloc(i+1); if (getc(f) != ':') lose("symbol : isn't"); if (fread(sn,1,i,f) != i) lose("can't read symbol name"); sn[i] = '\0'; if (fscanf(f,"%lu",&uli) != 1) lose("can't read symbol addr"); set_symbol(sn,uli); } for (i=0;ibefore || (i >= l.ann->before->nlines) ) return((DPOS){.type=DLT_NOSUCH}); l.type = DLT_BEFORE; l.u.alno = i; break; case 'a': if (fscanf(f,"%lu%d",&uli,&i) != 2) return((DPOS){.type=DLT_NOSUCH}); l = locaddr(uli); if (l.laddr != l.u.on.addr) return((DPOS){.type=DLT_NOSUCH}); if ( (i < 0) || !l.ann || !l.ann->after || (i >= l.ann->after->nlines) ) return((DPOS){.type=DLT_NOSUCH}); l.type = DLT_AFTER; l.u.alno = i; break; default: return((DPOS){.type=DLT_NOSUCH}); break; } return(l); } sprintf(&mnfmt[0],"%%%lus",sizeof(machinename)-2UL); if (fscanf(f,&mnfmt[0],&machinename[0]) != 1) lose("can't read machine name"); if (strcmp(&machinename[0],machine->names[0])) lose("for another machine"); if (fscanf(f,"%lu",&uli) != 1) lose("can't read coresize"); if (uli != coresize) lose("coresize different"); if (fscanf(f,"%lu",&uli) != 1) lose("can't read corebase"); if (uli != corebase) lose("corebase different"); while (1) { if (fscanf(f,"%d",&i) != 1) lose("can't read symbol length"); if (i == 0) break; sn = malloc(i+1); if (getc(f) != ':') lose("symbol's : isn't"); if (fread(sn,1,i,f) != i) lose("can't read symbol name"); sn[i] = '\0'; if (fscanf(f,"%lu",&uli) != 1) lose("can't read symbol addr"); set_symbol(sn,uli); } while (1) { int want_b; int want_o; int want_a; ANNOTATION *a; static void losea(const char *s) { free_annotation(a); lose(s); } static NOTE *get_note(void) { NOTE *n; int i; int l; char *t; if (fscanf(f,"%d",&i) != 1) losea("can't read line count"); if (i < 1) losea("invalid line count"); n = malloc(sizeof(NOTE)); n->nlines = i; n->alines = i; n->text = malloc(i*sizeof(char *)); for (i=0;inlines;i++) { t = 0; if ( (fscanf(f,"%d",&l) != 1) || (getc(f) != ':') || ((t=malloc(l+1)),(fread(t,1,l,f)!=l)) ) { for (i--;i>=0;i--) free(n->text[i]); free(n->text); free(n); free(t); losea("can't read text"); } t[l] = '\0'; n->text[i] = t; } return(n); } a = malloc(sizeof(ANNOTATION)); a->before = 0; a->on = 0; a->after = 0; do i = getc(f); while (i == '\n'); if (i == '.') break; if (i == 'b') { want_b = 1; i = getc(f); } else want_b = 0; if (i == 'o') { want_o = 1; i = getc(f); } else want_o = 0; if (i == 'a') { want_a = 1; i = getc(f); } else want_a = 0; ungetc(i,f); if (!want_b && !want_o && !want_a) losea("bad annotation flags"); if (want_b) a->before = get_note(); if (want_o) a->on = get_note(); if (want_a) a->after = get_note(); if (a->on && (a->on->nlines != 1)) losea("`on' nlines != 1"); if (fscanf(f,"%lu",&uli) != 1) losea("can't read annotation addr"); a->addr = uli; if (new_annotation(a)) losea("duplicate annotation"); } i = getc(f); if (i != '\n') lose("newline before flags isn't"); if (readcflags(f,flags,coresize) != coresize) lose("can't read flag vector"); curloc = get_loc(); if (curloc.type == DLT_NOSUCH) lose("invalid curloc"); if (fscanf(f,"%d",&i) != 1) lose("can't read stack depth"); if (i < 0) lose("stack depth negative"); stack.depth = i; ensure_stack(); for (i=0;ibefore || (i >= l.ann->before->nlines) ) return((DPOS){.type=DLT_NOSUCH}); l.type = DLT_BEFORE; l.u.alno = i; break; case 'a': if (fscanf(f,"%lu%d",&uli,&i) != 2) return((DPOS){.type=DLT_NOSUCH}); l = locaddr(uli); if (l.laddr != l.u.on.addr) return((DPOS){.type=DLT_NOSUCH}); if ( (i < 0) || !l.ann || !l.ann->after || (i >= l.ann->after->nlines) ) return((DPOS){.type=DLT_NOSUCH}); l.type = DLT_AFTER; l.u.alno = i; break; case 'l': if (! legacyok) return((DPOS){.type=DLT_NOSUCH}); l.type = DLT_LEGACY; break; default: return((DPOS){.type=DLT_NOSUCH}); break; } return(l); } sprintf(&mnfmt[0],"%%%lus",sizeof(machinename)-2UL); if (fscanf(f,&mnfmt[0],&machinename[0]) != 1) lose("can't read machine name"); if (strcmp(&machinename[0],machine->names[0])) lose("for another machine"); if (fscanf(f,"%lu",&uli) != 1) lose("can't read coresize"); if (uli != coresize) lose("coresize different"); if (fscanf(f,"%lu",&uli) != 1) lose("can't read corebase"); if (uli != corebase) lose("corebase different"); while (1) { if (fscanf(f,"%d",&i) != 1) lose("can't read symbol length"); if (i == 0) break; sn = malloc(i+1); if (getc(f) != ':') lose("symbol's : isn't"); if (fread(sn,1,i,f) != i) lose("can't read symbol name"); sn[i] = '\0'; if (fscanf(f,"%lu",&uli) != 1) lose("can't read symbol addr"); set_symbol(sn,uli); } while (1) { int want_b; int want_o; int want_a; ANNOTATION *a; static void losea(const char *s) { free_annotation(a); lose(s); } static NOTE *get_note(void) { NOTE *n; int i; int l; char *t; if (fscanf(f,"%d",&i) != 1) losea("can't read line count"); if (i < 1) losea("invalid line count"); n = malloc(sizeof(NOTE)); n->nlines = i; n->alines = i; n->text = malloc(i*sizeof(char *)); for (i=0;inlines;i++) { t = 0; if ( (fscanf(f,"%d",&l) != 1) || (getc(f) != ':') || ((t=malloc(l+1)),(fread(t,1,l,f)!=l)) ) { for (i--;i>=0;i--) free(n->text[i]); free(n->text); free(n); free(t); losea("can't read text"); } t[l] = '\0'; n->text[i] = t; } return(n); } a = malloc(sizeof(ANNOTATION)); a->before = 0; a->on = 0; a->after = 0; do i = getc(f); while (i == '\n'); if (i == '.') break; if (i == 'b') { want_b = 1; i = getc(f); } else want_b = 0; if (i == 'o') { want_o = 1; i = getc(f); } else want_o = 0; if (i == 'a') { want_a = 1; i = getc(f); } else want_a = 0; ungetc(i,f); if (!want_b && !want_o && !want_a) losea("bad annotation flags"); if (want_b) a->before = get_note(); if (want_o) a->on = get_note(); if (want_a) a->after = get_note(); if (a->on && (a->on->nlines != 1)) losea("`on' nlines != 1"); if (fscanf(f,"%lu",&uli) != 1) losea("can't read annotation addr"); a->addr = uli; if (new_annotation(a)) losea("duplicate annotation"); } i = getc(f); if (i != '\n') lose("newline before flags isn't"); if (readcflags(f,flags,coresize) != coresize) lose("can't read flag vector"); curloc = get_loc(0); if (curloc.type == DLT_NOSUCH) lose("invalid curloc"); if (fscanf(f,"%d",&i) != 1) lose("can't read stack depth"); if (i < 0) lose("stack depth negative"); stack.depth = i; ensure_stack(); for (i=0;i slash))) { if (! saved_T_file) asprintf(&saved_T_file,"%.*s.txt",(int)(dot-fn),fn); if (! saved_Y_file) asprintf(&saved_Y_file,"%.*s.sym",(int)(dot-fn),fn); } } f = fopen(fn,"r"); free(fn); if (f == 0) { beep(); move(LINES-1,0); standout(); printw("Can't open %.*s [any key to continue]",COLS-34,fn); clrtoeol(); refresh(); getch(); return; } if (0) { bad: uli = ftell(f); beep(); fclose(f); move(LINES-1,0); standout(); printw("Error at offset %lu: %s [any key to continue]",uli,failmsg); clrtoeol(); refresh(); getch(); map_htable(symtbl_n,free_symbol_v); free_htable(symtbl_n); free_htable(symtbl_a); map_htable(annotations,free_annotation_v); free_htable(annotations); free_stack(stack); bcopy(save_flags,flags,coresize*sizeof(CFLAG)); save_symtbl_n = symtbl_n; save_symtbl_a = symtbl_a; save_annotations = annotations; stack = save_stack; free(save_flags); return; } save_flags = malloc(coresize*sizeof(CFLAG)); bcopy(flags,save_flags,coresize*sizeof(CFLAG)); save_symtbl_n = symtbl_n; save_symtbl_a = symtbl_a; save_annotations = annotations; save_stack = stack; create_htables(); init_stack(); i = getc(f); if (i == EOF) fail("empty file"); if (i != '\n') { ungetc(i,f); read_historic(f,fail); } else { read_modern(f,fail); } fclose(f); recenterwin(); allredraw = 1; map_htable(save_symtbl_n,free_symbol_v); free_htable(save_symtbl_n); free_htable(save_symtbl_a); map_htable(save_annotations,free_annotation_v); free_htable(save_annotations); free_stack(save_stack); free(save_flags); } static void write_sym(void *svp) { SYMBOL *s; s = svp; fprintf(fileio_f,"%d:%s %lu\n",(int)strlen(s->name),s->name,(unsigned long int)s->addr); } static void write_annotation(void *avp) { ANNOTATION *a; int i; a = avp; if (!a->before && !a->on && !a->after) return; if (a->before) putc('b',fileio_f); if (a->on) putc('o',fileio_f); if (a->after) putc('a',fileio_f); if (a->before) { fprintf(fileio_f,"%d\n",a->before->nlines); for (i=0;ibefore->nlines;i++) fprintf(fileio_f,"%d:%s\n",(int)strlen(a->before->text[i]),a->before->text[i]); } if (a->on) { fprintf(fileio_f,"1\n%d:%s\n",(int)strlen(a->on->text[0]),a->on->text[0]); } if (a->after) { fprintf(fileio_f,"%d\n",a->after->nlines); for (i=0;iafter->nlines;i++) fprintf(fileio_f,"%d:%s\n",(int)strlen(a->after->text[i]),a->after->text[i]); } fprintf(fileio_f,"%lu\n",(unsigned long int)a->addr); } static void write_loc(DPOS l) { switch (l.type) { default: case DLT_NOSUCH: abort(); break; case DLT_ON: if (l.u.on.addr == l.laddr) fprintf(fileio_f,"o%lu\n",(unsigned long int)l.laddr); else fprintf(fileio_f,"O%lu %lu\n",(unsigned long int)l.laddr,(unsigned long int)l.u.on.addr); break; case DLT_BEFORE: fprintf(fileio_f,"b%lu %d\n",(unsigned long int)l.laddr,l.u.alno); break; case DLT_AFTER: fprintf(fileio_f,"a%lu %d\n",(unsigned long int)l.laddr,l.u.alno); break; case DLT_LEGACY: fprintf(fileio_f,"l"); break; } } static void S_command(void) { char *fn; FILE *f; int i; if (getstr("Save file name ",&fn,&saved_S_file) < 0) return; f = fopen(fn,"w"); if (f == 0) { beep(); move(LINES-1,0); standout(); printw("Can't open %.*s [any key to continue]",COLS-34,fn); clrtoeol(); refresh(); getch(); free(fn); return; } free(fn); fileio_f = f; fprintf(f,"\n2\n%s\n%lu\n%lu\n",machine->names[0],(unsigned long int)coresize,(unsigned long int)corebase); map_htable(symtbl_n,write_sym); fprintf(f,"0\n"); map_htable(annotations,write_annotation); fprintf(f,".\n"); writecflags(f,flags,coresize); write_loc(loc); fprintf(f,"%d\n",stack.depth); for (i=0;ibefore) { for (i=0;ibefore->nlines;i++) fprintf(f,"; %s\n",a->before->text[i]); } if (sp) { fprintf(f,"%12s: ",sp->name); } else { fprintf(f,"%12lx: ",(unsigned long int)(corebase+o)); } fileio_f = f; d = do_dis(corebase+o,&fileio_write); fileio_f = 0; if (a && a->on) fprintf(f," ; %s",a->on->text[0]); fprintf(f,"\n"); if (a && a->after) { for (i=0;iafter->nlines;i++) fprintf(f,"; %s\n",a->after->text[i]); } if (d < 0) break; o += d; } fclose(f); } static void undefine_symbol(int noisy) { char *name; SYMBOL *s; if (getstr("Undefine symbol named ",&name,0) < 0) return; s = symbol_for_name(name); free(name); if (s) { delete_symbol(s); allredraw = 1; } else if (noisy) { beep(); } } static void u_command(void) { undefine_symbol(1); } static void w_command(void) { if (changecur(1)) return; flags[loc.u.on.aoff] = CF_WORD; } static void x_command(void) { if (stack.depth > 0) { DPOS l; l = loc; loc = stack.stk[stack.depth-1]; stack.stk[stack.depth-1] = l; l = curwin->top; curwin->top = stack.wtop[stack.depth-1]; stack.wtop[stack.depth-1] = l; if (curwin->top.type == DLT_LEGACY) recenterwin(); curwin->redraw = 1; } else { beep(); } } static void text_write_sym(void *svp) { SYMBOL *s; s = svp; fprintf(fileio_f,"%s %lx\n",s->name,(unsigned long int)s->addr); } static void Y_command(void) { char *fn; FILE *f; if (getstr("Symbol file name ",&fn,&saved_Y_file) < 0) return; f = fopen(fn,"w"); free(fn); if (f == 0) { beep(); move(LINES-1,0); standout(); printw("Can't open %.*s [any key to continue]",COLS-34,fn); clrtoeol(); refresh(); getch(); return; } fileio_f = f; map_htable(symtbl_n,text_write_sym); fileio_f = 0; fclose(f); } static void z_command(void) { DPOS l; if (curline <= curwin->firstline) { beep(); return; } l = loc_dnline_nosuch(curwin->top); if (l.type == DLT_NOSUCH) { beep(); return; } curwin->top = l; curwin->redraw = 1; } static void Z_command(void) { DPOS l; if (curline+1 >= curwin->lastline) { beep(); return; } l = loc_upline_nosuch(curwin->top); if (l.type == DLT_NOSUCH) { beep(); return; } curwin->top = l; curwin->redraw = 1; } static void bang_command(void) { curwin->top = lines[curline].loc; curwin->redraw = 1; } static void quote_command(void) { if (checkchange(1)) return; if (flags[loc.u.on.aoff] == CF_CSTR) return; if (changecur(1)) abort(); flags[loc.u.on.aoff] = CF_STR; } static void push_command(void) { stack.depth ++; ensure_stack(); stack.stk[stack.depth-1] = loc; stack.wtop[stack.depth-1] = curwin->top; lines[curwin->lastline].flags |= LF_REDRAW; a_command(); } static void at_command(void) { char *fn; FILE *f; if (getstr("@",&fn,0) < 0) return; f = fopen(fn,"r"); if (f == 0) { beep(); move(LINES-1,0); standout(); printw("Can't open %.*s [any key to continue]",COLS-34,fn); clrtoeol(); refresh(); getch(); return; } istack_push(f); } static void star_command(void) { ADDR o; changecur(0); flags[loc.u.on.aoff] = CF_BYTE; for (o=loc.u.on.aoff+1;(o 0) { loc = stack.stk[--stack.depth]; curwin->top = stack.wtop[stack.depth]; if (curwin->top.type == DLT_LEGACY) recenterwin(); curwin->redraw = 1; } else { beep(); } } static void bar_command(void) { if (changecur(1)) return; if ((flags[loc.u.on.aoff] & ~CFF_INST) != CF_INST) { flags[loc.u.on.aoff] = CF_INST | CFF_INST_PARALLEL; } else { flags[loc.u.on.aoff] ^= CFF_INST_PARALLEL; } } static void ensure_annotation(void) { ANNOTATION *a; if (loc.ann) return; a = malloc(sizeof(ANNOTATION)); a->addr = loc.laddr; a->before = 0; a->on = 0; a->after = 0; add_new_hentry(annotations,a); loc.ann = a; } static void delete_note_line(NOTE *n, int l) { if (n->nlines < 1) abort(); n->nlines --; if (l != n->nlines) bcopy(&n->text[l+1],&n->text[l],(n->nlines-l)*sizeof(*n->text)); } static void remove_note(NOTE **np) { NOTE *n; n = *np; while (n->nlines > 0) delete_note_line(n,n->nlines-1); free(n->text); free(n); *np = 0; } static void ensure_note(NOTE **np) { if (*np == 0) { NOTE *n; n = malloc(sizeof(NOTE)); n->nlines = 0; n->alines = 0; n->text = 0; *np = n; } } static void replace_note_line(NOTE *n, int l, char *txt) { if ((l < 0) || (l >= n->nlines)) abort(); free(n->text[l]); n->text[l] = txt; } static void insert_note_line(NOTE *n, int l, char *txt) { if ((l < 0) || (l > n->nlines)) abort(); if (n->nlines >= n->alines) { int newa; newa = n->nlines + 8; n->text = realloc(n->text,newa*sizeof(*n->text)); while (n->alines < newa) n->text[n->alines++] = 0; } if (l < n->nlines) bcopy(&n->text[l],&n->text[l+1],(n->nlines-l)*sizeof(*n->text)); n->text[l] = txt; n->nlines ++; } static int matchlen(const char *s1, const char *s2, int len) { int i; for (i=0;(iaddr += inc; add_new_hentry(symtbl_a,sv); } static void list_annotation(void *av) { void *(*t)[2]; t = malloc(sizeof(*t)); t[0][0] = av; t[0][1] = alist; alist = t; } static void relocate_dpos(DPOS *p) { p->laddr += inc; switch (p->type) { case DLT_ON: p->u.on.addr += inc; break; } } if (geta("Relocate: new base address ",&newbase) < 0) return; inc = newbase - corebase; corebase += inc; coreend += inc; map_htable(symtbl_n,&relocate_sym); alist = 0; map_htable(annotations,&list_annotation); while (alist) { void *(*t)[2]; t = alist; alist = t[0][1]; del_this_hentry(annotations,t[0][0]); ((ANNOTATION *)t[0][0])->addr += inc; add_new_hentry(annotations,t[0][0]); free(t); } relocate_dpos(&loc); for (i=0;iflink;w!=wroot;w=w->flink) relocate_dpos(&w->top); allredraw = 1; } /* Gah. Wish I could count on having funopen(). */ static void colon_stack(void) { int cursor; int carrying; int i; int depth; char *tb; char *sb; int tl; int ta; int c1; int c2; int d1; int d2; DPOS *l; int c; char txtbuf[64]; int pa; int *perm; static void tappend(const char *s, int standout) { int l; l = strlen(s); if (tl+l > ta) { ta = tl + l + 16; tb = realloc(tb,ta); sb = realloc(sb,ta); } bcopy(s,tb+tl,l); memset(sb+tl,standout?1:0,l); tl += l; } static void swap(int a, int b) { int t; t = perm[a]; perm[a] = perm[b]; perm[b] = t; } static void ensure_perm(void) { if (depth+1 > pa) perm = realloc(perm,(pa=depth+1)*sizeof(*perm)); } if (stack.depth < 1) { beep(); return; } tb = 0; sb = 0; ta = 0; depth = stack.depth; pa = depth + 1; perm = malloc((depth+1)*sizeof(int)); for (i=depth-1;i>=0;i--) perm[i] = i; perm[depth] = -1; cursor = depth; carrying = 0; while (1) { if (istack) { c = istack_get(); if (c == EOF) continue; } else { tl = 0; if ((cursor < 0) || (cursor > depth)) abort(); for (i=depth;i>=0;i--) { if (i == cursor) { c1 = tl; tappend("[",1); } if (perm[i] < 0) l = &loc; else l = &stack.stk[perm[i]]; switch (l->type) { default: abort(); break; case DLT_ON: if (l->laddr != l->u.on.addr) { sprintf(&txtbuf[0],"%lx(%lx)",(unsigned long int)l->u.on.addr,l->laddr); } else { sprintf(&txtbuf[0],"%lx",(unsigned long int)l->u.on.addr); } break; case DLT_BEFORE: sprintf(&txtbuf[0],"%lx<%d",(unsigned long int)l->laddr,l->u.alno); break; case DLT_AFTER: sprintf(&txtbuf[0],"%lx>%d",(unsigned long int)l->laddr,l->u.alno); break; } tappend(&txtbuf[0],(i==cursor)&&carrying); if (i == cursor) { tappend("]",1); c2 = tl; } tappend(" ",0); } tl --; d1 = c1 - (COLS-10-(c2-c1)) / 2; d2 = d1 + COLS-10; if (d2 > tl) { d1 -= d2 - tl; d2 = tl; } if (d1 < 0) { d2 -= d1; d1 = 0; } if (d2 > tl) d2 = tl; move(LINES-1,0); standend(); if (d1 > 0) addstr("..."); else addstr(" "); for (i=d1;i 0) { cursor --; if (carrying) swap(cursor,cursor+1); } break; case '>': depth ++; ensure_perm(); bcopy(perm+cursor,perm+cursor+1,(depth-cursor)*sizeof(*perm)); cursor ++; break; case '<': if (depth < 1) { beep(); } else { if (cursor < depth) bcopy(perm+cursor+1,perm+cursor,(depth-cursor)*sizeof(*perm)); if (cursor > 0) cursor --; } depth --; break; case ' ': carrying = ! carrying; break; case '\r': case '\n': { DPOS v[depth+1][2]; for (i=depth;i>=0;i--) { if (perm[i] < 0) { v[i][0] = loc; v[i][1] = curwin->top; } else { v[i][0] = stack.stk[perm[i]]; v[i][1] = stack.wtop[perm[i]]; } } loc = v[depth][0]; curwin->top = v[depth][1]; if (curwin->top.type == DLT_LEGACY) recenterwin(); stack.depth = depth; ensure_stack(); for (i=depth-1;i>=0;i--) { stack.stk[i] = v[i][0]; stack.wtop[i] = v[i][1]; } curwin->redraw = 1; lines[curwin->lastline].flags |= LF_REDRAW; move(LINES-1,0); clrtoeol(); } if (0) { case '\7': beep(); } free(tb); free(sb); move(LINES-1,0); clrtoeol(); return; break; } } } static void colon_silent_undef(void) { undefine_symbol(0); } static void colon_command(void) { static const COLONCMD cmds[] = { { "relocate", &colon_relocate }, { "stack", &colon_stack }, { "s-undef", &colon_silent_undef }, { 0 } }; const COLONCMD *cmdvec; char *cmd; int len; int i; int j; int mlen; int mnum; const COLONCMD *mc; int cl; int b; if (getstr(": ",&cmd,0) < 0) return; len = strlen(cmd); mlen = 0; for (b=0;b<2;b++) { cmdvec = b ? machine->coloncmds : &cmds[0]; if (cmdvec == 0) continue; for (i=0;cmdvec[i].cmd;i++) { cl = strlen(cmdvec[i].cmd); if (len > cl) continue; j = matchlen(cmd,cmdvec[i].cmd,len); if (j > mlen) { mlen = j; mnum = 1; mc = &cmdvec[i]; } else if (j == mlen) { mnum ++; } } } if (mlen < 1) { beep(); move(LINES-1,0); standout(); printw("%.*s: unrecognized",COLS-15,cmd); clrtoeol(); refresh(); getch(); return; } if (mnum > 1) { beep(); move(LINES-1,0); standout(); printw("%.*s: ambiguous",COLS-15,cmd); clrtoeol(); refresh(); getch(); return; } free(cmd); (*mc->handler)(); } static void semicolon_command(void) { int c; char placech; char *txt; if (istack) { c = istack_get(); } else { move(LINES-1,0); standout(); addstr("; "); standend(); clrtoeol(); refresh(); c = getch(); } switch (loc.type) { case DLT_ON: case DLT_BEFORE: case DLT_AFTER: break; default: beep(); return; break; } switch (c) { default: beep(); return; break; case ';': case 'o': case 'O': placech = c; break; case 'd': { DPOS l; int up; l = loc_dnline_nosuch(loc); up = 0; if (l.type == DLT_NOSUCH) { l = loc_upline_nosuch(loc); up = 1; } switch (loc.type) { case DLT_ON: if (loc.ann) { remove_note(&loc.ann->on); lines[curline].flags |= LF_REDRAW; } return; break; case DLT_BEFORE: if (loc.ann->before->nlines < 2) { remove_note(&loc.ann->before); } else { delete_note_line(loc.ann->before,loc.u.alno); } break; case DLT_AFTER: if (loc.ann->after->nlines < 2) { remove_note(&loc.ann->after); } else { delete_note_line(loc.ann->after,loc.u.alno); } break; } if (loc.type != l.type) loc = l; if (up) { if (curline == 0) recenterwin(); else curline --; } curwin->redraw = 1; return; } break; } if (getstr("Text: ",&txt,0) < 0) return; ensure_annotation(); switch (loc.type) { default: abort(); break; case DLT_ON: switch (placech) { default: abort(); break; case ';': ensure_note(&loc.ann->on); if (loc.ann->on->nlines) { replace_note_line(loc.ann->on,0,txt); } else { insert_note_line(loc.ann->on,0,txt); } break; case 'o': ensure_note(&loc.ann->after); insert_note_line(loc.ann->after,0,txt); j_command(); break; case 'O': ensure_note(&loc.ann->before); insert_note_line(loc.ann->before,loc.ann->before->nlines,txt); loc = loc_upline_stop(loc); lines[curline].loc = loc; break; } break; case DLT_BEFORE: { NOTE *n; n = loc.ann->before; if (0) { case DLT_AFTER: n = loc.ann->after; } switch (placech) { default: abort(); break; case ';': replace_note_line(n,loc.u.alno,txt); break; case 'o': insert_note_line(n,loc.u.alno+1,txt); j_command(); break; case 'O': insert_note_line(n,loc.u.alno,txt); break; } } break; } curwin->redraw = 1; } static void redraw_win(WIN *w) { int lno; LINE *l; DPOS p; curline = -1; p = locaddr(w->top.laddr); w->top = p; for (lno=w->firstline;lnolastline;lno++) { l = &lines[lno]; l->flags |= LF_REDRAW; l->loc = p; if (p.type == DLT_NOSUCH) { l->type = LT_BLANK; continue; } l->type = LT_DIS; if ((p.type == loc.type) && (p.laddr == loc.laddr)) { switch (p.type) { default: abort(); break; case DLT_ON: l->type = LT_CURDIS; break; case DLT_BEFORE: case DLT_AFTER: if (p.u.alno == loc.u.alno) l->type = LT_CURDIS; } if (l->type == LT_CURDIS) curline = lno; } if (p.type == DLT_ON) { int adv; ADDR o; adv = skip(p.laddr); if (adv < 0) { l->type = LT_BLANK; p.type = DLT_NOSUCH; } else { o = (p.laddr - corebase) + adv; if ((o < coresize) && ISPREV(flags[o])) flags[o] = CF_NULL; } } p = loc_dnline_nosuch(p); } l = &lines[w->lastline]; l->type = (w == curwin) ? LT_CURMODE : LT_MODE; l->flags |= LF_REDRAW; w->redraw = 0; } static void redrawlines(void) { int lno; LINE *l; int cur; for (lno=0;lnoflags & LF_REDRAW) { l->flags &= ~LF_REDRAW; move(lno,0); cur = 0; switch (l->type) { case LT_BLANK: break; case LT_CURDIS: standout(); cur = 1; /* fall through */ case LT_DIS: switch (l->loc.type) { default: abort(); break; case DLT_NOSUCH: break; case DLT_ON: printw("%c ",(cur&&(loc.laddr!=loc.u.on.addr))?'+':' '); disas(l->loc.laddr); if (l->loc.ann && l->loc.ann->on) printw(" ; %s",l->loc.ann->on->text[0]); break; case DLT_BEFORE: printw(" ; %s",l->loc.ann->before->text[l->loc.u.alno]); break; case DLT_AFTER: printw(" ; %s",l->loc.ann->after->text[l->loc.u.alno]); break; } break; case LT_MODE: standout(); printw("--------"); break; case LT_CURMODE: standout(); printw("-------- "); switch (loc.type) { default: abort(); break; case DLT_ON: printw("Addr %lx",(unsigned long int)loc.u.on.addr); break; case DLT_BEFORE: printw("Before %lx (%d)",(unsigned long int)loc.laddr,loc.u.alno); break; case DLT_AFTER: printw("After %lx (%d)",(unsigned long int)loc.laddr,loc.u.alno); break; } { int i; int n; for ((i=stack.depth-1),(n=0);(i>=0)&&(n<8);i--,n++) { switch (stack.stk[i].type) { default: abort(); break; case DLT_ON: printw(" %lx",(unsigned long int)stack.stk[i].u.on.addr); if (stack.stk[i].laddr != stack.stk[i].u.on.addr) { printw("(%lx)",stack.stk[i].laddr); } break; case DLT_BEFORE: printw(" %lx<%d",(unsigned long int)stack.stk[i].laddr,stack.stk[i].u.alno); break; case DLT_AFTER: printw(" %lx>%d",(unsigned long int)stack.stk[i].laddr,stack.stk[i].u.alno); break; } } if (i >= 0) { printw(" ... [%d]",stack.depth); } } break; } standend(); clrtoeol(); } } } static void mainloop(void) { WIN *w; int cmd; while (1) { if (! istack) { if (mustrecenter) { mustrecenter = 0; recenterwin(); curwin->redraw = 1; } for (w=wroot->flink;w!=wroot;w=w->flink) { if (allredraw || w->redraw) { redraw_win(w); } } allredraw = 0; redrawlines(); move(LINES-1,0); standout(); printw("disas>"); standend(); printw(" "); clrtoeol(); move(0,COLS-2); refresh(); cmd = getch(); } else { cmd = istack_get(); if (cmd == EOF) continue; } if (machine->cmd && (*machine->cmd)(cmd)) continue; /* Character usage: * Used here: * !"*:;<>@ABCHILQRSTYZabcijklopsuwxz| * Used in machine-specific cases: * J_defghrvy * Available: * all control characters (most are arguably Bad Choices) * space * #$%&'()+,-./0123456789=?DEFGJKMNOPUVWX[\]^`defghmnqrtvy{}~ * delete * everything non-ASCII */ switch (cmd) { default: beep(); break; case 'Q': return; break; case '!': bang_command(); break; case '"': quote_command(); break; case '*': star_command(); break; case ':': colon_command(); break; case ';': semicolon_command(); break; case '<': pop_command(); break; case '>': push_command(); break; case '@': at_command(); break; case 'A': A_command(); break; case 'B': B_command(); break; case 'C': C_command(); break; case 'H': H_command(); break; case 'I': I_command(); break; case 'L': L_command(); break; case 'R': R_command(); break; case 'S': S_command(); break; case 'T': T_command(); break; case 'Y': Y_command(); break; case 'Z': Z_command(); break; case 'a': a_command(); break; case 'b': b_command(); break; case 'c': c_command(); break; case 'i': i_command(); break; case 'j': j_command(); break; case 'k': k_command(); break; case 'l': l_command(); break; case 'o': o_command(); break; case 'p': p_command(); break; case 's': s_command(); break; case 'u': u_command(); break; case 'w': w_command(); break; case 'x': x_command(); break; case 'z': z_command(); break; case '|': bar_command(); break; } } } static int setmachine(const char *name) { int i; int j; for (i=0;inames[j];j++) { if (!strcmp(name,machines[i]->names[j])) { machine = machines[i]; return(1); } } } return(0); } static void handleargs(int ac, char **av) { int skip; int errs; skip = 0; errs = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av != '-') { if (! datafile) { datafile = *av; } else if (! basestr) { basestr = *av; } else { fprintf(stderr,"%s: unrecognized argument `%s'\n",__progname,*av); errs ++; } continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs ++; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-base")) { WANTARG(); basestr = av[skip]; continue; } if (!strcmp(*av,"-file")) { WANTARG(); datafile = av[skip]; continue; } if (!strcmp(*av,"-mach") || !strcmp(*av,"-machine")) { WANTARG(); if (! setmachine(av[skip])) { fprintf(stderr,"%s: unknown machine name `%s'\n",__progname,av[skip]); errs ++; } continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if (errs) { exit(1); } } int main(int, char **); int main(int ac, char **av) { #ifdef NeXT malloc_debug(/*32+*/16+8+4+2); #endif handleargs(ac,av); startup(datafile,basestr); mainloop(); move(LINES-1,0); refresh(); endwin(); printf("\n"); exit(0); }