1implement Mdb; 2 3include "sys.m"; 4 sys: Sys; 5 stderr: ref Sys->FD; 6 print, sprint: import sys; 7 8include "draw.m"; 9include "string.m"; 10 str: String; 11include "bufio.m"; 12 bufio: Bufio; 13 Iobuf: import bufio; 14include "dis.m"; 15 dis: Dis; 16 Inst, Type, Data, Link, Mod: import dis; 17 XMAGIC: import Dis; 18 MUSTCOMPILE, DONTCOMPILE: import Dis; 19 AMP, AFP, AIMM, AXXX, AIND, AMASK: import Dis; 20 ARM, AXNON, AXIMM, AXINF, AXINM: import Dis; 21 DEFB, DEFW, DEFS, DEFF, DEFA, DIND, DAPOP, DEFL: import Dis; 22disfile: string; 23m: ref Mod; 24 25Mdb: module 26{ 27 init: fn(nil: ref Draw->Context, argv: list of string); 28}; 29 30mfd: ref Sys->FD; 31dot := 0; 32lastaddr := 0; 33count := 1; 34 35atoi(s: string): int 36{ 37 b := 10; 38 if(s == nil) 39 return 0; 40 if(s[0] == '0') { 41 b = 8; 42 s = s[1:]; 43 if(s == nil) 44 return 0; 45 if(s[0] == 'x' || s[0] == 'X') { 46 b = 16; 47 s = s[1:]; 48 } 49 } 50 n: int; 51 (n, nil) = str->toint(s, b); 52 return n; 53} 54 55eatws(s: string): string 56{ 57 for (i := 0; i < len s; i++) 58 if (s[i] != ' ' && s[i] != '\t') 59 return s[i:]; 60 return nil; 61} 62 63eatnum(s: string): string 64{ 65 if(len s == 0) 66 return s; 67 while(gotnum(s) || gotalpha(s)) 68 s = s[1:]; 69 return s; 70} 71 72gotnum(s: string): int 73{ 74 if(len s == 0) 75 return 0; 76 if(s[0] >= '0' && s[0] <= '9') 77 return 1; 78 else 79 return 0; 80} 81 82gotalpha(s: string): int 83{ 84 if(len s == 0) 85 return 0; 86 if((s[0] >= 'a' && s[0] <= 'z') || (s[0] >= 'A' && s[0] <= 'Z')) 87 return 1; 88 else 89 return 0; 90} 91 92getexpr(s: string): (string, int, int) 93{ 94 ov: int; 95 v := 0; 96 op := '+'; 97 for(;;) { 98 ov = v; 99 s = eatws(s); 100 if(s == nil) 101 return (nil, 0, 0); 102 if(s[0] == '.' || s[0] == '+' || s[0] == '^') { 103 v = dot; 104 s = s[1:]; 105 } else if(s[0] == '"') { 106 v = lastaddr; 107 s = s[1:]; 108 } else if(s[0] == '(') { 109 (s, v, nil) = getexpr(s[1:]); 110 s = s[1:]; 111 } else if(gotnum(s)) { 112 v = atoi(s); 113 s = eatnum(s); 114 } else 115 return (s, 0, 0); 116 case op { 117 '+' => v = ov+v; 118 '-' => v = ov-v; 119 '*' => v = ov*v; 120 '%' => v = ov/v; 121 '&' => v = ov&v; 122 '|' => v = ov|v; 123 } 124 if(s == nil) 125 return (nil, v, 1); 126 case s[0] { 127 '+' or '-' or '*' or '%' or '&' or '|' => 128 op = s[0]; s = s[1:]; 129 * => 130 return (eatws(s), v, 1); 131 } 132 } 133} 134 135lastcmd := ""; 136 137docmd(s: string) 138{ 139 ok: int; 140 n: int; 141 s = eatws(s); 142 (s, n, ok) = getexpr(s); 143 if(ok) { 144 dot = n; 145 lastaddr = n; 146 } 147 count = 1; 148 if(s != nil && s[0] == ',') { 149 (s, n, ok) = getexpr(s[1:]); 150 if(ok) 151 count = n; 152 } 153 if(s == nil && (s = lastcmd) == nil) 154 return; 155 lastcmd = s; 156 cmd := s[0]; 157 case cmd { 158 '?' or '/' => 159 case s[1] { 160 'w' => 161 writemem(2, s[2:]); 162 'W' => 163 writemem(4, s[2:]); 164 'i' => 165 das(); 166 * => 167 dumpmem(s[1:], cmd); 168 } 169 '$' => 170 case s[1] { 171 'D' => 172 desc(); 173 'h' => 174 hdr(); 175 'l' => 176 link(); 177 'i' => 178 imports(); 179 'd' => 180 dat(); 181 'H' => 182 handlers(); 183 's' => 184 if(m != nil) 185 print("%s\n", m.srcpath); 186 } 187 '=' => 188 dumpmem(s[1:], cmd); 189 * => 190 sys->fprint(stderr, "invalid cmd: %c\n", cmd); 191 } 192} 193 194octal(n: int, d: int): string 195{ 196 s: string; 197 do { 198 s = string (n%8) + s; 199 n /= 8; 200 } while(d-- > 1); 201 return "0" + s; 202} 203 204printable(c: int): string 205{ 206 case c { 207 32 to 126 => 208 return sprint("%c", c); 209 '\n' => 210 return "\\n"; 211 '\r' => 212 return "\\r"; 213 '\b' => 214 return "\\b"; 215 '\a' => 216 return "\\a"; 217 '\v' => 218 return "\\v"; 219 * => 220 return sprint("\\x%2.2x", c); 221 } 222 223} 224 225dumpmem(s: string, t: int) 226{ 227 n := 0; 228 c := count; 229 while(c-- > 0) for(p:=0; p<len s; p++) { 230 fmt := s[p]; 231 case fmt { 232 'b' or 'c' or 'C' => 233 n = 1; 234 'x' or 'd' or 'u' or 'o' => 235 n = 2; 236 'X' or 'D' or 'U' or 'O' => 237 n = 4; 238 's' or 'S' or 'r' or 'R' => 239 print("'%c' format not yet supported\n", fmt); 240 continue; 241 'n' => 242 print("\n"); 243 continue; 244 '+' => 245 dot++; 246 continue; 247 '-' => 248 dot--; 249 continue; 250 '^' => 251 dot -= n; 252 continue; 253 * => 254 print("unknown format '%c'\n", fmt); 255 continue; 256 } 257 b := array[n] of byte; 258 v: int; 259 if(t == '=') 260 v = dot; 261 else { 262 sys->seek(mfd, big dot, Sys->SEEKSTART); 263 sys->read(mfd, b, len b); 264 v = 0; 265 for(i := 0; i < n; i++) 266 v |= int b[i] << (8*i); 267 } 268 case fmt { 269 'c' => print("%c", v); 270 'C' => print("%s", printable(v)); 271 'b' => print("%#2.2ux ", v); 272 'x' => print("%#4.4ux ", v); 273 'X' => print("%#8.8ux ", v); 274 'd' => print("%-4d ", v); 275 'D' => print("%-8d ", v); 276 'u' => print("%-4ud ", v); 277 'U' => print("%-8ud ", v); 278 'o' => print("%s ", octal(v, 6)); 279 'O' => print("%s ", octal(v, 11)); 280 } 281 if(t != '=') 282 dot += n; 283 } 284 print("\n"); 285} 286 287writemem(n: int, s: string) 288{ 289 v: int; 290 ok: int; 291 s = eatws(s); 292 sys->seek(mfd, big dot, Sys->SEEKSTART); 293 for(;;) { 294 (s, v, ok) = getexpr(s); 295 if(!ok) 296 return; 297 b := array[n] of byte; 298 for(i := 0; i < n; i++) 299 b[i] = byte (v >> (8*i)); 300 if (sys->write(mfd, b, len b) != len b) 301 sys->fprint(stderr, "mdb: write error: %r\n"); 302 } 303} 304 305usage() 306{ 307 sys->fprint(stderr, "usage: mdb [-w] file [command]\n"); 308 raise "fail:usage"; 309} 310 311writeable := 0; 312 313init(nil: ref Draw->Context, argv: list of string) 314{ 315 sys = load Sys Sys->PATH; 316 stderr = sys->fildes(2); 317 str = load String String->PATH; 318 if (str == nil) { 319 sys->fprint(stderr, "mdb: cannot load %s: %r\n", String->PATH); 320 raise "fail:bad module"; 321 } 322 bufio = load Bufio Bufio->PATH; 323 if (bufio == nil) { 324 sys->fprint(stderr, "mdb: cannot load %s: %r\n", Bufio->PATH); 325 raise "fail:bad module"; 326 } 327 dis = load Dis Dis->PATH; 328 dis->init(); 329 330 if (len argv < 2) 331 usage(); 332 if (argv != nil) 333 argv = tl argv; 334 if (argv != nil && len hd argv && (hd argv)[0] == '-') { 335 if (hd argv != "-w") 336 usage(); 337 writeable = 1; 338 argv = tl argv; 339 } 340 if (argv == nil) 341 usage(); 342 fname := hd argv; 343 argv = tl argv; 344 cmd := ""; 345 if(argv != nil) 346 cmd = hd argv; 347 348 oflags := Sys->OREAD; 349 if (writeable) 350 oflags = Sys->ORDWR; 351 mfd = sys->open(fname, oflags); 352 if(mfd == nil) { 353 sys->fprint(stderr, "mdb: cannot open %s: %r\n", fname); 354 raise "fail:cannot open"; 355 } 356 (m, nil) = dis->loadobj(fname); 357 358 if(cmd != nil) 359 docmd(cmd); 360 else { 361 stdin := bufio->fopen(sys->fildes(0), Sys->OREAD); 362 while ((s := stdin.gets('\n')) != nil) { 363 if (s[len s -1] == '\n') 364 s = s[0:len s - 1]; 365 docmd(s); 366 } 367 } 368} 369 370link() 371{ 372 if(m == nil || m.magic == 0) 373 return; 374 375 for(i := 0; i < m.lsize; i++) { 376 l := m.links[i]; 377 print(" link %d,%d, 0x%ux, \"%s\"\n", 378 l.desc, l.pc, l.sig, l.name); 379 } 380} 381 382imports() 383{ 384 if(m == nil || m.magic == 0) 385 return; 386 387 mi := m.imports; 388 for(i := 0; i < len mi; i++) { 389 a := mi[i]; 390 for(j := 0; j < len a; j++) { 391 ai := a[j]; 392 print(" import 0x%ux, \"%s\"\n", ai.sig, ai.name); 393 } 394 } 395} 396 397handlers() 398{ 399 if(m == nil || m.magic == 0) 400 return; 401 402 hs := m.handlers; 403 for(i := 0; i < len hs; i++) { 404 h := hs[i]; 405 tt := -1; 406 for(j := 0; j < len m.types; j++) { 407 if(h.t == m.types[j]) { 408 tt = j; 409 break; 410 } 411 } 412 print(" %d-%d, o=%d, e=%d t=%d\n", h.pc1, h.pc2, h.eoff, h.ne, tt); 413 et := h.etab; 414 for(j = 0; j < len et; j++) { 415 e := et[j]; 416 if(e.s == nil) 417 print(" %d *\n", e.pc); 418 else 419 print(" %d \"%s\"\n", e.pc, e.s); 420 } 421 } 422} 423 424desc() 425{ 426 if(m == nil || m.magic == 0) 427 return; 428 429 for(i := 0; i < m.tsize; i++) { 430 h := m.types[i]; 431 s := sprint(" desc $%d, %d, \"", i, h.size); 432 for(j := 0; j < h.np; j++) 433 s += sprint("%.2ux", int h.map[j]); 434 s += "\"\n"; 435 print("%s", s); 436 } 437} 438 439hdr() 440{ 441 if(m == nil || m.magic == 0) 442 return; 443 s := sprint("%.8ux Version %d Dis VM\n", m.magic, m.magic - XMAGIC + 1); 444 s += sprint("%.8ux Runtime flags %s\n", m.rt, rtflag(m.rt)); 445 s += sprint("%8d bytes per stack extent\n\n", m.ssize); 446 447 448 s += sprint("%8d instructions\n", m.isize); 449 s += sprint("%8d data size\n", m.dsize); 450 s += sprint("%8d heap type descriptors\n", m.tsize); 451 s += sprint("%8d link directives\n", m.lsize); 452 s += sprint("%8d entry pc\n", m.entry); 453 s += sprint("%8d entry type descriptor\n\n", m.entryt); 454 455 if(m.sign == nil) 456 s += "Module is Insecure\n"; 457 print("%s", s); 458} 459 460rtflag(flag: int): string 461{ 462 if(flag == 0) 463 return ""; 464 465 s := "["; 466 467 if(flag & MUSTCOMPILE) 468 s += "MustCompile"; 469 if(flag & DONTCOMPILE) { 470 if(flag & MUSTCOMPILE) 471 s += "|"; 472 s += "DontCompile"; 473 } 474 s[len s] = ']'; 475 476 return s; 477} 478 479das() 480{ 481 if(m == nil || m.magic == 0) 482 return; 483 484 for(i := dot; count-- > 0 && i < m.isize; i++) { 485 if(i % 10 == 0) 486 print("#%d\n", i); 487 print("\t%s\n", dis->inst2s(m.inst[i])); 488 } 489} 490 491dat() 492{ 493 if(m == nil || m.magic == 0) 494 return; 495 print(" var @mp, %d\n", m.types[0].size); 496 497 s := ""; 498 for(d := m.data; d != nil; d = tl d) { 499 pick dat := hd d { 500 Bytes => 501 s = sprint("\tbyte @mp+%d", dat.off); 502 for(n := 0; n < dat.n; n++) 503 s += sprint(",%d", int dat.bytes[n]); 504 Words => 505 s = sprint("\tword @mp+%d", dat.off); 506 for(n := 0; n < dat.n; n++) 507 s += sprint(",%d", dat.words[n]); 508 String => 509 s = sprint("\tstring @mp+%d, \"%s\"", dat.off, mapstr(dat.str)); 510 Reals => 511 s = sprint("\treal @mp+%d", dat.off); 512 for(n := 0; n < dat.n; n++) 513 s += sprint(", %g", dat.reals[n]); 514 break; 515 Array => 516 s = sprint("\tarray @mp+%d,$%d,%d", dat.off, dat.typex, dat.length); 517 Aindex => 518 s = sprint("\tindir @mp+%d,%d", dat.off, dat.index); 519 Arestore => 520 s = "\tapop"; 521 break; 522 Bigs => 523 s = sprint("\tlong @mp+%d", dat.off); 524 for(n := 0; n < dat.n; n++) 525 s += sprint(", %bd", dat.bigs[n]); 526 } 527 print("%s\n", s); 528 } 529} 530 531mapstr(s: string): string 532{ 533 for(i := 0; i < len s; i++) 534 if(s[i] == '\n') 535 s = s[0:i] + "\\n" + s[i+1:]; 536 return s; 537} 538