1 /* 2 * Copyright (c) 2000, 2008, 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, 20 * CA 94065 USA or visit www.oracle.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.setVisible(true); 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 OopHandle handle = addr.getOopHandleAt(0); 1015 addAnnotation(addr, handle); 1016 } 1017 1018 public void visitCompOopAddress(Address addr) { 1019 if (Assert.ASSERTS_ENABLED) { 1020 Assert.that(addr.andWithMask(VM.getVM().getAddressSize() - 1) == null, 1021 "Address " + addr + "should have been aligned"); 1022 } 1023 OopHandle handle = addr.getCompOopHandleAt(0); 1024 addAnnotation(addr, handle); 1025 } 1026 1027 public void addAnnotation(Address addr, OopHandle handle) { 1028 // Check contents 1029 String anno = "null oop"; 1030 if (handle != null) { 1031 // Find location 1032 CollectedHeap collHeap = VM.getVM().getUniverse().heap(); 1033 boolean bad = true; 1034 anno = "BAD OOP"; 1035 if (collHeap instanceof GenCollectedHeap) { 1036 GenCollectedHeap heap = (GenCollectedHeap) collHeap; 1037 for (int i = 0; i < heap.nGens(); i++) { 1038 if (heap.getGen(i).isIn(handle)) { 1039 if (i == 0) { 1040 anno = "NewGen "; 1041 } else if (i == 1) { 1042 anno = "OldGen "; 1043 } else { 1044 anno = "Gen " + i + " "; 1045 } 1046 bad = false; 1047 break; 1048 } 1049 } 1050 1051 if (bad) { 1052 // Try perm gen 1053 if (heap.permGen().isIn(handle)) { 1054 anno = "PermGen "; 1055 bad = false; 1056 } 1057 } 1058 } else if (collHeap instanceof ParallelScavengeHeap) { 1059 ParallelScavengeHeap heap = (ParallelScavengeHeap) collHeap; 1060 if (heap.youngGen().isIn(handle)) { 1061 anno = "PSYoungGen "; 1062 bad = false; 1063 } else if (heap.oldGen().isIn(handle)) { 1064 anno = "PSOldGen "; 1065 bad = false; 1066 } else if (heap.permGen().isIn(handle)) { 1067 anno = "PSPermGen "; 1068 bad = false; 1069 } 1070 } else { 1071 // Optimistically assume the oop isn't bad 1072 anno = "[Unknown generation] "; 1073 bad = false; 1074 } 1075 1076 if (!bad) { 1077 try { 1078 Oop oop = VM.getVM().getObjectHeap().newOop(handle); 1079 if (oop instanceof Instance) { 1080 // Java-level objects always have workable names 1081 anno = anno + oop.getKlass().getName().asString(); 1082 } else { 1083 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 1084 Oop.printOopValueOn(oop, new PrintStream(bos)); 1085 anno = anno + bos.toString(); 1086 } 1087 } 1088 catch (AddressException e) { 1089 anno += "CORRUPT OOP"; 1090 } 1091 catch (NullPointerException e) { 1092 anno += "CORRUPT OOP (null pointer)"; 1093 } 1094 } 1095 } 1096 1097 annoPanel.addAnnotation(new Annotation(addr, addr.addOffsetTo(addressSize), anno)); 1098 } 1099 }, rm); 1100 } catch (Exception e) { 1101 System.err.println("Error while performing oopsDo for frame " + curFrame); 1102 e.printStackTrace(); 1103 } 1104 } 1105 1106 vf = nextVFrame; 1107 } 1108 1109 // This used to paint as we walked the frames. This caused the display to be refreshed 1110 // enough to be annoying on remote displays. It also would cause the annotations to 1111 // be displayed in varying order which caused some annotations to overwrite others 1112 // depending on the races between painting and adding annotations. This latter problem 1113 // still exists to some degree but moving this code here definitely seems to reduce it 1114 annoPanel.makeVisible(startAddr); 1115 annoPanel.repaint(); 1116 } 1117 }); 1118 } 1119 1120 /** NOTE we are in a different thread here than either the main 1121 thread or the Swing/AWT event handler thread, so we must be very 1122 careful when creating or removing widgets */ 1123 private void attach(String pidText) { 1124 try { 1125 this.pidText = pidText; 1126 pid = Integer.parseInt(pidText); 1127 } 1128 catch (NumberFormatException e) { 1129 SwingUtilities.invokeLater(new Runnable() { 1130 public void run() { 1131 setMenuItemsEnabled(attachMenuItems, true); 1132 JOptionPane.showInternalMessageDialog(desktop, 1133 "Unable to parse process ID \"" + HSDB.this.pidText + "\".\nPlease enter a number.", 1134 "Parse error", 1135 JOptionPane.WARNING_MESSAGE); 1136 } 1137 }); 1138 return; 1139 } 1140 1141 // Try to attach to this process 1142 Runnable remover = new Runnable() { 1143 public void run() { 1144 attachWaitDialog.setVisible(false); 1145 desktop.remove(attachWaitDialog); 1146 attachWaitDialog = null; 1147 } 1148 }; 1149 1150 try { 1151 SwingUtilities.invokeLater(new Runnable() { 1152 public void run() { 1153 JOptionPane pane = new JOptionPane("Attaching to process " + pid + ", please wait...", JOptionPane.INFORMATION_MESSAGE); 1154 pane.setOptions(new Object[] {}); 1155 attachWaitDialog = pane.createInternalFrame(desktop, "Attaching to Process"); 1156 attachWaitDialog.show(); 1157 } 1158 }); 1159 1160 // FIXME: display exec'd debugger's output messages during this 1161 // lengthy call 1162 agent.attach(pid); 1163 if (agent.getDebugger().hasConsole()) { 1164 showDbgConsoleMenuItem.setEnabled(true); 1165 } 1166 attached = true; 1167 SwingUtilities.invokeLater(remover); 1168 } 1169 catch (DebuggerException e) { 1170 SwingUtilities.invokeLater(remover); 1171 final String errMsg = formatMessage(e.getMessage(), 80); 1172 SwingUtilities.invokeLater(new Runnable() { 1173 public void run() { 1174 setMenuItemsEnabled(attachMenuItems, true); 1175 JOptionPane.showInternalMessageDialog(desktop, 1176 "Unable to connect to process ID " + pid + ":\n\n" + errMsg, 1177 "Unable to Connect", 1178 JOptionPane.WARNING_MESSAGE); 1179 } 1180 }); 1181 agent.detach(); 1182 return; 1183 } 1184 1185 // OK, the VM should be available. Create the Threads dialog. 1186 showThreadsDialog(); 1187 } 1188 1189 /** NOTE we are in a different thread here than either the main 1190 thread or the Swing/AWT event handler thread, so we must be very 1191 careful when creating or removing widgets */ 1192 private void attach(final String executablePath, final String corePath) { 1193 // Try to open this core file 1194 Runnable remover = new Runnable() { 1195 public void run() { 1196 attachWaitDialog.setVisible(false); 1197 desktop.remove(attachWaitDialog); 1198 attachWaitDialog = null; 1199 } 1200 }; 1201 1202 try { 1203 SwingUtilities.invokeLater(new Runnable() { 1204 public void run() { 1205 JOptionPane pane = new JOptionPane("Opening core file, please wait...", JOptionPane.INFORMATION_MESSAGE); 1206 pane.setOptions(new Object[] {}); 1207 attachWaitDialog = pane.createInternalFrame(desktop, "Opening Core File"); 1208 attachWaitDialog.show(); 1209 } 1210 }); 1211 1212 // FIXME: display exec'd debugger's output messages during this 1213 // lengthy call 1214 agent.attach(executablePath, corePath); 1215 if (agent.getDebugger().hasConsole()) { 1216 showDbgConsoleMenuItem.setEnabled(true); 1217 } 1218 attached = true; 1219 SwingUtilities.invokeLater(remover); 1220 } 1221 catch (DebuggerException e) { 1222 SwingUtilities.invokeLater(remover); 1223 final String errMsg = formatMessage(e.getMessage(), 80); 1224 SwingUtilities.invokeLater(new Runnable() { 1225 public void run() { 1226 setMenuItemsEnabled(attachMenuItems, true); 1227 JOptionPane.showInternalMessageDialog(desktop, 1228 "Unable to open core file\n" + corePath + ":\n\n" + errMsg, 1229 "Unable to Open Core File", 1230 JOptionPane.WARNING_MESSAGE); 1231 } 1232 }); 1233 agent.detach(); 1234 return; 1235 } 1236 1237 // OK, the VM should be available. Create the Threads dialog. 1238 showThreadsDialog(); 1239 } 1240 1241 /** NOTE we are in a different thread here than either the main 1242 thread or the Swing/AWT event handler thread, so we must be very 1243 careful when creating or removing widgets */ 1244 private void connect(final String remoteMachineName) { 1245 // Try to open this core file 1246 Runnable remover = new Runnable() { 1247 public void run() { 1248 attachWaitDialog.setVisible(false); 1249 desktop.remove(attachWaitDialog); 1250 attachWaitDialog = null; 1251 } 1252 }; 1253 1254 try { 1255 SwingUtilities.invokeLater(new Runnable() { 1256 public void run() { 1257 JOptionPane pane = new JOptionPane("Connecting to debug server, please wait...", JOptionPane.INFORMATION_MESSAGE); 1258 pane.setOptions(new Object[] {}); 1259 attachWaitDialog = pane.createInternalFrame(desktop, "Connecting to Debug Server"); 1260 attachWaitDialog.show(); 1261 } 1262 }); 1263 1264 agent.attach(remoteMachineName); 1265 if (agent.getDebugger().hasConsole()) { 1266 showDbgConsoleMenuItem.setEnabled(true); 1267 } 1268 attached = true; 1269 SwingUtilities.invokeLater(remover); 1270 } 1271 catch (DebuggerException e) { 1272 SwingUtilities.invokeLater(remover); 1273 final String errMsg = formatMessage(e.getMessage(), 80); 1274 SwingUtilities.invokeLater(new Runnable() { 1275 public void run() { 1276 setMenuItemsEnabled(attachMenuItems, true); 1277 JOptionPane.showInternalMessageDialog(desktop, 1278 "Unable to connect to machine \"" + remoteMachineName + "\":\n\n" + errMsg, 1279 "Unable to Connect", 1280 JOptionPane.WARNING_MESSAGE); 1281 } 1282 }); 1283 agent.detach(); 1284 return; 1285 } 1286 1287 // OK, the VM should be available. Create the Threads dialog. 1288 showThreadsDialog(); 1289 } 1290 1291 private void detachDebugger() { 1292 if (!attached) { 1293 return; 1294 } 1295 agent.detach(); 1296 attached = false; 1297 } 1298 1299 private void detach() { 1300 detachDebugger(); 1301 attachWaitDialog = null; 1302 threadsFrame = null; 1303 consoleFrame = null; 1304 setMenuItemsEnabled(attachMenuItems, true); 1305 setMenuItemsEnabled(detachMenuItems, false); 1306 toolsMenu.setEnabled(false); 1307 showDbgConsoleMenuItem.setEnabled(false); 1308 // FIXME: is this sufficient, or will I have to do anything else 1309 // to the components to kill them off? What about WorkerThreads? 1310 desktop.removeAll(); 1311 desktop.invalidate(); 1312 desktop.validate(); 1313 desktop.repaint(); 1314 } 1315 1316 /** NOTE that this is called from another thread than the main or 1317 Swing thread and we have to be careful about synchronization */ 1318 private void showThreadsDialog() { 1319 SwingUtilities.invokeLater(new Runnable() { 1320 public void run() { 1321 threadsFrame = new JInternalFrame("Java Threads"); 1322 threadsFrame.setResizable(true); 1323 threadsFrame.setIconifiable(true); 1324 JavaThreadsPanel threadsPanel = new JavaThreadsPanel(); 1325 threadsPanel.addPanelListener(HSDB.this); 1326 threadsFrame.getContentPane().add(threadsPanel); 1327 threadsFrame.setSize(500, 300); 1328 threadsFrame.pack(); 1329 desktop.add(threadsFrame); 1330 GraphicsUtilities.moveToInContainer(threadsFrame, 0.75f, 0.25f, 0, 20); 1331 threadsFrame.show(); 1332 setMenuItemsEnabled(attachMenuItems, false); 1333 setMenuItemsEnabled(detachMenuItems, true); 1334 toolsMenu.setEnabled(true); 1335 VM.registerVMInitializedObserver(new Observer() { 1336 public void update(Observable o, Object data) { 1337 computeRevPtrsMenuItem.setEnabled(true); 1338 } 1339 }); 1340 } 1341 }); 1342 } 1343 1344 private void showObjectHistogram() { 1345 sun.jvm.hotspot.oops.ObjectHistogram histo = new sun.jvm.hotspot.oops.ObjectHistogram(); 1346 ObjectHistogramCleanupThunk cleanup = 1347 new ObjectHistogramCleanupThunk(histo); 1348 doHeapIteration("Object Histogram", 1349 "Generating histogram...", 1350 histo, 1351 cleanup); 1352 } 1353 1354 class ObjectHistogramCleanupThunk implements CleanupThunk { 1355 sun.jvm.hotspot.oops.ObjectHistogram histo; 1356 1357 ObjectHistogramCleanupThunk(sun.jvm.hotspot.oops.ObjectHistogram histo) { 1358 this.histo = histo; 1359 } 1360 1361 public void heapIterationComplete() { 1362 SwingUtilities.invokeLater(new Runnable() { 1363 public void run() { 1364 JInternalFrame histoFrame = new JInternalFrame("Object Histogram"); 1365 histoFrame.setResizable(true); 1366 histoFrame.setClosable(true); 1367 histoFrame.setIconifiable(true); 1368 histoFrame.getContentPane().setLayout(new BorderLayout()); 1369 ObjectHistogramPanel panel = new ObjectHistogramPanel(histo); 1370 panel.addPanelListener(HSDB.this); 1371 histoFrame.getContentPane().add(panel); 1372 desktop.add(histoFrame); 1373 GraphicsUtilities.reshapeToAspectRatio(histoFrame, 4.0f / 3.0f, 0.6f, 1374 histoFrame.getParent().getSize()); 1375 GraphicsUtilities.centerInContainer(histoFrame); 1376 histoFrame.show(); 1377 } 1378 }); 1379 } 1380 } 1381 1382 public void showObjectsOfType(Klass type) { 1383 FindObjectByType finder = new FindObjectByType(type); 1384 FindObjectByTypeCleanupThunk cleanup = 1385 new FindObjectByTypeCleanupThunk(finder); 1386 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 1387 type.printValueOn(new PrintStream(bos)); 1388 String typeName = bos.toString(); 1389 doHeapIteration("Show Objects Of Type", 1390 "Finding instances of \"" + typeName + "\"", 1391 finder, 1392 cleanup); 1393 } 1394 1395 class FindObjectByTypeCleanupThunk implements CleanupThunk { 1396 FindObjectByType finder; 1397 1398 FindObjectByTypeCleanupThunk(FindObjectByType finder) { 1399 this.finder = finder; 1400 } 1401 1402 public void heapIterationComplete() { 1403 SwingUtilities.invokeLater(new Runnable() { 1404 public void run() { 1405 JInternalFrame finderFrame = new JInternalFrame("Show Objects of Type"); 1406 finderFrame.getContentPane().setLayout(new BorderLayout()); 1407 finderFrame.setResizable(true); 1408 finderFrame.setClosable(true); 1409 finderFrame.setIconifiable(true); 1410 ObjectListPanel panel = new ObjectListPanel(finder.getResults(), 1411 new HeapProgress("Reverse Pointers Analysis")); 1412 panel.addPanelListener(HSDB.this); 1413 finderFrame.getContentPane().add(panel); 1414 desktop.add(finderFrame); 1415 GraphicsUtilities.reshapeToAspectRatio(finderFrame, 4.0f / 3.0f, 0.6f, 1416 finderFrame.getParent().getSize()); 1417 GraphicsUtilities.centerInContainer(finderFrame); 1418 finderFrame.show(); 1419 } 1420 }); 1421 } 1422 } 1423 1424 private void showDebuggerConsole() { 1425 if (consoleFrame == null) { 1426 consoleFrame = new JInternalFrame("Debugger Console"); 1427 consoleFrame.setResizable(true); 1428 consoleFrame.setClosable(true); 1429 consoleFrame.setIconifiable(true); 1430 consoleFrame.getContentPane().setLayout(new BorderLayout()); 1431 consoleFrame.getContentPane().add(new DebuggerConsolePanel(agent.getDebugger()), BorderLayout.CENTER); 1432 GraphicsUtilities.reshapeToAspectRatio(consoleFrame, 5.0f, 0.9f, desktop.getSize()); 1433 } 1434 if (consoleFrame.getParent() == null) { 1435 desktop.add(consoleFrame); 1436 } 1437 consoleFrame.setVisible(true); 1438 consoleFrame.show(); 1439 consoleFrame.getContentPane().getComponent(0).requestFocus(); 1440 } 1441 1442 private void showConsole() { 1443 CommandProcessor.DebuggerInterface di = new CommandProcessor.DebuggerInterface() { 1444 public HotSpotAgent getAgent() { 1445 return agent; 1446 } 1447 public boolean isAttached() { 1448 return attached; 1449 } 1450 public void attach(String pid) { 1451 attach(pid); 1452 } 1453 public void attach(String java, String core) { 1454 } 1455 public void detach() { 1456 detachDebugger(); 1457 } 1458 public void reattach() { 1459 if (attached) { 1460 detachDebugger(); 1461 } 1462 if (pidText != null) { 1463 attach(pidText); 1464 } else { 1465 attach(execPath, coreFilename); 1466 } 1467 } 1468 }; 1469 1470 showPanel("Command Line", new CommandProcessorPanel(new CommandProcessor(di, null, null, null))); 1471 } 1472 1473 private void showFindByQueryPanel() { 1474 showPanel("Find Object by Query", new FindByQueryPanel()); 1475 } 1476 1477 private void showFindPanel() { 1478 showPanel("Find Pointer", new FindPanel()); 1479 } 1480 1481 private void showFindInHeapPanel() { 1482 showPanel("Find Address In Heap", new FindInHeapPanel()); 1483 } 1484 1485 private void showFindInCodeCachePanel() { 1486 showPanel("Find Address In Code Cache", new FindInCodeCachePanel()); 1487 } 1488 1489 private void showHeapParametersPanel() { 1490 showPanel("Heap Parameters", new HeapParametersPanel()); 1491 } 1492 1493 public void showThreadInfo(final JavaThread thread) { 1494 showPanel("Info for " + thread.getThreadName(), new ThreadInfoPanel(thread)); 1495 } 1496 1497 public void showJavaStackTrace(final JavaThread thread) { 1498 JavaStackTracePanel jstp = new JavaStackTracePanel(); 1499 showPanel("Java stack trace for " + thread.getThreadName(), jstp); 1500 jstp.setJavaThread(thread); 1501 } 1502 1503 private void showDeadlockDetectionPanel() { 1504 showPanel("Deadlock Detection", new DeadlockDetectionPanel()); 1505 } 1506 1507 private void showMonitorCacheDumpPanel() { 1508 showPanel("Monitor Cache Dump", new MonitorCacheDumpPanel()); 1509 } 1510 1511 public void showClassBrowser() { 1512 final JInternalFrame progressFrame = new JInternalFrame("Class Browser"); 1513 progressFrame.setResizable(true); 1514 progressFrame.setClosable(true); 1515 progressFrame.setIconifiable(true); 1516 progressFrame.getContentPane().setLayout(new BorderLayout()); 1517 final ProgressBarPanel bar = new ProgressBarPanel("Generating class list .."); 1518 bar.setIndeterminate(true); 1519 progressFrame.getContentPane().add(bar, BorderLayout.CENTER); 1520 desktop.add(progressFrame); 1521 progressFrame.pack(); 1522 GraphicsUtilities.centerInContainer(progressFrame); 1523 progressFrame.show(); 1524 1525 workerThread.invokeLater(new Runnable() { 1526 public void run() { 1527 HTMLGenerator htmlGen = new HTMLGenerator(); 1528 InstanceKlass[] klasses = SystemDictionaryHelper.getAllInstanceKlasses(); 1529 final String htmlText = htmlGen.genHTMLForKlassNames(klasses); 1530 SwingUtilities.invokeLater(new Runnable() { 1531 public void run() { 1532 JInternalFrame cbFrame = new JInternalFrame("Class Browser"); 1533 cbFrame.getContentPane().setLayout(new BorderLayout()); 1534 cbFrame.setResizable(true); 1535 cbFrame.setClosable(true); 1536 cbFrame.setIconifiable(true); 1537 ClassBrowserPanel cbPanel = new ClassBrowserPanel(); 1538 cbFrame.getContentPane().add(cbPanel, BorderLayout.CENTER); 1539 desktop.remove(progressFrame); 1540 desktop.repaint(); 1541 desktop.add(cbFrame); 1542 GraphicsUtilities.reshapeToAspectRatio(cbFrame, 1.25f, 0.85f, 1543 cbFrame.getParent().getSize()); 1544 cbFrame.show(); 1545 cbPanel.setClassesText(htmlText); 1546 } 1547 }); 1548 } 1549 }); 1550 } 1551 1552 public void showCodeViewer() { 1553 showPanel("Code Viewer", new CodeViewerPanel(), 1.25f, 0.85f); 1554 } 1555 1556 public void showCodeViewer(final Address address) { 1557 final CodeViewerPanel panel = new CodeViewerPanel(); 1558 showPanel("Code Viewer", panel, 1.25f, 0.85f); 1559 SwingUtilities.invokeLater(new Runnable() { 1560 public void run() { 1561 panel.viewAddress(address); 1562 } 1563 }); 1564 1565 } 1566 1567 public void showMemoryViewer() { 1568 showPanel("Memory Viewer", new MemoryViewer(agent.getDebugger(), agent.getTypeDataBase().getAddressSize() == 8)); 1569 } 1570 1571 public void showCommandLineFlags() { 1572 showPanel("Command Line Flags", new VMFlagsPanel()); 1573 } 1574 1575 public void showVMVersion() { 1576 showPanel("VM Version Info", new VMVersionInfoPanel()); 1577 } 1578 1579 public void showSystemProperties() { 1580 showPanel("System Properties", new SysPropsPanel()); 1581 } 1582 1583 private void showPanel(String name, JPanel panel) { 1584 showPanel(name, panel, 5.0f / 3.0f, 0.4f); 1585 } 1586 1587 private void showPanel(String name, JPanel panel, float aspectRatio, float fillRatio) { 1588 JInternalFrame frame = new JInternalFrame(name); 1589 frame.getContentPane().setLayout(new BorderLayout()); 1590 frame.setResizable(true); 1591 frame.setClosable(true); 1592 frame.setIconifiable(true); 1593 frame.setMaximizable(true); 1594 frame.getContentPane().add(panel, BorderLayout.CENTER); 1595 desktop.add(frame); 1596 GraphicsUtilities.reshapeToAspectRatio(frame, aspectRatio, fillRatio, frame.getParent().getSize()); 1597 GraphicsUtilities.randomLocation(frame); 1598 frame.show(); 1599 if (panel instanceof SAPanel) { 1600 ((SAPanel)panel).addPanelListener(this); 1601 } 1602 } 1603 1604 //-------------------------------------------------------------------------------- 1605 // Framework for heap iteration with progress bar 1606 // 1607 1608 interface CleanupThunk { 1609 public void heapIterationComplete(); 1610 } 1611 1612 class HeapProgress implements HeapProgressThunk { 1613 private JInternalFrame frame; 1614 private ProgressBarPanel bar; 1615 private String windowTitle; 1616 private String progressBarTitle; 1617 private CleanupThunk cleanup; 1618 1619 HeapProgress(String windowTitle) { 1620 this(windowTitle, "Percentage of heap visited", null); 1621 } 1622 1623 HeapProgress(String windowTitle, String progressBarTitle) { 1624 this(windowTitle, progressBarTitle, null); 1625 } 1626 1627 HeapProgress(String windowTitle, String progressBarTitle, CleanupThunk cleanup) { 1628 this.windowTitle = windowTitle; 1629 this.progressBarTitle = progressBarTitle; 1630 this.cleanup = cleanup; 1631 } 1632 1633 public void heapIterationFractionUpdate(final double fractionOfHeapVisited) { 1634 if (frame == null) { 1635 SwingUtilities.invokeLater(new Runnable() { 1636 public void run() { 1637 frame = new JInternalFrame(windowTitle); 1638 frame.setResizable(true); 1639 frame.setIconifiable(true); 1640 frame.getContentPane().setLayout(new BorderLayout()); 1641 bar = new ProgressBarPanel(progressBarTitle); 1642 frame.getContentPane().add(bar, BorderLayout.CENTER); 1643 desktop.add(frame); 1644 frame.pack(); 1645 GraphicsUtilities.constrainToSize(frame, frame.getParent().getSize()); 1646 GraphicsUtilities.centerInContainer(frame); 1647 frame.show(); 1648 } 1649 }); 1650 } 1651 1652 SwingUtilities.invokeLater(new Runnable() { 1653 public void run() { 1654 bar.setValue(fractionOfHeapVisited); 1655 } 1656 }); 1657 } 1658 1659 public void heapIterationComplete() { 1660 SwingUtilities.invokeLater(new Runnable() { 1661 public void run() { 1662 desktop.remove(frame); 1663 desktop.repaint(); 1664 if (VM.getVM().getRevPtrs() != null) { 1665 // Ended up computing reverse pointers as a side-effect 1666 computeRevPtrsMenuItem.setEnabled(false); 1667 } 1668 } 1669 }); 1670 1671 if (cleanup != null) { 1672 cleanup.heapIterationComplete(); 1673 } 1674 } 1675 } 1676 1677 class VisitHeap implements Runnable { 1678 HeapVisitor visitor; 1679 1680 VisitHeap(HeapVisitor visitor) { 1681 this.visitor = visitor; 1682 } 1683 1684 public void run() { 1685 VM.getVM().getObjectHeap().iterate(visitor); 1686 } 1687 } 1688 1689 private void doHeapIteration(String frameTitle, 1690 String progressBarText, 1691 HeapVisitor visitor, 1692 CleanupThunk cleanup) { 1693 sun.jvm.hotspot.oops.ObjectHistogram histo = new sun.jvm.hotspot.oops.ObjectHistogram(); 1694 HeapProgress progress = new HeapProgress(frameTitle, 1695 progressBarText, 1696 cleanup); 1697 HeapVisitor progVisitor = new ProgressiveHeapVisitor(visitor, progress); 1698 workerThread.invokeLater(new VisitHeap(progVisitor)); 1699 } 1700 1701 //-------------------------------------------------------------------------------- 1702 // Stack trace helper 1703 // 1704 1705 private static JavaVFrame getLastJavaVFrame(JavaThread cur) { 1706 RegisterMap regMap = cur.newRegisterMap(true); 1707 sun.jvm.hotspot.runtime.Frame f = cur.getCurrentFrameGuess(); 1708 if (f == null) return null; 1709 boolean imprecise = true; 1710 if (f.isInterpretedFrame() && !f.isInterpretedFrameValid()) { 1711 System.err.println("Correcting for invalid interpreter frame"); 1712 f = f.sender(regMap); 1713 imprecise = false; 1714 } 1715 VFrame vf = VFrame.newVFrame(f, regMap, cur, true, imprecise); 1716 if (vf == null) { 1717 System.err.println(" (Unable to create vframe for topmost frame guess)"); 1718 return null; 1719 } 1720 if (vf.isJavaFrame()) { 1721 return (JavaVFrame) vf; 1722 } 1723 return (JavaVFrame) vf.javaSender(); 1724 } 1725 1726 // Internal routine for debugging 1727 private static void dumpStack(JavaThread cur) { 1728 RegisterMap regMap = cur.newRegisterMap(true); 1729 sun.jvm.hotspot.runtime.Frame f = cur.getCurrentFrameGuess(); 1730 PrintStream tty = System.err; 1731 while (f != null) { 1732 tty.print("Found "); 1733 if (f.isInterpretedFrame()) { tty.print("interpreted"); } 1734 else if (f.isCompiledFrame()) { tty.print("compiled"); } 1735 else if (f.isEntryFrame()) { tty.print("entry"); } 1736 else if (f.isNativeFrame()) { tty.print("native"); } 1737 else if (f.isGlueFrame()) { tty.print("glue"); } 1738 else { tty.print("external"); } 1739 tty.print(" frame with PC = " + f.getPC() + ", SP = " + f.getSP() + ", FP = " + f.getFP()); 1740 if (f.isSignalHandlerFrameDbg()) { 1741 tty.print(" (SIGNAL HANDLER)"); 1742 } 1743 tty.println(); 1744 1745 if (!f.isFirstFrame()) { 1746 f = f.sender(regMap); 1747 } else { 1748 f = null; 1749 } 1750 } 1751 } 1752 1753 //-------------------------------------------------------------------------------- 1754 // Component utilities 1755 // 1756 1757 private static JMenuItem createMenuItem(String name, ActionListener l) { 1758 JMenuItem item = new JMenuItem(name); 1759 item.addActionListener(l); 1760 return item; 1761 } 1762 1763 /** Punctuates the given string with \n's where necessary to not 1764 exceed the given number of characters per line. Strips 1765 extraneous whitespace. */ 1766 private String formatMessage(String message, int charsPerLine) { 1767 StringBuffer buf = new StringBuffer(message.length()); 1768 StringTokenizer tokenizer = new StringTokenizer(message); 1769 int curLineLength = 0; 1770 while (tokenizer.hasMoreTokens()) { 1771 String tok = tokenizer.nextToken(); 1772 if (curLineLength + tok.length() > charsPerLine) { 1773 buf.append('\n'); 1774 curLineLength = 0; 1775 } else { 1776 if (curLineLength != 0) { 1777 buf.append(' '); 1778 ++curLineLength; 1779 } 1780 } 1781 buf.append(tok); 1782 curLineLength += tok.length(); 1783 } 1784 return buf.toString(); 1785 } 1786 1787 private void setMenuItemsEnabled(java.util.List items, boolean enabled) { 1788 for (Iterator iter = items.iterator(); iter.hasNext(); ) { 1789 ((JMenuItem) iter.next()).setEnabled(enabled); 1790 } 1791 } 1792 }