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