#include "univ.h" #include "master.pri" #include "process.pri" #include "expr.pub" #include "master.pub" #include "bpts.pri" #include "frame.pri" #include "memory.pub" #include "symtab.pri" #include "symbol.h" #include "srcdir.h" #include "asm.pub" #include "bpts.pri" #include "rt.h" #include "rtraw.h" #include "rtnrtx.h" SRCFILE("rtnrtx.c") #define K DB_KERNELID char *index(char*,char); char *NrtxSignalName(int); extern int dberrno; Process *RtNrtxMaster::domakeproc(char *proc, char *stab, char* comment) { return (Process*) new RtNrtxProcess(fd, boardid, child, proc, stab, comment); } void RtNrtxMaster::open() { Menu m; if (pad) { pad->makecurrent(); return; } pad = new Pad( (PadRcv*) this ); pad->options(TRUNCATE|SORTED); pad->name( "%s:%s", parent->name(), name()); pad->banner( "Nrtxpi %s:%s", parent->name(), name()); m.last("ps", (Action)&RtNrtxMaster::refresh, 1); m.last("kernel pi", (Action)&RtNrtxMaster::kpi); pad->menu(m); pad->makecurrent(); refresh(0); } Index RtNrtxMaster::carte() { Menu m; m.last("open board", (Action)&RtNrtxMaster::open); return m.index(); } void RtNrtxMaster::kpi() { if (!kernel) kernel = new RtRawMaster(fd, boardid, parent); kernel->open(); } void RtNrtxMaster::refresh(int c) { char s[128]; Process *p; pad->clear(); makeproc( "!", "a.out", 0); if (c) { int np = 0; ::dbrequest(fd, boardid, 0, DBR_NRTXNPROC, (int)&np, 0, sizeof(np)); for(int i = 0; i < np; i++) { int r = ::dbrequest(fd, boardid, i, DBR_GETSNAME, (int)s, 0,sizeof(s)); if (r >= 0) makeproc(sf("%s:%d",name(), i),sf("%s", s), 0); } } for( p = child; p; p = p->sibling ) if( p->core || (p->stabpath && !strcmp(p->stabpath,"!"))) insert(p); } char *RtNrtxMaster::kbd(char *s) { char core[64], syms[64]; while (*s == ' ') ++s; if (*s == '!') { for (++s; *s==' '; ++s) {} makeproc("!", s, 0); } else { int i = sscanf(s, "%s %s \n", core, syms); if (i <= 0 || i > 2 || !alldigits(core)) return help(); makeproc(sf("%s:%s",name(), core), i==2?sf("%s",syms):0, 0); } return 0; } char *RtNrtxMaster::help() { return " {process} | ! {program}"; } RtNrtxProcess::RtNrtxProcess(int f, int id, Process *sib, char *p, char *s, char *c) : (sib,p,s,c) { fd = f; boardid = id; } void RtNrtxProcess::takeover() { if( pad ){ open(); insert(ERRORKEY, "take over: already open"); return; } Pick( "take over", (Action)&RtNrtxProcess::substitute, (long) this ); } int RtNrtxProcess::accept( Action a ) { return a == (Action)&RtNrtxProcess::substitute; } void RtNrtxProcess::userclose() { if( sigmsk ){ sigmsk->hostclose(); delete sigmsk; sigmsk = 0; } Process::userclose(); ::dbrequest(fd, boardid, procid, DBR_CLOSE,0,0,0); } void RtNrtxProcess::substitute(RtNrtxProcess *t) { char *error; insert(ERRORKEY, 0); if( !core ){ insert(ERRORKEY, "that ought to work - but it doesn't"); return; } _bpts->lift(); if( error = core->reopen(0,t->stabpath) ){ _bpts->lay(); insert(ERRORKEY, error); return; } procpath = t->procpath; stabpath = t->stabpath; comment = t->comment; ::dbrequest(fd, boardid, procid, DBR_CLOSE,0,0,0); sscanf(index(procpath,':')+1, "%d", &procid); t->isdead = 1; master->insert(t); master->insert(this); banner(); if( _asm ) _asm->banner(); if( _bpts ) _bpts->banner(); if( memory ) memory->banner(); if( globals ) globals->banner(); if( sigmsk ){ sigmsk->banner(); sigmsk->updatecore(); } if( srcdir ) srcdir->banner(); core->symtab()->banner(); pad->clear(); _bpts->lay(); docycle(); } void RtNrtxProcess::open() { Menu m, s; char *error; Process::openpad(); if( core ) return; sscanf(index(procpath,':')+1, "%d", &procid); insert(ERRORKEY, "Checking process and symbol table..."); core = (Core*) new RtNrtxCore(fd, boardid, procid, this, master); if( error = core->open() ){ delete core; core = 0; m.last( "open process", (Action)&RtNrtxProcess::open); pad->menu( m ); insert(ERRORKEY, error); return; } insert(ERRORKEY, core->symtab()->warn()); globals = new Globals(core); _asm = core->newAsm(); m.last( "stop", (Action)&Process::stop ); m.last( "run", (Action)&Process::go ); m.last( "src text", (Action)&Process::srcfiles ); m.last( "Globals", (Action)&Process::openglobals ); m.last( "RawMemory", (Action)&Process::openmemory ); s.last( "Assembler", (Action)&Process::openasm ); s.last( "User Types",(Action)&Process::opentypes ); s.last("Journal", (Action)&Process::openjournal); s.last("Signals", (Action)&RtNrtxProcess::opensigmask); s.last("Bpt List", (Action)&Process::openbpts); _bpts = new Bpts(core); _bpts->lay(); sigmsk = new RtNrtxSigMask((RtNrtxCore *)core); m.last("kill?", (Action)&RtNrtxProcess::destroy ); m.last(s.index("more")); pad->menu(m); pad->makecurrent(); docycle(); } void RtNrtxProcess::opensigmask() { if (sigmsk) sigmsk->open(); } void RtNrtxProcess::destroy() { insert(ERRORKEY, core->destroy()); docycle(); } Index RtNrtxProcess::carte() { Menu m; if(procpath && !strcmp(procpath,"!") ){ m.last("hang & open proc",(Action)&RtNrtxProcess::hangopen); m.last("hang & take over",(Action)&RtNrtxProcess::hangtakeover); } else { m.last("open process", (Action)&RtNrtxProcess::open); m.last("take over", (Action)&RtNrtxProcess::takeover); } return m.index(); } void RtNrtxProcess::hang() { insert(ERRORKEY, "can't load real-time board"); procpath = sf("%s:-2",((RtNrtxMaster*)master)->name()); return; // master->makeproc("!", stabpath); // master->insert(this); } void RtNrtxProcess::hangopen() { hang(); open(); } void RtNrtxProcess::hangtakeover() { hang(); takeover(); } const long REG_SPECIAL = 0x40000000; // Address unlikely to be used Behavs RtNrtxCore::behavs() { readcontrol(); return behavetype(); } char *RtNrtxCore::destroy() { return dbreq(DBR_KILL, 0, 9); } int RtNrtxCore::fpvalid(long fp) { return fp != 0; } int RtNrtxCore::instack(long curfp, long prevfp) { return (curfp>prevfp); } long RtNrtxCore::regaddr() { return REG_SPECIAL; } char *RtNrtxCore::run() { return dbreq(DBR_RUN); } long RtNrtxCore::scratchaddr() { return kstate.scratchaddr; } char *RtNrtxCore::stop() { return dbreq(DBR_STOP); } char *RtNrtxCore::eventname() { return NrtxSignalName(pr.p_cursig); } RtNrtxCore::RtNrtxCore(int fd, int id, int pid, Process *p, Master *m):(p, m) { commfd = fd; boardid = id; procid = pid; } char *RtNrtxCore::problem() { if (dberrno == DBA_BAD) return "process exited"; return sf("communications time out (%d)", dberrno); } char *RtNrtxCore::readcontrol() { char *error = dbreq(DBR_NRTXPROC, (char*)&pr, 0, sizeof(pr)); if (error) { if (dberrno == DBA_KSTOPPED) return 0; pr.p_stat = 0; } return error; } char *RtNrtxCore::dbreq(int req, char* addr,int rarg, int sz) { if (::dbrequest(commfd, boardid, procid, req, (int)addr, rarg, sz) == -1) return "dbrequest failed"; return 0; } char *RtNrtxCore::laybpt(Trap *t) { t->saved = peek(t->stmt->range.lo)->sht; return dbreq(DBR_SETBKPT, 0, t->stmt->range.lo); } Behavs RtNrtxCore::behavetype() { switch( pr.p_stat ){ case SSLEEP: case SRUN: return ACTIVE; case SSTOP: switch( pr.p_cursig ){ case SIGSTOP: return HALTED; case SIGTRAP: return BREAKED; default: return PENDING; } } return ERRORED; } char *RtNrtxCore::open() { if( stabpath() ){ stabfd = ::open(stabpath(),0); if( stabfd<0 ) return SysErr( "symbol tables: " ); } else return "open error"; ::dbrequest(commfd, boardid, K, DBR_GETSTATE, (int)&kstate, 0, sizeof(kstate)); _online = 1; dbreq(DBR_OPEN); stabfstat(); long reloc; dbreq(DBR_NRTXRELOC, (char*)&reloc, 0, sizeof(reloc)); _symtab = new BsdSymTab(this, stabfd, _symtab, reloc); _symtab->read(); return readcontrol(); } char *RtNrtxCore::reopen(char *, char *newstabpath) { int compstabfd = -1; compstabfd = ::open(newstabpath, 0); struct stat compstabstat; if( compstabfd < 0 || ::fstat(compstabfd, &compstabstat) ) return "symbol table error"; if( compstabstat.st_mtime != stabstat.st_mtime ) return "symbol tables differ (modified time)"; if( compstabstat.st_size != stabstat.st_size ) return "symbol tables differ (file size)"; ::close(compstabfd); return readcontrol(); } char *RtNrtxCore::readwrite(long offset, char *buf, int r, int w) { if (offset >= REG_SPECIAL && offset <= (REG_SPECIAL + sizeof(Regs))) { offset = (offset - REG_SPECIAL) / sizeof(int); if( r ) return dbreq(DBR_GETREGS, buf, offset, r); return dbreq(DBR_PUTREGS, buf, offset, w); } if( r ) return dbreq(DBR_READ, buf, offset, r); return dbreq(DBR_WRITE, buf, offset, w); } const short M68K_RTS = 0x4E75; const int STEPWAIT = 15; char *RtNrtxCore::dostep(long lo, long hi, int sstep) { char *error; long fp0, time0, time(long); int i; static int waittime[] = {1,1,2,4,6}; if (pr.p_cursig==SIGTRAP) clrcurrsig(); time0 = ::time(0L); fp0 = fp(); for(;;){ if( hi && isM68KJSB(peek(pc())->sht) ) { error = stepoverM68KJSB(); goto next; } if (sstep) error = dbreq(DBR_STEP); else error = dbreq(DBR_RUN); if( !error ) { for (i = 0; ; i++) { error = readcontrol(); if (error || behavetype() != ACTIVE) break; if (i >= 5) return "single step timeout"; sleep(waittime[i]); } } if( !error && pr.p_cursig != SIGTRAP ) error = sf("single step error. signal=%d",pr.p_cursig); if( !error ) error = clrcurrsig(); next: if( error ) return error; if( !hi || pc()=hi || (fp()>fp0 && peek(pc())->sht != M68K_RTS)) return 0; if( ::time(0L) > time0+STEPWAIT ) return sf("single step timeout (%d secs)",STEPWAIT); } } char *RtNrtxCore.clrcurrsig() { char *error = dbreq(DBR_CSIG); if( !error ) pr.p_cursig = 0; return error; } char *RtNrtxCore::signalmask(long mask) { return dbreq(DBR_SMASK, 0, mask); } char *RtNrtxCore::sendsig(long sig) { return dbreq(DBR_KILL, 0, sig); } char *RtNrtxCore::exechang(long ehang) { if (ehang) return dbreq(DBR_SEXEC); else return dbreq(DBR_REXEC); } char *NrtxSignalName(int sig) { switch (sig) { case 0: return "0 (no signal)"; case SIGHUP: return "hangup"; case SIGINT: return "interrupt"; case SIGQUIT: return "quit"; case SIGILL: return "illegal instruction"; case SIGTRAP: return "trace/BPT"; case SIGIOT: return "IOT instruction"; case SIGEMT: return "EMT instruction"; case SIGFPE: return "floating exception"; case SIGKILL: return "kill"; case SIGBUS: return "bus error"; case SIGSEGV: return "memory fault"; case SIGSYS: return "bad system call"; case SIGPIPE: return "broken pipe"; case SIGALRM: return "alarm call"; case SIGTERM: return "terminated"; case SIGSTOP: return "stop"; case SIGCONT: return "continue"; case SIGCHLD: return "child termination"; } return sf("Signal %d", sig); } void RtNrtxSigMask::banner() { if( pad ){ pad->banner( "Signals: %s", core->procpath() ); pad->name( "Signals" ); } } RtNrtxSigMask::RtNrtxSigMask(RtNrtxCore *c) { core = c; pad = 0; mask = bit(SIGILL) |bit(SIGINT) |bit(SIGTRAP) |bit(SIGIOT) |bit(SIGEMT) |bit(SIGFPE) |bit(SIGBUS) |bit(SIGSEGV) |bit(SIGSYS) |bit(SIGPIPE) |bit(SIGSTOP); exechang = 1; updatecore(); } const long EXECKEY = 33; void RtNrtxSigMask::open() { Menu m; int i; if( !pad ){ pad = new Pad( (PadRcv*) this ); banner(); m.last("clear pending signal", (Action)&RtNrtxSigMask::clrcurrsig,0); m.last("clear pending and go", (Action)&RtNrtxSigMask::clrcurrsig,1); pad->menu(m); pad->options(TRUNCATE); for( i = 1; i <= EXECKEY; ++i ) linereq( i, 0 ); } pad->makecurrent(); } void RtNrtxSigMask::updatecore(char *error) { if( !error ) error = core->exechang(exechang); if( !error ) error = core->signalmask(mask); core->process()->pad->error(error); } void RtNrtxSigMask::execline(long e) { static char *i[] = { "clear", "hang" }; static char *l[] = { "", ">>> " }; Menu m; exechang = e &= 1; updatecore(); long comp = e^1; m.last( i[comp], (Action) &RtNrtxSigMask::execline, comp ); Attrib a = 0; pad->insert( EXECKEY, a, (PadRcv*)this, m, "%sexec()", l[e] ); } void RtNrtxSigBit::set(RtNrtxSigMask *s) { s->setsig(bit); } void RtNrtxSigBit::clr(RtNrtxSigMask *s) { s->clrsig(bit); } void RtNrtxSigBit::send(RtNrtxSigMask *s) { s->sendsig(bit); } void RtNrtxSigMask::linereq(long sig, Attrib a ) { Menu m; static RtNrtxSigBit *sigbit; if( !sigbit ) sigbit = new RtNrtxSigBit[33]; if( sig == EXECKEY ){ execline(exechang); return; } char *on = mask&bit(sig) ? ">>> " : ""; m.last( "send signal", (Action)&RtNrtxSigBit::send, (long)this ); if( on[0] == '>' ) m.first("trace off", (Action)&RtNrtxSigBit::clr, (long)this); else m.first("trace on", (Action)&RtNrtxSigBit::set, (long)this); sigbit[sig].bit = sig; pad->insert(sig, a, (PadRcv*)(sigbit+sig), m, "%s%s", on, NrtxSignalName(sig)); } void RtNrtxSigMask::signalmask(long sig) { linereq(sig, SELECTLINE); updatecore(); } void RtNrtxSigMask::sendsig(long sig) { updatecore(core->sendsig(sig)); } void RtNrtxSigMask::setsig(long sig) { mask |= bit(sig); signalmask( sig ); } void RtNrtxSigMask::clrsig(long sig) { mask &= ~bit(sig); if( sig==SIGSTOP || sig==SIGTRAP ) updatecore( "warning: debugging signal disabled" ); signalmask( sig ); } void RtNrtxSigMask::hostclose() { if( pad ){ delete pad; pad = 0; } } void RtNrtxSigMask::clrcurrsig(long andgo) { updatecore(core->clrcurrsig()); if( andgo ) core->process()->go(); else core->process()->cycle(); }