1 /* 2 * Copyright (c) 2005, 2011, 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; 26 27 import sun.jvm.hotspot.*; 28 import sun.jvm.hotspot.debugger.*; 29 30 import java.io.*; 31 import java.util.*; 32 33 public class CLHSDB { 34 public static void main(String[] args) { 35 new CLHSDB(args).run(); 36 } 37 38 private void run() { 39 // At this point, if pidText != null we are supposed to attach to it. 40 // Else, if execPath != null, it is the path of a jdk/bin/java 41 // and coreFilename is the pathname of a core file we are 42 // supposed to attach to. 43 44 agent = new HotSpotAgent(); 45 46 Runtime.getRuntime().addShutdownHook(new java.lang.Thread() { 47 public void run() { 48 detachDebugger(); 49 } 50 }); 51 52 if (pidText != null) { 53 attachDebugger(pidText); 54 } else if (execPath != null) { 55 attachDebugger(execPath, coreFilename); 56 } 57 58 59 CommandProcessor.DebuggerInterface di = new CommandProcessor.DebuggerInterface() { 60 public HotSpotAgent getAgent() { 61 return agent; 62 } 63 public boolean isAttached() { 64 return attached; 65 } 66 public void attach(String pid) { 67 attachDebugger(pid); 68 } 69 public void attach(String java, String core) { 70 attachDebugger(java, core); 71 } 72 public void detach() { 73 detachDebugger(); 74 } 75 public void reattach() { 76 if (attached) { 77 detachDebugger(); 78 } 79 if (pidText != null) { 80 attach(pidText); 81 } else { 82 attach(execPath, coreFilename); 83 } 84 } 85 }; 86 87 88 BufferedReader in = 89 new BufferedReader(new InputStreamReader(System.in)); 90 CommandProcessor cp = new CommandProcessor(di, in, System.out, System.err); 91 cp.run(true); 92 93 } 94 95 //-------------------------------------------------------------------------------- 96 // Internals only below this point 97 // 98 private HotSpotAgent agent; 99 private boolean attached; 100 // These had to be made data members because they are referenced in inner classes. 101 private String pidText; 102 private int pid; 103 private String execPath; 104 private String coreFilename; 105 106 private void doUsage() { 107 System.out.println("Usage: java CLHSDB [[pid] | [path-to-java-executable [path-to-corefile]] | help ]"); 108 System.out.println(" pid: attach to the process whose id is 'pid'"); 109 System.out.println(" path-to-java-executable: Debug a core file produced by this program"); 110 System.out.println(" path-to-corefile: Debug this corefile. The default is 'core'"); 111 System.out.println(" If no arguments are specified, you can select what to do from the GUI.\n"); 112 HotSpotAgent.showUsage(); 113 } 114 115 private CLHSDB(String[] args) { 116 switch (args.length) { 117 case (0): 118 break; 119 120 case (1): 121 if (args[0].equals("help") || args[0].equals("-help")) { 122 doUsage(); 123 System.exit(0); 124 } 125 // If all numbers, it is a PID to attach to 126 // Else, it is a pathname to a .../bin/java for a core file. 127 try { 128 int unused = Integer.parseInt(args[0]); 129 // If we get here, we have a PID and not a core file name 130 pidText = args[0]; 131 } catch (NumberFormatException e) { 132 execPath = args[0]; 133 coreFilename = "core"; 134 } 135 break; 136 137 case (2): 138 execPath = args[0]; 139 coreFilename = args[1]; 140 break; 141 142 default: 143 System.out.println("HSDB Error: Too many options specified"); 144 doUsage(); 145 System.exit(1); 146 } 147 } 148 149 /** NOTE we are in a different thread here than either the main 150 thread or the Swing/AWT event handler thread, so we must be very 151 careful when creating or removing widgets */ 152 private void attachDebugger(String pidText) { 153 try { 154 this.pidText = pidText; 155 pid = Integer.parseInt(pidText); 156 } 157 catch (NumberFormatException e) { 158 System.err.print("Unable to parse process ID \"" + pidText + "\".\nPlease enter a number."); 159 } 160 161 try { 162 System.err.println("Attaching to process " + pid + ", please wait..."); 163 164 // FIXME: display exec'd debugger's output messages during this 165 // lengthy call 166 agent.attach(pid); 167 attached = true; 168 } 169 catch (DebuggerException e) { 170 final String errMsg = formatMessage(e.getMessage(), 80); 171 System.err.println("Unable to connect to process ID " + pid + ":\n\n" + errMsg); 172 agent.detach(); 173 e.printStackTrace(); 174 return; 175 } 176 } 177 178 /** NOTE we are in a different thread here than either the main 179 thread or the Swing/AWT event handler thread, so we must be very 180 careful when creating or removing widgets */ 181 private void attachDebugger(final String executablePath, final String corePath) { 182 // Try to open this core file 183 try { 184 System.err.println("Opening core file, please wait..."); 185 186 // FIXME: display exec'd debugger's output messages during this 187 // lengthy call 188 agent.attach(executablePath, corePath); 189 attached = true; 190 } 191 catch (DebuggerException e) { 192 final String errMsg = formatMessage(e.getMessage(), 80); 193 System.err.println("Unable to open core file\n" + corePath + ":\n\n" + errMsg); 194 agent.detach(); 195 e.printStackTrace(); 196 return; 197 } 198 } 199 200 /** NOTE we are in a different thread here than either the main 201 thread or the Swing/AWT event handler thread, so we must be very 202 careful when creating or removing widgets */ 203 private void connect(final String remoteMachineName) { 204 // Try to open this core file 205 try { 206 System.err.println("Connecting to debug server, please wait..."); 207 agent.attach(remoteMachineName); 208 attached = true; 209 } 210 catch (DebuggerException e) { 211 final String errMsg = formatMessage(e.getMessage(), 80); 212 System.err.println("Unable to connect to machine \"" + remoteMachineName + "\":\n\n" + errMsg); 213 agent.detach(); 214 e.printStackTrace(); 215 return; 216 } 217 } 218 219 private void detachDebugger() { 220 if (!attached) { 221 return; 222 } 223 agent.detach(); 224 attached = false; 225 } 226 227 private void detach() { 228 detachDebugger(); 229 } 230 231 /** Punctuates the given string with \n's where necessary to not 232 exceed the given number of characters per line. Strips 233 extraneous whitespace. */ 234 private String formatMessage(String message, int charsPerLine) { 235 StringBuffer buf = new StringBuffer(message.length()); 236 StringTokenizer tokenizer = new StringTokenizer(message); 237 int curLineLength = 0; 238 while (tokenizer.hasMoreTokens()) { 239 String tok = tokenizer.nextToken(); 240 if (curLineLength + tok.length() > charsPerLine) { 241 buf.append('\n'); 242 curLineLength = 0; 243 } else { 244 if (curLineLength != 0) { 245 buf.append(' '); 246 ++curLineLength; 247 } 248 } 249 buf.append(tok); 250 curLineLength += tok.length(); 251 } 252 return buf.toString(); 253 } 254 }