0
|
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 }
|