blob: 374394f40144a0f790891e07247b00c5577f6fcc [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005-2006 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.tools.attach;
27
28import com.sun.tools.attach.VirtualMachine;
29import com.sun.tools.attach.AgentLoadException;
30import com.sun.tools.attach.AgentInitializationException;
31import com.sun.tools.attach.spi.AttachProvider;
32
33import java.io.InputStream;
34import java.io.IOException;
35import java.util.Properties;
36import java.util.Map;
37
38/*
39 * The HotSpot implementation of com.sun.tools.attach.VirtualMachine.
40 */
41
42public abstract class HotSpotVirtualMachine extends VirtualMachine {
43
44 HotSpotVirtualMachine(AttachProvider provider, String id) {
45 super(provider, id);
46 }
47
48 /*
49 * Load agent library
50 * If isAbsolute is true then the agent library is the absolute path
51 * to the library and thus will not be expanded in the target VM.
52 * if isAbsolute is false then the agent library is just a library
53 * name and it will be expended in the target VM.
54 */
55 private void loadAgentLibrary(String agentLibrary, boolean isAbsolute, String options)
56 throws AgentLoadException, AgentInitializationException, IOException
57 {
58 InputStream in = execute("load",
59 agentLibrary,
60 isAbsolute ? "true" : "false",
61 options);
62 try {
63 int result = readInt(in);
64 if (result != 0) {
65 throw new AgentInitializationException("Agent_OnAttach failed", result);
66 }
67 } finally {
68 in.close();
69
70 }
71 }
72
73 /*
74 * Load agent library - library name will be expanded in target VM
75 */
76 public void loadAgentLibrary(String agentLibrary, String options)
77 throws AgentLoadException, AgentInitializationException, IOException
78 {
79 loadAgentLibrary(agentLibrary, false, options);
80 }
81
82 /*
83 * Load agent - absolute path of library provided to target VM
84 */
85 public void loadAgentPath(String agentLibrary, String options)
86 throws AgentLoadException, AgentInitializationException, IOException
87 {
88 loadAgentLibrary(agentLibrary, true, options);
89 }
90
91 /*
92 * Load JPLIS agent which will load the agent JAR file and invoke
93 * the agentmain method.
94 */
95 public void loadAgent(String agent, String options)
96 throws AgentLoadException, AgentInitializationException, IOException
97 {
98 String args = agent;
99 if (options != null) {
100 args = args + "=" + options;
101 }
102 try {
103 loadAgentLibrary("instrument", args);
104 } catch (AgentLoadException x) {
105 throw new InternalError("instrument library is missing in target VM");
106 } catch (AgentInitializationException x) {
107 /*
108 * Translate interesting errors into the right exception and
109 * message (FIXME: create a better interface to the instrument
110 * implementation so this isn't necessary)
111 */
112 int rc = x.returnValue();
113 switch (rc) {
114 case JNI_ENOMEM:
115 throw new AgentLoadException("Insuffient memory");
116 case ATTACH_ERROR_BADJAR:
117 throw new AgentLoadException("Agent JAR not found or no Agent-Class attribute");
118 case ATTACH_ERROR_NOTONCP:
119 throw new AgentLoadException("Unable to add JAR file to system class path");
120 case ATTACH_ERROR_STARTFAIL:
121 throw new AgentInitializationException("Agent JAR loaded but agent failed to initialize");
122 default :
123 throw new AgentLoadException("Failed to load agent - unknown reason: " + rc);
124 }
125 }
126 }
127
128 /*
129 * The possible errors returned by JPLIS's agentmain
130 */
131 private static final int JNI_ENOMEM = -4;
132 private static final int ATTACH_ERROR_BADJAR = 100;
133 private static final int ATTACH_ERROR_NOTONCP = 101;
134 private static final int ATTACH_ERROR_STARTFAIL = 102;
135
136
137 /*
138 * Send "properties" command to target VM
139 */
140 public Properties getSystemProperties() throws IOException {
141 InputStream in = null;
142 Properties props = new Properties();
143 try {
144 in = executeCommand("properties");
145 props.load(in);
146 } finally {
147 if (in != null) in.close();
148 }
149 return props;
150 }
151
152 public Properties getAgentProperties() throws IOException {
153 InputStream in = null;
154 Properties props = new Properties();
155 try {
156 in = executeCommand("agentProperties");
157 props.load(in);
158 } finally {
159 if (in != null) in.close();
160 }
161 return props;
162 }
163
164 // --- HotSpot specific methods ---
165
166 // same as SIGQUIT
167 public void localDataDump() throws IOException {
168 executeCommand("datadump").close();
169 }
170
171 // Remote ctrl-break. The output of the ctrl-break actions can
172 // be read from the input stream.
173 public InputStream remoteDataDump(Object ... args) throws IOException {
174 return executeCommand("threaddump", args);
175 }
176
177 // Remote heap dump. The output (error message) can be read from the
178 // returned input stream.
179 public InputStream dumpHeap(Object ... args) throws IOException {
180 return executeCommand("dumpheap", args);
181 }
182
183 // Heap histogram (heap inspection in HotSpot)
184 public InputStream heapHisto(Object ... args) throws IOException {
185 return executeCommand("inspectheap", args);
186 }
187
188 // set JVM command line flag
189 public InputStream setFlag(String name, String value) throws IOException {
190 return executeCommand("setflag", name, value);
191 }
192
193 // print command line flag
194 public InputStream printFlag(String name) throws IOException {
195 return executeCommand("printflag", name);
196 }
197
198 // -- Supporting methods
199
200
201 /*
202 * Execute the given command in the target VM - specific platform
203 * implementation must implement this.
204 */
205 abstract InputStream execute(String cmd, Object ... args)
206 throws AgentLoadException, IOException;
207
208 /*
209 * Convenience method for simple commands
210 */
211 private InputStream executeCommand(String cmd, Object ... args) throws IOException {
212 try {
213 return execute(cmd, args);
214 } catch (AgentLoadException x) {
215 throw new InternalError("Should not get here");
216 }
217 }
218
219
220 /*
221 * Utility method to read an 'int' from the input stream. Ideally
222 * we should be using java.util.Scanner here but this implementation
223 * guarantees not to read ahead.
224 */
225 int readInt(InputStream in) throws IOException {
226 StringBuilder sb = new StringBuilder();
227
228 // read to \n or EOF
229 int n;
230 byte buf[] = new byte[1];
231 do {
232 n = in.read(buf, 0, 1);
233 if (n > 0) {
234 char c = (char)buf[0];
235 if (c == '\n') {
236 break; // EOL found
237 } else {
238 sb.append(c);
239 }
240 }
241 } while (n > 0);
242
243 if (sb.length() == 0) {
244 throw new IOException("Premature EOF");
245 }
246
247 int value;
248 try {
249 value = Integer.parseInt(sb.toString());
250 } catch (NumberFormatException x) {
251 throw new IOException("Non-numeric value found - int expected");
252 }
253 return value;
254 }
255
256 // -- attach timeout support
257
258 private static long defaultAttachTimeout = 5000;
259 private volatile long attachTimeout;
260
261 /*
262 * Return attach timeout based on the value of the sun.tools.attach.attachTimeout
263 * property, or the default timeout if the property is not set to a positive
264 * value.
265 */
266 long attachTimeout() {
267 if (attachTimeout == 0) {
268 synchronized(this) {
269 if (attachTimeout == 0) {
270 try {
271 String s =
272 System.getProperty("sun.tools.attach.attachTimeout");
273 attachTimeout = Long.parseLong(s);
274 } catch (SecurityException se) {
275 } catch (NumberFormatException ne) {
276 }
277 if (attachTimeout <= 0) {
278 attachTimeout = defaultAttachTimeout;
279 }
280 }
281 }
282 }
283 return attachTimeout;
284 }
285}