implement Debug; include "sys.m";sys: Sys;sprint, FD: import sys; include "string.m";str: String; include "draw.m"; include "debug.m"; include "dis.m"; dism: Dis; Command: module{ init: fn(ctxt: ref Draw->Context, argv: list of string);}; Spin: adt{ spin: int; pspin: int;}; SrcState: adt{ files: array of string; lastf: int; lastl: int; vers: int; # version number # 11 => more source states}; typenames := array[] of { Terror => "error", Tid => "id", Tadt => "adt", Tadtpick => "adtpick", Tarray => "array", Tbig => "big", Tbyte => "byte", Tchan => "chan", Treal => "real", Tfn => "fn", Targ => "arg", Tlocal => "local", Tglobal => "global", Tint => "int", Tlist => "list", Tmodule => "module", Tnil => "nil", Tnone => "none", Tref => "ref", Tstring => "string", Ttuple => "tuple", Tend => "end", Targs => "args", Tslice => "slice", Tpoly => "poly",}; tnone: ref Type;tnil: ref Type;tint: ref Type;tbyte: ref Type;tbig: ref Type;treal: ref Type;tstring: ref Type;tpoly: ref Type; IBY2WD: con 4;IBY2LG: con 8;H: con int 16rffffffff; ModHash: con 32;SymHash: con 32;mods:= array[ModHash] of list of ref Module;syms:= array[SymHash] of list of ref Sym; sblpath := array[] of{ ("/dis/", "/appl/cmd/"), ("/dis/", "/appl/"),}; init(): int{ sys = load Sys Sys->PATH; str = load String String->PATH; if(sys == nil || str == nil) return 0; tnone = ref Type(nil, Tnone, 0, "", nil, nil, nil); tnil = ref Type(nil, Tnil, IBY2WD, "nil", nil, nil, nil); tint = ref Type(nil, Tint, IBY2WD, "int", nil, nil, nil); tbyte = ref Type(nil, Tbyte, 1, "byte", nil, nil, nil); tbig = ref Type(nil, Tbig, IBY2LG, "big", nil, nil, nil); treal = ref Type(nil, Treal, IBY2LG, "real", nil, nil, nil); tstring = ref Type(nil, Tstring, IBY2WD, "string", nil, nil, nil); tpoly = ref Type(nil, Tpoly, IBY2WD, "polymorphic", nil, nil, nil); return 1;} prog(pid: int): (ref Prog, string){ spid := string pid; h := sys->open("/prog/"+spid+"/heap", sys->ORDWR); if(h == nil) return (nil, sprint("can't open heap file: %r")); c := sys->open("/prog/"+spid+"/ctl", sys->OWRITE); if(c == nil) return (nil, sprint("can't open ctl file: %r")); d := sys->open("/prog/"+spid+"/dbgctl", sys->ORDWR); if(d == nil) return (nil, sprint("can't open debug ctl file: %r")); s := sys->open("/prog/"+spid+"/stack", sys->OREAD); if(s == nil) return (nil, sprint("can't open stack file: %r")); return (ref Prog(pid, h, c, d, s), "");} startprog(dis, dir: string, ctxt: ref Draw->Context, argv: list of string): (ref Prog, string){ c := load Command dis; if(c == nil) return (nil, "module not loaded"); ack := chan of int; spin := ref Spin(1, 1); end := chan of int; spawn execer(ack, dir, c, ctxt, argv, spin, end); kid := <-ack; fd := sys->open("/prog/"+string kid+"/dbgctl", sys->ORDWR); if(fd == nil){ spin.spin = -1; <- end; return (nil, sprint("can't open debug ctl file: %r")); } done := chan of string; spawn stepper(done, fd, spin); wait: for(;;){ alt{ <-ack => sys->sleep(0); err := <-done => if(err != ""){ <- end; return(nil, err); } break wait; } } b := array[20] of byte; n := sys->read(fd, b, len b); if(n <= 0){ <- end; return(nil, sprint("%r")); } msg := string b[:n]; if(!str->prefix("new ", msg)){ <- end; return (nil, msg); } kid = int msg[len "new ":]; # clean up the execer slave b = array of byte "start"; sys->write(fd, b, len b); <- end; return prog(kid);} stepper(done: chan of string, ctl: ref FD, spin: ref Spin){ b := array of byte "step1"; while(spin.pspin){ if(sys->write(ctl, b, len b) != len b) done <-= sprint("can't start new thread: %r"); spin.spin = 0; } done <-= "";} execer(ack: chan of int, dir: string, c: Command, ctxt: ref Draw->Context, args: list of string, spin: ref Spin, end: chan of int){ pid := sys->pctl(Sys->NEWPGRP|Sys->FORKNS|Sys->NEWFD, 0::1::2::nil); sys->chdir(dir); while(spin.spin == 1) ack <-= pid; if(spin.spin == -1){ end <-= 0; exit; } spawn c->init(ctxt, args); spin.pspin = 0; end <-= 0; exit;} # format of each line is# fp pc mp prog compiled path# fp, pc, mp, and prog are %.8lux# compile is or 1# path is a stringProg.stack(p: self ref Prog): (array of ref Exp, string){ buf := array[8192] of byte; sys->seek(p.stk, big 0, 0); n := sys->read(p.stk, buf, len buf - 1); if(n < 0) return (nil, sprint("can't read stack file: %r")); buf[n] = byte 0; t := 0; nf := 0; for(s := 0; s < n; s = t+1){ t = strchr(buf, s, '\n'); if(buf[t] != byte '\n' || t-s < 40) continue; nf++; } e := array[nf] of ref Exp; nf = 0; for(s = 0; s < n; s = t+1){ t = strchr(buf, s, '\n'); if(buf[t] != byte '\n' || t-s < 40) continue; e[nf] = ref Exp("unknown fn", hex(buf[s+0:s+8]), hex(buf[s+9:s+17]), mkmod(hex(buf[s+18:s+26]), hex(buf[s+27:s+35]), buf[36] != byte '0', string buf[s+38:t]), p, nil); nf++; } return (e, "");} Prog.step(p: self ref Prog, how: int): string{ (stack, nil) := p.stack(); if(stack == nil) return "can't find initial pc"; src := stack[0].srcstr(); stmt := ftostmt(stack[0]); if(stack[0].m.sym == nil) how = -1; buf := array of byte("step1"); if(how == StepOut) buf = array of byte("toret"); while(sys->write(p.dbgctl, buf, len buf) == len buf){ (stk, err) := p.stack(); if(err != nil) return ""; case how{ StepExp => if(src != stk[0].srcstr()) return ""; StepStmt => if(stmt != ftostmt(stk[0])) return ""; if(stk[0].offset != stack[0].offset) return ""; StepOut => if(returned(stack, stk)) return ""; StepOver => if(stk[0].offset == stack[0].offset){ if(stmt != ftostmt(stk[0])) return ""; buf = array of byte("step1"); break; } if(returned(stack, stk)) return ""; buf = array of byte("toret"); * => return ""; } } return sprint("%r");} Prog.stop(p: self ref Prog): string{ return dbgctl(p, "stop");} Prog.unstop(p: self ref Prog): string{ return dbgctl(p, "unstop");} Prog.grab(p: self ref Prog): string{ return dbgctl(p, "step0");} Prog.start(p: self ref Prog): string{ return dbgctl(p, "start");} Prog.cont(p: self ref Prog): string{ return dbgctl(p, "cont");} dbgctl(p: ref Prog, msg: string): string{ b := array of byte msg; while(sys->write(p.dbgctl, b, len b) != len b) return sprint("%r"); return "";} returned(old, new: array of ref Exp): int{ n := len old; if(n > len new) return 1; return 0;} Prog.setbpt(p: self ref Prog, dis: string, pc:int): string{ b := array of byte("bpt set "+dis+" "+string pc); if(sys->write(p.dbgctl, b, len b) != len b) return sprint("can't set breakpoint: %r"); return "";} Prog.delbpt(p: self ref Prog, dis: string, pc:int): string{ b := array of byte("bpt del "+dis+" "+string pc); if(sys->write(p.dbgctl, b, len b) != len b) return sprint("can't del breakpoint: %r"); return "";} Prog.kill(p: self ref Prog): string{ b := array of byte "kill"; if(sys->write(p.ctl, b, len b) != len b) return sprint("can't kill process: %r"); return "";} Prog.event(p: self ref Prog): string{ b := array[100] of byte; n := sys->read(p.dbgctl, b, len b); if(n < 0) return sprint("error: %r"); return string b[:n];} ftostmt(e: ref Exp): int{ m := e.m; if(!m.comp && m.sym != nil && e.pc < len m.sym.srcstmt) return m.sym.srcstmt[e.pc]; return -1;} Exp.srcstr(e: self ref Exp): string{ m := e.m; if(!m.comp && m.sym != nil && e.pc < len m.sym.src){ src := m.sym.src[e.pc]; ss := src.start.file+":"+string src.start.line+"."+string src.start.pos+", "; if(src.stop.file != src.start.file) ss += src.stop.file+":"+string src.stop.line+"."; else if(src.stop.line != src.start.line) ss += string src.stop.line+"."; return ss+string src.stop.pos; } return sprint("Module %s PC %d", e.m.path, e.pc);} Exp.findsym(e: self ref Exp): string{ m := e.m; if(m.comp) return "compiled module"; if(m.sym != nil){ n := e.pc; fns := m.sym.fns; for(i := 0; i < len fns; i++){ if(n >= fns[i].offset && n < fns[i].stoppc){ e.name = fns[i].name; e.id = fns[i]; return ""; } } return "pc out of bounds"; } return "no symbol file";} Exp.src(e: self ref Exp): ref Src{ m := e.m; if(e.id == nil || m.sym == nil) return nil; src := e.id.src; if(src != nil) return src; if(e.id.t.kind == Tfn && !m.comp && e.pc < len m.sym.src && e.pc >= 0) return m.sym.src[e.pc]; return nil;} Type.getkind(t: self ref Type, sym: ref Sym): int{ if(t == nil) return -1; if(t.kind == Tid) return sym.adts[int t.name].getkind(sym); return t.kind;} Type.text(t: self ref Type, sym: ref Sym): string{ if (t == nil) return "no type"; s := typenames[t.kind]; case t.kind { Tadt or Tadtpick or Tmodule => s = t.name; Tid => return sym.adts[int t.name].text(sym); Tarray or Tlist or Tchan or Tslice => s += " of " + t.Of.text(sym); Tref => s += " " + t.Of.text(sym); Tfn => s += "("; for(i := 0; i < len t.ids; i++) s += t.ids[i].name + ": " + t.ids[i].t.text(sym); s += "): " + t.Of.text(sym); Ttuple or Tlocal or Tglobal or Targ => if(t.kind == Ttuple) s = ""; s += "("; for (i := 0; i < len t.ids; i++) { s += t.ids[i].t.text(sym); if (i < len t.ids - 1) s += ", "; } s += ")"; } return s;} Exp.typename(e: self ref Exp): string{ if (e.id == nil) return "no info"; return e.id.t.text(e.m.sym);} Exp.kind(e: self ref Exp): int{ if(e.id == nil) return -1; return e.id.t.getkind(e.m.sym);} EXPLISTMAX : con 32; # what's a good value for this ? Exp.expand(e: self ref Exp): array of ref Exp{ if(e.id == nil) return nil; t := e.id.t; if(t.kind == Tid) t = e.m.sym.adts[int t.name]; off := e.offset;Lines 1–500 of 1497. Load more
implement Debug; include "sys.m"; sys: Sys; sprint, FD: import sys; include "string.m"; str: String; include "draw.m"; include "debug.m"; include "dis.m"; dism: Dis; Command: module { init: fn(ctxt: ref Draw->Context, argv: list of string); }; Spin: adt { spin: int; pspin: int; }; SrcState: adt { files: array of string; lastf: int; lastl: int; vers: int; # version number # 11 => more source states }; typenames := array[] of { Terror => "error", Tid => "id", Tadt => "adt", Tadtpick => "adtpick", Tarray => "array", Tbig => "big", Tbyte => "byte", Tchan => "chan", Treal => "real", Tfn => "fn", Targ => "arg", Tlocal => "local", Tglobal => "global", Tint => "int", Tlist => "list", Tmodule => "module", Tnil => "nil", Tnone => "none", Tref => "ref", Tstring => "string", Ttuple => "tuple", Tend => "end", Targs => "args", Tslice => "slice", Tpoly => "poly", }; tnone: ref Type; tnil: ref Type; tint: ref Type; tbyte: ref Type; tbig: ref Type; treal: ref Type; tstring: ref Type; tpoly: ref Type; IBY2WD: con 4; IBY2LG: con 8; H: con int 16rffffffff; ModHash: con 32; SymHash: con 32; mods:= array[ModHash] of list of ref Module; syms:= array[SymHash] of list of ref Sym; sblpath := array[] of { ("/dis/", "/appl/cmd/"), ("/dis/", "/appl/"), }; init(): int { sys = load Sys Sys->PATH; str = load String String->PATH; if(sys == nil || str == nil) return 0; tnone = ref Type(nil, Tnone, 0, "", nil, nil, nil); tnil = ref Type(nil, Tnil, IBY2WD, "nil", nil, nil, nil); tint = ref Type(nil, Tint, IBY2WD, "int", nil, nil, nil); tbyte = ref Type(nil, Tbyte, 1, "byte", nil, nil, nil); tbig = ref Type(nil, Tbig, IBY2LG, "big", nil, nil, nil); treal = ref Type(nil, Treal, IBY2LG, "real", nil, nil, nil); tstring = ref Type(nil, Tstring, IBY2WD, "string", nil, nil, nil); tpoly = ref Type(nil, Tpoly, IBY2WD, "polymorphic", nil, nil, nil); return 1; } prog(pid: int): (ref Prog, string) { spid := string pid; h := sys->open("/prog/"+spid+"/heap", sys->ORDWR); if(h == nil) return (nil, sprint("can't open heap file: %r")); c := sys->open("/prog/"+spid+"/ctl", sys->OWRITE); if(c == nil) return (nil, sprint("can't open ctl file: %r")); d := sys->open("/prog/"+spid+"/dbgctl", sys->ORDWR); if(d == nil) return (nil, sprint("can't open debug ctl file: %r")); s := sys->open("/prog/"+spid+"/stack", sys->OREAD); if(s == nil) return (nil, sprint("can't open stack file: %r")); return (ref Prog(pid, h, c, d, s), ""); } startprog(dis, dir: string, ctxt: ref Draw->Context, argv: list of string): (ref Prog, string) { c := load Command dis; if(c == nil) return (nil, "module not loaded"); ack := chan of int; spin := ref Spin(1, 1); end := chan of int; spawn execer(ack, dir, c, ctxt, argv, spin, end); kid := <-ack; fd := sys->open("/prog/"+string kid+"/dbgctl", sys->ORDWR); if(fd == nil){ spin.spin = -1; <- end; return (nil, sprint("can't open debug ctl file: %r")); } done := chan of string; spawn stepper(done, fd, spin); wait: for(;;){ alt{ <-ack => sys->sleep(0); err := <-done => if(err != ""){ <- end; return(nil, err); } break wait; } } b := array[20] of byte; n := sys->read(fd, b, len b); if(n <= 0){ <- end; return(nil, sprint("%r")); } msg := string b[:n]; if(!str->prefix("new ", msg)){ <- end; return (nil, msg); } kid = int msg[len "new ":]; # clean up the execer slave b = array of byte "start"; sys->write(fd, b, len b); <- end; return prog(kid); } stepper(done: chan of string, ctl: ref FD, spin: ref Spin) { b := array of byte "step1"; while(spin.pspin){ if(sys->write(ctl, b, len b) != len b) done <-= sprint("can't start new thread: %r"); spin.spin = 0; } done <-= ""; } execer(ack: chan of int, dir: string, c: Command, ctxt: ref Draw->Context, args: list of string, spin: ref Spin, end: chan of int) { pid := sys->pctl(Sys->NEWPGRP|Sys->FORKNS|Sys->NEWFD, 0::1::2::nil); sys->chdir(dir); while(spin.spin == 1) ack <-= pid; if(spin.spin == -1){ end <-= 0; exit; } spawn c->init(ctxt, args); spin.pspin = 0; end <-= 0; exit; } # format of each line is # fp pc mp prog compiled path # fp, pc, mp, and prog are %.8lux # compile is or 1 # path is a string Prog.stack(p: self ref Prog): (array of ref Exp, string) { buf := array[8192] of byte; sys->seek(p.stk, big 0, 0); n := sys->read(p.stk, buf, len buf - 1); if(n < 0) return (nil, sprint("can't read stack file: %r")); buf[n] = byte 0; t := 0; nf := 0; for(s := 0; s < n; s = t+1){ t = strchr(buf, s, '\n'); if(buf[t] != byte '\n' || t-s < 40) continue; nf++; } e := array[nf] of ref Exp; nf = 0; for(s = 0; s < n; s = t+1){ t = strchr(buf, s, '\n'); if(buf[t] != byte '\n' || t-s < 40) continue; e[nf] = ref Exp("unknown fn", hex(buf[s+0:s+8]), hex(buf[s+9:s+17]), mkmod(hex(buf[s+18:s+26]), hex(buf[s+27:s+35]), buf[36] != byte '0', string buf[s+38:t]), p, nil); nf++; } return (e, ""); } Prog.step(p: self ref Prog, how: int): string { (stack, nil) := p.stack(); if(stack == nil) return "can't find initial pc"; src := stack[0].srcstr(); stmt := ftostmt(stack[0]); if(stack[0].m.sym == nil) how = -1; buf := array of byte("step1"); if(how == StepOut) buf = array of byte("toret"); while(sys->write(p.dbgctl, buf, len buf) == len buf){ (stk, err) := p.stack(); if(err != nil) return ""; case how{ StepExp => if(src != stk[0].srcstr()) return ""; StepStmt => if(stmt != ftostmt(stk[0])) return ""; if(stk[0].offset != stack[0].offset) return ""; StepOut => if(returned(stack, stk)) return ""; StepOver => if(stk[0].offset == stack[0].offset){ if(stmt != ftostmt(stk[0])) return ""; buf = array of byte("step1"); break; } if(returned(stack, stk)) return ""; buf = array of byte("toret"); * => return ""; } } return sprint("%r"); } Prog.stop(p: self ref Prog): string { return dbgctl(p, "stop"); } Prog.unstop(p: self ref Prog): string { return dbgctl(p, "unstop"); } Prog.grab(p: self ref Prog): string { return dbgctl(p, "step0"); } Prog.start(p: self ref Prog): string { return dbgctl(p, "start"); } Prog.cont(p: self ref Prog): string { return dbgctl(p, "cont"); } dbgctl(p: ref Prog, msg: string): string { b := array of byte msg; while(sys->write(p.dbgctl, b, len b) != len b) return sprint("%r"); return ""; } returned(old, new: array of ref Exp): int { n := len old; if(n > len new) return 1; return 0; } Prog.setbpt(p: self ref Prog, dis: string, pc:int): string { b := array of byte("bpt set "+dis+" "+string pc); if(sys->write(p.dbgctl, b, len b) != len b) return sprint("can't set breakpoint: %r"); return ""; } Prog.delbpt(p: self ref Prog, dis: string, pc:int): string { b := array of byte("bpt del "+dis+" "+string pc); if(sys->write(p.dbgctl, b, len b) != len b) return sprint("can't del breakpoint: %r"); return ""; } Prog.kill(p: self ref Prog): string { b := array of byte "kill"; if(sys->write(p.ctl, b, len b) != len b) return sprint("can't kill process: %r"); return ""; } Prog.event(p: self ref Prog): string { b := array[100] of byte; n := sys->read(p.dbgctl, b, len b); if(n < 0) return sprint("error: %r"); return string b[:n]; } ftostmt(e: ref Exp): int { m := e.m; if(!m.comp && m.sym != nil && e.pc < len m.sym.srcstmt) return m.sym.srcstmt[e.pc]; return -1; } Exp.srcstr(e: self ref Exp): string { m := e.m; if(!m.comp && m.sym != nil && e.pc < len m.sym.src){ src := m.sym.src[e.pc]; ss := src.start.file+":"+string src.start.line+"."+string src.start.pos+", "; if(src.stop.file != src.start.file) ss += src.stop.file+":"+string src.stop.line+"."; else if(src.stop.line != src.start.line) ss += string src.stop.line+"."; return ss+string src.stop.pos; } return sprint("Module %s PC %d", e.m.path, e.pc); } Exp.findsym(e: self ref Exp): string { m := e.m; if(m.comp) return "compiled module"; if(m.sym != nil){ n := e.pc; fns := m.sym.fns; for(i := 0; i < len fns; i++){ if(n >= fns[i].offset && n < fns[i].stoppc){ e.name = fns[i].name; e.id = fns[i]; return ""; } } return "pc out of bounds"; } return "no symbol file"; } Exp.src(e: self ref Exp): ref Src { m := e.m; if(e.id == nil || m.sym == nil) return nil; src := e.id.src; if(src != nil) return src; if(e.id.t.kind == Tfn && !m.comp && e.pc < len m.sym.src && e.pc >= 0) return m.sym.src[e.pc]; return nil; } Type.getkind(t: self ref Type, sym: ref Sym): int { if(t == nil) return -1; if(t.kind == Tid) return sym.adts[int t.name].getkind(sym); return t.kind; } Type.text(t: self ref Type, sym: ref Sym): string { if (t == nil) return "no type"; s := typenames[t.kind]; case t.kind { Tadt or Tadtpick or Tmodule => s = t.name; Tid => return sym.adts[int t.name].text(sym); Tarray or Tlist or Tchan or Tslice => s += " of " + t.Of.text(sym); Tref => s += " " + t.Of.text(sym); Tfn => s += "("; for(i := 0; i < len t.ids; i++) s += t.ids[i].name + ": " + t.ids[i].t.text(sym); s += "): " + t.Of.text(sym); Ttuple or Tlocal or Tglobal or Targ => if(t.kind == Ttuple) s = ""; s += "("; for (i := 0; i < len t.ids; i++) { s += t.ids[i].t.text(sym); if (i < len t.ids - 1) s += ", "; } s += ")"; } return s; } Exp.typename(e: self ref Exp): string { if (e.id == nil) return "no info"; return e.id.t.text(e.m.sym); } Exp.kind(e: self ref Exp): int { if(e.id == nil) return -1; return e.id.t.getkind(e.m.sym); } EXPLISTMAX : con 32; # what's a good value for this ? Exp.expand(e: self ref Exp): array of ref Exp { if(e.id == nil) return nil; t := e.id.t; if(t.kind == Tid) t = e.m.sym.adts[int t.name]; off := e.offset;