0
|
1 /*
|
|
2 * Copyright 2003-2004 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 package sun.jvm.hotspot.jdi;
|
|
26
|
|
27 import java.io.*;
|
|
28 import java.net.*;
|
|
29
|
|
30 /*
|
|
31 * This class loader is used for two different reasons:
|
|
32 *
|
|
33 * 1) To support multiple simultaneous debuggees.
|
|
34 *
|
|
35 * SA's architecture does not allow us to use multiple simultaneous
|
|
36 * debuggees. This is because of lots of static fields caching
|
|
37 * vmStruct fields and singleton assumption in classes such as
|
|
38 * 'sun.jvm.hotspot.runtime.VM'. Hence, we use instances of this
|
|
39 * class loader to create a separate namespace for each debuggee VM.
|
|
40 *
|
|
41 * 2) To support cross VM version debugging.
|
|
42 *
|
|
43 * SA has very close dependency on VM data structures. Due to this, a
|
|
44 * version of SA can only support debuggees running a same dot-dot release and
|
|
45 * update releases only. For eg. this version of SA supports only 1.4.2 and
|
|
46 * 1.4.2_xx releases only. But, users may want to debug debuggees running
|
|
47 * a different version of VM. To support this, we use an instance of this
|
|
48 * class loader to load classes from corresponding sa-jdi.jar.
|
|
49 *
|
|
50 * Note that JDI classes would still be loaded from the debugger's tools.jar
|
|
51 * and not from debuggee's tools.jar. This means that if JDI interface evolved
|
|
52 * b/w debuggee and debugger VM versions, user may still get problems. This is
|
|
53 * the case when debugger runs on 1.5.0 and debuggee runs on 1.4.2. Because JDI
|
|
54 * evolved b/w these versions (generics, enum, varargs etc.), 1.4.2 sa-jdi.jar
|
|
55 * won't implement 1.5.0 JDI properly and user would get verifier errors. This
|
|
56 * class loader solution is suited for different dot-dot release where JDI will
|
|
57 * not evolve but VM data structures might change and SA implementation might
|
|
58 * have to change. For example, a debuggee running 1.5.1 VM can be debugged
|
|
59 * with debugger running on 1.5.0 VM. Here, JDI is same but VM data structures
|
|
60 * could still change.
|
|
61 */
|
|
62
|
|
63 class SAJDIClassLoader extends URLClassLoader {
|
|
64 private static final boolean DEBUG;
|
|
65 static {
|
|
66 DEBUG = System.getProperty("sun.jvm.hotspot.jdi.SAJDIClassLoader.DEBUG") != null;
|
|
67 }
|
|
68
|
|
69 private ClassLoader parent;
|
|
70 private boolean classPathSet;
|
|
71
|
|
72 SAJDIClassLoader(ClassLoader parent) {
|
|
73 super(new URL[0], parent);
|
|
74 this.parent = parent;
|
|
75 }
|
|
76
|
|
77 SAJDIClassLoader(ClassLoader parent, String classPath) {
|
|
78 this(parent);
|
|
79 this.classPathSet = true;
|
|
80 try {
|
|
81 addURL(new File(classPath).toURL());
|
|
82 } catch(MalformedURLException mue) {
|
|
83 throw new RuntimeException(mue);
|
|
84 }
|
|
85 }
|
|
86
|
|
87 public synchronized Class loadClass(String name)
|
|
88 throws ClassNotFoundException {
|
|
89 // First, check if the class has already been loaded
|
|
90 Class c = findLoadedClass(name);
|
|
91 if (c == null) {
|
|
92 /* If we are loading any class in 'sun.jvm.hotspot.' or any of the
|
|
93 * sub-packages (except for 'debugger' sub-pkg. please refer below),
|
|
94 * we load it by 'this' loader. Or else, we forward the request to
|
|
95 * 'parent' loader, system loader etc. (rest of the code follows
|
|
96 * the patten in java.lang.ClassLoader.loadClass).
|
|
97 *
|
|
98 * 'sun.jvm.hotspot.debugger.' and sub-package classes are
|
|
99 * also loaded by parent loader. This is done for two reasons:
|
|
100 *
|
|
101 * 1. to avoid code bloat by too many classes.
|
|
102 * 2. to avoid loading same native library multiple times
|
|
103 * from multiple class loaders (which results in getting a
|
|
104 * UnsatisifiedLinkageError from System.loadLibrary).
|
|
105 */
|
|
106
|
|
107 if (name.startsWith("sun.jvm.hotspot.") &&
|
|
108 !name.startsWith("sun.jvm.hotspot.debugger.")) {
|
|
109 return findClass(name);
|
|
110 }
|
|
111 if (parent != null) {
|
|
112 c = parent.loadClass(name);
|
|
113 } else {
|
|
114 c = findSystemClass(name);
|
|
115 }
|
|
116 }
|
|
117 return c;
|
|
118 }
|
|
119
|
|
120 protected Class findClass(String name) throws ClassNotFoundException {
|
|
121 if (DEBUG) {
|
|
122 System.out.println("SA/JDI loader: about to load " + name);
|
|
123 }
|
|
124 if (classPathSet) {
|
|
125 return super.findClass(name);
|
|
126 } else {
|
|
127 byte[] b = null;
|
|
128 try {
|
|
129 InputStream in = getResourceAsStream(name.replace('.', '/') + ".class");
|
|
130 // Read until end of stream is reached
|
|
131 b = new byte[1024];
|
|
132 int total = 0;
|
|
133 int len = 0;
|
|
134 while ((len = in.read(b, total, b.length - total)) != -1) {
|
|
135 total += len;
|
|
136 if (total >= b.length) {
|
|
137 byte[] tmp = new byte[total * 2];
|
|
138 System.arraycopy(b, 0, tmp, 0, total);
|
|
139 b = tmp;
|
|
140 }
|
|
141 }
|
|
142 // Trim array to correct size, if necessary
|
|
143 if (total != b.length) {
|
|
144 byte[] tmp = new byte[total];
|
|
145 System.arraycopy(b, 0, tmp, 0, total);
|
|
146 b = tmp;
|
|
147 }
|
|
148 } catch (Exception exp) {
|
|
149 throw (ClassNotFoundException) new ClassNotFoundException().initCause(exp);
|
|
150 }
|
|
151 return defineClass(name, b, 0, b.length);
|
|
152 }
|
|
153 }
|
|
154 }
|