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