1 /* 2 * Copyright (c) 2002, 2013, 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 package sun.jvm.hotspot.tools; 26 27 import java.io.PrintStream; 28 29 import sun.jvm.hotspot.HotSpotAgent; 30 import sun.jvm.hotspot.SALauncher; 31 import sun.jvm.hotspot.debugger.DebuggerException; 32 import sun.jvm.hotspot.debugger.JVMDebugger; 33 import sun.jvm.hotspot.runtime.VM; 34 35 // generic command line or GUI tool. 36 // override run & code main as shown below. 37 38 public abstract class Tool implements Runnable { 39 private HotSpotAgent agent; 40 private JVMDebugger jvmDebugger; 41 private int debugeeType; 42 43 // debugeeType is one of constants below 44 protected static final int DEBUGEE_PID = 0; 45 protected static final int DEBUGEE_CORE = 1; 46 protected static final int DEBUGEE_REMOTE = 2; 47 48 public Tool() { 49 } 50 51 public Tool(JVMDebugger d) { 52 jvmDebugger = d; 53 } 54 55 public String getName() { 56 return getClass().getName(); 57 } 58 59 protected boolean needsJavaPrefix() { 60 return true; 61 } 62 63 protected void setAgent(HotSpotAgent a) { 64 agent = a; 65 } 66 67 protected void setDebugeeType(int dt) { 68 debugeeType = dt; 69 } 70 71 protected HotSpotAgent getAgent() { 72 return agent; 73 } 74 75 protected int getDebugeeType() { 76 return debugeeType; 77 } 78 79 protected void printUsage() { 80 String name = null; 81 if (needsJavaPrefix()) { 82 name = "java " + getName(); 83 } else { 84 name = getName(); 85 } 86 System.out.println("Usage: " + name + " [option] <pid>"); 87 System.out.println("\t\t(to connect to a live java process)"); 88 System.out.println(" or " + name + " [option] <executable> <core>"); 89 System.out.println("\t\t(to connect to a core file)"); 90 System.out.println(" or " + name + " [option] [server_id@]<remote server IP or hostname>"); 91 System.out.println("\t\t(to connect to a remote debug server)"); 92 System.out.println(); 93 System.out.println("where option must be one of:"); 94 printFlagsUsage(); 95 } 96 97 protected void printFlagsUsage() { 98 System.out.println(" -h | -help\tto print this help message"); 99 } 100 101 protected void usage() { 102 StackWalker walker = StackWalker.getInstance( 103 StackWalker.Option.RETAIN_CLASS_REFERENCE); 104 Boolean throughSALauncher = walker.walk(s -> 105 s.map(StackWalker.StackFrame::getDeclaringClass) 106 .anyMatch(c -> c.equals(SALauncher.class))); 107 if (throughSALauncher.booleanValue()) { 108 String toolName = this.getClass().getSimpleName().toLowerCase(); 109 SALauncher.toolHelp(toolName); 110 } else { 111 printUsage(); 112 } 113 } 114 115 /* 116 Derived class main should be of the following form: 117 118 public static void main(String[] args) { 119 <derived class> obj = new <derived class>; 120 obj.execute(args); 121 } 122 123 */ 124 125 protected void execute(String[] args) { 126 int returnStatus = 1; 127 128 try { 129 returnStatus = start(args); 130 } finally { 131 stop(); 132 } 133 134 // Exit with 0 or 1 135 System.exit(returnStatus); 136 } 137 138 public void stop() { 139 if (agent != null) { 140 agent.detach(); 141 } 142 } 143 144 private int start(String[] args) { 145 146 if ((args.length < 1) || (args.length > 2)) { 147 usage(); 148 return 1; 149 } 150 151 // Attempt to handle -h or -help or some invalid flag 152 if (args[0].startsWith("-h")) { 153 usage(); 154 return 0; 155 } else if (args[0].startsWith("-")) { 156 usage(); 157 return 1; 158 } 159 160 PrintStream err = System.err; 161 PrintStream out = System.out; 162 163 int pid = 0; 164 String coreFileName = null; 165 String executableName = null; 166 String remoteServer = null; 167 168 switch (args.length) { 169 case 1: 170 try { 171 pid = Integer.parseInt(args[0]); 172 debugeeType = DEBUGEE_PID; 173 } catch (NumberFormatException e) { 174 // try remote server 175 remoteServer = args[0]; 176 debugeeType = DEBUGEE_REMOTE; 177 } 178 break; 179 180 case 2: 181 executableName = args[0]; 182 coreFileName = args[1]; 183 debugeeType = DEBUGEE_CORE; 184 break; 185 186 default: 187 usage(); 188 return 1; 189 } 190 191 agent = new HotSpotAgent(); 192 try { 193 switch (debugeeType) { 194 case DEBUGEE_PID: 195 out.println("Attaching to process ID " + pid + ", please wait..."); 196 agent.attach(pid); 197 break; 198 199 case DEBUGEE_CORE: 200 out.println("Attaching to core " + coreFileName + 201 " from executable " + executableName + ", please wait..."); 202 agent.attach(executableName, coreFileName); 203 break; 204 205 case DEBUGEE_REMOTE: 206 out.println("Attaching to remote server " + remoteServer + ", please wait..."); 207 agent.attach(remoteServer); 208 break; 209 } 210 } 211 catch (DebuggerException e) { 212 switch (debugeeType) { 213 case DEBUGEE_PID: 214 err.print("Error attaching to process: "); 215 break; 216 217 case DEBUGEE_CORE: 218 err.print("Error attaching to core file: "); 219 break; 220 221 case DEBUGEE_REMOTE: 222 err.print("Error attaching to remote server: "); 223 break; 224 } 225 if (e.getMessage() != null) { 226 err.println(e.getMessage()); 227 e.printStackTrace(); 228 } 229 err.println(); 230 return 1; 231 } 232 233 out.println("Debugger attached successfully."); 234 startInternal(); 235 return 0; 236 } 237 238 // When using an existing JVMDebugger. 239 public void start() { 240 241 if (jvmDebugger == null) { 242 throw new RuntimeException("Tool.start() called with no JVMDebugger set."); 243 } 244 agent = new HotSpotAgent(); 245 agent.attach(jvmDebugger); 246 startInternal(); 247 } 248 249 // Remains of the start mechanism, common to both start methods. 250 private void startInternal() { 251 252 PrintStream out = System.out; 253 VM vm = VM.getVM(); 254 if (vm.isCore()) { 255 out.println("Core build detected."); 256 } else if (vm.isClientCompiler()) { 257 out.println("Client compiler detected."); 258 } else if (vm.isServerCompiler()) { 259 out.println("Server compiler detected."); 260 } else { 261 throw new RuntimeException("Fatal error: " 262 + "should have been able to detect core/C1/C2 build"); 263 } 264 265 String version = vm.getVMRelease(); 266 if (version != null) { 267 out.print("JVM version is "); 268 out.println(version); 269 } 270 271 run(); 272 } 273 }