#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" SRCFILE("rtraw.c") #define K DB_KERNELID Process *RtRawMaster::domakeproc(char *proc, char *stab, char* comment) { return (Process*) new RtRawProcess(fd, boardid, child, proc, stab, comment); } void RtRawMaster::open() { if (pad) { pad->makecurrent(); refresh(); return; } pad = new Pad( (PadRcv*) this ); pad->options(TRUNCATE|SORTED); pad->name( "%s:%s", parent->name(), name()); pad->banner( "Rawpi %s:%s", parent->name(), name()); pad->makecurrent(); refresh(); } Index RtRawMaster::carte() { Menu m; m.last("open board", (Action)&RtRawMaster::open); return m.index(); } void RtRawMaster::clean(Process *q) { Process *p = 0, *c = child, *t; while (c) { if (c->isdead || (c != q && !eqstr(c->procpath, "!") && c->pad)) { c->userclose(); if (!p) child = c->sibling; else p->sibling = c->sibling; t = c; c = c->sibling; delete t; } else { p = c; c = c->sibling; } } } void RtRawMaster::refresh() { char s[128]; DebugKstate dbk; pad->clear(); makeproc( "!", "a.out", 0); ::dbrequest(fd, boardid, K, DBR_GETSTATE, (int)&dbk, 0, sizeof(dbk)); if (dbk.state != DBKS_NULL) { ::dbrequest(fd, boardid, K, DBR_GETSNAME, (int)s, 0,sizeof(s)); makeproc(sf("%s:-1",name()), sf("%s", s), 0); } } char *RtRawMaster::kbd(char *s) { while( *s == ' ' ) ++s; switch( *s ){ case '!': for( ++s; *s==' '; ++s ) {} makeproc("!", s, 0); break; default: for(; *s==' '; ++s ) {} makeproc(sf("%s:-1",name()), s, 0); break; } return 0; } char *RtRawMaster::help() { return "! {load program} | cmd {attach to program}"; } RtRawProcess::RtRawProcess(int f, int id, Process *sib, char *p, char *s, char *c) : (sib,p,s,c) { fd = f; boardid = id; } void RtRawProcess::takeover() { if( pad ){ open(); insert(ERRORKEY, "take over: already open"); return; } Pick( "take over", (Action)&RtRawProcess::substitute, (long) this ); } int RtRawProcess::accept( Action a ) { return a == (Action)&RtRawProcess::substitute; } void RtRawProcess::substitute(RtRawProcess *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; 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( srcdir ) srcdir->banner(); core->symtab()->banner(); pad->clear(); _bpts->lay(); docycle(); } void RtRawProcess::open() { Menu m, s; char *error; Process::openpad(); if( core ) return; ((RtRawMaster*)master)->clean(this); insert(ERRORKEY, "Checking process and symbol table..."); core = (Core*) new RtRawCore(fd, boardid, this, master); if( error = core->open() ){ delete core; core = 0; m.last( "open process", (Action)&RtRawProcess::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("Bpt List", (Action)&Process::openbpts); _bpts = new Bpts(core); _bpts->lay(); m.last("kill?", (Action)&RtRawProcess::destroy ); m.last(s.index("more")); pad->menu(m); pad->makecurrent(); docycle(); } void RtRawProcess::destroy() { insert(ERRORKEY, core->destroy()); docycle(); } Index RtRawProcess::carte() { Menu m; if(procpath && !strcmp(procpath,"!") ){ m.last("hang & open proc",(Action)&RtRawProcess::hangopen); m.last("hang & take over",(Action)&RtRawProcess::hangtakeover); } else { m.last("open process", (Action)&RtRawProcess::open); m.last("take over", (Action)&RtRawProcess::takeover); } return m.index(); } void RtRawProcess::hang() { if( !dbload(fd, boardid, stabpath) ) { insert(ERRORKEY, "can't load real-time board"); return; } procpath = sf("%s:-1",((RtRawMaster*)master)->name()); master->makeproc("!", stabpath); master->insert(this); } void RtRawProcess::hangopen() { hang(); open(); } void RtRawProcess::hangtakeover() { hang(); takeover(); } const long REG_SPECIAL = 0x40000000; // Address unlikely to be used Behavs RtRawCore::behavs() { readcontrol(); return behavetype(); } char *RtRawCore::destroy() { return dbreq(DBR_KILL); } int RtRawCore::fpvalid(long fp) { return fp != 0; } int RtRawCore::instack(long curfp, long prevfp) { return (curfp>prevfp); } long RtRawCore::regaddr() { return REG_SPECIAL; } char *RtRawCore::run() { return dbreq(DBR_RUN); } long RtRawCore::scratchaddr() { return state.scratchaddr; } char *RtRawCore::stop() { return dbreq(DBR_STOP); } RtRawCore::RtRawCore(int fd, int id, Process *p, Master *m):(p, m) { commfd = fd; boardid = id; } char *RtRawCore::readcontrol() { return dbreq(DBR_GETSTATE, (char*)&state, 0, sizeof(state)); } int RtRawCore::nregs() { switch (attrib.machine) { case DBMT_68000: return NREGS_68000; case DBMT_68010: return NREGS_68010; case DBMT_68020: return NREGS_68020; default: return NREGS_USER; } } char *RtRawCore::dbreq(int req, char* addr,int rarg, int sz) { if (::dbrequest(commfd, boardid, K, req, (int)addr, rarg, sz) == -1) return "dbrequest failed"; return 0; } char *RtRawCore::eventname() { switch (state.state) { case DBKS_NULL: return "no process"; case DBKS_RUNNING: return "running"; case DBKS_STOPPED: return "traced"; case DBKS_ERROR: switch (state.code) { case 0: return "No process"; case TRAP_BUS_ERROR: return "bus error"; case TRAP_ADDR_ERROR: return "address error"; case TRAP_ZERO_DIVIDE: return "zero divide"; case TRAP_CHK: return "chk trap"; case TRAP_TRAPV: return "trapv trap"; case TRAP_PRIVILEGE: return "privilege violation"; case TRAP_TRACE: return "trace trap"; case TRAP_10_EMULATOR: case TRAP_11_EMULATOR: return "emulator trap"; case TRAP_COPROCESSOR: return "coprocessor error"; case TRAP_FORMAT_ERROR: return "format error"; case INTRPT_UNINITIALIZED: return "unintialized interrupt"; case INTRPT_SPURIOUS: return "spurious interrupt"; default: return sf("Unexpected trap or intrpt 0x%x\n", state.code); } default: return "unknown state"; } } char *RtRawCore::laybpt(Trap *t) { t->saved = peek(t->stmt->range.lo)->sht; return dbreq(DBR_SETBKPT, 0, t->stmt->range.lo); } Behavs RtRawCore::behavetype() { switch( state.state ){ case DBKS_NULL: state.code = 0; return PENDING; case DBKS_RUNNING: return ACTIVE; case DBKS_STOPPED: if (state.code == DBKC_TRAP) return BREAKED; else return HALTED; case DBKS_ERROR: default: return PENDING; } } char *RtRawCore::open() { if( stabpath() ){ stabfd = ::open(stabpath(),0); if( stabfd<0 ) return SysErr( "symbol tables: " ); } else return "open error"; dbreq(DBR_GETATTRIB, (char*)&attrib, 0, sizeof(attrib)); _online = 1; stabfstat(); _symtab = new BsdSymTab(this, stabfd, _symtab); _symtab->read(); return readcontrol(); } char *RtRawCore::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 *RtRawCore::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 *RtRawCore::dostep(long lo, long hi, int sstep) { char *error; long fp0, time0, time(long); int i; static int waittime[] = {1,1,2,4,6}; 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 && state.state != DBKS_STOPPED) error = "single step error"; 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); } }