1 /* 2 * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 20 * CA 95054 USA or visit www.sun.com if you need additional information or 21 * have any questions. 22 * 23 */ 24 25 // shorter names for SA packages 26 27 28 // SA package name abbreviations are kept in 'sapkg' object 29 // to avoid global namespace pollution 30 var sapkg = new Object(); 31 32 sapkg.hotspot = Packages.sun.jvm.hotspot; 33 sapkg.asm = sapkg.hotspot.asm; 34 sapkg.bugspot = sapkg.hotspot.bugspot; 35 sapkg.c1 = sapkg.hotspot.c1; 36 sapkg.code = sapkg.hotspot.code; 37 sapkg.compiler = sapkg.hotspot.compiler; 38 39 // 'debugger' is a JavaScript keyword :-( 40 // sapkg.debugger = sapkg.hotspot.debugger; 41 42 sapkg.interpreter = sapkg.hotspot.interpreter; 43 sapkg.livejvm = sapkg.hotspot.livejvm; 44 sapkg.jdi = sapkg.hotspot.jdi; 45 sapkg.memory = sapkg.hotspot.memory; 46 sapkg.oops = sapkg.hotspot.oops; 47 sapkg.runtime = sapkg.hotspot.runtime; 48 sapkg.tools = sapkg.hotspot.tools; 49 sapkg.types = sapkg.hotspot.types; 50 sapkg.ui = sapkg.hotspot.ui; 51 sapkg.utilities = sapkg.hotspot.utilities; 52 53 // SA singletons are kept in 'sa' object 54 var sa = new Object(); 55 sa.vm = sapkg.runtime.VM.getVM(); 56 sa.dbg = sa.vm.getDebugger(); 57 sa.cdbg = sa.dbg.CDebugger; 58 sa.heap = sa.vm.universe.heap(); 59 sa.systemDictionary = sa.vm.systemDictionary; 60 sa.sysDict = sa.systemDictionary; 61 sa.symbolTable = sa.vm.symbolTable; 62 sa.symTbl = sa.symbolTable; 63 sa.threads = sa.vm.threads; 64 sa.interpreter = sa.vm.interpreter; 65 sa.typedb = sa.vm.typeDataBase; 66 sa.codeCache = sa.vm.codeCache; 67 // 'objHeap' is different from 'heap'!. 68 // This is SA's Oop factory and heap-walker 69 sa.objHeap = sa.vm.objectHeap; 70 71 // few useful global variables 72 var OS = sa.vm.OS; 73 var CPU = sa.vm.CPU; 74 var LP64 = sa.vm.LP64; 75 var isClient = sa.vm.clientCompiler; 76 var isServer = sa.vm.serverCompiler; 77 var isCore = sa.vm.isCore(); 78 var addressSize = sa.vm.addressSize; 79 var oopSize = sa.vm.oopSize; 80 81 // this "main" function is called immediately 82 // after loading this script file 83 function main(globals, jvmarg) { 84 // wrap a sun.jvm.hotspot.utilities.soql.ScriptObject 85 // object so that the properties of it can be accessed 86 // in natural object.field syntax. 87 function wrapScriptObject(so) { 88 function unwrapScriptObject(wso) { 89 var objType = typeof(wso); 90 if ((objType == 'object' || 91 objType == 'function') 92 && "__wrapped__" in wso) { 93 return wso.__wrapped__; 94 } else { 95 return wso; 96 } 97 } 98 99 function prepareArgsArray(array) { 100 var args = new Array(array.length); 101 for (var a = 0; a < array.length; a++) { 102 var elem = array[a]; 103 elem = unwrapScriptObject(elem); 104 if (typeof(elem) == 'function') { 105 args[a] = new sapkg.utilities.soql.Callable() { 106 call: function(myargs) { 107 var tmp = new Array(myargs.length); 108 for (var i = 0; i < myargs.length; i++) { 109 tmp[i] = wrapScriptObject(myargs[i]); 110 } 111 return elem.apply(this, tmp); 112 } 113 } 114 } else { 115 args[a] = elem; 116 } 117 } 118 return args; 119 } 120 121 if (so instanceof sapkg.utilities.soql.ScriptObject) { 122 return new JSAdapter() { 123 __getIds__: function() { 124 return so.getIds(); 125 }, 126 127 __has__ : function(name) { 128 if (typeof(name) == 'number') { 129 return so["has(int)"](name); 130 } else { 131 if (name == '__wrapped__') { 132 return true; 133 } else if (so["has(java.lang.String)"](name)) { 134 return true; 135 } else if (name.equals('toString')) { 136 return true; 137 } else { 138 return false; 139 } 140 } 141 }, 142 143 __delete__ : function(name) { 144 if (typeof(name) == 'number') { 145 return so["delete(int)"](name); 146 } else { 147 return so["delete(java.lang.String)"](name); 148 } 149 }, 150 151 __get__ : function(name) { 152 if (! this.__has__(name)) { 153 return undefined; 154 } 155 if (typeof(name) == 'number') { 156 return wrapScriptObject(so["get(int)"](name)); 157 } else { 158 if (name == '__wrapped__') { 159 return so; 160 } else { 161 var value = so["get(java.lang.String)"](name); 162 if (value instanceof sapkg.utilities.soql.Callable) { 163 return function() { 164 var args = prepareArgsArray(arguments); 165 var r; 166 try { 167 r = value.call(args); 168 } catch (e) { 169 println("call to " + name + " failed!"); 170 throw e; 171 } 172 return wrapScriptObject(r); 173 } 174 } else if (name == 'toString') { 175 return function() { 176 return so.toString(); 177 } 178 } else { 179 return wrapScriptObject(value); 180 } 181 } 182 } 183 } 184 }; 185 } else { 186 return so; 187 } 188 } 189 190 // set "jvm" global variable that wraps a 191 // sun.jvm.hotspot.utilities.soql.JSJavaVM instance 192 if (jvmarg != null) { 193 jvm = wrapScriptObject(jvmarg); 194 // expose "heap" global variable 195 heap = jvm.heap; 196 } 197 198 // expose all "function" type properties of 199 // sun.jvm.hotspot.utilitites.soql.JSJavaScriptEngine 200 // as global functions here. 201 globals = wrapScriptObject(globals); 202 for (var prop in globals) { 203 if (typeof(globals[prop]) == 'function') { 204 this[prop] = globals[prop]; 205 } 206 } 207 208 // define "writeln" and "write" if not defined 209 if (typeof(writeln) == 'undefined') { 210 writeln = println; 211 } 212 213 if (typeof(write) == 'undefined') { 214 write = print; 215 } 216 217 // "registerCommand" function is defined if we 218 // are running as part of "CLHSDB" tool. CLHSDB 219 // tool exposes Unix-style commands. 220 221 // if "registerCommand" function is defined 222 // then register few global functions as "commands". 223 if (typeof(registerCommand) == 'function') { 224 this.printDis = function(addr, len) { 225 if (!addr) { 226 writeln("Usage: dis address [ length ]"); 227 } else { 228 dis(addr, len); 229 } 230 } 231 registerCommand("dis", "dis address [ length ]", "printDis"); 232 233 this.jclass = function(name) { 234 if (typeof(name) == "string") { 235 var clazz = sapkg.utilities.SystemDictionaryHelper.findInstanceKlass(name); 236 if (clazz) { 237 writeln(clazz.getName().asString() + " @" + clazz.getHandle().toString()); 238 } else { 239 writeln("class not found: " + name); 240 } 241 } else { 242 writeln("Usage: class name"); 243 } 244 } 245 registerCommand("class", "class name", "jclass"); 246 247 this.jclasses = function() { 248 forEachKlass(function (clazz) { 249 writeln(clazz.getName().asString() + " @" + clazz.getHandle().toString()); 250 }); 251 } 252 registerCommand("classes", "classes", "jclasses"); 253 254 this.printJDis = function(addr) { 255 if (!addr) { 256 writeln("Usage: jdis address"); 257 } else { 258 jdis(addr); 259 } 260 } 261 registerCommand("jdis", "jdis address", "printJDis"); 262 263 this.dclass = function(clazz, dir) { 264 if (!clazz) { 265 writeln("Usage: dumpclass { address | name } [ directory ]"); 266 } else { 267 if (!dir) { dir = "."; } 268 dumpClass(clazz, dir); 269 } 270 } 271 registerCommand("dumpclass", "dumpclass { address | name } [ directory ]", "dclass"); 272 registerCommand("dumpheap", "dumpheap [ file ]", "dumpHeap"); 273 274 this.jseval = function(str) { 275 if (!str) { 276 writeln("Usage: jseval script"); 277 } else { 278 var res = eval(str); 279 if (res) { writeln(res); } 280 } 281 } 282 registerCommand("jseval", "jseval script", "jseval"); 283 284 this.jsload = function(file) { 285 if (!file) { 286 writeln("Usage: jsload file"); 287 } else { 288 load(file); 289 } 290 } 291 registerCommand("jsload", "jsload file", "jsload"); 292 293 this.printMem = function(addr, len) { 294 if (!addr) { 295 writeln("Usage: mem [ length ]"); 296 } else { 297 mem(addr, len); 298 } 299 } 300 registerCommand("mem", "mem address [ length ]", "printMem"); 301 302 this.sysProps = function() { 303 for (var i in jvm.sysProps) { 304 writeln(i + ' = ' + jvm.sysProps[i]); 305 } 306 } 307 registerCommand("sysprops", "sysprops", "sysProps"); 308 309 this.printWhatis = function(addr) { 310 if (!addr) { 311 writeln("Usage: whatis address"); 312 } else { 313 writeln(whatis(addr)); 314 } 315 } 316 registerCommand("whatis", "whatis address", "printWhatis"); 317 } 318 } 319 320 // debugger functionality 321 322 // string-to-Address 323 function str2addr(str) { 324 return sa.dbg.parseAddress(str); 325 } 326 327 // number-to-Address 328 if (addressSize == 4) { 329 eval("function num2addr(num) { \ 330 return str2addr('0x' + java.lang.Integer.toHexString(0xffffffff & num)); \ 331 }"); 332 } else { 333 eval("function num2addr(num) { \ 334 return str2addr('0x' + java.lang.Long.toHexString(num)); \ 335 }"); 336 } 337 338 // generic any-type-to-Address 339 // use this convenience function to accept address in any 340 // format -- number, string or an Address instance. 341 function any2addr(addr) { 342 var type = typeof(addr); 343 if (type == 'number') { 344 return num2addr(addr); 345 } else if (type == 'string') { 346 return str2addr(addr); 347 } else { 348 return addr; 349 } 350 } 351 352 // Address-to-string 353 function addr2str(addr) { 354 if (addr == null) { 355 return (addressSize == 4)? '0x00000000' : '0x0000000000000000'; 356 } else { 357 return addr + ''; 358 } 359 } 360 361 // Address-to-number 362 function addr2num(addr) { 363 return sa.dbg.getAddressValue(addr); 364 } 365 366 // symbol-to-Address 367 function sym2addr(dso, sym) { 368 return sa.dbg.lookup(dso, sym); 369 } 370 371 // returns the ClosestSymbol or null 372 function closestSymbolFor(addr) { 373 if (sa.cdbg == null) { 374 // no CDebugger support, return null 375 return null; 376 } else { 377 var dso = sa.cdbg.loadObjectContainingPC(addr); 378 if (dso != null) { 379 return dso.closestSymbolToPC(addr); 380 } else { 381 return null; 382 } 383 } 384 } 385 386 // Address-to-symbol 387 // returns nearest symbol as string if found 388 // else returns address as string 389 function addr2sym(addr) { 390 var sym = closestSymbolFor(addr); 391 if (sym != null) { 392 return sym.name + '+' + sym.offset; 393 } else { 394 return addr2str(addr); 395 } 396 } 397 398 // read 'num' bytes at 'addr' and return an array as result. 399 // returns Java byte[] type result and not a JavaScript array. 400 function readBytesAt(addr, num) { 401 addr = any2addr(addr); 402 var res = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, num); 403 var i; 404 for (i = 0; i < num; i++) { 405 res[i] = addr.getJByteAt(i); 406 } 407 return res; 408 } 409 410 // read 'num' words at 'addr' and return an array as result. 411 // returns Java long[] type result and not a JavaScript array. 412 function readWordsAt(addr, num) { 413 addr = any2addr(addr); 414 var res = java.lang.reflect.Array.newInstance(java.lang.Long.TYPE, num); 415 var i; 416 for (i = 0; i < num; i++) { 417 res[i] = addr2num(addr.getAddressAt(i * addressSize)); 418 } 419 return res; 420 } 421 422 // read the 'C' string at 'addr' 423 function readCStrAt(addr) { 424 addr = any2addr(addr); 425 return sapkg.utilities.CStringUtilities.getString(addr); 426 } 427 428 // read the length of the 'C' string at 'addr' 429 function readCStrLen(addr) { 430 addr = any2addr(addr); 431 return sapkg.utilities.CStringUtilities.getStringLength(addr); 432 } 433 434 // iterate through ThreadList of CDebugger 435 function forEachThread(callback) { 436 if (sa.cdbg == null) { 437 // no CDebugger support 438 return; 439 } else { 440 var itr = sa.cdbg.threadList.iterator(); 441 while (itr.hasNext()) { 442 if (callback(itr.next()) == false) return; 443 } 444 } 445 } 446 447 // read register set of a ThreadProxy as name-value pairs 448 function readRegs(threadProxy) { 449 var ctx = threadProxy.context; 450 var num = ctx.numRegisters; 451 var res = new Object(); 452 var i; 453 for (i = 0; i < num; i++) { 454 res[ctx.getRegisterName(i)]= addr2str(ctx.getRegisterAsAddress(i)); 455 } 456 return res; 457 } 458 459 // print register set for a given ThreaProxy 460 function regs(threadProxy) { 461 var res = readRegs(threadProxy); 462 for (i in res) { 463 writeln(i, '=', res[i]); 464 } 465 } 466 467 // iterate through each CFrame of a given ThreadProxy 468 function forEachCFrame(threadProxy, callback) { 469 if (sa.cdbg == null) { 470 // no CDebugger support 471 return; 472 } else { 473 var cframe = sa.cdbg.topFrameForThread(threadProxy); 474 while (cframe != null) { 475 if (callback(cframe) == false) return; 476 cframe = cframe.sender(); 477 } 478 } 479 } 480 481 // iterate through list of load objects (DLLs, DSOs) 482 function forEachLoadObject(callback) { 483 if (sa.cdbg == null) { 484 // no CDebugger support 485 return; 486 } else { 487 var itr = sa.cdbg.loadObjectList.iterator(); 488 while (itr.hasNext()) { 489 if (callback(itr.next()) == false) return; 490 } 491 } 492 } 493 494 // print 'num' words at 'addr' 495 function mem(addr, num) { 496 if (num == undefined) { 497 num = 1; 498 } 499 addr = any2addr(addr); 500 var i; 501 for (i = 0; i < num; i++) { 502 var value = addr.getAddressAt(0); 503 writeln(addr2sym(addr) + ':', addr2str(value)); 504 addr = addr.addOffsetTo(addressSize); 505 } 506 writeln(); 507 } 508 509 // return the disassemble class for current CPU 510 function disassemblerClass() { 511 var DisAsmClass; 512 if (CPU == 'x86') { 513 DisAsmClass = sapkg.asm.x86.X86Disassembler; 514 } else if (CPU == 'sparc') { 515 DisAsmClass = sapkg.asm.sparc.SPARCV9Disassembler; 516 } 517 return DisAsmClass; 518 } 519 520 // print native code disassembly of 'num' bytes at 'addr' 521 function dis(addr, num) { 522 addr = any2addr(addr); 523 var nmethod = findNMethod(addr); 524 if (nmethod != null) { 525 // disassemble it as nmethod 526 nmethoddis(nmethod); 527 } else { 528 // raw disassembly 529 if (num == undefined) { 530 // size of one SPARC instruction and 531 // unknown number of Intel instructions. 532 num = 4; 533 } 534 DisAsmClass = disassemblerClass(); 535 if (DisAsmClass == undefined) { 536 // unsupported CPU 537 writeln(CPU + " is not yet supported!"); 538 return; 539 } 540 541 var bytes = readBytesAt(addr, num); 542 var disAsm = new DisAsmClass(addr2num(addr), bytes); 543 disAsm.decode(new sapkg.asm.InstructionVisitor() { 544 visit: function (pc, instr) { 545 write(addr2sym(num2addr(pc)) + ':', '\t'); 546 writeln(instr.asString(pc, 547 new sapkg.asm.SymbolFinder() { 548 getSymbolFor: function(addr) { 549 return addr2sym(num2addr(addr)); 550 } 551 })); 552 } 553 }); 554 } 555 } 556 557 // System dictionary functions 558 559 // find InstanceKlass by name 560 function findInstanceKlass(name) { 561 return sapkg.utilities.SystemDictionaryHelper.findInstanceKlass(name); 562 } 563 564 // get Java system loader (i.e., application launcher loader) 565 function systemLoader() { 566 return sa.sysDict.javaSystemLoader(); 567 } 568 569 // iterate system dictionary for each 'Klass' 570 function forEachKlass(callback) { 571 var VisitorClass = sapkg.memory.SystemDictionary.ClassVisitor; 572 var visitor = new VisitorClass() { visit: callback }; 573 sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary$ClassVisitor)"](visitor); 574 } 575 576 // iterate system dictionary for each 'Klass' and initiating loader 577 function forEachKlassAndLoader(callback) { 578 var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor; 579 var visitor = new VisitorClass() { visit: callback }; 580 sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary$ClassAndLoaderVisitor)"](visitor); 581 } 582 583 // iterate system dictionary for each primitive array klass 584 function forEachPrimArrayKlass(callback) { 585 var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor; 586 sa.sysDict.primArrayClassesDo(new VisitorClass() { visit: callback }); 587 } 588 589 // (hotspot) symbol table functions 590 591 // String-to-Symbol 592 function str2sym(str) { 593 return sa.symTbl.probe(str); 594 } 595 596 // Symbol-to-String 597 function sym2str(sym) { 598 return sym.asString(); 599 } 600 601 // oop functions 602 603 // Address-to-Oop 604 function addr2oop(addr) { 605 addr = any2addr(addr); 606 return sa.objHeap.newOop(addr.addOffsetToAsOopHandle(0)); 607 } 608 609 // Oop-to-Address 610 function oop2addr(oop) { 611 return oop.handle; 612 } 613 614 // 'oop' to higher-level java object wrapper in which for(i in o) 615 // works by iterating java level fields and javaobject.javafield 616 // syntax works. 617 function oop2obj(oop) { 618 return object(addr2str(oop.handle)); 619 } 620 621 // higher level java object wrapper to oop 622 function obj2oop(obj) { 623 return addr2oop(str2addr(address(obj))); 624 } 625 626 // Java heap iteration 627 628 // iterates Java heap for each Oop 629 function forEachOop(callback) { 630 sa.objHeap.iterate(new sapkg.oops.HeapVisitor() { doObj: callback }); 631 } 632 633 // iterates Java heap for each Oop of given 'klass'. 634 // 'includeSubtypes' tells whether to include objects 635 // of subtypes of 'klass' or not 636 function forEachOopOfKlass(callback, klass, includeSubtypes) { 637 if (klass == undefined) { 638 klass = findInstanceKlass("java.lang.Object"); 639 } 640 641 if (includeSubtypes == undefined) { 642 includeSubtypes = true; 643 } 644 sa.objHeap.iterateObjectsOfKlass( 645 new sapkg.oops.HeapVisitor() { doObj: callback }, 646 klass, includeSubtypes); 647 } 648 649 // code cache functions 650 651 // iterates CodeCache for each 'CodeBlob' 652 function forEachCodeBlob(callback) { 653 var VisitorClass = sapkg.code.CodeCacheVisitor; 654 sa.codeCache.iterate(new VisitorClass() { visit: callback }); 655 } 656 657 // find the ClodBlob (if any) that contains given address 658 function findCodeBlob(addr) { 659 addr = any2addr(addr); 660 return sa.codeCache.findBlobUnsafe(addr); 661 } 662 663 // find the NMethod (if any) that contains given address 664 function findNMethod(addr) { 665 var codeBlob = findCodeBlob(addr); 666 return (codeBlob != null && codeBlob.isNMethod())? codeBlob : null; 667 } 668 669 // returns PcDesc at given address or null 670 function pcDescAt(addr) { 671 addr = any2addr(addr); 672 var nmethod = findNMethod(addr); 673 return (nmethod != null)? nmethod.safepoints.get(addr) : null; 674 } 675 676 // helpers for nmethod disassembler 677 function printScope(scopeDesc) { 678 if (scopeDesc == null) { 679 return; 680 } 681 printScope(scopeDesc.sender()); 682 var method = scopeDesc.method; 683 var bci = scopeDesc.BCI; 684 var line = -1; 685 if (method.hasLineNumberTable()) { 686 line = method.getLineNumberFromBCI(bci); 687 } 688 689 write('\t', method.externalNameAndSignature(), '@', method.handle, 'bci=' + bci); 690 if (line != -1) { 691 write('line=' + line); 692 } 693 writeln(); 694 } 695 696 function printSafepointInfo(nmethod, pcDesc) { 697 var scopeDesc = nmethod.getScopeDescAt( 698 pcDesc.getRealPC(nmethod), 699 pcDesc.isAtCall()); 700 printScope(scopeDesc); 701 } 702 703 // print disassembly for a given nmethod 704 function nmethoddis(nmethod) { 705 var DisAsmClass = disassemblerClass(); 706 if (DisAsmClass == undefined) { 707 writeln(CPU + " is not yet supported!"); 708 return; 709 } 710 711 var method = nmethod.method; 712 writeln('NMethod:', method.externalNameAndSignature(), '@', method.handle); 713 714 var codeBegin = nmethod.codeBegin(); 715 var codeEnd = nmethod.codeEnd(); 716 var size = codeEnd.minus(codeBegin); 717 var code = readBytesAt(codeBegin, size); 718 var startPc = addr2num(codeBegin); 719 var verifiedEntryPoint = addr2num(nmethod.verifiedEntryPoint); 720 var entryPoint = addr2num(nmethod.entryPoint); 721 var interpreterEntryPoint = addr2num(nmethod.interpreterEntryPointOrNull); 722 var safepoints = nmethod.safepoints; 723 var disAsm = new DisAsmClass(startPc, code); 724 disAsm.decode(new sapkg.asm.InstructionVisitor() { 725 visit: function(curPc, instr) { 726 if (curPc == verifiedEntryPoint) { 727 writeln(); 728 writeln("Verified Entry Point:"); 729 } 730 if (curPc == entryPoint) { 731 writeln(); 732 writeln("Entry Point:"); 733 } 734 if (curPc == interpreterEntryPoint) { 735 writeln(""); 736 writeln("Interpreter Entry Point:"); 737 } 738 739 var pcDesc = safepoints.get(num2addr(curPc)); 740 var isSafepoint = (pcDesc != null); 741 if (isSafepoint && pcDesc.isAtCall()) { 742 printSafepointInfo(nmethod, pcDesc); 743 } 744 745 write(num2addr(curPc) + ':', '\t'); 746 writeln(instr.asString(curPc, 747 new sapkg.asm.SymbolFinder() { 748 getSymbolFor: function(addr) { 749 return addr2sym(num2addr(addr)); 750 } 751 })); 752 753 if (isSafepoint && !pcDesc.isAtCall()) { 754 printSafepointInfo(nmethod, pcDesc); 755 } 756 } 757 }); 758 } 759 760 // bytecode interpreter functions 761 762 // iterates interpreter codelets for each interpreter codelet 763 function forEachInterpCodelet(callback) { 764 var stubQueue = sa.interpreter.code; 765 var stub = stubQueue.first; 766 while (stub != null) { 767 if (callback(stub) == false) return; 768 stub = stubQueue.getNext(stub); 769 } 770 } 771 772 // helper for bytecode disassembler 773 function printExceptionTable(method) { 774 var expTbl = method.getExceptionTable(); 775 var len = expTbl.getLength(); 776 if (len != 0) { 777 var i; 778 var cpool = method.constants; 779 writeln("start", '\t', "end", '\t', "handler", '\t', "exception"); 780 writeln(""); 781 for (i = 0; i < len; i += 4) { 782 write(expTbl.getIntAt(i), '\t', 783 expTbl.getIntAt(i + 1), '\t', 784 expTbl.getIntAt(i + 2), '\t'); 785 var cpIndex = expTbl.getIntAt(i + 3); 786 var oop = (cpIndex == 0)? null : cpool.getObjAt(cpIndex); 787 if (oop == null) { 788 writeln("<any>"); 789 } else if (oop.isSymbol()) { 790 writeln(oop.asString().replace('/', '.')); 791 } else if (oop.isKlass()) { 792 writeln(oop.name.asString().replace('/', '.')); 793 } else { 794 writeln(cpIndex); 795 } 796 } 797 } 798 } 799 800 // print Java bytecode disassembly 801 function jdis(method) { 802 if (method.getByteCode == undefined) { 803 // method oop may be specified by address 804 method = addr2oop(any2addr(method)); 805 } 806 writeln(method, '-', method.externalNameAndSignature()); 807 if (method.isNative()) { 808 writeln("native method"); 809 return; 810 } 811 if (method.isAbstract()) { 812 writeln("abstract method"); 813 return; 814 } 815 816 writeln(); 817 var BytecodeDisAsmClass = sapkg.interpreter.BytecodeDisassembler; 818 var disAsm = new BytecodeDisAsmClass(method); 819 var bci = 0; 820 var hasLines = method.hasLineNumberTable(); 821 if (hasLines) { 822 writeln("bci", '\t', "line", '\t', "instruction"); 823 } else { 824 writeln("bci", '\t', "instruction"); 825 } 826 writeln(""); 827 disAsm.decode(new sapkg.interpreter.BytecodeVisitor() { 828 visit: function(bytecode) { 829 if (hasLines) { 830 var line = method.getLineNumberFromBCI(bci); 831 writeln(bci, '\t', line, '\t', bytecode); 832 } else { 833 writeln(bci, '\t', bytecode); 834 } 835 bci++; 836 } 837 }); 838 839 writeln(); 840 printExceptionTable(method); 841 } 842 843 // Java thread 844 845 // iterates each Thread 846 function forEachJavaThread(callback) { 847 var threads = sa.threads; 848 var thread = threads.first(); 849 while (thread != null) { 850 if (callback(thread) == false) return; 851 thread = thread.next(); 852 } 853 } 854 855 // iterate Frames of a given thread 856 function forEachFrame(javaThread, callback) { 857 var fr = javaThread.getLastFrameDbg(); 858 while (fr != null) { 859 if (callback(fr) == false) return; 860 fr = fr.sender(); 861 } 862 } 863 864 // iterate JavaVFrames of a given JavaThread 865 function forEachVFrame(javaThread, callback) { 866 var vfr = javaThread.getLastJavaVFrameDbg(); 867 while (vfr != null) { 868 if (callback(vfr) == false) return; 869 vfr = vfr.javaSender(); 870 } 871 } 872 873 function printStackTrace(javaThread) { 874 write("Thread "); 875 javaThread.printThreadIDOn(java.lang.System.out); 876 writeln(); 877 forEachVFrame(javaThread, function (vf) { 878 var method = vf.method; 879 write(' - ', method.externalNameAndSignature(), '@bci =', vf.getBCI()); 880 var line = method.getLineNumberFromBCI(vf.getBCI()); 881 if (line != -1) { write(', line=', line); } 882 if (vf.isCompiledFrame()) { write(" (Compiled Frame)"); } 883 if (vf.isInterpretedFrame()) { write(" (Interpreted Frame)"); } 884 writeln(); 885 }); 886 writeln(); 887 writeln(); 888 } 889 890 // print Java stack trace for all threads 891 function where(javaThread) { 892 if (javaThread == undefined) { 893 forEachJavaThread(function (jt) { printStackTrace(jt); }); 894 } else { 895 printStackTrace(javaThread); 896 } 897 } 898 899 // vmStructs access -- type database functions 900 901 // find a VM type 902 function findVMType(typeName) { 903 return sa.typedb.lookupType(typeName); 904 } 905 906 // iterate VM types 907 function forEachVMType(callback) { 908 var itr = sa.typedb.types; 909 while (itr.hasNext()) { 910 if (callback(itr.next()) == false) return; 911 } 912 } 913 914 // find VM int constant 915 function findVMIntConst(name) { 916 return sa.typedb.lookupIntConstant(name); 917 } 918 919 // find VM long constant 920 function findVMLongConst(name) { 921 return sa.typedb.lookupLongConstant(name); 922 } 923 924 // iterate VM int constants 925 function forEachVMIntConst(callback) { 926 var itr = sa.typedb.intConstants; 927 while (itr.hasNext()) { 928 if (callback(itr.next()) == false) return; 929 } 930 } 931 932 // iterate VM long constants 933 function forEachVMLongConst(callback) { 934 var itr = sa.typedb.longConstants; 935 while (itr.hasNext()) { 936 if (callback(itr.next()) == false) return; 937 } 938 } 939 940 // returns VM Type at address 941 function vmTypeof(addr) { 942 addr = any2addr(addr); 943 return sa.typedb.guessTypeForAddress(addr); 944 } 945 946 // does the given 'addr' points to an object of given 'type'? 947 // OR any valid Type at all (if type is undefined) 948 function isOfVMType(addr, type) { 949 addr = any2addr(addr); 950 if (type == undefined) { 951 return vmTypeof(addr) != null; 952 } else { 953 if (typeof(type) == 'string') { 954 type = findVMType(type); 955 } 956 return sa.typedb.addressTypeIsEqualToType(addr, type); 957 } 958 } 959 960 // reads static field value 961 function readVMStaticField(field) { 962 var type = field.type; 963 if (type.isCIntegerType() || type.isJavaPrimitiveType()) { 964 return field.value; 965 } else if (type.isPointerType()) { 966 return field.address; 967 } else if (type.isOopType()) { 968 return field.oopHandle; 969 } else { 970 return field.staticFieldAddress; 971 } 972 } 973 974 // reads given instance field of VM object at 'addr' 975 function readVMInstanceField(field, addr) { 976 var type = field.type; 977 if (type.isCIntegerType() || type.isJavaPrimitiveType()) { 978 return field.getValue(addr); 979 } else if (type.isPointerType()) { 980 return field.getAddress(addr); 981 } else if (type.isOopType()) { 982 return field.getOopHandle(addr); 983 } else { 984 return addr.addOffsetTo(field.offset); 985 } 986 } 987 988 // returns name-value of pairs of VM type at given address. 989 // If address is unspecified, reads static fields as name-value pairs. 990 function readVMType(type, addr) { 991 if (typeof(type) == 'string') { 992 type = findVMType(type); 993 } 994 if (addr != undefined) { 995 addr = any2addr(addr); 996 } 997 998 var result = new Object(); 999 var staticOnly = (addr == undefined); 1000 while (type != null) { 1001 var itr = type.fields; 1002 while (itr.hasNext()) { 1003 var field = itr.next(); 1004 var isStatic = field.isStatic(); 1005 if (staticOnly && isStatic) { 1006 result[field.name] = readVMStaticField(field); 1007 } else if (!staticOnly && !isStatic) { 1008 result[field.name] = readVMInstanceField(field, addr); 1009 } 1010 } 1011 type = type.superclass; 1012 } 1013 return result; 1014 } 1015 1016 function printVMType(type, addr) { 1017 if (typeof(type) == 'string') { 1018 type = findVMType(type); 1019 } 1020 var obj = readVMType(type, addr); 1021 while (type != null) { 1022 var itr = type.fields; 1023 while (itr.hasNext()) { 1024 var field = itr.next(); 1025 var name = field.name; 1026 var value = obj[name]; 1027 if (value != undefined) { 1028 writeln(field.type.name, type.name + '::' + name, '=', value); 1029 } 1030 } 1031 type = type.superclass; 1032 } 1033 } 1034 1035 // define readXXX and printXXX functions for each VM struct/class Type 1036 tmp = new Object(); 1037 tmp.itr = sa.typedb.types; 1038 while (tmp.itr.hasNext()) { 1039 tmp.type = tmp.itr.next(); 1040 tmp.name = tmp.type.name; 1041 if (tmp.type.isPointerType() || tmp.type.isOopType() || 1042 tmp.type.isCIntegerType() || tmp.type.isJavaPrimitiveType() || 1043 tmp.name.equals('address') || 1044 tmp.name.equals("<opaque>")) { 1045 // ignore; 1046 continue; 1047 } else { 1048 // some type names have ':'. replace to make it as a 1049 // JavaScript identifier 1050 tmp.name = tmp.name.replace(':', '_').replace('<', '_').replace('>', '_').replace('*', '_').replace(' ', '_'); 1051 eval("function read" + tmp.name + "(addr) {" + 1052 " return readVMType('" + tmp.name + "', addr);}"); 1053 eval("function print" + tmp.name + "(addr) {" + 1054 " printVMType('" + tmp.name + "', addr); }"); 1055 1056 /* FIXME: do we need this? 1057 if (typeof(registerCommand) != 'undefined') { 1058 var name = "print" + tmp.name; 1059 registerCommand(name, name + " [address]", name); 1060 } 1061 */ 1062 } 1063 } 1064 //clean-up the temporary 1065 delete tmp; 1066 1067 // VMObject factory 1068 1069 // VM type to SA class map 1070 var vmType2Class = new Object(); 1071 1072 // This is *not* exhaustive. Add more if needed. 1073 // code blobs 1074 vmType2Class["BufferBlob"] = sapkg.code.BufferBlob; 1075 vmType2Class["nmethod"] = sapkg.code.NMethod; 1076 vmType2Class["RuntimeStub"] = sapkg.code.RuntimeStub; 1077 vmType2Class["SafepointBlob"] = sapkg.code.SafepointBlob; 1078 vmType2Class["C2IAdapter"] = sapkg.code.C2IAdapter; 1079 vmType2Class["DeoptimizationBlob"] = sapkg.code.DeoptimizationBlob; 1080 vmType2Class["ExceptionBlob"] = sapkg.code.ExceptionBlob; 1081 vmType2Class["I2CAdapter"] = sapkg.code.I2CAdapter; 1082 vmType2Class["OSRAdapter"] = sapkg.code.OSRAdapter; 1083 vmType2Class["UncommonTrapBlob"] = sapkg.code.UncommonTrapBlob; 1084 vmType2Class["PCDesc"] = sapkg.code.PCDesc; 1085 1086 // interpreter 1087 vmType2Class["InterpreterCodelet"] = sapkg.interpreter.InterpreterCodelet; 1088 1089 // Java Threads 1090 vmType2Class["JavaThread"] = sapkg.runtime.JavaThread; 1091 vmType2Class["CompilerThread"] = sapkg.runtime.CompilerThread; 1092 vmType2Class["SurrogateLockerThread"] = sapkg.runtime.JavaThread; 1093 vmType2Class["DebuggerThread"] = sapkg.runtime.DebuggerThread; 1094 1095 // gc 1096 vmType2Class["GenCollectedHeap"] = sapkg.memory.GenCollectedHeap; 1097 vmType2Class["CompactingPermGenGen"] = sapkg.memory.CompactingPermGenGen; 1098 vmType2Class["DefNewGeneration"] = sapkg.memory.DefNewGeneration; 1099 vmType2Class["TenuredGeneration"] = sapkg.memory.TenuredGeneration; 1100 1101 // generic VMObject factory for a given address 1102 // This is equivalent to VirtualConstructor. 1103 function newVMObject(addr) { 1104 addr = any2addr(addr); 1105 var result = null; 1106 forEachVMType(function (type) { 1107 if (isOfVMType(addr, type)) { 1108 var clazz = vmType2Class[type.name]; 1109 if (clazz != undefined) { 1110 result = new clazz(addr); 1111 } 1112 return false; 1113 } else { 1114 return true; 1115 } 1116 }); 1117 return result; 1118 } 1119 1120 function vmobj2addr(vmobj) { 1121 return vmobj.address; 1122 } 1123 1124 function addr2vmobj(addr) { 1125 return newVMObject(addr); 1126 } 1127 1128 // Miscellaneous utilities 1129 1130 // returns PointerLocation that describes the given pointer 1131 function findPtr(addr) { 1132 addr = any2addr(addr); 1133 return sapkg.utilities.PointerFinder.find(addr); 1134 } 1135 1136 // is given address a valid Oop? 1137 function isOop(addr) { 1138 addr = any2addr(addr); 1139 var oopHandle = addr.addOffsetToAsOopHandle(0); 1140 return sapkg.utilities.RobustOopDeterminator.oopLooksValid(oopHandle); 1141 } 1142 1143 // returns description of given pointer as a String 1144 function whatis(addr) { 1145 addr = any2addr(addr); 1146 var ptrLoc = findPtr(addr); 1147 if (ptrLoc.isUnknown()) { 1148 var vmType = vmTypeof(addr); 1149 if (vmType != null) { 1150 return "pointer to " + vmType.name; 1151 } else { 1152 var sym = closestSymbolFor(addr); 1153 if (sym != null) { 1154 return sym.name + '+' + sym.offset; 1155 } else { 1156 return ptrLoc.toString(); 1157 } 1158 } 1159 } else { 1160 return ptrLoc.toString(); 1161 } 1162 }