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