1implement Debug; 2 3include "sys.m"; 4sys: Sys; 5sprint, FD: import sys; 6 7include "string.m"; 8str: String; 9 10include "draw.m"; 11 12include "debug.m"; 13 14include "dis.m"; 15 dism: Dis; 16 17Command: module 18{ 19 init: fn(ctxt: ref Draw->Context, argv: list of string); 20}; 21 22Spin: adt 23{ 24 spin: int; 25 pspin: int; 26}; 27 28SrcState: adt 29{ 30 files: array of string; 31 lastf: int; 32 lastl: int; 33 vers: int; # version number 34 # 11 => more source states 35}; 36 37typenames := array[] of { 38 Terror => "error", 39 Tid => "id", 40 Tadt => "adt", 41 Tadtpick => "adtpick", 42 Tarray => "array", 43 Tbig => "big", 44 Tbyte => "byte", 45 Tchan => "chan", 46 Treal => "real", 47 Tfn => "fn", 48 Targ => "arg", 49 Tlocal => "local", 50 Tglobal => "global", 51 Tint => "int", 52 Tlist => "list", 53 Tmodule => "module", 54 Tnil => "nil", 55 Tnone => "none", 56 Tref => "ref", 57 Tstring => "string", 58 Ttuple => "tuple", 59 Tend => "end", 60 Targs => "args", 61 Tslice => "slice", 62 Tpoly => "poly", 63}; 64 65tnone: ref Type; 66tnil: ref Type; 67tint: ref Type; 68tbyte: ref Type; 69tbig: ref Type; 70treal: ref Type; 71tstring: ref Type; 72tpoly: ref Type; 73 74IBY2WD: con 4; 75IBY2LG: con 8; 76H: con int 16rffffffff; 77 78ModHash: con 32; 79SymHash: con 32; 80mods:= array[ModHash] of list of ref Module; 81syms:= array[SymHash] of list of ref Sym; 82 83sblpath := array[] of 84{ 85 ("/dis/", "/appl/cmd/"), 86 ("/dis/", "/appl/"), 87}; 88 89init(): int 90{ 91 sys = load Sys Sys->PATH; 92 str = load String String->PATH; 93 if(sys == nil || str == nil) 94 return 0; 95 tnone = ref Type(nil, Tnone, 0, "", nil, nil, nil); 96 tnil = ref Type(nil, Tnil, IBY2WD, "nil", nil, nil, nil); 97 tint = ref Type(nil, Tint, IBY2WD, "int", nil, nil, nil); 98 tbyte = ref Type(nil, Tbyte, 1, "byte", nil, nil, nil); 99 tbig = ref Type(nil, Tbig, IBY2LG, "big", nil, nil, nil); 100 treal = ref Type(nil, Treal, IBY2LG, "real", nil, nil, nil); 101 tstring = ref Type(nil, Tstring, IBY2WD, "string", nil, nil, nil); 102 tpoly = ref Type(nil, Tpoly, IBY2WD, "polymorphic", nil, nil, nil); 103 return 1; 104} 105 106prog(pid: int): (ref Prog, string) 107{ 108 spid := string pid; 109 h := sys->open("/prog/"+spid+"/heap", sys->ORDWR); 110 if(h == nil) 111 return (nil, sprint("can't open heap file: %r")); 112 c := sys->open("/prog/"+spid+"/ctl", sys->OWRITE); 113 if(c == nil) 114 return (nil, sprint("can't open ctl file: %r")); 115 d := sys->open("/prog/"+spid+"/dbgctl", sys->ORDWR); 116 if(d == nil) 117 return (nil, sprint("can't open debug ctl file: %r")); 118 s := sys->open("/prog/"+spid+"/stack", sys->OREAD); 119 if(s == nil) 120 return (nil, sprint("can't open stack file: %r")); 121 return (ref Prog(pid, h, c, d, s), ""); 122} 123 124startprog(dis, dir: string, ctxt: ref Draw->Context, argv: list of string): (ref Prog, string) 125{ 126 c := load Command dis; 127 if(c == nil) 128 return (nil, "module not loaded"); 129 130 ack := chan of int; 131 spin := ref Spin(1, 1); 132 end := chan of int; 133 spawn execer(ack, dir, c, ctxt, argv, spin, end); 134 kid := <-ack; 135 136 fd := sys->open("/prog/"+string kid+"/dbgctl", sys->ORDWR); 137 if(fd == nil){ 138 spin.spin = -1; 139 <- end; 140 return (nil, sprint("can't open debug ctl file: %r")); 141 } 142 done := chan of string; 143 spawn stepper(done, fd, spin); 144 145wait: for(;;){ 146 alt{ 147 <-ack => 148 sys->sleep(0); 149 err := <-done => 150 if(err != ""){ 151 <- end; 152 return(nil, err); 153 } 154 break wait; 155 } 156 } 157 158 b := array[20] of byte; 159 n := sys->read(fd, b, len b); 160 if(n <= 0){ 161 <- end; 162 return(nil, sprint("%r")); 163 } 164 msg := string b[:n]; 165 if(!str->prefix("new ", msg)){ 166 <- end; 167 return (nil, msg); 168 } 169 170 kid = int msg[len "new ":]; 171 172 # clean up the execer slave 173 b = array of byte "start"; 174 sys->write(fd, b, len b); 175 176 <- end; 177 return prog(kid); 178} 179 180stepper(done: chan of string, ctl: ref FD, spin: ref Spin) 181{ 182 b := array of byte "step1"; 183 while(spin.pspin){ 184 if(sys->write(ctl, b, len b) != len b) 185 done <-= sprint("can't start new thread: %r"); 186 spin.spin = 0; 187 } 188 done <-= ""; 189} 190 191execer(ack: chan of int, dir: string, c: Command, ctxt: ref Draw->Context, args: list of string, spin: ref Spin, end: chan of int) 192{ 193 pid := sys->pctl(Sys->NEWPGRP|Sys->FORKNS|Sys->NEWFD, 0::1::2::nil); 194 sys->chdir(dir); 195 while(spin.spin == 1) 196 ack <-= pid; 197 if(spin.spin == -1){ 198 end <-= 0; 199 exit; 200 } 201 spawn c->init(ctxt, args); 202 spin.pspin = 0; 203 end <-= 0; 204 exit; 205} 206 207# format of each line is 208# fp pc mp prog compiled path 209# fp, pc, mp, and prog are %.8lux 210# compile is or 1 211# path is a string 212Prog.stack(p: self ref Prog): (array of ref Exp, string) 213{ 214 buf := array[8192] of byte; 215 sys->seek(p.stk, big 0, 0); 216 n := sys->read(p.stk, buf, len buf - 1); 217 if(n < 0) 218 return (nil, sprint("can't read stack file: %r")); 219 buf[n] = byte 0; 220 221 t := 0; 222 nf := 0; 223 for(s := 0; s < n; s = t+1){ 224 t = strchr(buf, s, '\n'); 225 if(buf[t] != byte '\n' || t-s < 40) 226 continue; 227 nf++; 228 } 229 230 e := array[nf] of ref Exp; 231 nf = 0; 232 for(s = 0; s < n; s = t+1){ 233 t = strchr(buf, s, '\n'); 234 if(buf[t] != byte '\n' || t-s < 40) 235 continue; 236 e[nf] = ref Exp("unknown fn", 237 hex(buf[s+0:s+8]), 238 hex(buf[s+9:s+17]), 239 mkmod(hex(buf[s+18:s+26]), hex(buf[s+27:s+35]), buf[36] != byte '0', string buf[s+38:t]), 240 p, 241 nil); 242 nf++; 243 } 244 245 return (e, ""); 246} 247 248Prog.step(p: self ref Prog, how: int): string 249{ 250 (stack, nil) := p.stack(); 251 if(stack == nil) 252 return "can't find initial pc"; 253 src := stack[0].srcstr(); 254 stmt := ftostmt(stack[0]); 255 256 if(stack[0].m.sym == nil) 257 how = -1; 258 259 buf := array of byte("step1"); 260 if(how == StepOut) 261 buf = array of byte("toret"); 262 while(sys->write(p.dbgctl, buf, len buf) == len buf){ 263 (stk, err) := p.stack(); 264 if(err != nil) 265 return ""; 266 case how{ 267 StepExp => 268 if(src != stk[0].srcstr()) 269 return ""; 270 StepStmt => 271 if(stmt != ftostmt(stk[0])) 272 return ""; 273 if(stk[0].offset != stack[0].offset) 274 return ""; 275 StepOut => 276 if(returned(stack, stk)) 277 return ""; 278 StepOver => 279 if(stk[0].offset == stack[0].offset){ 280 if(stmt != ftostmt(stk[0])) 281 return ""; 282 buf = array of byte("step1"); 283 break; 284 } 285 if(returned(stack, stk)) 286 return ""; 287 buf = array of byte("toret"); 288 * => 289 return ""; 290 } 291 } 292 return sprint("%r"); 293} 294 295Prog.stop(p: self ref Prog): string 296{ 297 return dbgctl(p, "stop"); 298} 299 300Prog.unstop(p: self ref Prog): string 301{ 302 return dbgctl(p, "unstop"); 303} 304 305Prog.grab(p: self ref Prog): string 306{ 307 return dbgctl(p, "step0"); 308} 309 310Prog.start(p: self ref Prog): string 311{ 312 return dbgctl(p, "start"); 313} 314 315Prog.cont(p: self ref Prog): string 316{ 317 return dbgctl(p, "cont"); 318} 319 320dbgctl(p: ref Prog, msg: string): string 321{ 322 b := array of byte msg; 323 while(sys->write(p.dbgctl, b, len b) != len b) 324 return sprint("%r"); 325 return ""; 326} 327 328returned(old, new: array of ref Exp): int 329{ 330 n := len old; 331 if(n > len new) 332 return 1; 333 return 0; 334} 335 336Prog.setbpt(p: self ref Prog, dis: string, pc:int): string 337{ 338 b := array of byte("bpt set "+dis+" "+string pc); 339 if(sys->write(p.dbgctl, b, len b) != len b) 340 return sprint("can't set breakpoint: %r"); 341 return ""; 342} 343 344Prog.delbpt(p: self ref Prog, dis: string, pc:int): string 345{ 346 b := array of byte("bpt del "+dis+" "+string pc); 347 if(sys->write(p.dbgctl, b, len b) != len b) 348 return sprint("can't del breakpoint: %r"); 349 return ""; 350} 351 352Prog.kill(p: self ref Prog): string 353{ 354 b := array of byte "kill"; 355 if(sys->write(p.ctl, b, len b) != len b) 356 return sprint("can't kill process: %r"); 357 return ""; 358} 359 360Prog.event(p: self ref Prog): string 361{ 362 b := array[100] of byte; 363 n := sys->read(p.dbgctl, b, len b); 364 if(n < 0) 365 return sprint("error: %r"); 366 return string b[:n]; 367} 368 369ftostmt(e: ref Exp): int 370{ 371 m := e.m; 372 if(!m.comp && m.sym != nil && e.pc < len m.sym.srcstmt) 373 return m.sym.srcstmt[e.pc]; 374 return -1; 375} 376 377Exp.srcstr(e: self ref Exp): string 378{ 379 m := e.m; 380 if(!m.comp && m.sym != nil && e.pc < len m.sym.src){ 381 src := m.sym.src[e.pc]; 382 ss := src.start.file+":"+string src.start.line+"."+string src.start.pos+", "; 383 if(src.stop.file != src.start.file) 384 ss += src.stop.file+":"+string src.stop.line+"."; 385 else if(src.stop.line != src.start.line) 386 ss += string src.stop.line+"."; 387 return ss+string src.stop.pos; 388 } 389 return sprint("Module %s PC %d", e.m.path, e.pc); 390} 391 392Exp.findsym(e: self ref Exp): string 393{ 394 m := e.m; 395 if(m.comp) 396 return "compiled module"; 397 if(m.sym != nil){ 398 n := e.pc; 399 fns := m.sym.fns; 400 for(i := 0; i < len fns; i++){ 401 if(n >= fns[i].offset && n < fns[i].stoppc){ 402 e.name = fns[i].name; 403 e.id = fns[i]; 404 return ""; 405 } 406 } 407 return "pc out of bounds"; 408 } 409 return "no symbol file"; 410} 411 412Exp.src(e: self ref Exp): ref Src 413{ 414 m := e.m; 415 if(e.id == nil || m.sym == nil) 416 return nil; 417 src := e.id.src; 418 if(src != nil) 419 return src; 420 if(e.id.t.kind == Tfn && !m.comp && e.pc < len m.sym.src && e.pc >= 0) 421 return m.sym.src[e.pc]; 422 return nil; 423} 424 425Type.getkind(t: self ref Type, sym: ref Sym): int 426{ 427 if(t == nil) 428 return -1; 429 if(t.kind == Tid) 430 return sym.adts[int t.name].getkind(sym); 431 return t.kind; 432} 433 434Type.text(t: self ref Type, sym: ref Sym): string 435{ 436 if (t == nil) 437 return "no type"; 438 s := typenames[t.kind]; 439 case t.kind { 440 Tadt or 441 Tadtpick or 442 Tmodule => 443 s = t.name; 444 Tid => 445 return sym.adts[int t.name].text(sym); 446 Tarray or 447 Tlist or 448 Tchan or 449 Tslice => 450 s += " of " + t.Of.text(sym); 451 Tref => 452 s += " " + t.Of.text(sym); 453 Tfn => 454 s += "("; 455 for(i := 0; i < len t.ids; i++) 456 s += t.ids[i].name + ": " + t.ids[i].t.text(sym); 457 s += "): " + t.Of.text(sym); 458 Ttuple or 459 Tlocal or 460 Tglobal or 461 Targ => 462 if(t.kind == Ttuple) 463 s = ""; 464 s += "("; 465 for (i := 0; i < len t.ids; i++) { 466 s += t.ids[i].t.text(sym); 467 if (i < len t.ids - 1) 468 s += ", "; 469 } 470 s += ")"; 471 } 472 return s; 473} 474 475Exp.typename(e: self ref Exp): string 476{ 477 if (e.id == nil) 478 return "no info"; 479 return e.id.t.text(e.m.sym); 480} 481 482Exp.kind(e: self ref Exp): int 483{ 484 if(e.id == nil) 485 return -1; 486 return e.id.t.getkind(e.m.sym); 487} 488 489EXPLISTMAX : con 32; # what's a good value for this ? 490 491Exp.expand(e: self ref Exp): array of ref Exp 492{ 493 if(e.id == nil) 494 return nil; 495 496 t := e.id.t; 497 if(t.kind == Tid) 498 t = e.m.sym.adts[int t.name]; 499 500 off := e.offset; 501 ids := t.ids; 502 case t.kind{ 503 Tadt or Tfn or Targ or Tlocal or Ttuple => 504 break; 505 Tadtpick => 506 break; 507 Tglobal => 508 ids = e.m.sym.vars; 509 off = e.m.data; 510 Tmodule => 511 (s, err) := pdata(e.p, off, "M"); 512 if(s == "nil" || err != "") 513 return nil; 514 off = hex(array of byte s); 515 Tref => 516 (s, err) := pdata(e.p, off, "P"); 517 if(s == "nil" || err != "") 518 return nil; 519 off = hex(array of byte s); 520 et := t.Of; 521 if(et.kind == Tid) 522 et = e.m.sym.adts[int et.name]; 523 ids = et.ids; 524 if(et.kind == Tadtpick){ 525 (s, err) = pdata(e.p, off, "W"); 526 tg := int s; 527 if(tg < 0 || tg > len et.tags || err != "" ) 528 return nil; 529 k := array[1 + len ids + len et.tags[tg].ids] of ref Exp; 530 k[0] = ref Exp(et.tags[tg].name, off+0, e.pc, e.m, e.p, ref Id(et.src, et.tags[tg].name, 0, 0, tint)); 531 x := 1; 532 for(i := 0; i < len ids; i++){ 533 id := ids[i]; 534 k[i+x] = ref Exp(id.name, off+id.offset, e.pc, e.m, e.p, id); 535 } 536 x += len ids; 537 ids = et.tags[tg].ids; 538 for(i = 0; i < len ids; i++){ 539 id := ids[i]; 540 k[i+x] = ref Exp(id.name, off+id.offset, e.pc, e.m, e.p, id); 541 } 542 return k; 543 } 544 Tlist => 545 (s, err) := pdata(e.p, off, "L"); 546 if(err != "") 547 return nil; 548 (tloff, hdoff) := str->splitl(s, "."); 549 hdoff = hdoff[1:]; 550 k := array[2] of ref Exp; 551 k[0] = ref Exp("hd", hex(array of byte hdoff), e.pc, e.m, e.p, ref Id(nil, "hd", H, H, t.Of)); 552 k[1] = ref Exp("tl", hex(array of byte tloff), e.pc, e.m, e.p, ref Id(nil, "tl", H, H, t)); 553 return k; 554 Tarray => 555 (s, nil) := pdata(e.p, e.offset, "A"); 556 if(s == "nil") 557 return nil; 558 (sn, sa) := str->splitl(s, "."); 559 n := int sn; 560 if(sa == "" || n <= 0) 561 return nil; 562 (off, nil) = str->toint(sa[1:], 16); 563 et := t.Of; 564 if(et.kind == Tid) 565 et = e.m.sym.adts[int et.name]; 566 esize := et.size; 567 if (n <= EXPLISTMAX || EXPLISTMAX == 0) { 568 k := array[n] of ref Exp; 569 for(i := 0; i < n; i++){ 570 name := string i; 571 k[i] = ref Exp(name, off+i*esize, e.pc, e.m, e.p, ref Id(nil, name, H, H, et)); 572 } 573 return k; 574 } 575 else { 576 # slice it 577 (p, q, r) := partition(n, EXPLISTMAX); 578 lb := 0; 579 k := array[p] of ref Exp; 580 st := ref Type(et.src, Tslice, 0, nil, et, nil, nil); 581 for (i := 0; i < p; i++){ 582 ub := lb+q-1; 583 if (--r >= 0) 584 ub++; 585 name := string lb + ".." + string ub; 586 k[i] = ref Exp(name, off+lb*esize, e.pc, e.m, e.p, ref Id(nil, name, H, H, st)); 587 lb = ub+1; 588 } 589 return k; 590 } 591 Tslice => 592 (lb, ub) := bounds(e.name); 593 if (lb > ub) 594 return nil; 595 n := ub-lb+1; 596 et := t.Of; 597 if(et.kind == Tid) 598 et = e.m.sym.adts[int et.name]; 599 esize := et.size; 600 if (n <= EXPLISTMAX || EXPLISTMAX == 0) { 601 k := array[n] of ref Exp; 602 for(i := 0; i < n; i++){ 603 name := string (i+lb); 604 k[i] = ref Exp(name, off+i*esize, e.pc, e.m, e.p, ref Id(nil, name, H, H, et)); 605 } 606 return k; 607 } 608 else { 609 # slice it again 610 (p, q, r) := partition(n, EXPLISTMAX); 611 lb0 := lb; 612 k := array[p] of ref Exp; 613 st := ref Type(et.src, Tslice, 0, nil, et, nil, nil); 614 for (i := 0; i < p; i++){ 615 ub = lb+q-1; 616 if (--r >= 0) 617 ub++; 618 name := string lb + ".." + string ub; 619 k[i] = ref Exp(name, off+(lb-lb0)*esize, e.pc, e.m, e.p, ref Id(nil, name, H, H, st)); 620 lb = ub+1; 621 } 622 return k; 623 } 624 Tchan => 625 (s, nil) := pdata(e.p, e.offset, "c"); 626 if(s == "nil") 627 return nil; 628 (sn, sa) := str->splitl(s, "."); 629 n := int sn; 630 if(sa == "" || n <= 0) 631 return nil; 632 (off, nil) = str->toint(sa[1:], 16); 633 (nil, sa) = str->splitl(sa[1:], "."); 634 (sn, sa) = str->splitl(sa[1:], "."); 635 f := int sn; 636 sz := int sa[1:]; 637 et := t.Of; 638 if(et.kind == Tid) 639 et = e.m.sym.adts[int et.name]; 640 esize := et.size; 641 k := array[sz] of ref Exp; 642 for(i := 0; i < sz; i++){ 643 name := string i; 644 j := (f+i)%n; 645 k[i] = ref Exp(name, off+j*esize, e.pc, e.m, e.p, ref Id(nil, name, H, H, et)); 646 } 647 return k; 648 * => 649 return nil; 650 } 651 k := array[len ids] of ref Exp; 652 for(i := 0; i < len k; i++){ 653 id := ids[i]; 654 k[i] = ref Exp(id.name, off+id.offset, e.pc, e.m, e.p, id); 655 } 656 return k; 657} 658 659Exp.val(e: self ref Exp): (string, int) 660{ 661 if(e.id == nil) 662 return (e.m.path+" unknown fn", 0); 663 t := e.id.t; 664 if(t.kind == Tid) 665 t = e.m.sym.adts[int t.name]; 666 667 w := 0; 668 s := ""; 669 err := ""; 670 p := e.p; 671 case t.kind{ 672 Tfn => 673 if(t.ids != nil) 674 w = 1; 675 src := e.m.sym.src[e.pc]; 676 ss := src.start.file+":"+string src.start.line+"."+string src.start.pos+", "; 677 if(src.stop.file != src.start.file) 678 ss += src.stop.file+":"+string src.stop.line+"."; 679 else if(src.stop.line != src.start.line) 680 ss += string src.stop.line+"."; 681 return (ss+string src.stop.pos, w); 682 Targ or Tlocal or Tglobal or Tadtpick or Ttuple => 683 return ("", 1); 684 Tadt => 685 return ("#" + string e.offset, 1); 686 Tnil => 687 s = "nil"; 688 Tbyte => 689 (s, err) = pdata(p, e.offset, "B"); 690 Tint => 691 (s, err) = pdata(p, e.offset, "W"); 692 Tbig => 693 (s, err) = pdata(p, e.offset, "V"); 694 Treal => 695 (s, err) = pdata(p, e.offset, "R"); 696 Tarray => 697 (s, err) = pdata(p, e.offset, "A"); 698 if(s == "nil") 699 break; 700 (n, a) := str->splitl(s, "."); 701 if(a == "") 702 return ("", 0); 703 s = "["+n+"] @"+a[1:]; 704 w = 1; 705 Tslice => 706 (lb, ub) := bounds(e.name); 707 s = sys->sprint("[:%d] @ %x", ub-lb+1, e.offset); 708 w = 1; 709 Tstring => 710 n : int; 711 (n, s, err) = pstring(p, e.offset); 712 if(err != "") 713 return ("", 0); 714 for(i := 0; i < len s; i++) 715 if(s[i] == '\n') 716 s[i] = '\u008a'; 717 s = "["+string n+"] \""+s+"\""; 718 Tref or Tlist or Tmodule or Tpoly=> 719 (s, err) = pdata(p, e.offset, "P"); 720 if(s == "nil") 721 break; 722 s = "@" + s; 723 w = 1; 724 Tchan => 725 (s, err) = pdata(p, e.offset, "c"); 726 if(s == "nil") 727 break; 728 (n, a) := str->splitl(s, "."); 729 if(a == "") 730 return ("", 0); 731 if(n == "0"){ 732 s = "@" + a[1:]; 733 w = 0; 734 } 735 else{ 736 (a, nil) = str->splitl(a[1:], "."); 737 s = "["+n+"] @"+a; 738 w = 1; 739 } 740 } 741 if(err != "") 742 return ("", 0); 743 return (s, w); 744} 745 746Sym.srctopc(s: self ref Sym, src: ref Src): int 747{ 748 srcs := s.src; 749 line := src.start.line; 750 pos := src.start.pos; 751 (nil, file) := str->splitr(src.start.file, "/"); 752 backup := -1; 753 delta := 80; 754 for(i := 0; i < len srcs; i++){ 755 ss := srcs[i]; 756 if(ss.start.file != file) 757 continue; 758 if(ss.start.line <= line && ss.start.pos <= pos 759 && ss.stop.line >= line && ss.stop.pos >= pos) 760 return i; 761 d := ss.start.line - line; 762 if(d >= 0 && d < delta){ 763 delta = d; 764 backup = i; 765 } 766 } 767 return backup; 768} 769 770Sym.pctosrc(s: self ref Sym, pc: int): ref Src 771{ 772 if(pc < 0 || pc >= len s.src) 773 return nil; 774 return s.src[pc]; 775} 776 777sym(sbl: string): (ref Sym, string) 778{ 779 h := 0; 780 for(i := 0; i < len sbl; i++) 781 h = (h << 1) + sbl[i]; 782 h &= SymHash - 1; 783 for(sl := syms[h]; sl != nil; sl = tl sl){ 784 s := hd sl; 785 if(sbl == s.path) 786 return (s, ""); 787 } 788 (sy, err) := loadsyms(sbl); 789 if(err != "") 790 return (nil, err); 791 syms[h] = sy :: syms[h]; 792 return (sy, ""); 793} 794 795Module.addsym(m: self ref Module, sym: ref Sym) 796{ 797 m.sym = sym; 798} 799 800Module.sbl(m: self ref Module): string 801{ 802 if(m.sym != nil) 803 return m.sym.path; 804 return ""; 805} 806 807Module.dis(m: self ref Module): string 808{ 809 return m.path; 810} 811 812findsbl(dis: string): string 813{ 814 n := len dis; 815 if(n <= 4 || dis[n-4: n] != ".dis") 816 dis += ".dis"; 817 if(dism == nil){ 818 dism = load Dis Dis->PATH; 819 if(dism != nil) 820 dism->init(); 821 } 822 if(dism != nil && (b := dism->src(dis)) != nil){ 823 n = len b; 824 if(n > 2 && b[n-2: n] == ".b"){ 825 sbl := b[0: n-2] + ".sbl"; 826 if(sys->open(sbl, Sys->OREAD) != nil) 827 return sbl; 828 } 829 } 830 return nil; 831} 832 833Module.stdsym(m: self ref Module) 834{ 835 if(m.sym != nil) 836 return; 837 if((sbl := findsbl(m.path)) != nil){ 838 (m.sym, nil) = sym(sbl); 839 return; 840 } 841 sbl = m.path; 842 n := len sbl; 843 if(n > 4 && sbl[n-4:n] == ".dis") 844 sbl = sbl[:n-4]+".sbl"; 845 else 846 sbl = sbl+".sbl"; 847 path := sbl; 848 fd := sys->open(sbl, sys->OREAD); 849 for(i := 0; fd == nil && i < len sblpath; i++){ 850 (dis, src) := sblpath[i]; 851 nd := len dis; 852 if(len sbl > nd && sbl[:nd] == dis){ 853 path = src + sbl[nd:]; 854 fd = sys->open(path, sys->OREAD); 855 } 856 } 857 if(fd == nil) 858 return; 859 (m.sym, nil) = sym(path); 860} 861 862mkmod(data, code, comp: int, dis: string): ref Module 863{ 864 h := 0; 865 for(i := 0; i < len dis; i++) 866 h = (h << 1) + dis[i]; 867 h &= ModHash - 1; 868 sym : ref Sym; 869 for(ml := mods[h]; ml != nil; ml = tl ml){ 870 m := hd ml; 871 if(m.path == dis && m.code == code && m.comp == comp){ 872 sym = m.sym; 873 if(m.data == data) 874 return m; 875 } 876 } 877 m := ref Module(dis, code, data, comp, sym); 878 mods[h] = m :: mods[h]; 879 return m; 880} 881 882pdata(p: ref Prog, a: int, fmt: string): (string, string) 883{ 884 b := array of byte sprint("0x%ux.%s1", a, fmt); 885 if(sys->write(p.heap, b, len b) != len b) 886 return ("", sprint("can't write heap: %r")); 887 888 buf := array[64] of byte; 889 sys->seek(p.heap, big 0, 0); 890 n := sys->read(p.heap, buf, len buf); 891 if(n <= 1) 892 return ("", sprint("can't read heap: %r")); 893 return (string buf[:n-1], ""); 894} 895 896pstring0(p: ref Prog, a: int, blen: int): (int, string, string) 897{ 898 b := array of byte sprint("0x%ux.C1", a); 899 if(sys->write(p.heap, b, len b) != len b) 900 return (-1, "", sprint("can't write heap: %r")); 901 902 buf := array[blen] of byte; 903 sys->seek(p.heap, big 0, 0); 904 n := sys->read(p.heap, buf, len buf-1); 905 if(n <= 1) 906 return (-1, "", sprint("can't read heap: %r")); 907 buf[n] = byte 0; 908 m := strchr(buf, 0, '.'); 909 if(buf[m++] != byte '.') 910 m = 0; 911 return (int string buf[0:m], string buf[m:n], ""); 912} 913 914pstring(p: ref Prog, a: int): (int, string, string) 915{ 916 m, n: int; 917 s, err: string; 918 919 m = 64; 920 for(;;){ 921 (n, s, err) = pstring0(p, a, m); 922 if(err != "" || n <= len s) 923 break; 924 # guard against broken devprog 925 if(m >= 3 * n) 926 return (-1, nil, "bad string"); 927 m *= 2; 928 } 929 return (n, s, err); 930} 931 932Prog.status(p: self ref Prog): (int, string, string, string) 933{ 934 fd := sys->open(sprint("/prog/%d/status", p.id), sys->OREAD); 935 if(fd == nil) 936 return (-1, "", sprint("can't open status file: %r"), ""); 937 buf := array[256] of byte; 938 n := sys->read(fd, buf, len buf); 939 if(n <= 0) 940 return (-1, "", sprint("can't read status file: %r"), ""); 941 (ni, info) := sys->tokenize(string buf[:n], " \t"); 942 if(ni != 6 && ni != 7) 943 return (-1, "", "can't parse status file", ""); 944 info = tl info; 945 if(ni == 6) 946 return (int hd info, hd tl info, hd tl tl info, hd tl tl tl tl info); 947 return (int hd info, hd tl info, hd tl tl tl info, hd tl tl tl tl tl info); 948} 949 950loadsyms(sbl: string): (ref Sym, string) 951{ 952 fd := sys->open(sbl, sys->OREAD); 953 if(fd == nil) 954 return (nil, sprint("Can't open symbol file '%s': %r", sbl)); 955 956 (ok, dir) := sys->fstat(fd); 957 if(ok < 0) 958 return (nil, sprint("Can't read symbol file '%s': %r", sbl)); 959 n := int dir.length; 960 buf := array[n+1] of byte; 961 if(sys->read(fd, buf, n) != n) 962 return (nil, sprint("Can't read symbol file '%s': %r", sbl)); 963 fd = nil; 964 buf[n] = byte 0; 965 966 s := ref Sym; 967 s.path = sbl; 968 969 n = strchr(buf, 0, '\n'); 970 vers := 0; 971 if(string buf[:n] == "limbo .sbl 1.") 972 vers = 10; 973 else if(string buf[:n] == "limbo .sbl 1.1") 974 vers = 11; 975 else if(string buf[:n] == "limbo .sbl 2.0") 976 vers = 20; 977 else if(string buf[:n] == "limbo .sbl 2.1") 978 vers = 21; 979 else 980 return (nil, "Symbol file "+sbl+" out of date"); 981 o := n += 1; 982 n = strchr(buf, o, '\n'); 983 if(buf[n] != byte '\n') 984 return (nil, "Corrupted symbol file "+sbl); 985 s.name = string buf[o:n++]; 986 ss := ref SrcState(nil, 0, 0, vers); 987 err : string; 988 if(n >= 0){ 989 err = "file"; 990 n = debugfiles(ss, buf, n); 991 } 992 if(n >= 0){ 993 err = "pc"; 994 n = debugpc(ss, s, buf, n); 995 } 996 if(n >= 0){ 997 err = "types"; 998 n = debugtys(ss, s, buf, n); 999 } 1000 if(n >= 0){ 1001 err = "fn"; 1002 n = debugfns(ss, s, buf, n); 1003 } 1004 vs: array of ref Id; 1005 if(n >= 0){ 1006 err = "global"; 1007 (vs, n) = debugid(ss, buf, n); 1008 } 1009 if(n < 0) 1010 return (nil, "Corrupted "+err+" symbol table in "+sbl); 1011 s.vars = vs; 1012 return (s, ""); 1013} 1014 1015# 1016# parse a source location 1017# format[file:][line.]pos,[file:][line.]pos' ' 1018# 1019debugsrc(ss: ref SrcState, buf: array of byte, p: int): (ref Src, int) 1020{ 1021 n: int; 1022 src: ref Src; 1023 1024 (n, p) = strtoi(buf, p); 1025 if(buf[p] == byte ':'){ 1026 ss.lastf = n; 1027 (n, p) = strtoi(buf, p + 1); 1028 } 1029 if(buf[p] == byte '.'){ 1030 ss.lastl = n; 1031 (n, p) = strtoi(buf, p + 1); 1032 } 1033 if(buf[p++] != byte ',' || ss.lastf >= len ss.files || ss.lastf < 0) 1034 return (nil, -1); 1035 src = ref Src; 1036 src.start.file = ss.files[ss.lastf]; 1037 src.start.line = ss.lastl; 1038 src.start.pos = n; 1039 1040 (n, p) = strtoi(buf, p); 1041 if(buf[p] == byte ':'){ 1042 ss.lastf = n; 1043 (n, p) = strtoi(buf, p+1); 1044 } 1045 if(buf[p] == byte '.'){ 1046 ss.lastl = n; 1047 (n, p) = strtoi(buf, p + 1); 1048 } 1049 if(buf[p++] != byte ' ' || ss.lastf >= len ss.files || ss.lastf < 0) 1050 return (nil, -1); 1051 src.stop.file = ss.files[ss.lastf]; 1052 src.stop.line = ss.lastl; 1053 src.stop.pos = n; 1054 return (src, p); 1055} 1056 1057# 1058# parse the file table 1059# item format: file: string 1060# 1061debugfiles(ss: ref SrcState, buf: array of byte, p: int): int 1062{ 1063 n, q: int; 1064 1065 (n, p) = strtoi(buf, p); 1066 if(buf[p++] != byte '\n') 1067 return -1; 1068 ss.files = array[n] of string; 1069 for(i := 0; i < n; i++){ 1070 q = strchr(buf, p, '\n'); 1071 ss.files[i] = string buf[p:q]; 1072 p = q + 1; 1073 } 1074 return p; 1075} 1076 1077# 1078# parse the pc to source table 1079# item format: Source stmt 1080# 1081debugpc(ss: ref SrcState, s: ref Sym, buf: array of byte, p: int): int 1082{ 1083 ns: int; 1084 1085 (ns, p) = strtoi(buf, p); 1086 if(buf[p++] != byte '\n') 1087 return -1; 1088 s.src = array[ns] of ref Src; 1089 s.srcstmt = array[ns] of int; 1090 for(i := 0; i < ns; i++){ 1091 (s.src[i], p) = debugsrc(ss, buf, p); 1092 if(p < 0) 1093 return -1; 1094 (s.srcstmt[i], p) = strtoi(buf, p); 1095 if(buf[p++] != byte '\n') 1096 return -1; 1097 } 1098 return p; 1099} 1100 1101# 1102# parse the type table 1103# format: linear list of types 1104# 1105debugtys(ss: ref SrcState, s: ref Sym, buf: array of byte, p: int): int 1106{ 1107 na: int; 1108 1109 (na, p) = strtoi(buf, p); 1110 if(buf[p++] != byte '\n') 1111 return -1; 1112 s.adts = array[na] of ref Type; 1113 adts := s.adts; 1114 for(i := 0; i < na; i++){ 1115 if(ss.vers < 20) 1116 (adts[i], p) = debugadt(ss, buf, p); 1117 else 1118 (adts[i], p) = debugtype(ss, buf, p); 1119 if(p < 0) 1120 return -1; 1121 } 1122 return p; 1123} 1124 1125# 1126# parse the function table 1127# format: pc:name:argids localids rettype 1128# 1129debugfns(ss: ref SrcState, s: ref Sym, buf: array of byte, p: int): int 1130{ 1131 t: ref Type; 1132 args, locals: array of ref Id; 1133 nf, pc, q: int; 1134 1135 (nf, p) = strtoi(buf, p); 1136 if(buf[p++] != byte '\n') 1137 return -1; 1138 s.fns = array[nf] of ref Id; 1139 fns := s.fns; 1140 for(i := 0; i < nf; i++){ 1141 (pc, p) = strtoi(buf, p); 1142 if(buf[p++] != byte ':') 1143 return -2; 1144 q = strchr(buf, p, '\n'); 1145 if(buf[q] != byte '\n') 1146 return -3; 1147 name := string buf[p:q]; 1148 (args, p) = debugid(ss, buf, q + 1); 1149 if(p == -1) 1150 return -4; 1151 (locals, p) = debugid(ss, buf, p); 1152 if(p == -1) 1153 return -5; 1154 (t, p) = debugtype(ss, buf, p); 1155 if(p == -1) 1156 return -6; 1157 nk := 1 + (len args != 0) + (len locals != 0); 1158 kids := array[nk] of ref Id; 1159 nk = 0; 1160 if(len locals != 0) 1161 kids[nk++] = ref Id(nil, "locals", 0, 0, ref Type(nil, Tlocal, 0, nil, nil, locals, nil)); 1162 if(len args != 0) 1163 kids[nk++] = ref Id(nil, "args", 0, 0, ref Type(nil, Targ, 0, nil, nil, args, nil)); 1164 kids[nk++] = ref Id(nil, "module", 0, 0, ref Type(nil, Tglobal, 0, nil, nil, nil, nil)); 1165 args = nil; 1166 locals = nil; 1167 fns[i] = ref Id(nil, name, pc, 0, ref Type(nil, Tfn, 0, name, t, kids, nil)); 1168 } 1169 for(i = 1; i < nf; i++) 1170 fns[i-1].stoppc = fns[i].offset; 1171 fns[i-1].stoppc = len s.src; 1172 return p; 1173} 1174 1175# 1176# parse a list of ids 1177# format: offset ':' name ':' src type '\n' 1178# 1179debugid(ss: ref SrcState, buf: array of byte, p: int): (array of ref Id, int) 1180{ 1181 t: ref Type; 1182 off, nd, q, qq, tq: int; 1183 src: ref Src; 1184 1185 (nd, p) = strtoi(buf, p); 1186 if(buf[p++] != byte '\n') 1187 return (nil, -1); 1188 d := array[nd] of ref Id; 1189 for(i := 0; i < nd; i++){ 1190 (off, q) = strtoi(buf, p); 1191 if(buf[q++] != byte ':') 1192 return (nil, -1); 1193 qq = strchr(buf, q, ':'); 1194 if(buf[qq] != byte ':') 1195 return (nil, -1); 1196 tq = qq + 1; 1197 if(ss.vers > 10){ 1198 (src, tq) = debugsrc(ss, buf, tq); 1199 if(tq < 0) 1200 return (nil, -1); 1201 } 1202 (t, p) = debugtype(ss, buf, tq); 1203 if(p == -1 || buf[p++] != byte '\n') 1204 return (nil, -1); 1205 d[i] = ref Id(src, string buf[q:qq], off, 0, t); 1206 } 1207 return (d, p); 1208} 1209 1210idlist(a: array of ref Id): list of ref Id 1211{ 1212 n := len a; 1213 ids : list of ref Id = nil; 1214 while(n-- > 0) 1215 ids = a[n] :: ids; 1216 return ids; 1217} 1218 1219# 1220# parse a type description 1221# 1222debugtype(ss: ref SrcState, buf: array of byte, p: int): (ref Type, int) 1223{ 1224 t: ref Type; 1225 d: array of ref Id; 1226 q, k: int; 1227 src: ref Src; 1228 1229 size := 0; 1230 case int buf[p++]{ 1231 '@' => 1232 k = Tid; 1233 'A' => 1234 k = Tarray; 1235 size = IBY2WD; 1236 'B' => 1237 return (tbig, p); 1238 'C' => k = Tchan; 1239 size = IBY2WD; 1240 'L' => 1241 k = Tlist; 1242 size = IBY2WD; 1243 'N' => 1244 return (tnil, p); 1245 'R' => 1246 k = Tref; 1247 size = IBY2WD; 1248 'a' => 1249 k = Tadt; 1250 if(ss.vers < 20) 1251 size = -1; 1252 'b' => 1253 return (tbyte, p); 1254 'f' => 1255 return (treal, p); 1256 'i' => 1257 return (tint, p); 1258 'm' => 1259 k = Tmodule; 1260 size = IBY2WD; 1261 'n' => 1262 return (tnone, p); 1263 'p' => 1264 k = Tadtpick; 1265 's' => 1266 return (tstring, p); 1267 't' => 1268 k = Ttuple; 1269 size = -1; 1270 'F' => 1271 k = Tfn; 1272 size = IBY2WD; 1273 'P' => 1274 return (tpoly, p); 1275 * => 1276 k = Terror; 1277 } 1278 1279 if(size == -1){ 1280 q = strchr(buf, p, '.'); 1281 if(buf[q] == byte '.'){ 1282 size = int string buf[p:q]; 1283 p = q+1; 1284 } 1285 } 1286 1287 case k{ 1288 Tid => 1289 q = strchr(buf, p, '\n'); 1290 if(buf[q] != byte '\n') 1291 return (nil, -1); 1292 t = ref Type(nil, Tid, -1, string buf[p:q], nil, nil, nil); 1293 p = q + 1; 1294 Tadt => 1295 if(ss.vers < 20){ 1296 q = strchr(buf, p, '\n'); 1297 if(buf[q] != byte '\n') 1298 return (nil, -1); 1299 t = ref Type(nil, Tid, size, string buf[p:q], nil, nil, nil); 1300 p = q + 1; 1301 }else 1302 (t, p) = debugadt(ss, buf, p); 1303 Tadtpick => 1304 (t, p) = debugadt(ss, buf, p); 1305 t.kind = Tadtpick; 1306 (t.tags, p) = debugtag(ss, buf, p); 1307 Tmodule => 1308 q = strchr(buf, p, '\n'); 1309 if(buf[q] != byte '\n') 1310 return (nil, -1); 1311 t = ref Type(nil, k, size, string buf[p:q], nil, nil, nil); 1312 p = q + 1; 1313 if(ss.vers > 10){ 1314 (src, p) = debugsrc(ss, buf, p); 1315 t.src = src; 1316 } 1317 if(ss.vers > 20) 1318 (t.ids, p) = debugid(ss, buf, p); 1319 Tref or Tarray or Tlist or Tchan => # ref, array, list, chan 1320 (t, p) = debugtype(ss, buf, p); 1321 t = ref Type(nil, k, size, "", t, nil, nil); 1322 1323 Ttuple => # tuple 1324 (d, p) = debugid(ss, buf, p); 1325 t = ref Type(nil, k, size, "", nil, d, nil); 1326 1327 Tfn => # fn 1328 (d, p) = debugid(ss, buf, p); 1329 (t, p) = debugtype(ss, buf, p); 1330 t = ref Type(nil, k, size, "", t, d, nil); 1331 1332 * => 1333 p = -1; 1334 } 1335 return (t, p); 1336} 1337 1338# 1339# parse an adt type spec 1340# format: name ' ' src size '\n' ids 1341# 1342debugadt(ss: ref SrcState, buf: array of byte, p: int): (ref Type, int) 1343{ 1344 src: ref Src; 1345 1346 q := strchr(buf, p, ' '); 1347 if(buf[q] != byte ' ') 1348 return (nil, -1); 1349 sq := q + 1; 1350 if(ss.vers > 10){ 1351 (src, sq) = debugsrc(ss, buf, sq); 1352 if(sq < 0) 1353 return (nil, -1); 1354 } 1355 qq := strchr(buf, sq, '\n'); 1356 if(buf[qq] != byte '\n') 1357 return (nil, -1); 1358 (d, pp) := debugid(ss, buf, qq + 1); 1359 if(pp == -1) 1360 return (nil, -1); 1361 t := ref Type(src, Tadt, int string buf[sq:qq], string buf[p:q], nil, d, nil); 1362 return (t, pp); 1363} 1364 1365# 1366# parse a list of tags 1367# format: 1368# name ':' src size '\n' ids 1369# or 1370# name ':' src '\n' 1371# 1372debugtag(ss: ref SrcState, buf: array of byte, p: int): (array of ref Type, int) 1373{ 1374 d: array of ref Id; 1375 ntg, q, pp, np: int; 1376 src: ref Src; 1377 1378 (ntg, p) = strtoi(buf, p); 1379 if(buf[p++] != byte '\n') 1380 return (nil, -1); 1381 tg := array[ntg] of ref Type; 1382 for(i := 0; i < ntg; i++){ 1383 pp = strchr(buf, p, ':'); 1384 if(buf[pp] != byte ':') 1385 return (nil, -1); 1386 q = pp + 1; 1387 (src, q) = debugsrc(ss, buf, q); 1388 if(q < 0) 1389 return (nil, -1); 1390 if(buf[q] == byte '\n'){ 1391 np = q + 1; 1392 if(i <= 0) 1393 return (nil, -1); 1394 tg[i] = ref Type(src, Tadt, tg[i-1].size, string buf[p:pp], nil, tg[i-1].ids, nil); 1395 }else{ 1396 np = strchr(buf, q, '\n'); 1397 if(buf[np] != byte '\n') 1398 return (nil, -1); 1399 size := int string buf[q:np]; 1400 (d, np) = debugid(ss, buf, np+1); 1401 if(np == -1) 1402 return (nil, -1); 1403 tg[i] = ref Type(src, Tadt, size, string buf[p:pp], nil, d, nil); 1404 } 1405 p = np; 1406 } 1407 return (tg, p); 1408} 1409 1410strchr(a: array of byte, p, c: int): int 1411{ 1412 bc := byte c; 1413 while((b := a[p]) != byte 0 && b != bc) 1414 p++; 1415 return p; 1416} 1417 1418strtoi(a: array of byte, start: int): (int, int) 1419{ 1420 p := start; 1421 for(; c := int a[p]; p++){ 1422 case c{ 1423 ' ' or '\t' or '\n' or '\r' => 1424 continue; 1425 } 1426 break; 1427 } 1428 1429 # sign 1430 neg := c == '-'; 1431 if(neg || c == '+') 1432 p++; 1433 1434 # digits 1435 n := 0; 1436 nn := 0; 1437 ndig := 0; 1438 over := 0; 1439 for(; c = int a[p]; p++){ 1440 if(c < '0' || c > '9') 1441 break; 1442 ndig++; 1443 nn = n * 10 + (c - '0'); 1444 if(nn < n) 1445 over = 1; 1446 n = nn; 1447 } 1448 if(ndig == 0) 1449 return (0, start); 1450 if(neg) 1451 n = -n; 1452 if(over) 1453 if(neg) 1454 n = 2147483647; 1455 else 1456 n = int -2147483648; 1457 return (n, p); 1458} 1459 1460hex(a: array of byte): int 1461{ 1462 n := 0; 1463 for(i := 0; i < len a; i++){ 1464 c := int a[i]; 1465 if(c >= '0' && c <= '9') 1466 c -= '0'; 1467 else 1468 c -= 'a' - 10; 1469 n = (n << 4) + (c & 15); 1470 } 1471 return n; 1472} 1473 1474partition(n : int, max : int) : (int, int, int) 1475{ 1476 p := n/max; 1477 if (n%max != 0) 1478 p++; 1479 if (p > max) 1480 p = max; 1481 q := n/p; 1482 r := n-p*q; 1483 return (p, q, r); 1484} 1485 1486bounds(s : string) : (int, int) 1487{ 1488 lb := int s; 1489 for (i := 0; i < len s; i++) 1490 if (s[i] == '.') 1491 break; 1492 if (i+1 >= len s || s[i] != '.' || s[i+1] != '.') 1493 return (1, 0); 1494 ub := int s[i+2:]; 1495 return (lb, ub); 1496} 1497