1 /* 2 * Copyright 2005 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; 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 return; 174 } 175 } 176 177 /** NOTE we are in a different thread here than either the main 178 thread or the Swing/AWT event handler thread, so we must be very 179 careful when creating or removing widgets */ 180 private void attachDebugger(final String executablePath, final String corePath) { 181 // Try to open this core file 182 try { 183 System.err.println("Opening core file, please wait..."); 184 185 // FIXME: display exec'd debugger's output messages during this 186 // lengthy call 187 agent.attach(executablePath, corePath); 188 attached = true; 189 } 190 catch (DebuggerException e) { 191 final String errMsg = formatMessage(e.getMessage(), 80); 192 System.err.println("Unable to open core file\n" + corePath + ":\n\n" + errMsg); 193 agent.detach(); 194 return; 195 } 196 } 197 198 /** NOTE we are in a different thread here than either the main 199 thread or the Swing/AWT event handler thread, so we must be very 200 careful when creating or removing widgets */ 201 private void connect(final String remoteMachineName) { 202 // Try to open this core file 203 try { 204 System.err.println("Connecting to debug server, please wait..."); 205 agent.attach(remoteMachineName); 206 attached = true; 207 } 208 catch (DebuggerException e) { 209 final String errMsg = formatMessage(e.getMessage(), 80); 210 System.err.println("Unable to connect to machine \"" + remoteMachineName + "\":\n\n" + errMsg); 211 agent.detach(); 212 return; 213 } 214 } 215 216 private void detachDebugger() { 217 if (!attached) { 218 return; 219 } 220 agent.detach(); 221 attached = false; 222 } 223 224 private void detach() { 225 detachDebugger(); 226 } 227 228 /** Punctuates the given string with \n's where necessary to not 229 exceed the given number of characters per line. Strips 230 extraneous whitespace. */ 231 private String formatMessage(String message, int charsPerLine) { 232 StringBuffer buf = new StringBuffer(message.length()); 233 StringTokenizer tokenizer = new StringTokenizer(message); 234 int curLineLength = 0; 235 while (tokenizer.hasMoreTokens()) { 236 String tok = tokenizer.nextToken(); 237 if (curLineLength + tok.length() > charsPerLine) { 238 buf.append('\n'); 239 curLineLength = 0; 240 } else { 241 if (curLineLength != 0) { 242 buf.append(' '); 243 ++curLineLength; 244 } 245 } 246 buf.append(tok); 247 curLineLength += tok.length(); 248 } 249 return buf.toString(); 250 } 251 }