0
|
1 /*
|
|
2 * Copyright 2000-2006 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 java.io.*;
|
|
28 import java.awt.*;
|
|
29 import java.awt.event.*;
|
|
30 import java.math.*;
|
|
31 import javax.swing.*;
|
|
32 import javax.swing.tree.*;
|
|
33 import java.util.*;
|
|
34
|
|
35 import sun.jvm.hotspot.code.*;
|
|
36 import sun.jvm.hotspot.compiler.*;
|
|
37 import sun.jvm.hotspot.debugger.*;
|
|
38 import sun.jvm.hotspot.gc_implementation.parallelScavenge.*;
|
|
39 import sun.jvm.hotspot.gc_interface.*;
|
|
40 import sun.jvm.hotspot.interpreter.*;
|
|
41 import sun.jvm.hotspot.memory.*;
|
|
42 import sun.jvm.hotspot.oops.*;
|
|
43 import sun.jvm.hotspot.runtime.*;
|
|
44 import sun.jvm.hotspot.ui.*;
|
|
45 import sun.jvm.hotspot.ui.tree.*;
|
|
46 import sun.jvm.hotspot.ui.classbrowser.*;
|
|
47 import sun.jvm.hotspot.utilities.*;
|
|
48
|
|
49 /** The top-level HotSpot Debugger. FIXME: make this an embeddable
|
|
50 component! (Among other things, figure out what to do with the
|
|
51 menu bar...) */
|
|
52
|
|
53 public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
|
|
54 public static void main(String[] args) {
|
|
55 new HSDB(args).run();
|
|
56 }
|
|
57
|
|
58 //--------------------------------------------------------------------------------
|
|
59 // Internals only below this point
|
|
60 //
|
|
61 private HotSpotAgent agent;
|
|
62 private JDesktopPane desktop;
|
|
63 private boolean attached;
|
|
64 /** List <JMenuItem> */
|
|
65 private java.util.List attachMenuItems;
|
|
66 /** List <JMenuItem> */
|
|
67 private java.util.List detachMenuItems;
|
|
68 private JMenu toolsMenu;
|
|
69 private JMenuItem showDbgConsoleMenuItem;
|
|
70 private JMenuItem computeRevPtrsMenuItem;
|
|
71 private JInternalFrame attachWaitDialog;
|
|
72 private JInternalFrame threadsFrame;
|
|
73 private JInternalFrame consoleFrame;
|
|
74 private WorkerThread workerThread;
|
|
75 // These had to be made data members because they are referenced in inner classes.
|
|
76 private String pidText;
|
|
77 private int pid;
|
|
78 private String execPath;
|
|
79 private String coreFilename;
|
|
80
|
|
81 private void doUsage() {
|
|
82 System.out.println("Usage: java HSDB [[pid] | [path-to-java-executable [path-to-corefile]] | help ]");
|
|
83 System.out.println(" pid: attach to the process whose id is 'pid'");
|
|
84 System.out.println(" path-to-java-executable: Debug a core file produced by this program");
|
|
85 System.out.println(" path-to-corefile: Debug this corefile. The default is 'core'");
|
|
86 System.out.println(" If no arguments are specified, you can select what to do from the GUI.\n");
|
|
87 HotSpotAgent.showUsage();
|
|
88 }
|
|
89
|
|
90 private HSDB(String[] args) {
|
|
91 switch (args.length) {
|
|
92 case (0):
|
|
93 break;
|
|
94
|
|
95 case (1):
|
|
96 if (args[0].equals("help") || args[0].equals("-help")) {
|
|
97 doUsage();
|
|
98 System.exit(0);
|
|
99 }
|
|
100 // If all numbers, it is a PID to attach to
|
|
101 // Else, it is a pathname to a .../bin/java for a core file.
|
|
102 try {
|
|
103 int unused = Integer.parseInt(args[0]);
|
|
104 // If we get here, we have a PID and not a core file name
|
|
105 pidText = args[0];
|
|
106 } catch (NumberFormatException e) {
|
|
107 execPath = args[0];
|
|
108 coreFilename = "core";
|
|
109 }
|
|
110 break;
|
|
111
|
|
112 case (2):
|
|
113 execPath = args[0];
|
|
114 coreFilename = args[1];
|
|
115 break;
|
|
116
|
|
117 default:
|
|
118 System.out.println("HSDB Error: Too many options specified");
|
|
119 doUsage();
|
|
120 System.exit(1);
|
|
121 }
|
|
122 }
|
|
123
|
|
124 private void run() {
|
|
125 // At this point, if pidText != null we are supposed to attach to it.
|
|
126 // Else, if execPath != null, it is the path of a jdk/bin/java
|
|
127 // and coreFilename is the pathname of a core file we are
|
|
128 // supposed to attach to.
|
|
129
|
|
130 agent = new HotSpotAgent();
|
|
131 workerThread = new WorkerThread();
|
|
132 attachMenuItems = new java.util.ArrayList();
|
|
133 detachMenuItems = new java.util.ArrayList();
|
|
134
|
|
135 JFrame frame = new JFrame("HSDB - HotSpot Debugger");
|
|
136 frame.setSize(800, 600);
|
|
137 frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
|
138
|
|
139 JMenuBar menuBar = new JMenuBar();
|
|
140
|
|
141 //
|
|
142 // File menu
|
|
143 //
|
|
144
|
|
145 JMenu menu = new JMenu("File");
|
|
146 menu.setMnemonic(KeyEvent.VK_F);
|
|
147 JMenuItem item;
|
|
148 item = createMenuItem("Attach to HotSpot process...",
|
|
149 new ActionListener() {
|
|
150 public void actionPerformed(ActionEvent e) {
|
|
151 showAttachDialog();
|
|
152 }
|
|
153 });
|
|
154 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.ALT_MASK));
|
|
155 item.setMnemonic(KeyEvent.VK_A);
|
|
156 menu.add(item);
|
|
157 attachMenuItems.add(item);
|
|
158
|
|
159 item = createMenuItem("Open HotSpot core file...",
|
|
160 new ActionListener() {
|
|
161 public void actionPerformed(ActionEvent e) {
|
|
162 showOpenCoreFileDialog();
|
|
163 }
|
|
164 });
|
|
165 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.ALT_MASK));
|
|
166 item.setMnemonic(KeyEvent.VK_O);
|
|
167 menu.add(item);
|
|
168 attachMenuItems.add(item);
|
|
169
|
|
170 item = createMenuItem("Connect to debug server...",
|
|
171 new ActionListener() {
|
|
172 public void actionPerformed(ActionEvent e) {
|
|
173 showConnectDialog();
|
|
174 }
|
|
175 });
|
|
176 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.ALT_MASK));
|
|
177 item.setMnemonic(KeyEvent.VK_S);
|
|
178 menu.add(item);
|
|
179 attachMenuItems.add(item);
|
|
180
|
|
181 item = createMenuItem("Detach",
|
|
182 new ActionListener() {
|
|
183 public void actionPerformed(ActionEvent e) {
|
|
184 detach();
|
|
185 }
|
|
186 });
|
|
187 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, ActionEvent.ALT_MASK));
|
|
188 item.setMnemonic(KeyEvent.VK_S);
|
|
189 menu.add(item);
|
|
190 detachMenuItems.add(item);
|
|
191
|
|
192 // Disable detach menu items at first
|
|
193 setMenuItemsEnabled(detachMenuItems, false);
|
|
194
|
|
195 menu.addSeparator();
|
|
196
|
|
197 item = createMenuItem("Exit",
|
|
198 new ActionListener() {
|
|
199 public void actionPerformed(ActionEvent e) {
|
|
200 System.exit(0);
|
|
201 }
|
|
202 });
|
|
203 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.ALT_MASK));
|
|
204 item.setMnemonic(KeyEvent.VK_X);
|
|
205 menu.add(item);
|
|
206 menuBar.add(menu);
|
|
207
|
|
208 //
|
|
209 // Tools menu
|
|
210 //
|
|
211
|
|
212 toolsMenu = new JMenu("Tools");
|
|
213 toolsMenu.setMnemonic(KeyEvent.VK_T);
|
|
214
|
|
215 item = createMenuItem("Class Browser",
|
|
216 new ActionListener() {
|
|
217 public void actionPerformed(ActionEvent e) {
|
|
218 showClassBrowser();
|
|
219 }
|
|
220 });
|
|
221 item.setMnemonic(KeyEvent.VK_B);
|
|
222
|
|
223 toolsMenu.add(item);
|
|
224
|
|
225 item = createMenuItem("Code Viewer",
|
|
226 new ActionListener() {
|
|
227 public void actionPerformed(ActionEvent e) {
|
|
228 showCodeViewer();
|
|
229 }
|
|
230 });
|
|
231 item.setMnemonic(KeyEvent.VK_C);
|
|
232
|
|
233 toolsMenu.add(item);
|
|
234
|
|
235
|
|
236 item = createMenuItem("Compute Reverse Ptrs",
|
|
237 new ActionListener() {
|
|
238 public void actionPerformed(ActionEvent e) {
|
|
239 fireComputeReversePtrs();
|
|
240 }
|
|
241 });
|
|
242 computeRevPtrsMenuItem = item;
|
|
243 item.setMnemonic(KeyEvent.VK_M);
|
|
244 toolsMenu.add(item);
|
|
245
|
|
246 item = createMenuItem("Deadlock Detection",
|
|
247 new ActionListener() {
|
|
248 public void actionPerformed(ActionEvent e) {
|
|
249 showDeadlockDetectionPanel();
|
|
250 }
|
|
251 });
|
|
252 item.setMnemonic(KeyEvent.VK_D);
|
|
253 toolsMenu.add(item);
|
|
254
|
|
255 item = createMenuItem("Find Object by Query",
|
|
256 new ActionListener() {
|
|
257 public void actionPerformed(ActionEvent e) {
|
|
258 showFindByQueryPanel();
|
|
259 }
|
|
260 });
|
|
261 item.setMnemonic(KeyEvent.VK_Q);
|
|
262 toolsMenu.add(item);
|
|
263
|
|
264
|
|
265 item = createMenuItem("Find Pointer",
|
|
266 new ActionListener() {
|
|
267 public void actionPerformed(ActionEvent e) {
|
|
268 showFindPanel();
|
|
269 }
|
|
270 });
|
|
271 item.setMnemonic(KeyEvent.VK_P);
|
|
272 toolsMenu.add(item);
|
|
273
|
|
274 item = createMenuItem("Find Value In Heap",
|
|
275 new ActionListener() {
|
|
276 public void actionPerformed(ActionEvent e) {
|
|
277 showFindInHeapPanel();
|
|
278 }
|
|
279 });
|
|
280 item.setMnemonic(KeyEvent.VK_V);
|
|
281 toolsMenu.add(item);
|
|
282
|
|
283 item = createMenuItem("Find Value In Code Cache",
|
|
284 new ActionListener() {
|
|
285 public void actionPerformed(ActionEvent e) {
|
|
286 showFindInCodeCachePanel();
|
|
287 }
|
|
288 });
|
|
289 item.setMnemonic(KeyEvent.VK_A);
|
|
290 toolsMenu.add(item);
|
|
291
|
|
292 item = createMenuItem("Heap Parameters",
|
|
293 new ActionListener() {
|
|
294 public void actionPerformed(ActionEvent e) {
|
|
295 showHeapParametersPanel();
|
|
296 }
|
|
297 });
|
|
298 item.setMnemonic(KeyEvent.VK_H);
|
|
299 toolsMenu.add(item);
|
|
300
|
|
301 item = createMenuItem("Inspector",
|
|
302 new ActionListener() {
|
|
303 public void actionPerformed(ActionEvent e) {
|
|
304 showInspector(null);
|
|
305 }
|
|
306 });
|
|
307 item.setMnemonic(KeyEvent.VK_R);
|
|
308 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.ALT_MASK));
|
|
309 toolsMenu.add(item);
|
|
310
|
|
311 item = createMenuItem("Memory Viewer",
|
|
312 new ActionListener() {
|
|
313 public void actionPerformed(ActionEvent e) {
|
|
314 showMemoryViewer();
|
|
315 }
|
|
316 });
|
|
317 item.setMnemonic(KeyEvent.VK_M);
|
|
318 toolsMenu.add(item);
|
|
319
|
|
320 item = createMenuItem("Monitor Cache Dump",
|
|
321 new ActionListener() {
|
|
322 public void actionPerformed(ActionEvent e) {
|
|
323 showMonitorCacheDumpPanel();
|
|
324 }
|
|
325 });
|
|
326 item.setMnemonic(KeyEvent.VK_D);
|
|
327 toolsMenu.add(item);
|
|
328
|
|
329 item = createMenuItem("Object Histogram",
|
|
330 new ActionListener() {
|
|
331 public void actionPerformed(ActionEvent e) {
|
|
332 showObjectHistogram();
|
|
333 }
|
|
334 });
|
|
335 item.setMnemonic(KeyEvent.VK_O);
|
|
336 toolsMenu.add(item);
|
|
337
|
|
338 item = createMenuItem("Show System Properties",
|
|
339 new ActionListener() {
|
|
340 public void actionPerformed(ActionEvent e) {
|
|
341 showSystemProperties();
|
|
342 }
|
|
343 });
|
|
344 item.setMnemonic(KeyEvent.VK_S);
|
|
345 toolsMenu.add(item);
|
|
346
|
|
347 item = createMenuItem("Show VM Version",
|
|
348 new ActionListener() {
|
|
349 public void actionPerformed(ActionEvent e) {
|
|
350 showVMVersion();
|
|
351 }
|
|
352 });
|
|
353 item.setMnemonic(KeyEvent.VK_M);
|
|
354 toolsMenu.add(item);
|
|
355
|
|
356 item = createMenuItem("Show -XX flags",
|
|
357 new ActionListener() {
|
|
358 public void actionPerformed(ActionEvent e) {
|
|
359 showCommandLineFlags();
|
|
360 }
|
|
361 });
|
|
362 item.setMnemonic(KeyEvent.VK_X);
|
|
363 toolsMenu.add(item);
|
|
364
|
|
365 toolsMenu.setEnabled(false);
|
|
366 menuBar.add(toolsMenu);
|
|
367
|
|
368 //
|
|
369 // Windows menu
|
|
370 //
|
|
371
|
|
372 JMenu windowsMenu = new JMenu("Windows");
|
|
373 windowsMenu.setMnemonic(KeyEvent.VK_W);
|
|
374 item = createMenuItem("Console",
|
|
375 new ActionListener() {
|
|
376 public void actionPerformed(ActionEvent e) {
|
|
377 showConsole();
|
|
378 }
|
|
379 });
|
|
380 item.setMnemonic(KeyEvent.VK_C);
|
|
381 windowsMenu.add(item);
|
|
382 showDbgConsoleMenuItem = createMenuItem("Debugger Console",
|
|
383 new ActionListener() {
|
|
384 public void actionPerformed(ActionEvent e) {
|
|
385 showDebuggerConsole();
|
|
386 }
|
|
387 });
|
|
388 showDbgConsoleMenuItem.setMnemonic(KeyEvent.VK_D);
|
|
389 windowsMenu.add(showDbgConsoleMenuItem);
|
|
390 showDbgConsoleMenuItem.setEnabled(false);
|
|
391
|
|
392 menuBar.add(windowsMenu);
|
|
393
|
|
394
|
|
395 frame.setJMenuBar(menuBar);
|
|
396
|
|
397 desktop = new JDesktopPane();
|
|
398 frame.getContentPane().add(desktop);
|
|
399 GraphicsUtilities.reshapeToAspectRatio(frame, 4.0f/3.0f, 0.75f, Toolkit.getDefaultToolkit().getScreenSize());
|
|
400 GraphicsUtilities.centerInContainer(frame, Toolkit.getDefaultToolkit().getScreenSize());
|
|
401 frame.show();
|
|
402
|
|
403 Runtime.getRuntime().addShutdownHook(new java.lang.Thread() {
|
|
404 public void run() {
|
|
405 detachDebugger();
|
|
406 }
|
|
407 });
|
|
408
|
|
409 if (pidText != null) {
|
|
410 attach(pidText);
|
|
411 } else if (execPath != null) {
|
|
412 attach(execPath, coreFilename);
|
|
413 }
|
|
414 }
|
|
415
|
|
416 // FIXME: merge showAttachDialog, showOpenCoreFileDialog, showConnectDialog
|
|
417 private void showAttachDialog() {
|
|
418 // FIXME: create filtered text field which only accepts numbers
|
|
419 setMenuItemsEnabled(attachMenuItems, false);
|
|
420 final JInternalFrame attachDialog = new JInternalFrame("Attach to HotSpot process");
|
|
421 attachDialog.getContentPane().setLayout(new BorderLayout());
|
|
422
|
|
423 JPanel panel = new JPanel();
|
|
424 panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
|
|
425 panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
|
426 attachDialog.setBackground(panel.getBackground());
|
|
427
|
|
428 panel.add(new JLabel("Enter process ID:"));
|
|
429 final JTextField pidTextField = new JTextField(10);
|
|
430 ActionListener attacher = new ActionListener() {
|
|
431 public void actionPerformed(ActionEvent e) {
|
|
432 attachDialog.setVisible(false);
|
|
433 desktop.remove(attachDialog);
|
|
434 workerThread.invokeLater(new Runnable() {
|
|
435 public void run() {
|
|
436 attach(pidTextField.getText());
|
|
437 }
|
|
438 });
|
|
439 }
|
|
440 };
|
|
441
|
|
442 pidTextField.addActionListener(attacher);
|
|
443 panel.add(pidTextField);
|
|
444 attachDialog.getContentPane().add(panel, BorderLayout.NORTH);
|
|
445
|
|
446 Box vbox = Box.createVerticalBox();
|
|
447 panel = new JPanel();
|
|
448 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
|
449 panel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
|
|
450 JTextArea ta = new JTextArea(
|
|
451 "Enter the process ID of a currently-running HotSpot process. On " +
|
|
452 "Solaris and most Unix operating systems, this can be determined by " +
|
|
453 "typing \"ps -u <your username> | grep java\"; the process ID is the " +
|
|
454 "first number which appears on the resulting line. On Windows, the " +
|
|
455 "process ID is present in the Task Manager, which can be brought up " +
|
|
456 "while logged on to the desktop by pressing Ctrl-Alt-Delete.");
|
|
457 ta.setLineWrap(true);
|
|
458 ta.setWrapStyleWord(true);
|
|
459 ta.setEditable(false);
|
|
460 ta.setBackground(panel.getBackground());
|
|
461 panel.add(ta);
|
|
462 vbox.add(panel);
|
|
463
|
|
464 Box hbox = Box.createHorizontalBox();
|
|
465 hbox.add(Box.createGlue());
|
|
466 JButton button = new JButton("OK");
|
|
467 button.addActionListener(attacher);
|
|
468 hbox.add(button);
|
|
469 hbox.add(Box.createHorizontalStrut(20));
|
|
470 button = new JButton("Cancel");
|
|
471 button.addActionListener(new ActionListener() {
|
|
472 public void actionPerformed(ActionEvent e) {
|
|
473 attachDialog.setVisible(false);
|
|
474 desktop.remove(attachDialog);
|
|
475 setMenuItemsEnabled(attachMenuItems, true);
|
|
476 }
|
|
477 });
|
|
478 hbox.add(button);
|
|
479 hbox.add(Box.createGlue());
|
|
480 panel = new JPanel();
|
|
481 panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
|
482 panel.add(hbox);
|
|
483 vbox.add(panel);
|
|
484
|
|
485 attachDialog.getContentPane().add(vbox, BorderLayout.SOUTH);
|
|
486
|
|
487 desktop.add(attachDialog);
|
|
488 attachDialog.setSize(400, 300);
|
|
489 GraphicsUtilities.centerInContainer(attachDialog);
|
|
490 attachDialog.show();
|
|
491 pidTextField.requestFocus();
|
|
492 }
|
|
493
|
|
494 // FIXME: merge showAttachDialog, showOpenCoreFileDialog, showConnectDialog
|
|
495 private void showOpenCoreFileDialog() {
|
|
496 setMenuItemsEnabled(attachMenuItems, false);
|
|
497 final JInternalFrame dialog = new JInternalFrame("Open Core File");
|
|
498 dialog.getContentPane().setLayout(new BorderLayout());
|
|
499
|
|
500 JPanel panel = new JPanel();
|
|
501 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
|
502 panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
|
503 dialog.setBackground(panel.getBackground());
|
|
504
|
|
505 Box hbox = Box.createHorizontalBox();
|
|
506 Box vbox = Box.createVerticalBox();
|
|
507 vbox.add(new JLabel("Path to core file:"));
|
|
508 vbox.add(new JLabel("Path to Java executable:"));
|
|
509 hbox.add(vbox);
|
|
510
|
|
511 vbox = Box.createVerticalBox();
|
|
512 final JTextField corePathField = new JTextField(40);
|
|
513 final JTextField execPathField = new JTextField(40);
|
|
514 vbox.add(corePathField);
|
|
515 vbox.add(execPathField);
|
|
516 hbox.add(vbox);
|
|
517
|
|
518 final JButton browseCorePath = new JButton("Browse ..");
|
|
519 final JButton browseExecPath = new JButton("Browse ..");
|
|
520 browseCorePath.addActionListener(new ActionListener() {
|
|
521 public void actionPerformed(ActionEvent e) {
|
|
522 JFileChooser fileChooser = new JFileChooser(new File("."));
|
|
523 int retVal = fileChooser.showOpenDialog(dialog);
|
|
524 if (retVal == JFileChooser.APPROVE_OPTION) {
|
|
525 corePathField.setText(fileChooser.getSelectedFile().getPath());
|
|
526 }
|
|
527 }
|
|
528 });
|
|
529 browseExecPath.addActionListener(new ActionListener() {
|
|
530 public void actionPerformed(ActionEvent e) {
|
|
531 JFileChooser fileChooser = new JFileChooser(new File("."));
|
|
532 int retVal = fileChooser.showOpenDialog(dialog);
|
|
533 if (retVal == JFileChooser.APPROVE_OPTION) {
|
|
534 execPathField.setText(fileChooser.getSelectedFile().getPath());
|
|
535 }
|
|
536 }
|
|
537 });
|
|
538 vbox = Box.createVerticalBox();
|
|
539 vbox.add(browseCorePath);
|
|
540 vbox.add(browseExecPath);
|
|
541 hbox.add(vbox);
|
|
542
|
|
543 panel.add(hbox);
|
|
544 dialog.getContentPane().add(panel, BorderLayout.NORTH);
|
|
545
|
|
546 ActionListener attacher = new ActionListener() {
|
|
547 public void actionPerformed(ActionEvent e) {
|
|
548 dialog.setVisible(false);
|
|
549 desktop.remove(dialog);
|
|
550 workerThread.invokeLater(new Runnable() {
|
|
551 public void run() {
|
|
552 attach(execPathField.getText(), corePathField.getText());
|
|
553 }
|
|
554 });
|
|
555 }
|
|
556 };
|
|
557 corePathField.addActionListener(attacher);
|
|
558 execPathField.addActionListener(attacher);
|
|
559
|
|
560 vbox = Box.createVerticalBox();
|
|
561 panel = new JPanel();
|
|
562 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
|
563 panel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
|
|
564 JTextArea ta = new JTextArea(
|
|
565 "Enter the full path names to the core file from a HotSpot process " +
|
|
566 "and the Java executable from which it came. The latter is typically " +
|
|
567 "located in the JDK/JRE directory under the directory " +
|
|
568 "jre/bin/<arch>/native_threads.");
|
|
569 ta.setLineWrap(true);
|
|
570 ta.setWrapStyleWord(true);
|
|
571 ta.setEditable(false);
|
|
572 ta.setBackground(panel.getBackground());
|
|
573 panel.add(ta);
|
|
574 vbox.add(panel);
|
|
575
|
|
576 hbox = Box.createHorizontalBox();
|
|
577 hbox.add(Box.createGlue());
|
|
578 JButton button = new JButton("OK");
|
|
579 button.addActionListener(attacher);
|
|
580 hbox.add(button);
|
|
581 hbox.add(Box.createHorizontalStrut(20));
|
|
582 button = new JButton("Cancel");
|
|
583 button.addActionListener(new ActionListener() {
|
|
584 public void actionPerformed(ActionEvent e) {
|
|
585 dialog.setVisible(false);
|
|
586 desktop.remove(dialog);
|
|
587 setMenuItemsEnabled(attachMenuItems, true);
|
|
588 }
|
|
589 });
|
|
590 hbox.add(button);
|
|
591 hbox.add(Box.createGlue());
|
|
592 panel = new JPanel();
|
|
593 panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
|
594 panel.add(hbox);
|
|
595 vbox.add(panel);
|
|
596
|
|
597 dialog.getContentPane().add(vbox, BorderLayout.SOUTH);
|
|
598
|
|
599 desktop.add(dialog);
|
|
600 dialog.setSize(500, 300);
|
|
601 GraphicsUtilities.centerInContainer(dialog);
|
|
602 dialog.show();
|
|
603 corePathField.requestFocus();
|
|
604 }
|
|
605
|
|
606 // FIXME: merge showAttachDialog, showOpenCoreFileDialog, showConnectDialog
|
|
607 private void showConnectDialog() {
|
|
608 // FIXME: create filtered text field which only accepts numbers
|
|
609 setMenuItemsEnabled(attachMenuItems, false);
|
|
610 final JInternalFrame dialog = new JInternalFrame("Connect to HotSpot Debug Server");
|
|
611 dialog.getContentPane().setLayout(new BorderLayout());
|
|
612
|
|
613 JPanel panel = new JPanel();
|
|
614 panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
|
|
615 panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
|
616 dialog.setBackground(panel.getBackground());
|
|
617
|
|
618 panel.add(new JLabel("Enter machine name:"));
|
|
619 final JTextField pidTextField = new JTextField(40);
|
|
620 ActionListener attacher = new ActionListener() {
|
|
621 public void actionPerformed(ActionEvent e) {
|
|
622 dialog.setVisible(false);
|
|
623 desktop.remove(dialog);
|
|
624 workerThread.invokeLater(new Runnable() {
|
|
625 public void run() {
|
|
626 connect(pidTextField.getText());
|
|
627 }
|
|
628 });
|
|
629 }
|
|
630 };
|
|
631
|
|
632 pidTextField.addActionListener(attacher);
|
|
633 panel.add(pidTextField);
|
|
634 dialog.getContentPane().add(panel, BorderLayout.NORTH);
|
|
635
|
|
636 Box vbox = Box.createVerticalBox();
|
|
637 panel = new JPanel();
|
|
638 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
|
639 panel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
|
|
640 JTextArea ta = new JTextArea(
|
|
641 "Enter the name of a machine on which the HotSpot \"Debug Server\" is " +
|
|
642 "running and is attached to a process or core file.");
|
|
643 ta.setLineWrap(true);
|
|
644 ta.setWrapStyleWord(true);
|
|
645 ta.setEditable(false);
|
|
646 ta.setBackground(panel.getBackground());
|
|
647 panel.add(ta);
|
|
648 vbox.add(panel);
|
|
649
|
|
650 Box hbox = Box.createHorizontalBox();
|
|
651 hbox.add(Box.createGlue());
|
|
652 JButton button = new JButton("OK");
|
|
653 button.addActionListener(attacher);
|
|
654 hbox.add(button);
|
|
655 hbox.add(Box.createHorizontalStrut(20));
|
|
656 button = new JButton("Cancel");
|
|
657 button.addActionListener(new ActionListener() {
|
|
658 public void actionPerformed(ActionEvent e) {
|
|
659 dialog.setVisible(false);
|
|
660 desktop.remove(dialog);
|
|
661 setMenuItemsEnabled(attachMenuItems, true);
|
|
662 }
|
|
663 });
|
|
664 hbox.add(button);
|
|
665 hbox.add(Box.createGlue());
|
|
666 panel = new JPanel();
|
|
667 panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
|
668 panel.add(hbox);
|
|
669 vbox.add(panel);
|
|
670
|
|
671 dialog.getContentPane().add(vbox, BorderLayout.SOUTH);
|
|
672
|
|
673 desktop.add(dialog);
|
|
674 dialog.setSize(400, 300);
|
|
675 GraphicsUtilities.centerInContainer(dialog);
|
|
676 dialog.show();
|
|
677 pidTextField.requestFocus();
|
|
678 }
|
|
679
|
|
680 public void showThreadOopInspector(JavaThread thread) {
|
|
681 showInspector(new OopTreeNodeAdapter(thread.getThreadObj(), null));
|
|
682 }
|
|
683
|
|
684 public void showInspector(SimpleTreeNode adapter) {
|
|
685 showPanel("Inspector", new Inspector(adapter), 1.0f, 0.65f);
|
|
686 }
|
|
687
|
|
688 public void showLiveness(Oop oop, LivenessPathList liveness) {
|
|
689 ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
690 PrintStream tty = new PrintStream(bos);
|
|
691 int numPaths = liveness.size();
|
|
692 for (int i = 0; i < numPaths; i++) {
|
|
693 tty.println("Path " + (i + 1) + " of " + numPaths + ":");
|
|
694 liveness.get(i).printOn(tty);
|
|
695 }
|
|
696 JTextArea ta = new JTextArea(bos.toString());
|
|
697 ta.setLineWrap(true);
|
|
698 ta.setWrapStyleWord(true);
|
|
699 ta.setEditable(false);
|
|
700
|
|
701 JPanel panel = new JPanel();
|
|
702 panel.setLayout(new BorderLayout());
|
|
703
|
|
704 JScrollPane scroller = new JScrollPane();
|
|
705 scroller.getViewport().add(ta);
|
|
706
|
|
707 panel.add(scroller, BorderLayout.CENTER);
|
|
708
|
|
709 bos = new ByteArrayOutputStream();
|
|
710 tty = new PrintStream(bos);
|
|
711 tty.print("Liveness result for ");
|
|
712 Oop.printOopValueOn(oop, tty);
|
|
713
|
|
714 JInternalFrame frame = new JInternalFrame(bos.toString());
|
|
715 frame.setResizable(true);
|
|
716 frame.setClosable(true);
|
|
717 frame.setIconifiable(true);
|
|
718 frame.getContentPane().setLayout(new BorderLayout());
|
|
719 frame.getContentPane().add(panel, BorderLayout.CENTER);
|
|
720 frame.pack();
|
|
721 desktop.add(frame);
|
|
722 GraphicsUtilities.reshapeToAspectRatio(frame, 0.5f / 0.2f, 0.5f, frame.getParent().getSize());
|
|
723 frame.show();
|
|
724 }
|
|
725
|
|
726 private void fireComputeReversePtrs() {
|
|
727 // Possible this might have been computed elsewhere
|
|
728 if (VM.getVM().getRevPtrs() != null) {
|
|
729 computeRevPtrsMenuItem.setEnabled(false);
|
|
730 return;
|
|
731 }
|
|
732
|
|
733 workerThread.invokeLater(new Runnable() {
|
|
734 public void run() {
|
|
735 HeapProgress progress = new HeapProgress("Reverse Pointers Analysis");
|
|
736 try {
|
|
737 ReversePtrsAnalysis analysis = new ReversePtrsAnalysis();
|
|
738 analysis.setHeapProgressThunk(progress);
|
|
739 analysis.run();
|
|
740 computeRevPtrsMenuItem.setEnabled(false);
|
|
741 } catch (OutOfMemoryError e) {
|
|
742 final String errMsg = formatMessage(e.toString(), 80);
|
|
743 SwingUtilities.invokeLater(new Runnable() {
|
|
744 public void run() {
|
|
745 JOptionPane.showInternalMessageDialog(desktop,
|
|
746 "Error computing reverse pointers:" + errMsg,
|
|
747 "Error",
|
|
748 JOptionPane.WARNING_MESSAGE);
|
|
749 }
|
|
750 });
|
|
751 } finally {
|
|
752 // make sure the progress bar goes away
|
|
753 progress.heapIterationComplete();
|
|
754 }
|
|
755 }
|
|
756 });
|
|
757 }
|
|
758
|
|
759 // Simple struct containing signal information
|
|
760 class SignalInfo {
|
|
761 public int sigNum;
|
|
762 public String sigName;
|
|
763 }
|
|
764
|
|
765 // Need to have mutable vframe as well as visible memory panel
|
|
766 abstract class StackWalker implements Runnable {
|
|
767 protected JavaVFrame vf;
|
|
768 protected AnnotatedMemoryPanel annoPanel;
|
|
769
|
|
770 StackWalker(JavaVFrame vf, AnnotatedMemoryPanel annoPanel) {
|
|
771 this.vf = vf;
|
|
772 this.annoPanel = annoPanel;
|
|
773 }
|
|
774 }
|
|
775
|
|
776 public void showThreadStackMemory(final JavaThread thread) {
|
|
777 // dumpStack(thread);
|
|
778 JavaVFrame vframe = getLastJavaVFrame(thread);
|
|
779 if (vframe == null) {
|
|
780 JOptionPane.showInternalMessageDialog(desktop,
|
|
781 "Thread \"" + thread.getThreadName() +
|
|
782 "\" has no Java frames on its stack",
|
|
783 "Show Stack Memory",
|
|
784 JOptionPane.INFORMATION_MESSAGE);
|
|
785 return;
|
|
786 }
|
|
787
|
|
788 JInternalFrame stackFrame = new JInternalFrame("Stack Memory for " + thread.getThreadName());
|
|
789 stackFrame.getContentPane().setLayout(new BorderLayout());
|
|
790 stackFrame.setResizable(true);
|
|
791 stackFrame.setClosable(true);
|
|
792 stackFrame.setIconifiable(true);
|
|
793 final long addressSize = agent.getTypeDataBase().getAddressSize();
|
|
794 boolean is64Bit = (addressSize == 8);
|
|
795 // This is somewhat of a hack to guess a thread's stack limits since the
|
|
796 // JavaThread doesn't support this functionality. However it is nice in that
|
|
797 // it locks us into the active region of the thread's stack and not its
|
|
798 // theoretical limits.
|
|
799 //
|
|
800 sun.jvm.hotspot.runtime.Frame tmpFrame = thread.getCurrentFrameGuess();
|
|
801 Address sp = tmpFrame.getSP();
|
|
802 Address starting = sp;
|
|
803 Address maxSP = starting;
|
|
804 Address minSP = starting;
|
|
805 RegisterMap tmpMap = thread.newRegisterMap(false);
|
|
806 while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) {
|
|
807 tmpFrame = tmpFrame.sender(tmpMap);
|
|
808 if (tmpFrame != null) {
|
|
809 sp = tmpFrame.getSP();
|
|
810 if (sp != null) {
|
|
811 maxSP = AddressOps.max(maxSP, sp);
|
|
812 minSP = AddressOps.min(minSP, sp);
|
|
813 }
|
|
814 }
|
|
815
|
|
816 }
|
|
817 // It is useful to be able to see say +/- 8K on the current stack range
|
|
818 AnnotatedMemoryPanel annoMemPanel = new AnnotatedMemoryPanel(agent.getDebugger(), is64Bit, starting,
|
|
819 minSP.addOffsetTo(-8192),
|
|
820 maxSP.addOffsetTo( 8192));
|
|
821
|
|
822 stackFrame.getContentPane().add(annoMemPanel, BorderLayout.CENTER);
|
|
823 desktop.add(stackFrame);
|
|
824 GraphicsUtilities.reshapeToAspectRatio(stackFrame, 4.0f / 3.0f, 0.85f, stackFrame.getParent().getSize());
|
|
825 stackFrame.show();
|
|
826
|
|
827 // Stackmap computation for interpreted frames is expensive; do
|
|
828 // all stackwalking work in another thread for better GUI
|
|
829 // responsiveness
|
|
830 workerThread.invokeLater(new StackWalker(vframe, annoMemPanel) {
|
|
831 public void run() {
|
|
832 Address startAddr = null;
|
|
833
|
|
834 // As this is a debugger, we want to provide potential crash
|
|
835 // information to the user, i.e., by marking signal handler frames
|
|
836 // on the stack. Since this system is currently targeted at
|
|
837 // annotating the Java frames (interpreted or compiled) on the
|
|
838 // stack and not, for example, "external" frames (note the current
|
|
839 // absence of a PC-to-symbol lookup mechanism at the Debugger
|
|
840 // level), we want to mark any Java frames which were interrupted
|
|
841 // by a signal. We do this by making two passes over the stack,
|
|
842 // one which finds signal handler frames and puts the parent
|
|
843 // frames in a table and one which finds Java frames and if they
|
|
844 // are in the table indicates that they were interrupted by a signal.
|
|
845
|
|
846 Map interruptedFrameMap = new HashMap();
|
|
847 {
|
|
848 sun.jvm.hotspot.runtime.Frame tmpFrame = thread.getCurrentFrameGuess();
|
|
849 RegisterMap tmpMap = thread.newRegisterMap(false);
|
|
850 while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) {
|
|
851 if (tmpFrame.isSignalHandlerFrameDbg()) {
|
|
852 // Add some information to the map that we can extract later
|
|
853 sun.jvm.hotspot.runtime.Frame interruptedFrame = tmpFrame.sender(tmpMap);
|
|
854 SignalInfo info = new SignalInfo();
|
|
855 info.sigNum = tmpFrame.getSignalNumberDbg();
|
|
856 info.sigName = tmpFrame.getSignalNameDbg();
|
|
857 interruptedFrameMap.put(interruptedFrame, info);
|
|
858 }
|
|
859 tmpFrame = tmpFrame.sender(tmpMap);
|
|
860 }
|
|
861 }
|
|
862
|
|
863 while (vf != null) {
|
|
864 String anno = null;
|
|
865 JavaVFrame curVFrame = vf;
|
|
866 sun.jvm.hotspot.runtime.Frame curFrame = curVFrame.getFrame();
|
|
867 Method interpreterFrameMethod = null;
|
|
868
|
|
869 if (curVFrame.isInterpretedFrame()) {
|
|
870 anno = "Interpreted frame";
|
|
871 } else {
|
|
872 anno = "Compiled frame";
|
|
873 if (curVFrame.isDeoptimized()) {
|
|
874 anno += " (deoptimized)";
|
|
875 }
|
|
876 }
|
|
877 if (curVFrame.mayBeImpreciseDbg()) {
|
|
878 anno += "; information may be imprecise";
|
|
879 }
|
|
880
|
|
881 if (curVFrame.isInterpretedFrame()) {
|
|
882 // Find the codelet
|
|
883 InterpreterCodelet codelet = VM.getVM().getInterpreter().getCodeletContaining(curFrame.getPC());
|
|
884 String description = null;
|
|
885 if (codelet != null) {
|
|
886 description = codelet.getDescription();
|
|
887 }
|
|
888 if (description == null) {
|
|
889 anno += "\n(Unknown interpreter codelet)";
|
|
890 } else {
|
|
891 anno += "\nExecuting in codelet \"" + description + "\" at PC = " + curFrame.getPC();
|
|
892 }
|
|
893 } else if (curVFrame.isCompiledFrame()) {
|
|
894 anno += "\nExecuting at PC = " + curFrame.getPC();
|
|
895 }
|
|
896
|
|
897 if (startAddr == null) {
|
|
898 startAddr = curFrame.getSP();
|
|
899 }
|
|
900
|
|
901 // FIXME: some compiled frames with empty oop map sets have been
|
|
902 // found (for example, Vector's inner Enumeration class, method
|
|
903 // "hasMoreElements"). Not sure yet why these cases are showing
|
|
904 // up -- should be possible (though unlikely) for safepoint code
|
|
905 // to patch the return instruction of these methods and then
|
|
906 // later attempt to get an oop map for that instruction. For
|
|
907 // now, we warn if we find such a method.
|
|
908 boolean shouldSkipOopMaps = false;
|
|
909 if (curVFrame.isCompiledFrame()) {
|
|
910 CodeBlob cb = VM.getVM().getCodeCache().findBlob(curFrame.getPC());
|
|
911 OopMapSet maps = cb.getOopMaps();
|
|
912 if ((maps == null) || (maps.getSize() == 0)) {
|
|
913 shouldSkipOopMaps = true;
|
|
914 }
|
|
915 }
|
|
916
|
|
917 // Add signal information to annotation if necessary
|
|
918 SignalInfo sigInfo = (SignalInfo) interruptedFrameMap.get(curFrame);
|
|
919 if (sigInfo != null) {
|
|
920 // This frame took a signal and we need to report it.
|
|
921 anno = (anno + "\n*** INTERRUPTED BY SIGNAL " + Integer.toString(sigInfo.sigNum) +
|
|
922 " (" + sigInfo.sigName + ")");
|
|
923 }
|
|
924
|
|
925 JavaVFrame nextVFrame = curVFrame;
|
|
926 sun.jvm.hotspot.runtime.Frame nextFrame = curFrame;
|
|
927 do {
|
|
928 curVFrame = nextVFrame;
|
|
929 curFrame = nextFrame;
|
|
930
|
|
931 try {
|
|
932 Method method = curVFrame.getMethod();
|
|
933 if (interpreterFrameMethod == null && curVFrame.isInterpretedFrame()) {
|
|
934 interpreterFrameMethod = method;
|
|
935 }
|
|
936 int bci = curVFrame.getBCI();
|
|
937 String lineNumberAnno = "";
|
|
938 if (method.hasLineNumberTable()) {
|
|
939 if ((bci == DebugInformationRecorder.SYNCHRONIZATION_ENTRY_BCI) ||
|
|
940 (bci >= 0 && bci < method.getCodeSize())) {
|
|
941 lineNumberAnno = ", line " + method.getLineNumberFromBCI(bci);
|
|
942 } else {
|
|
943 lineNumberAnno = " (INVALID BCI)";
|
|
944 }
|
|
945 }
|
|
946 anno += "\n" + method.getMethodHolder().getName().asString() + "." +
|
|
947 method.getName().asString() + method.getSignature().asString() +
|
|
948 "\n@bci " + bci + lineNumberAnno;
|
|
949 } catch (Exception e) {
|
|
950 anno += "\n(ERROR while iterating vframes for frame " + curFrame + ")";
|
|
951 }
|
|
952
|
|
953 nextVFrame = curVFrame.javaSender();
|
|
954 if (nextVFrame != null) {
|
|
955 nextFrame = nextVFrame.getFrame();
|
|
956 }
|
|
957 } while (nextVFrame != null && nextFrame.equals(curFrame));
|
|
958
|
|
959 if (shouldSkipOopMaps) {
|
|
960 anno = anno + "\nNOTE: null or empty OopMapSet found for this CodeBlob";
|
|
961 }
|
|
962
|
|
963 if (curFrame.getFP() != null) {
|
|
964 annoPanel.addAnnotation(new Annotation(curFrame.getSP(),
|
|
965 curFrame.getFP(),
|
|
966 anno));
|
|
967 } else {
|
|
968 if (VM.getVM().getCPU().equals("x86") || VM.getVM().getCPU().equals("amd64")) {
|
|
969 // For C2, which has null frame pointers on x86/amd64
|
|
970 CodeBlob cb = VM.getVM().getCodeCache().findBlob(curFrame.getPC());
|
|
971 Address sp = curFrame.getSP();
|
|
972 if (Assert.ASSERTS_ENABLED) {
|
|
973 Assert.that(cb.getFrameSize() > 0, "CodeBlob must have non-zero frame size");
|
|
974 }
|
|
975 annoPanel.addAnnotation(new Annotation(sp,
|
|
976 sp.addOffsetTo(cb.getFrameSize()),
|
|
977 anno));
|
|
978 } else {
|
|
979 Assert.that(VM.getVM().getCPU().equals("ia64"), "only ia64 should reach here");
|
|
980 }
|
|
981 }
|
|
982
|
|
983 // Add interpreter frame annotations
|
|
984 if (curFrame.isInterpretedFrame()) {
|
|
985 annoPanel.addAnnotation(new Annotation(curFrame.addressOfInterpreterFrameExpressionStack(),
|
|
986 curFrame.addressOfInterpreterFrameTOS(),
|
|
987 "Interpreter expression stack"));
|
|
988 if (interpreterFrameMethod != null) {
|
|
989 // The offset is just to get the right stack slots highlighted in the output
|
|
990 int offset = 1;
|
|
991 annoPanel.addAnnotation(new Annotation(curFrame.addressOfInterpreterFrameLocal(offset),
|
|
992 curFrame.addressOfInterpreterFrameLocal((int) interpreterFrameMethod.getMaxLocals() + offset),
|
|
993 "Interpreter locals area for frame with SP = " + curFrame.getSP()));
|
|
994 }
|
|
995 String methodAnno = "Interpreter frame methodOop";
|
|
996 if (interpreterFrameMethod == null) {
|
|
997 methodAnno += " (BAD OOP)";
|
|
998 }
|
|
999 Address a = curFrame.addressOfInterpreterFrameMethod();
|
|
1000 annoPanel.addAnnotation(new Annotation(a, a.addOffsetTo(addressSize), methodAnno));
|
|
1001 a = curFrame.addressOfInterpreterFrameCPCache();
|
|
1002 annoPanel.addAnnotation(new Annotation(a, a.addOffsetTo(addressSize), "Interpreter constant pool cache"));
|
|
1003 }
|
|
1004
|
|
1005 RegisterMap rm = (RegisterMap) vf.getRegisterMap().clone();
|
|
1006 if (!shouldSkipOopMaps) {
|
|
1007 try {
|
|
1008 curFrame.oopsDo(new AddressVisitor() {
|
|
1009 public void visitAddress(Address addr) {
|
|
1010 if (Assert.ASSERTS_ENABLED) {
|
|
1011 Assert.that(addr.andWithMask(VM.getVM().getAddressSize() - 1) == null,
|
|
1012 "Address " + addr + "should have been aligned");
|
|
1013 }
|
|
1014 // Check contents
|
|
1015 OopHandle handle = addr.getOopHandleAt(0);
|
|
1016 String anno = "null oop";
|
|
1017 if (handle != null) {
|
|
1018 // Find location
|
|
1019 CollectedHeap collHeap = VM.getVM().getUniverse().heap();
|
|
1020 boolean bad = true;
|
|
1021 anno = "BAD OOP";
|
|
1022 if (collHeap instanceof GenCollectedHeap) {
|
|
1023 GenCollectedHeap heap = (GenCollectedHeap) collHeap;
|
|
1024 for (int i = 0; i < heap.nGens(); i++) {
|
|
1025 if (heap.getGen(i).isIn(handle)) {
|
|
1026 if (i == 0) {
|
|
1027 anno = "NewGen ";
|
|
1028 } else if (i == 1) {
|
|
1029 anno = "OldGen ";
|
|
1030 } else {
|
|
1031 anno = "Gen " + i + " ";
|
|
1032 }
|
|
1033 bad = false;
|
|
1034 break;
|
|
1035 }
|
|
1036 }
|
|
1037
|
|
1038 if (bad) {
|
|
1039 // Try perm gen
|
|
1040 if (heap.permGen().isIn(handle)) {
|
|
1041 anno = "PermGen ";
|
|
1042 bad = false;
|
|
1043 }
|
|
1044 }
|
|
1045 } else if (collHeap instanceof ParallelScavengeHeap) {
|
|
1046 ParallelScavengeHeap heap = (ParallelScavengeHeap) collHeap;
|
|
1047 if (heap.youngGen().isIn(handle)) {
|
|
1048 anno = "PSYoungGen ";
|
|
1049 bad = false;
|
|
1050 } else if (heap.oldGen().isIn(handle)) {
|
|
1051 anno = "PSOldGen ";
|
|
1052 bad = false;
|
|
1053 } else if (heap.permGen().isIn(handle)) {
|
|
1054 anno = "PSPermGen ";
|
|
1055 bad = false;
|
|
1056 }
|
|
1057 } else {
|
|
1058 // Optimistically assume the oop isn't bad
|
|
1059 anno = "[Unknown generation] ";
|
|
1060 bad = false;
|
|
1061 }
|
|
1062
|
|
1063 if (!bad) {
|
|
1064 try {
|
|
1065 Oop oop = VM.getVM().getObjectHeap().newOop(handle);
|
|
1066 if (oop instanceof Instance) {
|
|
1067 // Java-level objects always have workable names
|
|
1068 anno = anno + oop.getKlass().getName().asString();
|
|
1069 } else {
|
|
1070 ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
1071 Oop.printOopValueOn(oop, new PrintStream(bos));
|
|
1072 anno = anno + bos.toString();
|
|
1073 }
|
|
1074 }
|
|
1075 catch (AddressException e) {
|
|
1076 anno += "CORRUPT OOP";
|
|
1077 }
|
|
1078 catch (NullPointerException e) {
|
|
1079 anno += "CORRUPT OOP (null pointer)";
|
|
1080 }
|
|
1081 }
|
|
1082 }
|
|
1083
|
|
1084 annoPanel.addAnnotation(new Annotation(addr, addr.addOffsetTo(addressSize), anno));
|
|
1085 }
|
|
1086 }, rm);
|
|
1087 } catch (Exception e) {
|
|
1088 System.err.println("Error while performing oopsDo for frame " + curFrame);
|
|
1089 e.printStackTrace();
|
|
1090 }
|
|
1091 }
|
|
1092
|
|
1093 vf = nextVFrame;
|
|
1094 }
|
|
1095
|
|
1096 // This used to paint as we walked the frames. This caused the display to be refreshed
|
|
1097 // enough to be annoying on remote displays. It also would cause the annotations to
|
|
1098 // be displayed in varying order which caused some annotations to overwrite others
|
|
1099 // depending on the races between painting and adding annotations. This latter problem
|
|
1100 // still exists to some degree but moving this code here definitely seems to reduce it
|
|
1101 annoPanel.makeVisible(startAddr);
|
|
1102 annoPanel.repaint();
|
|
1103 }
|
|
1104 });
|
|
1105 }
|
|
1106
|
|
1107 /** NOTE we are in a different thread here than either the main
|
|
1108 thread or the Swing/AWT event handler thread, so we must be very
|
|
1109 careful when creating or removing widgets */
|
|
1110 private void attach(String pidText) {
|
|
1111 try {
|
|
1112 this.pidText = pidText;
|
|
1113 pid = Integer.parseInt(pidText);
|
|
1114 }
|
|
1115 catch (NumberFormatException e) {
|
|
1116 SwingUtilities.invokeLater(new Runnable() {
|
|
1117 public void run() {
|
|
1118 setMenuItemsEnabled(attachMenuItems, true);
|
|
1119 JOptionPane.showInternalMessageDialog(desktop,
|
|
1120 "Unable to parse process ID \"" + HSDB.this.pidText + "\".\nPlease enter a number.",
|
|
1121 "Parse error",
|
|
1122 JOptionPane.WARNING_MESSAGE);
|
|
1123 }
|
|
1124 });
|
|
1125 return;
|
|
1126 }
|
|
1127
|
|
1128 // Try to attach to this process
|
|
1129 Runnable remover = new Runnable() {
|
|
1130 public void run() {
|
|
1131 attachWaitDialog.setVisible(false);
|
|
1132 desktop.remove(attachWaitDialog);
|
|
1133 attachWaitDialog = null;
|
|
1134 }
|
|
1135 };
|
|
1136
|
|
1137 try {
|
|
1138 SwingUtilities.invokeLater(new Runnable() {
|
|
1139 public void run() {
|
|
1140 JOptionPane pane = new JOptionPane("Attaching to process " + pid + ", please wait...", JOptionPane.INFORMATION_MESSAGE);
|
|
1141 pane.setOptions(new Object[] {});
|
|
1142 attachWaitDialog = pane.createInternalFrame(desktop, "Attaching to Process");
|
|
1143 attachWaitDialog.show();
|
|
1144 }
|
|
1145 });
|
|
1146
|
|
1147 // FIXME: display exec'd debugger's output messages during this
|
|
1148 // lengthy call
|
|
1149 agent.attach(pid);
|
|
1150 if (agent.getDebugger().hasConsole()) {
|
|
1151 showDbgConsoleMenuItem.setEnabled(true);
|
|
1152 }
|
|
1153 attached = true;
|
|
1154 SwingUtilities.invokeLater(remover);
|
|
1155 }
|
|
1156 catch (DebuggerException e) {
|
|
1157 SwingUtilities.invokeLater(remover);
|
|
1158 final String errMsg = formatMessage(e.getMessage(), 80);
|
|
1159 SwingUtilities.invokeLater(new Runnable() {
|
|
1160 public void run() {
|
|
1161 setMenuItemsEnabled(attachMenuItems, true);
|
|
1162 JOptionPane.showInternalMessageDialog(desktop,
|
|
1163 "Unable to connect to process ID " + pid + ":\n\n" + errMsg,
|
|
1164 "Unable to Connect",
|
|
1165 JOptionPane.WARNING_MESSAGE);
|
|
1166 }
|
|
1167 });
|
|
1168 agent.detach();
|
|
1169 return;
|
|
1170 }
|
|
1171
|
|
1172 // OK, the VM should be available. Create the Threads dialog.
|
|
1173 showThreadsDialog();
|
|
1174 }
|
|
1175
|
|
1176 /** NOTE we are in a different thread here than either the main
|
|
1177 thread or the Swing/AWT event handler thread, so we must be very
|
|
1178 careful when creating or removing widgets */
|
|
1179 private void attach(final String executablePath, final String corePath) {
|
|
1180 // Try to open this core file
|
|
1181 Runnable remover = new Runnable() {
|
|
1182 public void run() {
|
|
1183 attachWaitDialog.setVisible(false);
|
|
1184 desktop.remove(attachWaitDialog);
|
|
1185 attachWaitDialog = null;
|
|
1186 }
|
|
1187 };
|
|
1188
|
|
1189 try {
|
|
1190 SwingUtilities.invokeLater(new Runnable() {
|
|
1191 public void run() {
|
|
1192 JOptionPane pane = new JOptionPane("Opening core file, please wait...", JOptionPane.INFORMATION_MESSAGE);
|
|
1193 pane.setOptions(new Object[] {});
|
|
1194 attachWaitDialog = pane.createInternalFrame(desktop, "Opening Core File");
|
|
1195 attachWaitDialog.show();
|
|
1196 }
|
|
1197 });
|
|
1198
|
|
1199 // FIXME: display exec'd debugger's output messages during this
|
|
1200 // lengthy call
|
|
1201 agent.attach(executablePath, corePath);
|
|
1202 if (agent.getDebugger().hasConsole()) {
|
|
1203 showDbgConsoleMenuItem.setEnabled(true);
|
|
1204 }
|
|
1205 attached = true;
|
|
1206 SwingUtilities.invokeLater(remover);
|
|
1207 }
|
|
1208 catch (DebuggerException e) {
|
|
1209 SwingUtilities.invokeLater(remover);
|
|
1210 final String errMsg = formatMessage(e.getMessage(), 80);
|
|
1211 SwingUtilities.invokeLater(new Runnable() {
|
|
1212 public void run() {
|
|
1213 setMenuItemsEnabled(attachMenuItems, true);
|
|
1214 JOptionPane.showInternalMessageDialog(desktop,
|
|
1215 "Unable to open core file\n" + corePath + ":\n\n" + errMsg,
|
|
1216 "Unable to Open Core File",
|
|
1217 JOptionPane.WARNING_MESSAGE);
|
|
1218 }
|
|
1219 });
|
|
1220 agent.detach();
|
|
1221 return;
|
|
1222 }
|
|
1223
|
|
1224 // OK, the VM should be available. Create the Threads dialog.
|
|
1225 showThreadsDialog();
|
|
1226 }
|
|
1227
|
|
1228 /** NOTE we are in a different thread here than either the main
|
|
1229 thread or the Swing/AWT event handler thread, so we must be very
|
|
1230 careful when creating or removing widgets */
|
|
1231 private void connect(final String remoteMachineName) {
|
|
1232 // Try to open this core file
|
|
1233 Runnable remover = new Runnable() {
|
|
1234 public void run() {
|
|
1235 attachWaitDialog.setVisible(false);
|
|
1236 desktop.remove(attachWaitDialog);
|
|
1237 attachWaitDialog = null;
|
|
1238 }
|
|
1239 };
|
|
1240
|
|
1241 try {
|
|
1242 SwingUtilities.invokeLater(new Runnable() {
|
|
1243 public void run() {
|
|
1244 JOptionPane pane = new JOptionPane("Connecting to debug server, please wait...", JOptionPane.INFORMATION_MESSAGE);
|
|
1245 pane.setOptions(new Object[] {});
|
|
1246 attachWaitDialog = pane.createInternalFrame(desktop, "Connecting to Debug Server");
|
|
1247 attachWaitDialog.show();
|
|
1248 }
|
|
1249 });
|
|
1250
|
|
1251 agent.attach(remoteMachineName);
|
|
1252 if (agent.getDebugger().hasConsole()) {
|
|
1253 showDbgConsoleMenuItem.setEnabled(true);
|
|
1254 }
|
|
1255 attached = true;
|
|
1256 SwingUtilities.invokeLater(remover);
|
|
1257 }
|
|
1258 catch (DebuggerException e) {
|
|
1259 SwingUtilities.invokeLater(remover);
|
|
1260 final String errMsg = formatMessage(e.getMessage(), 80);
|
|
1261 SwingUtilities.invokeLater(new Runnable() {
|
|
1262 public void run() {
|
|
1263 setMenuItemsEnabled(attachMenuItems, true);
|
|
1264 JOptionPane.showInternalMessageDialog(desktop,
|
|
1265 "Unable to connect to machine \"" + remoteMachineName + "\":\n\n" + errMsg,
|
|
1266 "Unable to Connect",
|
|
1267 JOptionPane.WARNING_MESSAGE);
|
|
1268 }
|
|
1269 });
|
|
1270 agent.detach();
|
|
1271 return;
|
|
1272 }
|
|
1273
|
|
1274 // OK, the VM should be available. Create the Threads dialog.
|
|
1275 showThreadsDialog();
|
|
1276 }
|
|
1277
|
|
1278 private void detachDebugger() {
|
|
1279 if (!attached) {
|
|
1280 return;
|
|
1281 }
|
|
1282 agent.detach();
|
|
1283 attached = false;
|
|
1284 }
|
|
1285
|
|
1286 private void detach() {
|
|
1287 detachDebugger();
|
|
1288 attachWaitDialog = null;
|
|
1289 threadsFrame = null;
|
|
1290 consoleFrame = null;
|
|
1291 setMenuItemsEnabled(attachMenuItems, true);
|
|
1292 setMenuItemsEnabled(detachMenuItems, false);
|
|
1293 toolsMenu.setEnabled(false);
|
|
1294 showDbgConsoleMenuItem.setEnabled(false);
|
|
1295 // FIXME: is this sufficient, or will I have to do anything else
|
|
1296 // to the components to kill them off? What about WorkerThreads?
|
|
1297 desktop.removeAll();
|
|
1298 desktop.invalidate();
|
|
1299 desktop.validate();
|
|
1300 desktop.repaint();
|
|
1301 }
|
|
1302
|
|
1303 /** NOTE that this is called from another thread than the main or
|
|
1304 Swing thread and we have to be careful about synchronization */
|
|
1305 private void showThreadsDialog() {
|
|
1306 SwingUtilities.invokeLater(new Runnable() {
|
|
1307 public void run() {
|
|
1308 threadsFrame = new JInternalFrame("Java Threads");
|
|
1309 threadsFrame.setResizable(true);
|
|
1310 threadsFrame.setIconifiable(true);
|
|
1311 JavaThreadsPanel threadsPanel = new JavaThreadsPanel();
|
|
1312 threadsPanel.addPanelListener(HSDB.this);
|
|
1313 threadsFrame.getContentPane().add(threadsPanel);
|
|
1314 threadsFrame.setSize(500, 300);
|
|
1315 threadsFrame.pack();
|
|
1316 desktop.add(threadsFrame);
|
|
1317 GraphicsUtilities.moveToInContainer(threadsFrame, 0.75f, 0.25f, 0, 20);
|
|
1318 threadsFrame.show();
|
|
1319 setMenuItemsEnabled(attachMenuItems, false);
|
|
1320 setMenuItemsEnabled(detachMenuItems, true);
|
|
1321 toolsMenu.setEnabled(true);
|
|
1322 VM.registerVMInitializedObserver(new Observer() {
|
|
1323 public void update(Observable o, Object data) {
|
|
1324 computeRevPtrsMenuItem.setEnabled(true);
|
|
1325 }
|
|
1326 });
|
|
1327 }
|
|
1328 });
|
|
1329 }
|
|
1330
|
|
1331 private void showObjectHistogram() {
|
|
1332 sun.jvm.hotspot.oops.ObjectHistogram histo = new sun.jvm.hotspot.oops.ObjectHistogram();
|
|
1333 ObjectHistogramCleanupThunk cleanup =
|
|
1334 new ObjectHistogramCleanupThunk(histo);
|
|
1335 doHeapIteration("Object Histogram",
|
|
1336 "Generating histogram...",
|
|
1337 histo,
|
|
1338 cleanup);
|
|
1339 }
|
|
1340
|
|
1341 class ObjectHistogramCleanupThunk implements CleanupThunk {
|
|
1342 sun.jvm.hotspot.oops.ObjectHistogram histo;
|
|
1343
|
|
1344 ObjectHistogramCleanupThunk(sun.jvm.hotspot.oops.ObjectHistogram histo) {
|
|
1345 this.histo = histo;
|
|
1346 }
|
|
1347
|
|
1348 public void heapIterationComplete() {
|
|
1349 SwingUtilities.invokeLater(new Runnable() {
|
|
1350 public void run() {
|
|
1351 JInternalFrame histoFrame = new JInternalFrame("Object Histogram");
|
|
1352 histoFrame.setResizable(true);
|
|
1353 histoFrame.setClosable(true);
|
|
1354 histoFrame.setIconifiable(true);
|
|
1355 histoFrame.getContentPane().setLayout(new BorderLayout());
|
|
1356 ObjectHistogramPanel panel = new ObjectHistogramPanel(histo);
|
|
1357 panel.addPanelListener(HSDB.this);
|
|
1358 histoFrame.getContentPane().add(panel);
|
|
1359 desktop.add(histoFrame);
|
|
1360 GraphicsUtilities.reshapeToAspectRatio(histoFrame, 4.0f / 3.0f, 0.6f,
|
|
1361 histoFrame.getParent().getSize());
|
|
1362 GraphicsUtilities.centerInContainer(histoFrame);
|
|
1363 histoFrame.show();
|
|
1364 }
|
|
1365 });
|
|
1366 }
|
|
1367 }
|
|
1368
|
|
1369 public void showObjectsOfType(Klass type) {
|
|
1370 FindObjectByType finder = new FindObjectByType(type);
|
|
1371 FindObjectByTypeCleanupThunk cleanup =
|
|
1372 new FindObjectByTypeCleanupThunk(finder);
|
|
1373 ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
1374 type.printValueOn(new PrintStream(bos));
|
|
1375 String typeName = bos.toString();
|
|
1376 doHeapIteration("Show Objects Of Type",
|
|
1377 "Finding instances of \"" + typeName + "\"",
|
|
1378 finder,
|
|
1379 cleanup);
|
|
1380 }
|
|
1381
|
|
1382 class FindObjectByTypeCleanupThunk implements CleanupThunk {
|
|
1383 FindObjectByType finder;
|
|
1384
|
|
1385 FindObjectByTypeCleanupThunk(FindObjectByType finder) {
|
|
1386 this.finder = finder;
|
|
1387 }
|
|
1388
|
|
1389 public void heapIterationComplete() {
|
|
1390 SwingUtilities.invokeLater(new Runnable() {
|
|
1391 public void run() {
|
|
1392 JInternalFrame finderFrame = new JInternalFrame("Show Objects of Type");
|
|
1393 finderFrame.getContentPane().setLayout(new BorderLayout());
|
|
1394 finderFrame.setResizable(true);
|
|
1395 finderFrame.setClosable(true);
|
|
1396 finderFrame.setIconifiable(true);
|
|
1397 ObjectListPanel panel = new ObjectListPanel(finder.getResults(),
|
|
1398 new HeapProgress("Reverse Pointers Analysis"));
|
|
1399 panel.addPanelListener(HSDB.this);
|
|
1400 finderFrame.getContentPane().add(panel);
|
|
1401 desktop.add(finderFrame);
|
|
1402 GraphicsUtilities.reshapeToAspectRatio(finderFrame, 4.0f / 3.0f, 0.6f,
|
|
1403 finderFrame.getParent().getSize());
|
|
1404 GraphicsUtilities.centerInContainer(finderFrame);
|
|
1405 finderFrame.show();
|
|
1406 }
|
|
1407 });
|
|
1408 }
|
|
1409 }
|
|
1410
|
|
1411 private void showDebuggerConsole() {
|
|
1412 if (consoleFrame == null) {
|
|
1413 consoleFrame = new JInternalFrame("Debugger Console");
|
|
1414 consoleFrame.setResizable(true);
|
|
1415 consoleFrame.setClosable(true);
|
|
1416 consoleFrame.setIconifiable(true);
|
|
1417 consoleFrame.getContentPane().setLayout(new BorderLayout());
|
|
1418 consoleFrame.getContentPane().add(new DebuggerConsolePanel(agent.getDebugger()), BorderLayout.CENTER);
|
|
1419 GraphicsUtilities.reshapeToAspectRatio(consoleFrame, 5.0f, 0.9f, desktop.getSize());
|
|
1420 }
|
|
1421 if (consoleFrame.getParent() == null) {
|
|
1422 desktop.add(consoleFrame);
|
|
1423 }
|
|
1424 consoleFrame.setVisible(true);
|
|
1425 consoleFrame.show();
|
|
1426 consoleFrame.getContentPane().getComponent(0).requestFocus();
|
|
1427 }
|
|
1428
|
|
1429 private void showConsole() {
|
|
1430 CommandProcessor.DebuggerInterface di = new CommandProcessor.DebuggerInterface() {
|
|
1431 public HotSpotAgent getAgent() {
|
|
1432 return agent;
|
|
1433 }
|
|
1434 public boolean isAttached() {
|
|
1435 return attached;
|
|
1436 }
|
|
1437 public void attach(String pid) {
|
|
1438 attach(pid);
|
|
1439 }
|
|
1440 public void attach(String java, String core) {
|
|
1441 }
|
|
1442 public void detach() {
|
|
1443 detachDebugger();
|
|
1444 }
|
|
1445 public void reattach() {
|
|
1446 if (attached) {
|
|
1447 detachDebugger();
|
|
1448 }
|
|
1449 if (pidText != null) {
|
|
1450 attach(pidText);
|
|
1451 } else {
|
|
1452 attach(execPath, coreFilename);
|
|
1453 }
|
|
1454 }
|
|
1455 };
|
|
1456
|
|
1457 showPanel("Command Line", new CommandProcessorPanel(new CommandProcessor(di, null, null, null)));
|
|
1458 }
|
|
1459
|
|
1460 private void showFindByQueryPanel() {
|
|
1461 showPanel("Find Object by Query", new FindByQueryPanel());
|
|
1462 }
|
|
1463
|
|
1464 private void showFindPanel() {
|
|
1465 showPanel("Find Pointer", new FindPanel());
|
|
1466 }
|
|
1467
|
|
1468 private void showFindInHeapPanel() {
|
|
1469 showPanel("Find Address In Heap", new FindInHeapPanel());
|
|
1470 }
|
|
1471
|
|
1472 private void showFindInCodeCachePanel() {
|
|
1473 showPanel("Find Address In Code Cache", new FindInCodeCachePanel());
|
|
1474 }
|
|
1475
|
|
1476 private void showHeapParametersPanel() {
|
|
1477 showPanel("Heap Parameters", new HeapParametersPanel());
|
|
1478 }
|
|
1479
|
|
1480 public void showThreadInfo(final JavaThread thread) {
|
|
1481 showPanel("Info for " + thread.getThreadName(), new ThreadInfoPanel(thread));
|
|
1482 }
|
|
1483
|
|
1484 public void showJavaStackTrace(final JavaThread thread) {
|
|
1485 JavaStackTracePanel jstp = new JavaStackTracePanel();
|
|
1486 showPanel("Java stack trace for " + thread.getThreadName(), jstp);
|
|
1487 jstp.setJavaThread(thread);
|
|
1488 }
|
|
1489
|
|
1490 private void showDeadlockDetectionPanel() {
|
|
1491 showPanel("Deadlock Detection", new DeadlockDetectionPanel());
|
|
1492 }
|
|
1493
|
|
1494 private void showMonitorCacheDumpPanel() {
|
|
1495 showPanel("Monitor Cache Dump", new MonitorCacheDumpPanel());
|
|
1496 }
|
|
1497
|
|
1498 public void showClassBrowser() {
|
|
1499 final JInternalFrame progressFrame = new JInternalFrame("Class Browser");
|
|
1500 progressFrame.setResizable(true);
|
|
1501 progressFrame.setClosable(true);
|
|
1502 progressFrame.setIconifiable(true);
|
|
1503 progressFrame.getContentPane().setLayout(new BorderLayout());
|
|
1504 final ProgressBarPanel bar = new ProgressBarPanel("Generating class list ..");
|
|
1505 bar.setIndeterminate(true);
|
|
1506 progressFrame.getContentPane().add(bar, BorderLayout.CENTER);
|
|
1507 desktop.add(progressFrame);
|
|
1508 progressFrame.pack();
|
|
1509 GraphicsUtilities.centerInContainer(progressFrame);
|
|
1510 progressFrame.show();
|
|
1511
|
|
1512 workerThread.invokeLater(new Runnable() {
|
|
1513 public void run() {
|
|
1514 HTMLGenerator htmlGen = new HTMLGenerator();
|
|
1515 InstanceKlass[] klasses = SystemDictionaryHelper.getAllInstanceKlasses();
|
|
1516 final String htmlText = htmlGen.genHTMLForKlassNames(klasses);
|
|
1517 SwingUtilities.invokeLater(new Runnable() {
|
|
1518 public void run() {
|
|
1519 JInternalFrame cbFrame = new JInternalFrame("Class Browser");
|
|
1520 cbFrame.getContentPane().setLayout(new BorderLayout());
|
|
1521 cbFrame.setResizable(true);
|
|
1522 cbFrame.setClosable(true);
|
|
1523 cbFrame.setIconifiable(true);
|
|
1524 ClassBrowserPanel cbPanel = new ClassBrowserPanel();
|
|
1525 cbFrame.getContentPane().add(cbPanel, BorderLayout.CENTER);
|
|
1526 desktop.remove(progressFrame);
|
|
1527 desktop.repaint();
|
|
1528 desktop.add(cbFrame);
|
|
1529 GraphicsUtilities.reshapeToAspectRatio(cbFrame, 1.25f, 0.85f,
|
|
1530 cbFrame.getParent().getSize());
|
|
1531 cbFrame.show();
|
|
1532 cbPanel.setClassesText(htmlText);
|
|
1533 }
|
|
1534 });
|
|
1535 }
|
|
1536 });
|
|
1537 }
|
|
1538
|
|
1539 public void showCodeViewer() {
|
|
1540 showPanel("Code Viewer", new CodeViewerPanel(), 1.25f, 0.85f);
|
|
1541 }
|
|
1542
|
|
1543 public void showCodeViewer(final Address address) {
|
|
1544 final CodeViewerPanel panel = new CodeViewerPanel();
|
|
1545 showPanel("Code Viewer", panel, 1.25f, 0.85f);
|
|
1546 SwingUtilities.invokeLater(new Runnable() {
|
|
1547 public void run() {
|
|
1548 panel.viewAddress(address);
|
|
1549 }
|
|
1550 });
|
|
1551
|
|
1552 }
|
|
1553
|
|
1554 public void showMemoryViewer() {
|
|
1555 showPanel("Memory Viewer", new MemoryViewer(agent.getDebugger(), agent.getTypeDataBase().getAddressSize() == 8));
|
|
1556 }
|
|
1557
|
|
1558 public void showCommandLineFlags() {
|
|
1559 showPanel("Command Line Flags", new VMFlagsPanel());
|
|
1560 }
|
|
1561
|
|
1562 public void showVMVersion() {
|
|
1563 showPanel("VM Version Info", new VMVersionInfoPanel());
|
|
1564 }
|
|
1565
|
|
1566 public void showSystemProperties() {
|
|
1567 showPanel("System Properties", new SysPropsPanel());
|
|
1568 }
|
|
1569
|
|
1570 private void showPanel(String name, JPanel panel) {
|
|
1571 showPanel(name, panel, 5.0f / 3.0f, 0.4f);
|
|
1572 }
|
|
1573
|
|
1574 private void showPanel(String name, JPanel panel, float aspectRatio, float fillRatio) {
|
|
1575 JInternalFrame frame = new JInternalFrame(name);
|
|
1576 frame.getContentPane().setLayout(new BorderLayout());
|
|
1577 frame.setResizable(true);
|
|
1578 frame.setClosable(true);
|
|
1579 frame.setIconifiable(true);
|
|
1580 frame.setMaximizable(true);
|
|
1581 frame.getContentPane().add(panel, BorderLayout.CENTER);
|
|
1582 desktop.add(frame);
|
|
1583 GraphicsUtilities.reshapeToAspectRatio(frame, aspectRatio, fillRatio, frame.getParent().getSize());
|
|
1584 GraphicsUtilities.randomLocation(frame);
|
|
1585 frame.show();
|
|
1586 if (panel instanceof SAPanel) {
|
|
1587 ((SAPanel)panel).addPanelListener(this);
|
|
1588 }
|
|
1589 }
|
|
1590
|
|
1591 //--------------------------------------------------------------------------------
|
|
1592 // Framework for heap iteration with progress bar
|
|
1593 //
|
|
1594
|
|
1595 interface CleanupThunk {
|
|
1596 public void heapIterationComplete();
|
|
1597 }
|
|
1598
|
|
1599 class HeapProgress implements HeapProgressThunk {
|
|
1600 private JInternalFrame frame;
|
|
1601 private ProgressBarPanel bar;
|
|
1602 private String windowTitle;
|
|
1603 private String progressBarTitle;
|
|
1604 private CleanupThunk cleanup;
|
|
1605
|
|
1606 HeapProgress(String windowTitle) {
|
|
1607 this(windowTitle, "Percentage of heap visited", null);
|
|
1608 }
|
|
1609
|
|
1610 HeapProgress(String windowTitle, String progressBarTitle) {
|
|
1611 this(windowTitle, progressBarTitle, null);
|
|
1612 }
|
|
1613
|
|
1614 HeapProgress(String windowTitle, String progressBarTitle, CleanupThunk cleanup) {
|
|
1615 this.windowTitle = windowTitle;
|
|
1616 this.progressBarTitle = progressBarTitle;
|
|
1617 this.cleanup = cleanup;
|
|
1618 }
|
|
1619
|
|
1620 public void heapIterationFractionUpdate(final double fractionOfHeapVisited) {
|
|
1621 if (frame == null) {
|
|
1622 SwingUtilities.invokeLater(new Runnable() {
|
|
1623 public void run() {
|
|
1624 frame = new JInternalFrame(windowTitle);
|
|
1625 frame.setResizable(true);
|
|
1626 frame.setIconifiable(true);
|
|
1627 frame.getContentPane().setLayout(new BorderLayout());
|
|
1628 bar = new ProgressBarPanel(progressBarTitle);
|
|
1629 frame.getContentPane().add(bar, BorderLayout.CENTER);
|
|
1630 desktop.add(frame);
|
|
1631 frame.pack();
|
|
1632 GraphicsUtilities.constrainToSize(frame, frame.getParent().getSize());
|
|
1633 GraphicsUtilities.centerInContainer(frame);
|
|
1634 frame.show();
|
|
1635 }
|
|
1636 });
|
|
1637 }
|
|
1638
|
|
1639 SwingUtilities.invokeLater(new Runnable() {
|
|
1640 public void run() {
|
|
1641 bar.setValue(fractionOfHeapVisited);
|
|
1642 }
|
|
1643 });
|
|
1644 }
|
|
1645
|
|
1646 public void heapIterationComplete() {
|
|
1647 SwingUtilities.invokeLater(new Runnable() {
|
|
1648 public void run() {
|
|
1649 desktop.remove(frame);
|
|
1650 desktop.repaint();
|
|
1651 if (VM.getVM().getRevPtrs() != null) {
|
|
1652 // Ended up computing reverse pointers as a side-effect
|
|
1653 computeRevPtrsMenuItem.setEnabled(false);
|
|
1654 }
|
|
1655 }
|
|
1656 });
|
|
1657
|
|
1658 if (cleanup != null) {
|
|
1659 cleanup.heapIterationComplete();
|
|
1660 }
|
|
1661 }
|
|
1662 }
|
|
1663
|
|
1664 class VisitHeap implements Runnable {
|
|
1665 HeapVisitor visitor;
|
|
1666
|
|
1667 VisitHeap(HeapVisitor visitor) {
|
|
1668 this.visitor = visitor;
|
|
1669 }
|
|
1670
|
|
1671 public void run() {
|
|
1672 VM.getVM().getObjectHeap().iterate(visitor);
|
|
1673 }
|
|
1674 }
|
|
1675
|
|
1676 private void doHeapIteration(String frameTitle,
|
|
1677 String progressBarText,
|
|
1678 HeapVisitor visitor,
|
|
1679 CleanupThunk cleanup) {
|
|
1680 sun.jvm.hotspot.oops.ObjectHistogram histo = new sun.jvm.hotspot.oops.ObjectHistogram();
|
|
1681 HeapProgress progress = new HeapProgress(frameTitle,
|
|
1682 progressBarText,
|
|
1683 cleanup);
|
|
1684 HeapVisitor progVisitor = new ProgressiveHeapVisitor(visitor, progress);
|
|
1685 workerThread.invokeLater(new VisitHeap(progVisitor));
|
|
1686 }
|
|
1687
|
|
1688 //--------------------------------------------------------------------------------
|
|
1689 // Stack trace helper
|
|
1690 //
|
|
1691
|
|
1692 private static JavaVFrame getLastJavaVFrame(JavaThread cur) {
|
|
1693 RegisterMap regMap = cur.newRegisterMap(true);
|
|
1694 sun.jvm.hotspot.runtime.Frame f = cur.getCurrentFrameGuess();
|
|
1695 if (f == null) return null;
|
|
1696 boolean imprecise = true;
|
|
1697 if (f.isInterpretedFrame() && !f.isInterpretedFrameValid()) {
|
|
1698 System.err.println("Correcting for invalid interpreter frame");
|
|
1699 f = f.sender(regMap);
|
|
1700 imprecise = false;
|
|
1701 }
|
|
1702 VFrame vf = VFrame.newVFrame(f, regMap, cur, true, imprecise);
|
|
1703 if (vf == null) {
|
|
1704 System.err.println(" (Unable to create vframe for topmost frame guess)");
|
|
1705 return null;
|
|
1706 }
|
|
1707 if (vf.isJavaFrame()) {
|
|
1708 return (JavaVFrame) vf;
|
|
1709 }
|
|
1710 return (JavaVFrame) vf.javaSender();
|
|
1711 }
|
|
1712
|
|
1713 // Internal routine for debugging
|
|
1714 private static void dumpStack(JavaThread cur) {
|
|
1715 RegisterMap regMap = cur.newRegisterMap(true);
|
|
1716 sun.jvm.hotspot.runtime.Frame f = cur.getCurrentFrameGuess();
|
|
1717 PrintStream tty = System.err;
|
|
1718 while (f != null) {
|
|
1719 tty.print("Found ");
|
|
1720 if (f.isInterpretedFrame()) { tty.print("interpreted"); }
|
|
1721 else if (f.isCompiledFrame()) { tty.print("compiled"); }
|
|
1722 else if (f.isEntryFrame()) { tty.print("entry"); }
|
|
1723 else if (f.isNativeFrame()) { tty.print("native"); }
|
|
1724 else if (f.isGlueFrame()) { tty.print("glue"); }
|
|
1725 else { tty.print("external"); }
|
|
1726 tty.print(" frame with PC = " + f.getPC() + ", SP = " + f.getSP() + ", FP = " + f.getFP());
|
|
1727 if (f.isSignalHandlerFrameDbg()) {
|
|
1728 tty.print(" (SIGNAL HANDLER)");
|
|
1729 }
|
|
1730 tty.println();
|
|
1731
|
|
1732 if (!f.isFirstFrame()) {
|
|
1733 f = f.sender(regMap);
|
|
1734 } else {
|
|
1735 f = null;
|
|
1736 }
|
|
1737 }
|
|
1738 }
|
|
1739
|
|
1740 //--------------------------------------------------------------------------------
|
|
1741 // Component utilities
|
|
1742 //
|
|
1743
|
|
1744 private static JMenuItem createMenuItem(String name, ActionListener l) {
|
|
1745 JMenuItem item = new JMenuItem(name);
|
|
1746 item.addActionListener(l);
|
|
1747 return item;
|
|
1748 }
|
|
1749
|
|
1750 /** Punctuates the given string with \n's where necessary to not
|
|
1751 exceed the given number of characters per line. Strips
|
|
1752 extraneous whitespace. */
|
|
1753 private String formatMessage(String message, int charsPerLine) {
|
|
1754 StringBuffer buf = new StringBuffer(message.length());
|
|
1755 StringTokenizer tokenizer = new StringTokenizer(message);
|
|
1756 int curLineLength = 0;
|
|
1757 while (tokenizer.hasMoreTokens()) {
|
|
1758 String tok = tokenizer.nextToken();
|
|
1759 if (curLineLength + tok.length() > charsPerLine) {
|
|
1760 buf.append('\n');
|
|
1761 curLineLength = 0;
|
|
1762 } else {
|
|
1763 if (curLineLength != 0) {
|
|
1764 buf.append(' ');
|
|
1765 ++curLineLength;
|
|
1766 }
|
|
1767 }
|
|
1768 buf.append(tok);
|
|
1769 curLineLength += tok.length();
|
|
1770 }
|
|
1771 return buf.toString();
|
|
1772 }
|
|
1773
|
|
1774 private void setMenuItemsEnabled(java.util.List items, boolean enabled) {
|
|
1775 for (Iterator iter = items.iterator(); iter.hasNext(); ) {
|
|
1776 ((JMenuItem) iter.next()).setEnabled(enabled);
|
|
1777 }
|
|
1778 }
|
|
1779 }
|