/************************************************************* * File: mon/cli.c * Purpose: Command line interface for MON * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 970216 Start of revision history * 970216 Switched over to using addCmdRec() * 970303 trace_mode removed. * 970409 Switched over to using addEnvRec() * 971007 Removed %s from printf on break in gotintr * 980420 Added ifndef around flush_target for NON_CACHED build * 980602 Added shrc_needed to delay execution of shrc cmds. * 980715 Added arg to shrc() call. * 980717 Always flush D then I for copyback D caches. * 980725 Added compare command. * 990317 Changed full_vers size to 200 because of pjb prefix */ #include #include #include #include #include #include #include #include #define PREGS /* enable pseudo regs */ jmp_buf intrbuf; int xvwmode; /* crossview mode */ int noecho; char prnbuf[LINESZ]; char line[LINESZ]; CmdRec *cmdChain; extern int clilst,*curlst; extern int shrc_needed; void gotintr(int); char *badhexsym = "%s: neither hex value nor symbol\n"; Optdesc sh_opts[] = { {"","The command shell"}, {"^P","recall previous cmd"}, {"^N","recall next cmd"}, {"^F","move cursor right"}, {"^B","move cursor left"}, {"^A","move cursor far left"}, {"^E","move cursor far right"}, {"^D","delete char at cursor"}, {"^H","delete char before cursor"}, {"",""}, {"!!","repeat last cmd"}, {"!str","recall and execute cmd str"}, {"!num","recall and execute cmd num"}, {"",""}, {"+-*/()","operators"}, {"^addr","contents of address"}, {"@name","contents of register"}, {"&name","value of symbol"}, {"0xnum","hex number"}, {"0onum","octal number"}, {"0tnum","decimal number"}, {0}}; int do_vers(); char full_vers_info[200]; Optdesc vers_opts[] = { {"[-a]","display version info"}, {"-a","display all version info"}, {0}}; #ifdef CROSSVIEW int do_cp(),do_echo(),do_sc(),do_gc(),do_sr(),do_mr(); int gmx(),smx(),do_init(),do_lo(); #endif CmdRec moncmds[] = { {"h",h_opts,help}, {"hi",hi_opts,dohi}, {"m",m_opts,modify}, {"r",r_opts,registers}, {"d",d_opts,dump}, {"l",l_opts,dis}, {"copy",copy_opts,copy}, {"fill",fill_opts,fill}, {"search",search_opts,search}, {"compare",compare_opts,compare_cmd}, {"when",w_opts,when}, {"g",g_opts,go}, {"c",c_opts,cont}, {"t",t_opts,trace}, {"to",to_opts,trace}, {"b",b_opts,setbp}, {"db",db_opts,clrbp}, {"sym",sym_opts,do_sym}, {"ls",ls_opts,do_ls}, {"set",set_opts,do_set}, {"vers",vers_opts,do_vers}, {"sh",sh_opts,no_cmd}, {"more",more_opts,no_cmd}, #ifdef GDB_SUPPORT {"debug",debug_opts,debug}, #endif #ifdef CROSSVIEW {"xvw",crossview_opts,no_cmd}, {"cp",0,do_cp}, /* copy memory range */ {"echo",0,do_echo}, /* echo args */ {"sc",0,do_sc}, /* set config */ {"gc",0,do_gc}, /* get config */ {"sr",0,do_sr}, /* set register */ {"mr",0,do_mr}, /* display modified regs */ {"gmb",0,gmx}, /* get memory as bytes */ {"smb",0,smx}, /* set memory as bytes */ {"gmh",0,gmx}, /* get memory as half-words */ {"smh",0,smx}, /* set memory as half-words */ {"gmw",0,gmx}, /* get memory as words */ {"smw",0,smx}, /* set memory as words */ {"lo",0,do_lo}, /* binary download */ {"init",0,do_init}, /* warm (cold) reboot */ #endif {0}}; /************************************************************* * void moninit(void) DEF */ void moninit(void) { int i; for (i=0;moncmds[i].name;i++) addCmdRec(&moncmds[i]); histinit(); envinit(); ioctl_setup(STDIN); c0regNames = regs_hw; c2cRegNames = regs_hw; c2dRegNames = regs_hw; if (!matchenv("regstyle")) regnames = regs_hw; else regnames = regs_sw; } /************************************************************* * void monmain(void) DEF * Called after moninit has been executed * o Prompts for commands and calls do_cmd to execute them * o The setjmp is used to pass control back here if a ^C is typed */ void monmain(void) { int i,t1,rptcmd; char prompt[20],tmp[8],*p,*t; char buf[100]; ADDR adr; #ifdef PMCC ioctl(STDIN,SETINTR,intrbuf); if (setjmp(intrbuf) == 1) { /* on INTR */ if (curlst == &clilst && regChain) { /* 970826 */ adr = getPc(); disasm(buf,adr,read_target32(adr)); printf("break!\n%s\n",buf); /* 971007 */ } else printf("break!\n"); /* 971007 */ } #else setjmp(intrbuf); if (signal(SIGINT,SIG_IGN) != SIG_IGN) signal(SIGINT,gotintr); #endif disableints(); swlst(1); if (bptTmpId != -1) { clrbpt(bptTmpId); bptTmpId = -1; } if (shrc_needed) { shrc_needed = 0; shrc(1); } while (1) { ioctl_restore(STDIN); /* in case it has been left in a funny state */ #ifndef NON_CACHED flush_target(DCACHE); flush_target(ICACHE); #endif if (!*line) { /* line is empty */ /* don't hang if the env var is bad */ if (getMonEnv("prompt")) strcpy(prompt,getMonEnv("prompt")); else strcpy(prompt,"BAD> "); if (p = strchr(prompt,'!')) { strdchr(p); /* delete the bang */ sprintf(tmp,"%d",histno); stristr(p,tmp); } printf("%s",prompt); get_cmd(line); if (!*line || strempty(line)) { /* blank */ rptcmd = matchenv("rptcmd"); if (rptcmd) { /* repeat requested */ t = gethistn(histno-1); if (rptcmd == 1) strcpy(line,t); /* all cmds */ else if (rptcmd == 2) { /* trace only */ if (wordsz(t) > 10) continue; getword(tmp,t); if (strequ(tmp,"t")||strequ(tmp,"to")) strcpy(line,tmp); else continue; } else { printf("bad rptcmd value [%s]\n", getMonEnv("rptcmd")); continue; } } else continue; } } do_cmd(line); } } /************************************************************* * int do_cmd(char *cmd) DEF * execute a command, the string pointed to by p. * warning: p does get written to * o Commands are invoked as if executed from a standard command * shell. i.e. they are passed an argc/argv argument list. */ int do_cmd(char *cmd) { char *av[MAX_AC]; /* argument holder */ int ac; /* # of arguments */ char *t,tmp[200]; int i,c,r; CmdRec *p; for (;*cmd;) { /* look for ';' that is not enclosed within "" or '' */ for (t=cmd;*t;) { c = *t; if(c == '\'' || c == '"') { t++; while(*t && *t != c) ++t; if(*t) t++; } else if (c == ';') break; else t++; } /* copy the 1st cmd into tmp, and then remove it from cmd */ strNcpy(tmp,cmd,t-cmd); if (c == ';') i = (t-cmd)+1; else i = t-cmd; for (;i>0;i--) strdchr(cmd); /* find and then execute the command specified in tmp */ ac = argvize(av,tmp); if(ac > 0) { if (strequ(av[0],"stop")) return(1); for (p=cmdChain;p;p=p->next) if (strequ(p->name,av[0])) break; if (p) (p->func)(ac,av,p); else printf("%s: Command not found.\n",av[0]); } } return(0); } Optdesc h_opts[] = { {"[*|cmd..]","The help command"}, {0}}; /************************************************************* * int help(int ac,char *av[]) DEF * the 'help' command */ int help(int ac,char *av[]) { int i,j,namemax,optsmax,descmax,len; int ln,siz; CmdRec *p; namemax = optsmax = descmax = 0; for (p=cmdChain;p;p=p->next) { len = strlen(p->name); if (len > namemax) namemax = len; if (p->opts) { if (p->opts->name) { len = strlen(p->opts->name); if (len > optsmax) optsmax = len; } if (p->opts->desc) { len = strlen(p->opts->desc); if (len > descmax) descmax = len; } } } if (!atob(&siz,getMonEnv("moresz"),10)) { printf("%s: bad moresz value\n",getMonEnv("moresz")); return(1); } ioctl_cbreak(0L); ln = siz; if (ac >= 2) { /* extended help */ if (strequ(av[1],"*")) { /* all commands */ for (p=cmdChain;p;p=p->next) { if (prhelp(p,&ln,siz,namemax,optsmax)) break; } } else { /* specific commands */ for (j=1;jnext) { if (strequ(p->name,av[j])) break; } if (p) { if (prhelp(p,&ln,siz,namemax,optsmax)) break; } else printf("%s: Command not found\n",av[j]); } } } else { /* general help only */ for (p=cmdChain,i=0;p;p=p->next) { if (!p->opts) continue; printf("%*s %-*s",namemax,p->name,descmax,p->opts->desc); if (i%2 != 0) printf("\n"); else printf(" "); i++; } if (i%2 != 0) printf("\n"); } return(0); } /************************************************************* * int prhelp(CmdRec *p,int *lnp,int siz,int namemax,int optsmax) DEF */ int prhelp(CmdRec *p,int *lnp,int siz,int namemax,int optsmax) { Optdesc *o; int i; if (!p->opts) return(0); sprintf(prnbuf,"%*s %-*s %s",namemax,p->name,optsmax, p->opts->name, p->opts->desc); if (more(prnbuf,lnp,siz)) return(1); o = p->opts; if (o) { for (i=1;o[i].name;i++) { sprintf(prnbuf,"%*s %15s %s",namemax,"", o[i].name,o[i].desc); if (more(prnbuf,lnp,siz)) return(1); } } return(0); } /************************************************************* * int no_cmd(int ac,char *av[]) DEF */ int no_cmd(int ac,char *av[]) { printf("The %s command cannot be invoked by name.\n",av[0]); return(0); } #if 0 /************************************************************* * int printfb(char *fmt,Ulong a1,Ulong a2,Ulong a3,Ulong a4) DEF * A buffered printf used for printing the PMON banner. */ int printfb(char *fmt,Ulong a1,Ulong a2,Ulong a3,Ulong a4) { char tmp[80]; int len,islf; islf = 0; sprintf(tmp,fmt,a1,a2,a3,a4); len = strlen(tmp); if (len == 0) return(0); if (!strcmp(fmt,"\n")) islf = 1; if ((strlen(prnbuf)+len) > 70 || islf) { printf("\n"); *prnbuf = 0; } if (strlen(prnbuf)) strcat(prnbuf," "); strcat(prnbuf,tmp); printf("%s ",tmp); return(1); } #endif /************************************************************* * int printfb(char *fmt,...) DEF * A buffered printf used for printing the PMON banner. */ int printfb(const char *fmt,...) { va_list ap; char tmp[80]; int len,islf; islf = 0; va_start(ap,fmt); vsprintf(tmp,fmt,ap); va_end(ap); len = strlen(tmp); if (len == 0) return(0); if (!strcmp(fmt,"\n")) islf = 1; if ((strlen(prnbuf)+len) > 70 || islf) { printf("\n"); *prnbuf = 0; } if (strlen(prnbuf)) strcat(prnbuf," "); strcat(prnbuf,tmp); printf("%s ",tmp); return(1); } /************************************************************* * int get_rsa(U64 *vp,char *p) DEF * Get Register/Symbol/Address * This function evaluates expressions on the command line * using recursive decent. It understands expressions * containing any combination of register names, symbols, * constants, perens, and the operators +-* /. In addition * it also permits the '^' operator to dereference any * address. */ int get_rsa(U64 *vp,char *p) { int r,inbase,inalpha; U64 v1,v2; char *q,subexpr[LINESZ]; Ulong v; /* strip enclosing parens */ while (*p == '(' && strbalp(p) == p+strlen(p)-1) { strdchr(p); p[strlen(p)-1] = 0; } if (q=strrpset(p,"+-")) { /* is compound */ strNcpy(subexpr,p,q-p); r = get_rsa(&v1,subexpr); if (r == 0) return(r); r = get_rsa(&v2,q+1); if (r == 0) return(r); if (*q == '+') *vp = addRV(v1,v2); else *vp = subRV(v1,v2); return(1); } if (q=strrpset(p,"*/")) { strNcpy(subexpr,p,q-p); r = get_rsa(&v1,subexpr); if (r == 0) return(r); r = get_rsa(&v2,q+1); if (r == 0) return(r); if (*q == '*') *vp = mulRV(v1,v2); else *vp = divRV(v1,v2); return(1); } if (*p == '^') { r = get_rsa(&v2,p+1); if (r == 0) return(r); *vp = read_target(XT_MEM,v2.lo,4); return(1); } if (*p == '@') { #ifdef PREGS /* preg */ if (ispreg(&p[1])) { *vp = mkRV(getPreg(p[1]-'a')); r = 1; } else { r = getreg(vp,&p[1]); if (r == 0) printf("%s: bad register name\n",&p[1]); } #else r = getreg(vp,&p[1]); if (r == 0) printf("%s: bad register name\n",&p[1]); #endif } else if (strequ(p,".")) { r = getreg(vp,"pc"); if (r == 0) printf("%s: bad register name\n",&p[1]); } else if (*p == '&') { r = sym2adr(&v,&p[1]); if (r == 0) printf("%s: bad symbol name\n",&p[1]); else *vp = mkRV(v); } else if (isdigit(*p)) { inbase = matchenv("inbase"); if (inbase == IB_TEN) r = atobRV(vp,p,10); else if (inbase == IB_SIXTEEN) r = atobRV(vp,p,16); else if (inbase == IB_EIGHT) r = atobRV(vp,p,8); else if (inbase == IB_AUTO) r = atobRV(vp,p,0); else { printf("%s: bad inbase value\n",getMonEnv("inbase")); return(0); } if (r == 0) { r = atobRV(vp,p,0); if (r == 0) printf("%s: bad base %s value\n", p,getMonEnv("inbase")); } } else if (isxdigit(*p)) { inalpha = matchenv("inalpha"); if (inalpha == IA_HEX) { r = atobRV(vp,p,16); if (r == 0) { r = sym2adr(&v,p); if (r == 0) printf(badhexsym,p); else *vp = mkRV(v); } } else if (inalpha == IA_SYMBOL) { r = sym2adr(&v,p); if (r == 0) { r = atobRV(vp,p,16); if (r == 0) printf(badhexsym,p); } else *vp = mkRV(v); } else { printf("%s: bad inalpha value\n",getMonEnv("inalpha")); return(0); } } else { r = sym2adr(&v,p); if (r == 0) printf("%s: bad symbol name\n",p); else *vp = mkRV(v); } return(r); } /************************************************************* * int stop(char *cmdstr) DEF */ int stop(char *cmdstr) { char cmd[LINESZ]; #ifdef CROSSVIEW if (xvwmode) longjmp(intrbuf,2); #endif if (cmdstr) strcpy(cmd,cmdstr); else strcpy(cmd,getMonEnv("brkcmd")); do_cmd(cmd); longjmp(intrbuf,2); return(1); } /************************************************************* * void addCmdRec(CmdRec *p) DEF * add a CmdRec to the cmdChain */ void addCmdRec(CmdRec *p) { CmdRec *q; p->next = 0; if (!cmdChain) { /* empty */ cmdChain = p; } else { for (q=cmdChain;q->next;q=q->next) ; /* find end of chain */ q->next = p; } } /************************************************************* * int do_vers(int ac,char *av[]) DEF * display version number */ int do_vers(int ac,char *av[]) { if (ac == 1) printf("%s\n",vers); else printf("%s\n",full_vers_info); return(1); }