1/*
2 * Copyright (c) 2004, 2017, 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
30var sapkg = new Object();
31
32sapkg.hotspot = Packages.sun.jvm.hotspot;
33sapkg.asm = sapkg.hotspot.asm;
34sapkg.c1 = sapkg.hotspot.c1;
35sapkg.code = sapkg.hotspot.code;
36sapkg.compiler = sapkg.hotspot.compiler;
37
38// 'debugger' is a JavaScript keyword, but ES5 relaxes the
39// restriction of using keywords as property name
40sapkg.debugger = sapkg.hotspot.debugger;
41
42sapkg.interpreter = sapkg.hotspot.interpreter;
43sapkg.jdi = sapkg.hotspot.jdi;
44sapkg.memory = sapkg.hotspot.memory;
45sapkg.oops = sapkg.hotspot.oops;
46sapkg.runtime = sapkg.hotspot.runtime;
47sapkg.tools = sapkg.hotspot.tools;
48sapkg.types = sapkg.hotspot.types;
49sapkg.ui = sapkg.hotspot.ui;
50sapkg.utilities = sapkg.hotspot.utilities;
51
52// SA singletons are kept in 'sa' object
53var sa = new Object();
54sa.vm = sapkg.runtime.VM.getVM();
55sa.dbg = sa.vm.getDebugger();
56sa.cdbg = sa.dbg.CDebugger;
57sa.heap = sa.vm.universe.heap();
58sa.systemDictionary = sa.vm.systemDictionary;
59sa.sysDict = sa.systemDictionary;
60sa.symbolTable = sa.vm.symbolTable;
61sa.symTbl = sa.symbolTable;
62sa.threads = sa.vm.threads;
63sa.interpreter = sa.vm.interpreter;
64sa.typedb = sa.vm.typeDataBase;
65sa.codeCache = sa.vm.codeCache;
66// 'objHeap' is different from 'heap'!.
67// This is SA's Oop factory and heap-walker
68sa.objHeap = sa.vm.objectHeap;
69
70// few useful global variables
71var OS = sa.vm.OS;
72var CPU = sa.vm.CPU;
73var LP64 = sa.vm.LP64;
74var isClient = sa.vm.clientCompiler;
75var isServer = sa.vm.serverCompiler;
76var isCore = sa.vm.isCore();
77var addressSize = sa.vm.addressSize;
78var oopSize = sa.vm.oopSize;
79
80// this "main" function is called immediately
81// after loading this script file
82function 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
326function str2addr(str) {
327   return sa.dbg.parseAddress(str);
328}
329
330// number-to-Address
331if (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.
344function 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
356function addr2str(addr) {
357   if (addr == null) {
358      return (addressSize == 4)? '0x00000000' : '0x0000000000000000';
359   } else {
360      return addr + '';
361   }
362}
363
364// Address-to-number
365function addr2num(addr) {
366   return sa.dbg.getAddressValue(addr);
367}
368
369// symbol-to-Address
370function sym2addr(dso, sym) {
371   return sa.dbg.lookup(dso, sym);
372}
373
374function 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
384function 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
396function 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.
407function 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'
418function 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'
424function readCStrLen(addr) {
425   addr = any2addr(addr);
426   return sapkg.utilities.CStringUtilities.getStringLength(addr);
427}
428
429// iterate through ThreadList of CDebugger
430function 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
443function 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
455function 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
463function 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)
477function 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'
490function 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
507function findInstanceKlass(name) {
508   return sapkg.utilities.SystemDictionaryHelper.findInstanceKlass(name);
509}
510
511// get Java system loader (i.e., application launcher loader)
512function systemLoader() {
513   return sa.sysDict.javaSystemLoader();
514}
515
516// iterate class loader data for each 'Klass'
517function 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
524function 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.
533function oop2obj(oop) {
534   return object(addr2str(oop.handle));
535}
536
537// higher level java object wrapper to oop
538function obj2oop(obj) {
539   return addr2oop(str2addr(address(obj)));
540}
541
542// Java heap iteration
543
544// iterates Java heap for each Oop
545function 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
557function 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
579function 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
589function 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
598function 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
606function 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
624function 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
635function findVMType(typeName) {
636   return sa.typedb.lookupType(typeName);
637}
638
639// iterate VM types
640function 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
648function findVMIntConst(name) {
649   return sa.typedb.lookupIntConstant(name);
650}
651
652// find VM long constant
653function findVMLongConst(name) {
654   return sa.typedb.lookupLongConstant(name);
655}
656
657// iterate VM int constants
658function 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
666function 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
674function 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)
681function 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
694function 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'
708function 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.
723function 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
749function 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
769tmp = new Object();
770tmp.itr = sa.typedb.types;
771while (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
798delete tmp;
799
800// VMObject factory
801
802// VM type to SA class map
803var  vmType2Class = new Object();
804
805// C2 only classes
806try{
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
817vmType2Class["BufferBlob"] = sapkg.code.BufferBlob;
818vmType2Class["nmethod"] = sapkg.code.NMethod;
819vmType2Class["RuntimeStub"] = sapkg.code.RuntimeStub;
820vmType2Class["SafepointBlob"] = sapkg.code.SafepointBlob;
821vmType2Class["C2IAdapter"] = sapkg.code.C2IAdapter;
822vmType2Class["DeoptimizationBlob"] = sapkg.code.DeoptimizationBlob;
823vmType2Class["I2CAdapter"] = sapkg.code.I2CAdapter;
824vmType2Class["OSRAdapter"] = sapkg.code.OSRAdapter;
825vmType2Class["PCDesc"] = sapkg.code.PCDesc;
826
827// interpreter
828vmType2Class["InterpreterCodelet"] = sapkg.interpreter.InterpreterCodelet;
829
830// Java Threads
831vmType2Class["JavaThread"] = sapkg.runtime.JavaThread;
832vmType2Class["CompilerThread"] = sapkg.runtime.CompilerThread;
833vmType2Class["CodeCacheSweeperThread"] = sapkg.runtime.CodeCacheSweeperThread;
834vmType2Class["DebuggerThread"] = sapkg.runtime.DebuggerThread;
835
836// gc
837vmType2Class["GenCollectedHeap"] = sapkg.memory.GenCollectedHeap;
838vmType2Class["DefNewGeneration"] = sapkg.memory.DefNewGeneration;
839vmType2Class["TenuredGeneration"] = sapkg.memory.TenuredGeneration;
840
841// generic VMObject factory for a given address
842// This is equivalent to VirtualConstructor.
843function 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
860function vmobj2addr(vmobj) {
861   return vmobj.address;
862}
863
864function addr2vmobj(addr) {
865   return newVMObject(addr);
866}
867
868// Miscellaneous utilities
869
870// returns PointerLocation that describes the given pointer
871function findPtr(addr) {
872   addr = any2addr(addr);
873   return sapkg.utilities.PointerFinder.find(addr);
874}
875
876// is given address a valid Oop?
877function 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
884function 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}
911