1 /*
   2  * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * 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.c1 = sapkg.hotspot.c1;
  35 sapkg.code = sapkg.hotspot.code;
  36 sapkg.compiler = sapkg.hotspot.compiler;
  37 
  38 // 'debugger' is a JavaScript keyword, but ES5 relaxes the
  39 // restriction of using keywords as property name
  40 sapkg.debugger = sapkg.hotspot.debugger;
  41 
  42 sapkg.interpreter = sapkg.hotspot.interpreter;
  43 sapkg.jdi = sapkg.hotspot.jdi;
  44 sapkg.memory = sapkg.hotspot.memory;
  45 sapkg.oops = sapkg.hotspot.oops;
  46 sapkg.runtime = sapkg.hotspot.runtime;
  47 sapkg.tools = sapkg.hotspot.tools;
  48 sapkg.types = sapkg.hotspot.types;
  49 sapkg.ui = sapkg.hotspot.ui;
  50 sapkg.utilities = sapkg.hotspot.utilities;
  51 
  52 // SA singletons are kept in 'sa' object
  53 var sa = new Object();
  54 sa.vm = sapkg.runtime.VM.getVM();
  55 sa.dbg = sa.vm.getDebugger();
  56 sa.cdbg = sa.dbg.CDebugger;
  57 sa.heap = sa.vm.universe.heap();
  58 sa.systemDictionary = sa.vm.systemDictionary;
  59 sa.sysDict = sa.systemDictionary;
  60 sa.symbolTable = sa.vm.symbolTable;
  61 sa.symTbl = sa.symbolTable;
  62 sa.threads = sa.vm.threads;
  63 sa.interpreter = sa.vm.interpreter;
  64 sa.typedb = sa.vm.typeDataBase;
  65 sa.codeCache = sa.vm.codeCache;
  66 // 'objHeap' is different from 'heap'!. 
  67 // This is SA's Oop factory and heap-walker
  68 sa.objHeap = sa.vm.objectHeap;
  69 
  70 // few useful global variables
  71 var OS = sa.vm.OS;
  72 var CPU = sa.vm.CPU;
  73 var LP64 = sa.vm.LP64;
  74 var isClient = sa.vm.clientCompiler;
  75 var isServer = sa.vm.serverCompiler;
  76 var isCore = sa.vm.isCore();
  77 var addressSize = sa.vm.addressSize;
  78 var oopSize = sa.vm.oopSize;
  79 
  80 // this "main" function is called immediately
  81 // after loading this script file
  82 function main(globals, jvmarg) {
  83   // wrap a sun.jvm.hotspot.utilities.soql.ScriptObject
  84   // object so that the properties of it can be accessed
  85   // in natural object.field syntax.
  86   function wrapScriptObject(so) {
  87     function unwrapScriptObject(wso) {
  88       var objType = typeof(wso);
  89       if ((objType == 'object' ||
  90            objType == 'function')
  91           && "__wrapped__" in wso) {
  92         return wso.__wrapped__;
  93       } else {
  94         return wso;
  95       }
  96     }
  97 
  98     function prepareArgsArray(array) {
  99       var args = new Array(array.length);
 100       for (var a = 0; a < array.length; a++) {
 101         var elem = array[a];
 102         elem = unwrapScriptObject(elem);
 103         if (typeof(elem) == 'function') {
 104           args[a] = new sapkg.utilities.soql.Callable() {
 105             call: function(myargs) {
 106               var tmp = new Array(myargs.length);
 107               for (var i = 0; i < myargs.length; i++) {
 108                 tmp[i] = wrapScriptObject(myargs[i]);
 109               }
 110               return elem.apply(this, tmp);
 111             }
 112           }
 113         } else {
 114           args[a] = elem;
 115         }
 116       }
 117       return args;
 118     }
 119 
 120     // Handle __has__ specially to avoid metacircularity problems
 121     // when called from __get__.
 122     // Calling
 123     //   this.__has__(name)
 124     // will in turn call
 125     //   this.__call__('__has__', name)
 126     // which is not handled below
 127     function __has__(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     if (so instanceof sapkg.utilities.soql.ScriptObject) {
 144       return new JSAdapter() {
 145         __getIds__: function() {
 146           return so.getIds();
 147         },
 148   
 149         __has__ : __has__,
 150   
 151         __delete__ : function(name) {
 152           if (typeof(name) == 'number') {
 153             return so["delete(int)"](name);
 154           } else {
 155             return so["delete(java.lang.String)"](name);
 156           }
 157         },
 158   
 159         __get__ : function(name) {
 160               // don't call this.__has__(name); see comments above function __has__
 161           if (! __has__.call(this, name)) {
 162             return undefined;
 163           }
 164           if (typeof(name) == 'number') {
 165             return wrapScriptObject(so["get(int)"](name));
 166           } else {
 167             if (name == '__wrapped__') {
 168               return so;
 169             } else {
 170               var value = so["get(java.lang.String)"](name);
 171               if (value instanceof sapkg.utilities.soql.Callable) {
 172                 return function() {
 173                   var args = prepareArgsArray(arguments);
 174                   var r;
 175                   try {
 176                     r = value.call(Java.to(args, 'java.lang.Object[]'));
 177                   } catch (e) {
 178                     println("call to " + name + " failed!");
 179                     throw e;
 180                   }
 181                   return wrapScriptObject(r);
 182                 }
 183               } else if (name == 'toString') {
 184                 return function() { 
 185                   return so.toString();
 186                 }
 187               } else {
 188                 return wrapScriptObject(value);
 189               }
 190             }
 191           }
 192         }
 193       };
 194     } else {
 195       return so;
 196     }
 197   }
 198 
 199   // set "jvm" global variable that wraps a 
 200   // sun.jvm.hotspot.utilities.soql.JSJavaVM instance
 201   if (jvmarg != null) {
 202     jvm = wrapScriptObject(jvmarg);
 203     // expose "heap" global variable
 204     heap = jvm.heap;
 205   }
 206 
 207   // expose all "function" type properties of
 208   // sun.jvm.hotspot.utilitites.soql.JSJavaScriptEngine
 209   // as global functions here.
 210   globals = wrapScriptObject(globals);
 211   for (var prop in globals) {    
 212     if (typeof(globals[prop]) == 'function') {
 213       this[prop] = globals[prop];
 214     }    
 215   }
 216 
 217   // define "writeln" and "write" if not defined
 218   if (typeof(println) == 'undefined') {
 219     println = function (str) {
 220       java.lang.System.out.println(String(str));
 221     }
 222   }
 223 
 224   if (typeof(print) == 'undefined') {
 225     print = function (str) {
 226       java.lang.System.out.print(String(str));
 227     }
 228   }
 229 
 230   if (typeof(writeln) == 'undefined') {
 231     writeln = println;
 232   }
 233 
 234   if (typeof(write) == 'undefined') {
 235     write = print;
 236   }
 237 
 238   // "registerCommand" function is defined if we
 239   // are running as part of "CLHSDB" tool. CLHSDB
 240   // tool exposes Unix-style commands. 
 241 
 242   // if "registerCommand" function is defined
 243   // then register few global functions as "commands".
 244   if (typeof(registerCommand) == 'function') {
 245     this.jclass = function(name) {
 246       if (typeof(name) == "string") {
 247          var clazz = sapkg.utilities.SystemDictionaryHelper.findInstanceKlass(name);
 248          if (clazz) {
 249              writeln(clazz.getName().asString() + " @" + clazz.getAddress().toString());
 250          } else {
 251              writeln("class not found: " + name);
 252          } 
 253       } else {
 254          writeln("Usage: class name");
 255       }
 256     }
 257     registerCommand("class", "class name", "jclass");
 258 
 259     this.jclasses = function() {
 260       forEachKlass(function (clazz) {
 261         writeln(clazz.getName().asString() + " @" + clazz.getAddress().toString()); 
 262       });
 263     }
 264     registerCommand("classes", "classes", "jclasses");
 265 
 266     this.dclass = function(clazz, dir) {
 267       if (!clazz) {
 268          writeln("Usage: dumpclass { address | name } [ directory ]");
 269       } else {
 270          if (!dir) { dir = "."; }
 271          dumpClass(clazz, dir);
 272       }
 273     }
 274     registerCommand("dumpclass", "dumpclass { address | name } [ directory ]", "dclass");
 275     registerCommand("dumpheap", "dumpheap [ file ]", "dumpHeap");
 276 
 277     this.jseval = function(str) {
 278       if (!str) {
 279          writeln("Usage: jseval script");
 280       } else {
 281          var res = eval(str);
 282          if (res) { writeln(res); }
 283       }
 284     }
 285     registerCommand("jseval", "jseval script", "jseval");
 286 
 287     this.jsload = function(file) {
 288       if (!file) {
 289          writeln("Usage: jsload file");
 290       } else {
 291          load(file);
 292       }
 293     }
 294     registerCommand("jsload", "jsload file", "jsload");
 295 
 296     this.printMem = function(addr, len) {
 297       if (!addr) {
 298          writeln("Usage: mem [ length ]");
 299       } else {
 300          mem(addr, len);
 301       }
 302     }
 303     registerCommand("mem", "mem address [ length ]", "printMem");
 304 
 305     this.sysProps = function() {
 306       for (var i in jvm.sysProps) {
 307          writeln(i + ' = ' + jvm.sysProps[i]);
 308       }
 309     }
 310     registerCommand("sysprops", "sysprops", "sysProps");
 311 
 312     this.printWhatis = function(addr) {
 313       if (!addr) {
 314          writeln("Usage: whatis address");
 315       } else {
 316          writeln(whatis(addr));
 317       }
 318     }
 319     registerCommand("whatis", "whatis address", "printWhatis");
 320   }  
 321 }
 322 
 323 // debugger functionality
 324 
 325 // string-to-Address
 326 function str2addr(str) {
 327    return sa.dbg.parseAddress(str);
 328 }
 329 
 330 // number-to-Address
 331 if (addressSize == 4) {
 332    eval("function num2addr(num) { \
 333             return str2addr('0x' + java.lang.Integer.toHexString(0xffffffff & num)); \
 334          }");
 335 } else {
 336    eval("function num2addr(num) { \
 337             return str2addr('0x' + java.lang.Long.toHexString(num));  \
 338          }");
 339 }
 340 
 341 // generic any-type-to-Address
 342 // use this convenience function to accept address in any
 343 // format -- number, string or an Address instance.
 344 function any2addr(addr) {
 345    var type = typeof(addr);
 346    if (type == 'number') {
 347       return num2addr(addr);
 348    } else if (type == 'string') {         
 349       return str2addr(addr);
 350    } else {
 351       return addr;
 352    }
 353 }
 354 
 355 // Address-to-string
 356 function addr2str(addr) {
 357    if (addr == null) {
 358       return (addressSize == 4)? '0x00000000' : '0x0000000000000000';
 359    } else {
 360       return addr + '';
 361    }
 362 }
 363 
 364 // Address-to-number
 365 function addr2num(addr) {
 366    return sa.dbg.getAddressValue(addr);
 367 }
 368 
 369 // symbol-to-Address
 370 function sym2addr(dso, sym) {
 371    return sa.dbg.lookup(dso, sym);
 372 }
 373 
 374 function loadObjectContainingPC(addr) {
 375     if (sa.cdbg == null) {
 376       // no CDebugger support, return null
 377       return null;
 378     }
 379 
 380     return  sa.cdbg.loadObjectContainingPC(addr);
 381 }
 382 
 383 // returns the ClosestSymbol or null
 384 function closestSymbolFor(addr) {
 385     var dso = loadObjectContainingPC(addr);
 386     if (dso != null) {
 387       return dso.closestSymbolToPC(addr);
 388     }
 389 
 390     return null;
 391 }
 392 
 393 // Address-to-symbol
 394 // returns nearest symbol as string if found
 395 // else returns address as string
 396 function addr2sym(addr) {
 397     var sym = closestSymbolFor(addr);
 398     if (sym != null)  {
 399        return sym.name + '+' + sym.offset;
 400     } else {
 401        return addr2str(addr);
 402     }
 403 }
 404 
 405 // read 'num' words at 'addr' and return an array as result.
 406 // returns Java long[] type result and not a JavaScript array.
 407 function readWordsAt(addr, num) {
 408    addr = any2addr(addr);
 409    var res = java.lang.reflect.Array.newInstance(java.lang.Long.TYPE, num);
 410    var i;
 411    for (i = 0; i < num; i++) {
 412       res[i] = addr2num(addr.getAddressAt(i * addressSize));
 413    }
 414    return res;
 415 }
 416 
 417 // read the 'C' string at 'addr'
 418 function readCStrAt(addr) {
 419    addr = any2addr(addr);
 420    return sapkg.utilities.CStringUtilities.getString(addr);
 421 }
 422 
 423 // read the length of the 'C' string at 'addr'
 424 function readCStrLen(addr) {
 425    addr = any2addr(addr);
 426    return sapkg.utilities.CStringUtilities.getStringLength(addr);
 427 }
 428 
 429 // iterate through ThreadList of CDebugger
 430 function forEachThread(callback) {
 431    if (sa.cdbg == null) {
 432       // no CDebugger support
 433       return;
 434    } else {
 435       var itr = sa.cdbg.threadList.iterator();
 436       while (itr.hasNext()) {
 437          if (callback(itr.next()) == false) return;
 438       }
 439    }
 440 }
 441 
 442 // read register set of a ThreadProxy as name-value pairs
 443 function readRegs(threadProxy) {
 444    var ctx = threadProxy.context;
 445    var num = ctx.numRegisters;
 446    var res = new Object();
 447    var i;
 448    for (i = 0; i < num; i++) {
 449       res[ctx.getRegisterName(i)]= addr2str(ctx.getRegisterAsAddress(i));
 450    }
 451    return res;
 452 }
 453 
 454 // print register set for a given ThreaProxy
 455 function regs(threadProxy) {
 456    var res = readRegs(threadProxy);
 457    for (i in res) {
 458       writeln(i, '=', res[i]);
 459    }
 460 }
 461 
 462 // iterate through each CFrame of a given ThreadProxy
 463 function forEachCFrame(threadProxy, callback) {   
 464    if (sa.cdbg == null) {
 465       // no CDebugger support
 466       return;
 467    } else {
 468       var cframe = sa.cdbg.topFrameForThread(threadProxy);
 469       while (cframe != null) {
 470          if (callback(cframe) == false) return;
 471          cframe = cframe.sender();
 472       }
 473    }
 474 }
 475 
 476 // iterate through list of load objects (DLLs, DSOs)
 477 function forEachLoadObject(callback) {
 478    if (sa.cdbg == null) {
 479       // no CDebugger support
 480       return;
 481    } else {
 482       var itr = sa.cdbg.loadObjectList.iterator();
 483       while (itr.hasNext()) {
 484          if (callback(itr.next()) == false) return;
 485       }
 486    }
 487 }
 488 
 489 // print 'num' words at 'addr'
 490 function mem(addr, num) {
 491    if (num == undefined) {
 492       num = 1;
 493    }
 494    addr = any2addr(addr);   
 495    var i;
 496    for (i = 0; i < num; i++) {
 497       var value = addr.getAddressAt(0);      
 498       writeln(addr2sym(addr) + ':', addr2str(value)); 
 499       addr = addr.addOffsetTo(addressSize);      
 500    }
 501    writeln();
 502 }
 503 
 504 // System dictionary functions
 505 
 506 // find InstanceKlass by name
 507 function findInstanceKlass(name) {
 508    return sapkg.utilities.SystemDictionaryHelper.findInstanceKlass(name);
 509 }
 510 
 511 // get Java system loader (i.e., application launcher loader)
 512 function systemLoader() {
 513    return sa.sysDict.javaSystemLoader();
 514 }
 515 
 516 // iterate class loader data for each 'Klass' 
 517 function forEachKlass(callback) {
 518    var VisitorClass = sapkg.classfile.ClassLoaderDataGraph.ClassVisitor;
 519    var visitor = new VisitorClass() { visit: callback };
 520    sa.sysDict["classesDo(sun.jvm.hotspot.classfile.ClassLoaderDataGraph.ClassVisitor)"](visitor);
 521 }
 522 
 523 // iterate system dictionary for each 'Klass' and initiating loader
 524 function forEachKlassAndLoader(callback) {
 525    var VisitorClass = sapkg.classfile.ClassLoaderDataGraph.ClassAndLoaderVisitor;
 526    var visitor = new VisitorClass() { visit: callback };
 527    sa.sysDict["allEntriesDo(sun.jvm.hotspot.classfile.ClassLoaderDataGraph.ClassAndLoaderVisitor)"](visitor);
 528 }
 529 
 530 // 'oop' to higher-level java object wrapper in which for(i in o) 
 531 // works by iterating java level fields and javaobject.javafield
 532 // syntax works.
 533 function oop2obj(oop) {
 534    return object(addr2str(oop.handle));
 535 }
 536 
 537 // higher level java object wrapper to oop
 538 function obj2oop(obj) {
 539    return addr2oop(str2addr(address(obj)));
 540 }
 541 
 542 // Java heap iteration
 543 
 544 // iterates Java heap for each Oop
 545 function forEachOop(callback) {
 546    function empty() { }
 547    sa.objHeap.iterate(new sapkg.oops.HeapVisitor() {
 548        prologue: empty,
 549        doObj: callback,
 550        epilogue: empty
 551    });
 552 }
 553 
 554 // iterates Java heap for each Oop of given 'klass'.
 555 // 'includeSubtypes' tells whether to include objects 
 556 // of subtypes of 'klass' or not
 557 function forEachOopOfKlass(callback, klass, includeSubtypes) {
 558    if (klass == undefined) {
 559        klass = findInstanceKlass("java.lang.Object");
 560    }
 561 
 562    if (includeSubtypes == undefined) {
 563       includeSubtypes = true;
 564    }
 565 
 566    function empty() { }
 567    sa.objHeap.iterateObjectsOfKlass(
 568         new sapkg.oops.HeapVisitor() {
 569             prologue: empty,
 570             doObj: callback,
 571             epilogue: empty
 572         },
 573         klass, includeSubtypes);
 574 }
 575 
 576 // Java thread
 577 
 578 // iterates each Thread
 579 function forEachJavaThread(callback) {
 580    var threads = sa.threads;
 581    var thread = threads.first();
 582    while (thread != null) {
 583       if (callback(thread) == false) return;
 584       thread = thread.next();
 585    }  
 586 }
 587 
 588 // iterate Frames of a given thread
 589 function forEachFrame(javaThread, callback) {
 590    var fr = javaThread.getLastFrameDbg();
 591    while (fr != null) { 
 592      if (callback(fr) == false) return;
 593      fr = fr.sender();
 594    }
 595 }
 596 
 597 // iterate JavaVFrames of a given JavaThread
 598 function forEachVFrame(javaThread, callback) {
 599    var vfr = javaThread.getLastJavaVFrameDbg();
 600    while (vfr != null) {
 601       if (callback(vfr) == false) return;
 602       vfr = vfr.javaSender();
 603    }
 604 }
 605 
 606 function printStackTrace(javaThread) {
 607    write("Thread ");
 608    javaThread.printThreadIDOn(java.lang.System.out);
 609    writeln();
 610    forEachVFrame(javaThread, function (vf) {
 611       var method = vf.method;
 612       write(' - ', method.externalNameAndSignature(), '@bci =', vf.getBCI());
 613       var line = method.getLineNumberFromBCI(vf.getBCI());
 614       if (line != -1) { write(', line=', line); }
 615       if (vf.isCompiledFrame()) { write(" (Compiled Frame)"); }
 616       if (vf.isInterpretedFrame()) { write(" (Interpreted Frame)"); }
 617       writeln();
 618    });
 619    writeln();
 620    writeln();
 621 }
 622 
 623 // print Java stack trace for all threads
 624 function where(javaThread) {
 625    if (javaThread == undefined) {
 626       forEachJavaThread(function (jt) { printStackTrace(jt); });
 627    } else {
 628       printStackTrace(javaThread);
 629    }
 630 }
 631 
 632 // vmStructs access -- type database functions
 633 
 634 // find a VM type
 635 function findVMType(typeName) {
 636    return sa.typedb.lookupType(typeName);
 637 }
 638 
 639 // iterate VM types
 640 function forEachVMType(callback) {
 641    var itr = sa.typedb.types;
 642    while (itr.hasNext()) {
 643       if (callback(itr.next()) == false) return;
 644    }
 645 }
 646 
 647 // find VM int constant
 648 function findVMIntConst(name) {
 649    return sa.typedb.lookupIntConstant(name);
 650 }
 651 
 652 // find VM long constant
 653 function findVMLongConst(name) {
 654    return sa.typedb.lookupLongConstant(name);
 655 }
 656 
 657 // iterate VM int constants
 658 function forEachVMIntConst(callback) {
 659    var itr = sa.typedb.intConstants;
 660    while (itr.hasNext()) {
 661       if (callback(itr.next()) == false) return;
 662    } 
 663 }
 664 
 665 // iterate VM long constants
 666 function forEachVMLongConst(callback) {
 667    var itr = sa.typedb.longConstants;
 668    while (itr.hasNext()) {
 669       if (callback(itr.next()) == false) return;
 670    } 
 671 }
 672 
 673 // returns VM Type at address
 674 function vmTypeof(addr) {
 675    addr = any2addr(addr);
 676    return sa.typedb.guessTypeForAddress(addr);
 677 }
 678 
 679 // does the given 'addr' points to an object of given 'type'?
 680 // OR any valid Type at all (if type is undefined)
 681 function isOfVMType(addr, type) {
 682    addr = any2addr(addr);
 683    if (type == undefined) {
 684       return vmTypeof(addr) != null;
 685    } else {
 686       if (typeof(type) == 'string') {
 687          type = findVMType(type);
 688       } 
 689       return sa.typedb.addressTypeIsEqualToType(addr, type);
 690    }
 691 }
 692 
 693 // reads static field value
 694 function readVMStaticField(field) {
 695    var type = field.type;
 696    if (type.isCIntegerType() || type.isJavaPrimitiveType()) {
 697       return field.value;
 698    } else if (type.isPointerType()) {
 699       return field.address;
 700    } else if (type.isOopType()) {
 701       return field.oopHandle;      
 702    } else {
 703       return field.staticFieldAddress;
 704    }
 705 }
 706 
 707 // reads given instance field of VM object at 'addr'
 708 function readVMInstanceField(field, addr) {
 709    var type = field.type;
 710    if (type.isCIntegerType() || type.isJavaPrimitiveType()) {
 711       return field.getValue(addr);
 712    } else if (type.isPointerType()) {
 713       return field.getAddress(addr);
 714    } else if (type.isOopType()) {
 715       return field.getOopHandle(addr);
 716    } else {
 717       return addr.addOffsetTo(field.offset);
 718    }
 719 }
 720 
 721 // returns name-value of pairs of VM type at given address.
 722 // If address is unspecified, reads static fields as name-value pairs.
 723 function readVMType(type, addr) {
 724    if (typeof(type) == 'string') {
 725       type = findVMType(type);
 726    }
 727    if (addr != undefined) {
 728       addr = any2addr(addr);
 729    }
 730 
 731    var result = new Object();
 732    var staticOnly = (addr == undefined);
 733    while (type != null) {
 734       var itr = type.fields;
 735       while (itr.hasNext()) {
 736          var field = itr.next();
 737          var isStatic = field.isStatic();
 738          if (staticOnly && isStatic) {
 739             result[field.name] = readVMStaticField(field);
 740          } else if (!staticOnly && !isStatic) {
 741             result[field.name] = readVMInstanceField(field, addr);
 742          }
 743       }
 744       type = type.superclass;
 745    } 
 746    return result;
 747 }
 748 
 749 function printVMType(type, addr) {
 750    if (typeof(type) == 'string') {
 751       type = findVMType(type);
 752    }
 753    var obj = readVMType(type, addr);
 754    while (type != null) {
 755       var itr = type.fields;
 756       while (itr.hasNext()) {
 757          var field = itr.next();
 758          var name = field.name;
 759          var value = obj[name];
 760          if (value != undefined) {
 761             writeln(field.type.name, type.name + '::' + name, '=', value);
 762          }
 763       }
 764       type = type.superclass;  
 765    }
 766 }
 767 
 768 // define readXXX and printXXX functions for each VM struct/class Type
 769 tmp = new Object();
 770 tmp.itr = sa.typedb.types;
 771 while (tmp.itr.hasNext()) {
 772    tmp.type = tmp.itr.next();
 773    tmp.name = tmp.type.name;
 774    if (tmp.type.isPointerType() || tmp.type.isOopType() ||
 775       tmp.type.isCIntegerType() || tmp.type.isJavaPrimitiveType() ||
 776       tmp.name.equals('address') ||
 777       tmp.name.equals("<opaque>")) {
 778          // ignore;
 779          continue;
 780    } else {
 781       // some type names have ':', '<', '>', '*', ' '. replace to make it as a
 782       // JavaScript identifier
 783       tmp.name = ("" + tmp.name).replace(/[:<>* ]/g, '_');
 784       eval("function read" + tmp.name + "(addr) {" +
 785            "   return readVMType('" + tmp.name + "', addr);}"); 
 786       eval("function print" + tmp.name + "(addr) {" + 
 787            "   printVMType('" + tmp.name + "', addr); }");
 788 
 789       /* FIXME: do we need this?
 790       if (typeof(registerCommand) != 'undefined') {
 791           var name = "print" + tmp.name;
 792           registerCommand(name, name + " [address]", name);
 793       }
 794       */
 795    }
 796 }
 797 //clean-up the temporary
 798 delete tmp;
 799 
 800 // VMObject factory
 801 
 802 // VM type to SA class map
 803 var  vmType2Class = new Object();
 804 
 805 // C2 only classes
 806 try{
 807   vmType2Class["ExceptionBlob"] = sapkg.code.ExceptionBlob;
 808   vmType2Class["UncommonTrapBlob"] = sapkg.code.UncommonTrapBlob;
 809 } catch(e) {
 810   // Ignore exception. C2 specific objects might be not 
 811   // available in client VM
 812 }
 813 
 814 
 815 // This is *not* exhaustive. Add more if needed.
 816 // code blobs
 817 vmType2Class["BufferBlob"] = sapkg.code.BufferBlob;
 818 vmType2Class["nmethod"] = sapkg.code.NMethod;
 819 vmType2Class["RuntimeStub"] = sapkg.code.RuntimeStub;
 820 vmType2Class["SafepointBlob"] = sapkg.code.SafepointBlob;
 821 vmType2Class["C2IAdapter"] = sapkg.code.C2IAdapter;
 822 vmType2Class["DeoptimizationBlob"] = sapkg.code.DeoptimizationBlob;
 823 vmType2Class["I2CAdapter"] = sapkg.code.I2CAdapter;
 824 vmType2Class["OSRAdapter"] = sapkg.code.OSRAdapter;
 825 vmType2Class["PCDesc"] = sapkg.code.PCDesc;
 826 
 827 // interpreter
 828 vmType2Class["InterpreterCodelet"] = sapkg.interpreter.InterpreterCodelet;
 829 
 830 // Java Threads
 831 vmType2Class["JavaThread"] = sapkg.runtime.JavaThread;
 832 vmType2Class["CompilerThread"] = sapkg.runtime.CompilerThread;
 833 vmType2Class["CodeCacheSweeperThread"] = sapkg.runtime.CodeCacheSweeperThread;
 834 vmType2Class["DebuggerThread"] = sapkg.runtime.DebuggerThread;
 835 
 836 // gc
 837 vmType2Class["GenCollectedHeap"] = sapkg.memory.GenCollectedHeap;
 838 vmType2Class["DefNewGeneration"] = sapkg.memory.DefNewGeneration;
 839 vmType2Class["TenuredGeneration"] = sapkg.memory.TenuredGeneration;
 840 
 841 // generic VMObject factory for a given address
 842 // This is equivalent to VirtualConstructor.
 843 function newVMObject(addr) {
 844    addr = any2addr(addr);
 845    var result = null;
 846    forEachVMType(function (type) {
 847                     if (isOfVMType(addr, type)) {
 848                        var clazz = vmType2Class[type.name];
 849                        if (clazz != undefined) {
 850                           result = new clazz(addr);
 851                        }
 852                        return false;
 853                     } else {
 854                        return true;
 855                     }
 856                  });
 857    return result;
 858 }
 859 
 860 function vmobj2addr(vmobj) {
 861    return vmobj.address;
 862 }
 863 
 864 function addr2vmobj(addr) {
 865    return newVMObject(addr);
 866 }     
 867 
 868 // Miscellaneous utilities
 869 
 870 // returns PointerLocation that describes the given pointer
 871 function findPtr(addr) {
 872    addr = any2addr(addr);
 873    return sapkg.utilities.PointerFinder.find(addr);
 874 }
 875 
 876 // is given address a valid Oop?
 877 function isOop(addr) {
 878    addr = any2addr(addr);
 879    var oopHandle = addr.addOffsetToAsOopHandle(0);
 880    return sapkg.utilities.RobustOopDeterminator.oopLooksValid(oopHandle);
 881 }
 882 
 883 // returns description of given pointer as a String
 884 function whatis(addr) {
 885   addr = any2addr(addr);
 886   var ptrLoc = findPtr(addr);
 887   if (!ptrLoc.isUnknown()) {
 888     return ptrLoc.toString();
 889   }
 890 
 891   var vmType = vmTypeof(addr);
 892   if (vmType != null) {
 893     return "pointer to " + vmType.name;
 894   }
 895 
 896   var dso = loadObjectContainingPC(addr);
 897   if (dso == null) {
 898     return ptrLoc.toString();
 899   }
 900 
 901   var sym = dso.closestSymbolToPC(addr);
 902   if (sym != null) {
 903     return sym.name + '+' + sym.offset;
 904   }
 905 
 906   var s = dso.getName();
 907   var p = s.lastIndexOf("/");
 908   var base = dso.getBase();
 909   return s.substring(p+1, s.length) + '+' + addr.minus(base);
 910 }