| /* |
| * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| // shorter names for SA packages |
| |
| |
| // SA package name abbreviations are kept in 'sapkg' object |
| // to avoid global namespace pollution |
| var sapkg = new Object(); |
| |
| sapkg.hotspot = Packages.sun.jvm.hotspot; |
| sapkg.asm = sapkg.hotspot.asm; |
| sapkg.c1 = sapkg.hotspot.c1; |
| sapkg.code = sapkg.hotspot.code; |
| sapkg.compiler = sapkg.hotspot.compiler; |
| |
| // 'debugger' is a JavaScript keyword, but ES5 relaxes the |
| // restriction of using keywords as property name |
| sapkg.debugger = sapkg.hotspot.debugger; |
| |
| sapkg.interpreter = sapkg.hotspot.interpreter; |
| sapkg.jdi = sapkg.hotspot.jdi; |
| sapkg.memory = sapkg.hotspot.memory; |
| sapkg.oops = sapkg.hotspot.oops; |
| sapkg.runtime = sapkg.hotspot.runtime; |
| sapkg.tools = sapkg.hotspot.tools; |
| sapkg.types = sapkg.hotspot.types; |
| sapkg.ui = sapkg.hotspot.ui; |
| sapkg.utilities = sapkg.hotspot.utilities; |
| |
| // SA singletons are kept in 'sa' object |
| var sa = new Object(); |
| sa.vm = sapkg.runtime.VM.getVM(); |
| sa.dbg = sa.vm.getDebugger(); |
| sa.cdbg = sa.dbg.CDebugger; |
| sa.heap = sa.vm.universe.heap(); |
| sa.systemDictionary = sa.vm.systemDictionary; |
| sa.sysDict = sa.systemDictionary; |
| sa.symbolTable = sa.vm.symbolTable; |
| sa.symTbl = sa.symbolTable; |
| sa.threads = sa.vm.threads; |
| sa.interpreter = sa.vm.interpreter; |
| sa.typedb = sa.vm.typeDataBase; |
| sa.codeCache = sa.vm.codeCache; |
| // 'objHeap' is different from 'heap'!. |
| // This is SA's Oop factory and heap-walker |
| sa.objHeap = sa.vm.objectHeap; |
| |
| // few useful global variables |
| var OS = sa.vm.OS; |
| var CPU = sa.vm.CPU; |
| var LP64 = sa.vm.LP64; |
| var isClient = sa.vm.clientCompiler; |
| var isServer = sa.vm.serverCompiler; |
| var isCore = sa.vm.isCore(); |
| var addressSize = sa.vm.addressSize; |
| var oopSize = sa.vm.oopSize; |
| |
| // this "main" function is called immediately |
| // after loading this script file |
| function main(globals, jvmarg) { |
| // wrap a sun.jvm.hotspot.utilities.soql.ScriptObject |
| // object so that the properties of it can be accessed |
| // in natural object.field syntax. |
| function wrapScriptObject(so) { |
| function unwrapScriptObject(wso) { |
| var objType = typeof(wso); |
| if ((objType == 'object' || |
| objType == 'function') |
| && "__wrapped__" in wso) { |
| return wso.__wrapped__; |
| } else { |
| return wso; |
| } |
| } |
| |
| function prepareArgsArray(array) { |
| var args = new Array(array.length); |
| for (var a = 0; a < array.length; a++) { |
| var elem = array[a]; |
| elem = unwrapScriptObject(elem); |
| if (typeof(elem) == 'function') { |
| args[a] = new sapkg.utilities.soql.Callable() { |
| call: function(myargs) { |
| var tmp = new Array(myargs.length); |
| for (var i = 0; i < myargs.length; i++) { |
| tmp[i] = wrapScriptObject(myargs[i]); |
| } |
| return elem.apply(this, tmp); |
| } |
| } |
| } else { |
| args[a] = elem; |
| } |
| } |
| return args; |
| } |
| |
| // Handle __has__ specially to avoid metacircularity problems |
| // when called from __get__. |
| // Calling |
| // this.__has__(name) |
| // will in turn call |
| // this.__call__('__has__', name) |
| // which is not handled below |
| function __has__(name) { |
| if (typeof(name) == 'number') { |
| return so["has(int)"](name); |
| } else { |
| if (name == '__wrapped__') { |
| return true; |
| } else if (so["has(java.lang.String)"](name)) { |
| return true; |
| } else if (name.equals('toString')) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| } |
| |
| if (so instanceof sapkg.utilities.soql.ScriptObject) { |
| return new JSAdapter() { |
| __getIds__: function() { |
| return so.getIds(); |
| }, |
| |
| __has__ : __has__, |
| |
| __delete__ : function(name) { |
| if (typeof(name) == 'number') { |
| return so["delete(int)"](name); |
| } else { |
| return so["delete(java.lang.String)"](name); |
| } |
| }, |
| |
| __get__ : function(name) { |
| // don't call this.__has__(name); see comments above function __has__ |
| if (! __has__.call(this, name)) { |
| return undefined; |
| } |
| if (typeof(name) == 'number') { |
| return wrapScriptObject(so["get(int)"](name)); |
| } else { |
| if (name == '__wrapped__') { |
| return so; |
| } else { |
| var value = so["get(java.lang.String)"](name); |
| if (value instanceof sapkg.utilities.soql.Callable) { |
| return function() { |
| var args = prepareArgsArray(arguments); |
| var r; |
| try { |
| r = value.call(Java.to(args, 'java.lang.Object[]')); |
| } catch (e) { |
| println("call to " + name + " failed!"); |
| throw e; |
| } |
| return wrapScriptObject(r); |
| } |
| } else if (name == 'toString') { |
| return function() { |
| return so.toString(); |
| } |
| } else { |
| return wrapScriptObject(value); |
| } |
| } |
| } |
| } |
| }; |
| } else { |
| return so; |
| } |
| } |
| |
| // set "jvm" global variable that wraps a |
| // sun.jvm.hotspot.utilities.soql.JSJavaVM instance |
| if (jvmarg != null) { |
| jvm = wrapScriptObject(jvmarg); |
| // expose "heap" global variable |
| heap = jvm.heap; |
| } |
| |
| // expose all "function" type properties of |
| // sun.jvm.hotspot.utilitites.soql.JSJavaScriptEngine |
| // as global functions here. |
| globals = wrapScriptObject(globals); |
| for (var prop in globals) { |
| if (typeof(globals[prop]) == 'function') { |
| this[prop] = globals[prop]; |
| } |
| } |
| |
| // define "writeln" and "write" if not defined |
| if (typeof(println) == 'undefined') { |
| println = function (str) { |
| java.lang.System.out.println(String(str)); |
| } |
| } |
| |
| if (typeof(print) == 'undefined') { |
| print = function (str) { |
| java.lang.System.out.print(String(str)); |
| } |
| } |
| |
| if (typeof(writeln) == 'undefined') { |
| writeln = println; |
| } |
| |
| if (typeof(write) == 'undefined') { |
| write = print; |
| } |
| |
| // "registerCommand" function is defined if we |
| // are running as part of "CLHSDB" tool. CLHSDB |
| // tool exposes Unix-style commands. |
| |
| // if "registerCommand" function is defined |
| // then register few global functions as "commands". |
| if (typeof(registerCommand) == 'function') { |
| this.jclass = function(name) { |
| if (typeof(name) == "string") { |
| var clazz = sapkg.utilities.SystemDictionaryHelper.findInstanceKlass(name); |
| if (clazz) { |
| writeln(clazz.getName().asString() + " @" + clazz.getAddress().toString()); |
| } else { |
| writeln("class not found: " + name); |
| } |
| } else { |
| writeln("Usage: class name"); |
| } |
| } |
| registerCommand("class", "class name", "jclass"); |
| |
| this.jclasses = function() { |
| forEachKlass(function (clazz) { |
| writeln(clazz.getName().asString() + " @" + clazz.getAddress().toString()); |
| }); |
| } |
| registerCommand("classes", "classes", "jclasses"); |
| |
| this.dclass = function(clazz, dir) { |
| if (!clazz) { |
| writeln("Usage: dumpclass { address | name } [ directory ]"); |
| } else { |
| if (!dir) { dir = "."; } |
| dumpClass(clazz, dir); |
| } |
| } |
| registerCommand("dumpclass", "dumpclass { address | name } [ directory ]", "dclass"); |
| registerCommand("dumpheap", "dumpheap [ file ]", "dumpHeap"); |
| |
| this.jseval = function(str) { |
| if (!str) { |
| writeln("Usage: jseval script"); |
| } else { |
| var res = eval(str); |
| if (res) { writeln(res); } |
| } |
| } |
| registerCommand("jseval", "jseval script", "jseval"); |
| |
| this.jsload = function(file) { |
| if (!file) { |
| writeln("Usage: jsload file"); |
| } else { |
| load(file); |
| } |
| } |
| registerCommand("jsload", "jsload file", "jsload"); |
| |
| this.printMem = function(addr, len) { |
| if (!addr) { |
| writeln("Usage: mem [ length ]"); |
| } else { |
| mem(addr, len); |
| } |
| } |
| registerCommand("mem", "mem address [ length ]", "printMem"); |
| |
| this.sysProps = function() { |
| for (var i in jvm.sysProps) { |
| writeln(i + ' = ' + jvm.sysProps[i]); |
| } |
| } |
| registerCommand("sysprops", "sysprops", "sysProps"); |
| |
| this.printWhatis = function(addr) { |
| if (!addr) { |
| writeln("Usage: whatis address"); |
| } else { |
| writeln(whatis(addr)); |
| } |
| } |
| registerCommand("whatis", "whatis address", "printWhatis"); |
| } |
| } |
| |
| // debugger functionality |
| |
| // string-to-Address |
| function str2addr(str) { |
| return sa.dbg.parseAddress(str); |
| } |
| |
| // number-to-Address |
| if (addressSize == 4) { |
| eval("function num2addr(num) { \ |
| return str2addr('0x' + java.lang.Integer.toHexString(0xffffffff & num)); \ |
| }"); |
| } else { |
| eval("function num2addr(num) { \ |
| return str2addr('0x' + java.lang.Long.toHexString(num)); \ |
| }"); |
| } |
| |
| // generic any-type-to-Address |
| // use this convenience function to accept address in any |
| // format -- number, string or an Address instance. |
| function any2addr(addr) { |
| var type = typeof(addr); |
| if (type == 'number') { |
| return num2addr(addr); |
| } else if (type == 'string') { |
| return str2addr(addr); |
| } else { |
| return addr; |
| } |
| } |
| |
| // Address-to-string |
| function addr2str(addr) { |
| if (addr == null) { |
| return (addressSize == 4)? '0x00000000' : '0x0000000000000000'; |
| } else { |
| return addr + ''; |
| } |
| } |
| |
| // Address-to-number |
| function addr2num(addr) { |
| return sa.dbg.getAddressValue(addr); |
| } |
| |
| // symbol-to-Address |
| function sym2addr(dso, sym) { |
| return sa.dbg.lookup(dso, sym); |
| } |
| |
| function loadObjectContainingPC(addr) { |
| if (sa.cdbg == null) { |
| // no CDebugger support, return null |
| return null; |
| } |
| |
| return sa.cdbg.loadObjectContainingPC(addr); |
| } |
| |
| // returns the ClosestSymbol or null |
| function closestSymbolFor(addr) { |
| var dso = loadObjectContainingPC(addr); |
| if (dso != null) { |
| return dso.closestSymbolToPC(addr); |
| } |
| |
| return null; |
| } |
| |
| // Address-to-symbol |
| // returns nearest symbol as string if found |
| // else returns address as string |
| function addr2sym(addr) { |
| var sym = closestSymbolFor(addr); |
| if (sym != null) { |
| return sym.name + '+' + sym.offset; |
| } else { |
| return addr2str(addr); |
| } |
| } |
| |
| // read 'num' words at 'addr' and return an array as result. |
| // returns Java long[] type result and not a JavaScript array. |
| function readWordsAt(addr, num) { |
| addr = any2addr(addr); |
| var res = java.lang.reflect.Array.newInstance(java.lang.Long.TYPE, num); |
| var i; |
| for (i = 0; i < num; i++) { |
| res[i] = addr2num(addr.getAddressAt(i * addressSize)); |
| } |
| return res; |
| } |
| |
| // read the 'C' string at 'addr' |
| function readCStrAt(addr) { |
| addr = any2addr(addr); |
| return sapkg.utilities.CStringUtilities.getString(addr); |
| } |
| |
| // read the length of the 'C' string at 'addr' |
| function readCStrLen(addr) { |
| addr = any2addr(addr); |
| return sapkg.utilities.CStringUtilities.getStringLength(addr); |
| } |
| |
| // iterate through ThreadList of CDebugger |
| function forEachThread(callback) { |
| if (sa.cdbg == null) { |
| // no CDebugger support |
| return; |
| } else { |
| var itr = sa.cdbg.threadList.iterator(); |
| while (itr.hasNext()) { |
| if (callback(itr.next()) == false) return; |
| } |
| } |
| } |
| |
| // read register set of a ThreadProxy as name-value pairs |
| function readRegs(threadProxy) { |
| var ctx = threadProxy.context; |
| var num = ctx.numRegisters; |
| var res = new Object(); |
| var i; |
| for (i = 0; i < num; i++) { |
| res[ctx.getRegisterName(i)]= addr2str(ctx.getRegisterAsAddress(i)); |
| } |
| return res; |
| } |
| |
| // print register set for a given ThreaProxy |
| function regs(threadProxy) { |
| var res = readRegs(threadProxy); |
| for (i in res) { |
| writeln(i, '=', res[i]); |
| } |
| } |
| |
| // iterate through each CFrame of a given ThreadProxy |
| function forEachCFrame(threadProxy, callback) { |
| if (sa.cdbg == null) { |
| // no CDebugger support |
| return; |
| } else { |
| var cframe = sa.cdbg.topFrameForThread(threadProxy); |
| while (cframe != null) { |
| if (callback(cframe) == false) return; |
| cframe = cframe.sender(); |
| } |
| } |
| } |
| |
| // iterate through list of load objects (DLLs, DSOs) |
| function forEachLoadObject(callback) { |
| if (sa.cdbg == null) { |
| // no CDebugger support |
| return; |
| } else { |
| var itr = sa.cdbg.loadObjectList.iterator(); |
| while (itr.hasNext()) { |
| if (callback(itr.next()) == false) return; |
| } |
| } |
| } |
| |
| // print 'num' words at 'addr' |
| function mem(addr, num) { |
| if (num == undefined) { |
| num = 1; |
| } |
| addr = any2addr(addr); |
| var i; |
| for (i = 0; i < num; i++) { |
| var value = addr.getAddressAt(0); |
| writeln(addr2sym(addr) + ':', addr2str(value)); |
| addr = addr.addOffsetTo(addressSize); |
| } |
| writeln(); |
| } |
| |
| // System dictionary functions |
| |
| // find InstanceKlass by name |
| function findInstanceKlass(name) { |
| return sapkg.utilities.SystemDictionaryHelper.findInstanceKlass(name); |
| } |
| |
| // get Java system loader (i.e., application launcher loader) |
| function systemLoader() { |
| return sa.sysDict.javaSystemLoader(); |
| } |
| |
| // iterate class loader data for each 'Klass' |
| function forEachKlass(callback) { |
| var VisitorClass = sapkg.classfile.ClassLoaderDataGraph.ClassVisitor; |
| var visitor = new VisitorClass() { visit: callback }; |
| sa.sysDict["classesDo(sun.jvm.hotspot.classfile.ClassLoaderDataGraph.ClassVisitor)"](visitor); |
| } |
| |
| // iterate system dictionary for each 'Klass' and initiating loader |
| function forEachKlassAndLoader(callback) { |
| var VisitorClass = sapkg.classfile.ClassLoaderDataGraph.ClassAndLoaderVisitor; |
| var visitor = new VisitorClass() { visit: callback }; |
| sa.sysDict["allEntriesDo(sun.jvm.hotspot.classfile.ClassLoaderDataGraph.ClassAndLoaderVisitor)"](visitor); |
| } |
| |
| // 'oop' to higher-level java object wrapper in which for(i in o) |
| // works by iterating java level fields and javaobject.javafield |
| // syntax works. |
| function oop2obj(oop) { |
| return object(addr2str(oop.handle)); |
| } |
| |
| // higher level java object wrapper to oop |
| function obj2oop(obj) { |
| return addr2oop(str2addr(address(obj))); |
| } |
| |
| // Java heap iteration |
| |
| // iterates Java heap for each Oop |
| function forEachOop(callback) { |
| function empty() { } |
| sa.objHeap.iterate(new sapkg.oops.HeapVisitor() { |
| prologue: empty, |
| doObj: callback, |
| epilogue: empty |
| }); |
| } |
| |
| // iterates Java heap for each Oop of given 'klass'. |
| // 'includeSubtypes' tells whether to include objects |
| // of subtypes of 'klass' or not |
| function forEachOopOfKlass(callback, klass, includeSubtypes) { |
| if (klass == undefined) { |
| klass = findInstanceKlass("java.lang.Object"); |
| } |
| |
| if (includeSubtypes == undefined) { |
| includeSubtypes = true; |
| } |
| |
| function empty() { } |
| sa.objHeap.iterateObjectsOfKlass( |
| new sapkg.oops.HeapVisitor() { |
| prologue: empty, |
| doObj: callback, |
| epilogue: empty |
| }, |
| klass, includeSubtypes); |
| } |
| |
| // Java thread |
| |
| // iterates each Thread |
| function forEachJavaThread(callback) { |
| var threads = sa.threads; |
| var thread = threads.first(); |
| while (thread != null) { |
| if (callback(thread) == false) return; |
| thread = thread.next(); |
| } |
| } |
| |
| // iterate Frames of a given thread |
| function forEachFrame(javaThread, callback) { |
| var fr = javaThread.getLastFrameDbg(); |
| while (fr != null) { |
| if (callback(fr) == false) return; |
| fr = fr.sender(); |
| } |
| } |
| |
| // iterate JavaVFrames of a given JavaThread |
| function forEachVFrame(javaThread, callback) { |
| var vfr = javaThread.getLastJavaVFrameDbg(); |
| while (vfr != null) { |
| if (callback(vfr) == false) return; |
| vfr = vfr.javaSender(); |
| } |
| } |
| |
| function printStackTrace(javaThread) { |
| write("Thread "); |
| javaThread.printThreadIDOn(java.lang.System.out); |
| writeln(); |
| forEachVFrame(javaThread, function (vf) { |
| var method = vf.method; |
| write(' - ', method.externalNameAndSignature(), '@bci =', vf.getBCI()); |
| var line = method.getLineNumberFromBCI(vf.getBCI()); |
| if (line != -1) { write(', line=', line); } |
| if (vf.isCompiledFrame()) { write(" (Compiled Frame)"); } |
| if (vf.isInterpretedFrame()) { write(" (Interpreted Frame)"); } |
| writeln(); |
| }); |
| writeln(); |
| writeln(); |
| } |
| |
| // print Java stack trace for all threads |
| function where(javaThread) { |
| if (javaThread == undefined) { |
| forEachJavaThread(function (jt) { printStackTrace(jt); }); |
| } else { |
| printStackTrace(javaThread); |
| } |
| } |
| |
| // vmStructs access -- type database functions |
| |
| // find a VM type |
| function findVMType(typeName) { |
| return sa.typedb.lookupType(typeName); |
| } |
| |
| // iterate VM types |
| function forEachVMType(callback) { |
| var itr = sa.typedb.types; |
| while (itr.hasNext()) { |
| if (callback(itr.next()) == false) return; |
| } |
| } |
| |
| // find VM int constant |
| function findVMIntConst(name) { |
| return sa.typedb.lookupIntConstant(name); |
| } |
| |
| // find VM long constant |
| function findVMLongConst(name) { |
| return sa.typedb.lookupLongConstant(name); |
| } |
| |
| // iterate VM int constants |
| function forEachVMIntConst(callback) { |
| var itr = sa.typedb.intConstants; |
| while (itr.hasNext()) { |
| if (callback(itr.next()) == false) return; |
| } |
| } |
| |
| // iterate VM long constants |
| function forEachVMLongConst(callback) { |
| var itr = sa.typedb.longConstants; |
| while (itr.hasNext()) { |
| if (callback(itr.next()) == false) return; |
| } |
| } |
| |
| // returns VM Type at address |
| function vmTypeof(addr) { |
| addr = any2addr(addr); |
| return sa.typedb.guessTypeForAddress(addr); |
| } |
| |
| // does the given 'addr' points to an object of given 'type'? |
| // OR any valid Type at all (if type is undefined) |
| function isOfVMType(addr, type) { |
| addr = any2addr(addr); |
| if (type == undefined) { |
| return vmTypeof(addr) != null; |
| } else { |
| if (typeof(type) == 'string') { |
| type = findVMType(type); |
| } |
| return sa.typedb.addressTypeIsEqualToType(addr, type); |
| } |
| } |
| |
| // reads static field value |
| function readVMStaticField(field) { |
| var type = field.type; |
| if (type.isCIntegerType() || type.isJavaPrimitiveType()) { |
| return field.value; |
| } else if (type.isPointerType()) { |
| return field.address; |
| } else if (type.isOopType()) { |
| return field.oopHandle; |
| } else { |
| return field.staticFieldAddress; |
| } |
| } |
| |
| // reads given instance field of VM object at 'addr' |
| function readVMInstanceField(field, addr) { |
| var type = field.type; |
| if (type.isCIntegerType() || type.isJavaPrimitiveType()) { |
| return field.getValue(addr); |
| } else if (type.isPointerType()) { |
| return field.getAddress(addr); |
| } else if (type.isOopType()) { |
| return field.getOopHandle(addr); |
| } else { |
| return addr.addOffsetTo(field.offset); |
| } |
| } |
| |
| // returns name-value of pairs of VM type at given address. |
| // If address is unspecified, reads static fields as name-value pairs. |
| function readVMType(type, addr) { |
| if (typeof(type) == 'string') { |
| type = findVMType(type); |
| } |
| if (addr != undefined) { |
| addr = any2addr(addr); |
| } |
| |
| var result = new Object(); |
| var staticOnly = (addr == undefined); |
| while (type != null) { |
| var itr = type.fields; |
| while (itr.hasNext()) { |
| var field = itr.next(); |
| var isStatic = field.isStatic(); |
| if (staticOnly && isStatic) { |
| result[field.name] = readVMStaticField(field); |
| } else if (!staticOnly && !isStatic) { |
| result[field.name] = readVMInstanceField(field, addr); |
| } |
| } |
| type = type.superclass; |
| } |
| return result; |
| } |
| |
| function printVMType(type, addr) { |
| if (typeof(type) == 'string') { |
| type = findVMType(type); |
| } |
| var obj = readVMType(type, addr); |
| while (type != null) { |
| var itr = type.fields; |
| while (itr.hasNext()) { |
| var field = itr.next(); |
| var name = field.name; |
| var value = obj[name]; |
| if (value != undefined) { |
| writeln(field.type.name, type.name + '::' + name, '=', value); |
| } |
| } |
| type = type.superclass; |
| } |
| } |
| |
| // define readXXX and printXXX functions for each VM struct/class Type |
| tmp = new Object(); |
| tmp.itr = sa.typedb.types; |
| while (tmp.itr.hasNext()) { |
| tmp.type = tmp.itr.next(); |
| tmp.name = tmp.type.name; |
| if (tmp.type.isPointerType() || tmp.type.isOopType() || |
| tmp.type.isCIntegerType() || tmp.type.isJavaPrimitiveType() || |
| tmp.name.equals('address') || |
| tmp.name.equals("<opaque>")) { |
| // ignore; |
| continue; |
| } else { |
| // some type names have ':', '<', '>', '*', ' '. replace to make it as a |
| // JavaScript identifier |
| tmp.name = ("" + tmp.name).replace(/[:<>* ]/g, '_'); |
| eval("function read" + tmp.name + "(addr) {" + |
| " return readVMType('" + tmp.name + "', addr);}"); |
| eval("function print" + tmp.name + "(addr) {" + |
| " printVMType('" + tmp.name + "', addr); }"); |
| |
| /* FIXME: do we need this? |
| if (typeof(registerCommand) != 'undefined') { |
| var name = "print" + tmp.name; |
| registerCommand(name, name + " [address]", name); |
| } |
| */ |
| } |
| } |
| //clean-up the temporary |
| delete tmp; |
| |
| // VMObject factory |
| |
| // VM type to SA class map |
| var vmType2Class = new Object(); |
| |
| // C2 only classes |
| try{ |
| vmType2Class["ExceptionBlob"] = sapkg.code.ExceptionBlob; |
| vmType2Class["UncommonTrapBlob"] = sapkg.code.UncommonTrapBlob; |
| } catch(e) { |
| // Ignore exception. C2 specific objects might be not |
| // available in client VM |
| } |
| |
| |
| // This is *not* exhaustive. Add more if needed. |
| // code blobs |
| vmType2Class["BufferBlob"] = sapkg.code.BufferBlob; |
| vmType2Class["nmethod"] = sapkg.code.NMethod; |
| vmType2Class["RuntimeStub"] = sapkg.code.RuntimeStub; |
| vmType2Class["SafepointBlob"] = sapkg.code.SafepointBlob; |
| vmType2Class["C2IAdapter"] = sapkg.code.C2IAdapter; |
| vmType2Class["DeoptimizationBlob"] = sapkg.code.DeoptimizationBlob; |
| vmType2Class["I2CAdapter"] = sapkg.code.I2CAdapter; |
| vmType2Class["OSRAdapter"] = sapkg.code.OSRAdapter; |
| vmType2Class["PCDesc"] = sapkg.code.PCDesc; |
| |
| // interpreter |
| vmType2Class["InterpreterCodelet"] = sapkg.interpreter.InterpreterCodelet; |
| |
| // Java Threads |
| vmType2Class["JavaThread"] = sapkg.runtime.JavaThread; |
| vmType2Class["CompilerThread"] = sapkg.runtime.CompilerThread; |
| vmType2Class["CodeCacheSweeperThread"] = sapkg.runtime.CodeCacheSweeperThread; |
| vmType2Class["DebuggerThread"] = sapkg.runtime.DebuggerThread; |
| |
| // gc |
| vmType2Class["GenCollectedHeap"] = sapkg.memory.GenCollectedHeap; |
| vmType2Class["DefNewGeneration"] = sapkg.memory.DefNewGeneration; |
| vmType2Class["TenuredGeneration"] = sapkg.memory.TenuredGeneration; |
| |
| // generic VMObject factory for a given address |
| // This is equivalent to VirtualConstructor. |
| function newVMObject(addr) { |
| addr = any2addr(addr); |
| var result = null; |
| forEachVMType(function (type) { |
| if (isOfVMType(addr, type)) { |
| var clazz = vmType2Class[type.name]; |
| if (clazz != undefined) { |
| result = new clazz(addr); |
| } |
| return false; |
| } else { |
| return true; |
| } |
| }); |
| return result; |
| } |
| |
| function vmobj2addr(vmobj) { |
| return vmobj.address; |
| } |
| |
| function addr2vmobj(addr) { |
| return newVMObject(addr); |
| } |
| |
| // Miscellaneous utilities |
| |
| // returns PointerLocation that describes the given pointer |
| function findPtr(addr) { |
| addr = any2addr(addr); |
| return sapkg.utilities.PointerFinder.find(addr); |
| } |
| |
| // is given address a valid Oop? |
| function isOop(addr) { |
| addr = any2addr(addr); |
| var oopHandle = addr.addOffsetToAsOopHandle(0); |
| return sapkg.utilities.RobustOopDeterminator.oopLooksValid(oopHandle); |
| } |
| |
| // returns description of given pointer as a String |
| function whatis(addr) { |
| addr = any2addr(addr); |
| var ptrLoc = findPtr(addr); |
| if (!ptrLoc.isUnknown()) { |
| return ptrLoc.toString(); |
| } |
| |
| var vmType = vmTypeof(addr); |
| if (vmType != null) { |
| return "pointer to " + vmType.name; |
| } |
| |
| var dso = loadObjectContainingPC(addr); |
| if (dso == null) { |
| return ptrLoc.toString(); |
| } |
| |
| var sym = dso.closestSymbolToPC(addr); |
| if (sym != null) { |
| return sym.name + '+' + sym.offset; |
| } |
| |
| var s = dso.getName(); |
| var p = s.lastIndexOf("/"); |
| var base = dso.getBase(); |
| return s.substring(p+1, s.length) + '+' + addr.minus(base); |
| } |