1 /* 2 * Copyright (c) 2005, 2006, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.tools.attach; 27 28 import com.sun.tools.attach.VirtualMachine; 29 import com.sun.tools.attach.AgentLoadException; 30 import com.sun.tools.attach.AgentInitializationException; 31 import com.sun.tools.attach.spi.AttachProvider; 32 33 import java.io.InputStream; 34 import java.io.IOException; 35 import java.util.Properties; 36 import java.util.Map; 37 38 /* 39 * The HotSpot implementation of com.sun.tools.attach.VirtualMachine. 40 */ 41 42 public 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", x); 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", x); 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 }