implement WmRt; include "sys.m"; sys: Sys; sprint: import sys; include "bufio.m"; bufio: Bufio; Iobuf: import bufio; include "draw.m"; include "tk.m"; tk: Tk; Toplevel: import tk; include "wmlib.m"; wmlib: Wmlib; include "dis.m"; dis: Dis; Inst, Type, Data, Link, Mod: import dis; XMAGIC: import Dis; MUSTCOMPILE, DONTCOMPILE: import Dis; AMP, AFP, AIMM, AXXX, AIND, AMASK: import Dis; ARM, AXNON, AXIMM, AXINF, AXINM: import Dis; DEFB, DEFW, DEFS, DEFF, DEFA, DIND, DAPOP, DEFL: import Dis; WmRt: module { init: fn(ctxt: ref Draw->Context, argv: list of string); }; t: ref Toplevel; disfile: string; TK: con 1; m: ref Mod; rt, ss: int; rt_cfg := array[] of { "frame .m", "menubutton .m.open -text File -menu .file", "menubutton .m.prop -text Properties -menu .prop", "menubutton .m.view -text View -menu .view", "label .m.l", "pack .m.open .m.view .m.prop -side left", "pack .m.l -side right", "frame .b", "text .b.t -width 12c -height 7c -yscrollcommand {.b.s set} -bg white", "scrollbar .b.s -command {.b.t yview}", "pack .b.s -fill y -side left", "pack .b.t -fill both -expand 1", "pack .m -anchor w -fill x", "pack .b -fill both -expand 1", "pack propagate . 0", "update", "menu .prop", ".prop add checkbutton -text {Must compile} -command {send cmd must}", ".prop add checkbutton -text {Don't compile} -command {send cmd dont}", ".prop add separator", ".prop add command -text {Set stack extent} -command {send cmd stack}", ".prop add command -text {Sign module} -command {send cmd sign}", "menu .view", ".view add command -text {Header} -command {send cmd hdr}", ".view add command -text {Code segment} -command {send cmd code}", ".view add command -text {Data segment} -command {send cmd data}", ".view add command -text {Type descriptors} -command {send cmd type}", ".view add command -text {Link descriptors} -command {send cmd link}", "menu .file", ".file add command -text {Open module} -command {send cmd open}", ".file add separator", ".file add command -text {Write .dis module} -command {send cmd save}", ".file add command -text {Write .s file} -command {send cmd list}", }; init(ctxt: ref Draw->Context, nil: list of string) { sys = load Sys Sys->PATH; tk = load Tk Tk->PATH; wmlib = load Wmlib Wmlib->PATH; wmlib->init(); menubut: chan of string; (t, menubut) = wmlib->titlebar(ctxt.screen, "", "Dis Module Manager", Wmlib->Appl); cmd := chan of string; tk->namechan(t, cmd, "cmd"); wmlib->tkcmds(t, rt_cfg); dis = load Dis Dis->PATH; if(dis == nil) { wmlib->dialog(t, "error -fg red", "Load Module", "wmrt requires Dis", 0, "Exit"::nil); return; } dis->init(); for(;;) alt { menu := <-menubut => if(menu[0] == 'e') return; wmlib->titlectl(t, menu); s := <-cmd => case s { "open" => openfile(ctxt); "save" => writedis(); "list" => writeasm(); "hdr" => hdr(); "code" => das(TK); "data" => dat(TK); "type" => desc(TK); "link" => link(TK); "must" => rt ^= MUSTCOMPILE; "dont" => rt ^= DONTCOMPILE; "stack" => spawn stack(ctxt); "sign" => wmlib->dialog(t, "error -fg red", "Signed Modules", "not implemented", 0, "Continue"::nil); } } } stack_cfg := array[] of { "scale .s -length 200 -to 32768 -resolution 128 -orient horizontal", "frame .f", "pack .s .f -pady 5 -fill x -expand 1", "update", }; stack(ctxt: ref Draw->Context) { (s, sbut) := wmlib->titlebar(ctxt.screen, wmlib->geom(t), "Dis Stack", 0); cmd := chan of string; tk->namechan(s, cmd, "cmd"); wmlib->tkcmds(s, stack_cfg); for(;;) alt { wmctl := <-sbut => if(wmctl[0] == 'e') { ss = int tk->cmd(s, ".s get"); return; } wmlib->titlectl(s, wmctl); } } openfile(ctxt: ref Draw->Context) { pattern := list of { "*.dis (Dis VM module)", "* (All files)" }; for(;;) { disfile = wmlib->filename(ctxt.screen, t, "Dis file", pattern, nil); if(disfile == "") break; s: string; (m, s) = dis->loadobj(disfile); if(s == nil) { tk->cmd(t, ".m.l configure -text {"+m.name+"}"); das(TK); return; } r := wmlib->dialog(t, "error -fg red", "Open Dis File", s, 0, "Retry" :: "Abort" :: nil); if(r == 1) return; } } writedis() { if(m == nil || m.magic == 0) { wmlib->dialog(t, "error -fg red", "Write .dis", "no module loaded", 0, "Continue"::nil); return; } if(m.rt == rt && m.ssize == ss) return; fd: ref Sys->FD; for(;;) { fd = sys->open(disfile, Sys->OWRITE); if(fd != nil) break; r := wmlib->dialog(t, "error -fg red", "Open Dis File", "open failed: "+sprint("%r"), 0, "Retry" :: "Abort" :: nil); if(r == 0) continue; else return; } sys->seek(fd, 4, Sys->SEEKSTART); # skip magic discon(fd, rt); discon(fd, ss); m.rt = rt; m.ssize = ss; } discon(fd: ref Sys->FD, val: int) { a: array of byte; if(val >= -64 && val <= 63) a = array[] of { byte(val & ~16r80) }; else if(val >= -8192 && val <= 8191) a = array[] of { byte((val>>8) & ~16rC0 | 16r80), byte val }; else a = array[] of { byte(val>>24 | 16rC0), byte(val>>16), byte(val>>8), byte val }; sys->write(fd, a, len a); } fasm: ref Iobuf; writeasm() { if(m == nil || m.magic == 0) { wmlib->dialog(t, "error -fg red", "Write .s", "no module loaded", 0, "Continue"::nil); return; } bufio = load Bufio Bufio->PATH; if(bufio == nil) { wmlib->dialog(t, "error -fg red", "Write .s", "Bufio load failed: "+sprint("%r"), 0, "Exit"::nil); return; } for(;;) { asmfile: string; if(len disfile > 4 && disfile[len disfile-4:] == ".dis") asmfile = disfile[0:len disfile-3] + "s"; else asmfile = disfile + ".s"; fasm = bufio->create(asmfile, Sys->OWRITE|Sys->OTRUNC, 8r666); if(fasm != nil) break; r := wmlib->dialog(t, "error -fg red", "Create .s file", "open failed: "+sprint("%r"), 0, "Retry" :: "Abort" :: nil); if(r == 0) continue; else return; } das(!TK); fasm.puts("\tentry\t" + string m.entry + "," + string m.entryt + "\n"); desc(!TK); dat(!TK); fasm.puts("\tmodule\t" + m.name + "\n"); link(!TK); fasm.close(); } link(flag: int) { if(m == nil || m.magic == 0) { wmlib->dialog(t, "error -fg red", "Link Descriptors", "no module loaded", 0, "Continue"::nil); return; } if(flag == TK) tk->cmd(t, ".b.t delete 1.0 end"); for(i := 0; i < m.lsize; i++) { l := m.links[i]; s := sprint(" link %d,%d, 0x%ux, \"%s\"\n", l.desc, l.pc, l.sig, l.name); if(flag == TK) tk->cmd(t, ".b.t insert end '"+s); else fasm.puts(s); } if(flag == TK) tk->cmd(t, ".b.t see 1.0; update"); } desc(flag: int) { if(m == nil || m.magic == 0) { wmlib->dialog(t, "error -fg red", "Type Descriptors", "no module loaded", 0, "Continue"::nil); return; } if(flag == TK) tk->cmd(t, ".b.t delete 1.0 end"); for(i := 0; i < m.tsize; i++) { h := m.types[i]; s := sprint(" desc $%d, %d, \"", i, h.size); for(j := 0; j < h.np; j++) s += sprint("%.2ux", int h.map[j]); s += "\"\n"; if(flag == TK) tk->cmd(t, ".b.t insert end '"+s); else fasm.puts(s); } if(flag == TK) tk->cmd(t, ".b.t see 1.0; update"); } hdr() { if(m == nil || m.magic == 0) { wmlib->dialog(t, "error -fg red", "Header", "no module loaded", 0, "Continue"::nil); return; } tk->cmd(t, ".b.t delete 1.0 end"); s := sprint("%.8ux Version %d Dis VM\n", m.magic, m.magic - XMAGIC + 1); s += sprint("%.8ux Runtime flags %s\n", m.rt, rtflag(m.rt)); s += sprint("%8d bytes per stack extent\n\n", m.ssize); s += sprint("%8d instructions\n", m.isize); s += sprint("%8d data size\n", m.dsize); s += sprint("%8d heap type descriptors\n", m.tsize); s += sprint("%8d link directives\n", m.lsize); s += sprint("%8d entry pc\n", m.entry); s += sprint("%8d entry type descriptor\n\n", m.entryt); if(m.sign == nil) s += "Module is Insecure\n"; tk->cmd(t, ".b.t insert end '"+s); tk->cmd(t, ".b.t see 1.0; update"); } rtflag(flag: int): string { if(flag == 0) return ""; s := "["; if(flag & MUSTCOMPILE) s += "MustCompile"; if(flag & DONTCOMPILE) { if(flag & MUSTCOMPILE) s += "|"; s += "DontCompile"; } s[len s] = ']'; return s; } das(flag: int) { if(m == nil || m.magic == 0) { wmlib->dialog(t, "error -fg red", "Assembly", "no module loaded", 0, "Continue"::nil); return; } if(flag == TK) tk->cmd(t, ".b.t delete 1.0 end"); fi := 0; si := 0; for(i := 0; i < m.isize; i++) { prefix := ""; if(flag == TK) prefix = sprint(".b.t insert end '%4d ", i); else { if(i % 10 == 0) fasm.puts("#" + string i + "\n"); prefix = sprint("\t"); } s := prefix + dis->inst2s(m.inst[i]) + "\n"; if(flag == TK) tk->cmd(t, s); else fasm.puts(s); } if(flag == TK) tk->cmd(t, ".b.t see 1.0; update"); } dat(flag: int) { if(m == nil || m.magic == 0) { wmlib->dialog(t, "error -fg red", "Module Data", "no module loaded", 0, "Continue"::nil); return; } s := sprint(" var @mp, %d\n", m.types[0].size); if(flag == TK) { tk->cmd(t, ".b.t delete 1.0 end"); tk->cmd(t, ".b.t insert end '"+s); } else fasm.puts(s); s = ""; for(d := m.data; d != nil; d = tl d) { pick dat := hd d { Bytes => s = sprint("\tbyte @mp+%d", dat.off); for(n := 0; n < dat.n; n++) s += sprint(",%d", int dat.bytes[n]); Words => s = sprint("\tword @mp+%d", dat.off); for(n := 0; n < dat.n; n++) s += sprint(",%d", dat.words[n]); String => s = sprint("\tstring @mp+%d, \"%s\"", dat.off, mapstr(dat.str)); Reals => s = sprint("\treal @mp+%d", dat.off); for(n := 0; n < dat.n; n++) s += sprint(", %g", dat.reals[n]); break; Array => s = sprint("\tarray @mp+%d,$%d,%d", dat.off, dat.typex, dat.length); Aindex => s = sprint("\tindir @mp+%d,%d", dat.off, dat.index); Arestore => s = "\tapop"; break; Bigs => s = sprint("\tlong @mp+%d", dat.off); for(n := 0; n < dat.n; n++) s += sprint(", %bd", dat.bigs[n]); } if(flag == TK) tk->cmd(t, ".b.t insert end '"+s+"\n"); else fasm.puts(s+"\n"); } if(flag == TK) tk->cmd(t, ".b.t see 1.0; update"); } mapstr(s: string): string { for(i := 0; i < len s; i++) { if(s[i] == '\n') s = s[0:i] + "\\n" + s[i+1:]; } return s; }