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