1 /* 2 * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 package sun.jvm.hotspot; 26 27 import java.io.*; 28 import java.awt.*; 29 import java.awt.event.*; 30 import javax.swing.*; 31 import java.util.*; 32 33 import sun.jvm.hotspot.code.*; 34 import sun.jvm.hotspot.compiler.*; 35 import sun.jvm.hotspot.debugger.*; 36 import sun.jvm.hotspot.gc.epsilon.*; 37 import sun.jvm.hotspot.gc.parallel.*; 38 import sun.jvm.hotspot.gc.shared.*; 39 import sun.jvm.hotspot.gc.shenandoah.*; 40 import sun.jvm.hotspot.gc.g1.*; 41 import sun.jvm.hotspot.gc.z.*; 42 import sun.jvm.hotspot.interpreter.*; 43 import sun.jvm.hotspot.memory.*; 44 import sun.jvm.hotspot.oops.*; 45 import sun.jvm.hotspot.runtime.*; 46 import sun.jvm.hotspot.ui.*; 47 import sun.jvm.hotspot.ui.tree.*; 48 import sun.jvm.hotspot.ui.classbrowser.*; 49 import sun.jvm.hotspot.utilities.*; 50 import sun.jvm.hotspot.utilities.Observable; 51 import sun.jvm.hotspot.utilities.Observer; 52 53 /** The top-level HotSpot Debugger. FIXME: make this an embeddable 54 component! (Among other things, figure out what to do with the 55 menu bar...) */ 56 57 public class HSDB implements ObjectHistogramPanel.Listener, SAListener { main(String[] args)58 public static void main(String[] args) { 59 new HSDB(args).run(); 60 } 61 62 //-------------------------------------------------------------------------------- 63 // Internals only below this point 64 // 65 private HotSpotAgent agent; 66 private JVMDebugger jvmDebugger; 67 private JDesktopPane desktop; 68 private boolean attached; 69 private boolean argError; 70 private JFrame frame; 71 private java.util.List<JMenuItem> attachMenuItems; 72 private java.util.List<JMenuItem> detachMenuItems; 73 private JMenu toolsMenu; 74 private JMenuItem showDbgConsoleMenuItem; 75 private JMenuItem computeRevPtrsMenuItem; 76 private JInternalFrame attachWaitDialog; 77 private JInternalFrame threadsFrame; 78 private JInternalFrame consoleFrame; 79 private WorkerThread workerThread; 80 // These had to be made data members because they are referenced in inner classes. 81 private String pidText; 82 private int pid; 83 private String execPath; 84 private String coreFilename; 85 doUsage()86 private void doUsage() { 87 System.out.println("Usage: java HSDB [[pid] | [path-to-java-executable [path-to-corefile]] | help ]"); 88 System.out.println(" pid: attach to the process whose id is 'pid'"); 89 System.out.println(" path-to-java-executable: Debug a core file produced by this program"); 90 System.out.println(" path-to-corefile: Debug this corefile. The default is 'core'"); 91 System.out.println(" If no arguments are specified, you can select what to do from the GUI.\n"); 92 HotSpotAgent.showUsage(); 93 argError = true; 94 } 95 HSDB(JVMDebugger d)96 public HSDB(JVMDebugger d) { 97 jvmDebugger = d; 98 } 99 HSDB(String[] args)100 private HSDB(String[] args) { 101 switch (args.length) { 102 case (0): 103 break; 104 105 case (1): 106 if (args[0].equals("help") || args[0].equals("-help")) { 107 doUsage(); 108 } 109 // If all numbers, it is a PID to attach to 110 // Else, it is a pathname to a .../bin/java for a core file. 111 try { 112 int unused = Integer.parseInt(args[0]); 113 // If we get here, we have a PID and not a core file name 114 pidText = args[0]; 115 } catch (NumberFormatException e) { 116 execPath = args[0]; 117 coreFilename = "core"; 118 } 119 break; 120 121 case (2): 122 execPath = args[0]; 123 coreFilename = args[1]; 124 break; 125 126 default: 127 System.out.println("HSDB Error: Too many options specified"); 128 doUsage(); 129 } 130 } 131 132 private class CloseUI extends WindowAdapter { 133 134 @Override windowClosing(WindowEvent e)135 public void windowClosing(WindowEvent e) { 136 workerThread.shutdown(); 137 frame.dispose(); 138 } 139 140 } 141 run()142 public void run() { 143 // Don't start the UI if there were bad arguments. 144 if (argError) { 145 return; 146 } 147 148 // Create frame first, to catch any GUI creation issues 149 // before we initialize agent 150 151 frame = new JFrame("HSDB - HotSpot Debugger"); 152 frame.setSize(800, 600); 153 frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); 154 frame.addWindowListener(new CloseUI()); 155 156 agent = new HotSpotAgent(); 157 workerThread = new WorkerThread(); 158 attachMenuItems = new java.util.ArrayList<>(); 159 detachMenuItems = new java.util.ArrayList<>(); 160 161 162 JMenuBar menuBar = new JMenuBar(); 163 164 // 165 // File menu 166 // 167 168 JMenu menu = new JMenu("File"); 169 menu.setMnemonic(KeyEvent.VK_F); 170 JMenuItem item; 171 item = createMenuItem("Attach to HotSpot process...", 172 new ActionListener() { 173 public void actionPerformed(ActionEvent e) { 174 showAttachDialog(); 175 } 176 }); 177 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.ALT_MASK)); 178 item.setMnemonic(KeyEvent.VK_A); 179 menu.add(item); 180 attachMenuItems.add(item); 181 182 item = createMenuItem("Open HotSpot core file...", 183 new ActionListener() { 184 public void actionPerformed(ActionEvent e) { 185 showOpenCoreFileDialog(); 186 } 187 }); 188 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.ALT_MASK)); 189 item.setMnemonic(KeyEvent.VK_O); 190 menu.add(item); 191 attachMenuItems.add(item); 192 193 item = createMenuItem("Connect to debug server...", 194 new ActionListener() { 195 public void actionPerformed(ActionEvent e) { 196 showConnectDialog(); 197 } 198 }); 199 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.ALT_MASK)); 200 item.setMnemonic(KeyEvent.VK_S); 201 menu.add(item); 202 attachMenuItems.add(item); 203 204 item = createMenuItem("Detach", 205 new ActionListener() { 206 public void actionPerformed(ActionEvent e) { 207 detach(); 208 } 209 }); 210 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, ActionEvent.ALT_MASK)); 211 item.setMnemonic(KeyEvent.VK_S); 212 menu.add(item); 213 detachMenuItems.add(item); 214 215 // Disable detach menu items at first 216 setMenuItemsEnabled(detachMenuItems, false); 217 218 menu.addSeparator(); 219 220 item = createMenuItem("Exit", 221 new ActionListener() { 222 public void actionPerformed(ActionEvent e) { 223 workerThread.shutdown(); 224 frame.dispose(); 225 } 226 }); 227 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.ALT_MASK)); 228 item.setMnemonic(KeyEvent.VK_X); 229 menu.add(item); 230 menuBar.add(menu); 231 232 // 233 // Tools menu 234 // 235 236 toolsMenu = new JMenu("Tools"); 237 toolsMenu.setMnemonic(KeyEvent.VK_T); 238 239 item = createMenuItem("Class Browser", 240 new ActionListener() { 241 public void actionPerformed(ActionEvent e) { 242 showClassBrowser(); 243 } 244 }); 245 item.setMnemonic(KeyEvent.VK_B); 246 247 toolsMenu.add(item); 248 249 item = createMenuItem("Code Viewer", 250 new ActionListener() { 251 public void actionPerformed(ActionEvent e) { 252 showCodeViewer(); 253 } 254 }); 255 item.setMnemonic(KeyEvent.VK_C); 256 257 toolsMenu.add(item); 258 259 260 item = createMenuItem("Compute Reverse Ptrs", 261 new ActionListener() { 262 public void actionPerformed(ActionEvent e) { 263 fireComputeReversePtrs(); 264 } 265 }); 266 computeRevPtrsMenuItem = item; 267 item.setMnemonic(KeyEvent.VK_M); 268 toolsMenu.add(item); 269 270 item = createMenuItem("Deadlock Detection", 271 new ActionListener() { 272 public void actionPerformed(ActionEvent e) { 273 showDeadlockDetectionPanel(); 274 } 275 }); 276 item.setMnemonic(KeyEvent.VK_D); 277 toolsMenu.add(item); 278 279 280 item = createMenuItem("Find Pointer", 281 new ActionListener() { 282 public void actionPerformed(ActionEvent e) { 283 showFindPanel(); 284 } 285 }); 286 item.setMnemonic(KeyEvent.VK_P); 287 toolsMenu.add(item); 288 289 item = createMenuItem("Find Value In Heap", 290 new ActionListener() { 291 public void actionPerformed(ActionEvent e) { 292 showFindInHeapPanel(); 293 } 294 }); 295 item.setMnemonic(KeyEvent.VK_V); 296 toolsMenu.add(item); 297 298 item = createMenuItem("Find Value In Code Cache", 299 new ActionListener() { 300 public void actionPerformed(ActionEvent e) { 301 showFindInCodeCachePanel(); 302 } 303 }); 304 item.setMnemonic(KeyEvent.VK_A); 305 toolsMenu.add(item); 306 307 item = createMenuItem("Heap Parameters", 308 new ActionListener() { 309 public void actionPerformed(ActionEvent e) { 310 showHeapParametersPanel(); 311 } 312 }); 313 item.setMnemonic(KeyEvent.VK_H); 314 toolsMenu.add(item); 315 316 item = createMenuItem("Inspector", 317 new ActionListener() { 318 public void actionPerformed(ActionEvent e) { 319 showInspector(null); 320 } 321 }); 322 item.setMnemonic(KeyEvent.VK_R); 323 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.ALT_MASK)); 324 toolsMenu.add(item); 325 326 item = createMenuItem("Memory Viewer", 327 new ActionListener() { 328 public void actionPerformed(ActionEvent e) { 329 showMemoryViewer(); 330 } 331 }); 332 item.setMnemonic(KeyEvent.VK_M); 333 toolsMenu.add(item); 334 335 item = createMenuItem("Monitor Cache Dump", 336 new ActionListener() { 337 public void actionPerformed(ActionEvent e) { 338 showMonitorCacheDumpPanel(); 339 } 340 }); 341 item.setMnemonic(KeyEvent.VK_D); 342 toolsMenu.add(item); 343 344 item = createMenuItem("Object Histogram", 345 new ActionListener() { 346 public void actionPerformed(ActionEvent e) { 347 showObjectHistogram(); 348 } 349 }); 350 item.setMnemonic(KeyEvent.VK_O); 351 toolsMenu.add(item); 352 353 item = createMenuItem("Show System Properties", 354 new ActionListener() { 355 public void actionPerformed(ActionEvent e) { 356 showSystemProperties(); 357 } 358 }); 359 item.setMnemonic(KeyEvent.VK_S); 360 toolsMenu.add(item); 361 362 item = createMenuItem("Show VM Version", 363 new ActionListener() { 364 public void actionPerformed(ActionEvent e) { 365 showVMVersion(); 366 } 367 }); 368 item.setMnemonic(KeyEvent.VK_M); 369 toolsMenu.add(item); 370 371 item = createMenuItem("Show -XX flags", 372 new ActionListener() { 373 public void actionPerformed(ActionEvent e) { 374 showCommandLineFlags(); 375 } 376 }); 377 item.setMnemonic(KeyEvent.VK_X); 378 toolsMenu.add(item); 379 380 toolsMenu.setEnabled(false); 381 menuBar.add(toolsMenu); 382 383 // 384 // Windows menu 385 // 386 387 JMenu windowsMenu = new JMenu("Windows"); 388 windowsMenu.setMnemonic(KeyEvent.VK_W); 389 item = createMenuItem("Console", 390 new ActionListener() { 391 public void actionPerformed(ActionEvent e) { 392 showConsole(); 393 } 394 }); 395 item.setMnemonic(KeyEvent.VK_C); 396 windowsMenu.add(item); 397 showDbgConsoleMenuItem = createMenuItem("Debugger Console", 398 new ActionListener() { 399 public void actionPerformed(ActionEvent e) { 400 showDebuggerConsole(); 401 } 402 }); 403 showDbgConsoleMenuItem.setMnemonic(KeyEvent.VK_D); 404 windowsMenu.add(showDbgConsoleMenuItem); 405 showDbgConsoleMenuItem.setEnabled(false); 406 407 menuBar.add(windowsMenu); 408 409 410 frame.setJMenuBar(menuBar); 411 412 desktop = new JDesktopPane(); 413 frame.getContentPane().add(desktop); 414 GraphicsUtilities.reshapeToAspectRatio(frame, 4.0f/3.0f, 0.75f, Toolkit.getDefaultToolkit().getScreenSize()); 415 GraphicsUtilities.centerInContainer(frame, Toolkit.getDefaultToolkit().getScreenSize()); 416 frame.setVisible(true); 417 418 Runtime.getRuntime().addShutdownHook(new java.lang.Thread() { 419 public void run() { 420 detachDebugger(); 421 } 422 }); 423 424 // If jvmDebugger is already set, we have been given a JVMDebugger. 425 // Otherwise, if pidText != null we are supposed to attach to it. 426 // Finally, if execPath != null, it is the path of a jdk/bin/java 427 // and coreFilename is the pathname of a core file we are 428 // supposed to attach to. 429 430 if (jvmDebugger != null) { 431 attach(jvmDebugger); 432 } else if (pidText != null) { 433 attach(pidText); 434 } else if (execPath != null) { 435 attach(execPath, coreFilename); 436 } 437 } 438 439 // FIXME: merge showAttachDialog, showOpenCoreFileDialog, showConnectDialog showAttachDialog()440 private void showAttachDialog() { 441 // FIXME: create filtered text field which only accepts numbers 442 setMenuItemsEnabled(attachMenuItems, false); 443 final JInternalFrame attachDialog = new JInternalFrame("Attach to HotSpot process"); 444 attachDialog.getContentPane().setLayout(new BorderLayout()); 445 446 JPanel panel = new JPanel(); 447 panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); 448 panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 449 attachDialog.setBackground(panel.getBackground()); 450 451 panel.add(new JLabel("Enter process ID:")); 452 final JTextField pidTextField = new JTextField(10); 453 ActionListener attacher = new ActionListener() { 454 public void actionPerformed(ActionEvent e) { 455 attachDialog.setVisible(false); 456 desktop.remove(attachDialog); 457 workerThread.invokeLater(new Runnable() { 458 public void run() { 459 attach(pidTextField.getText()); 460 } 461 }); 462 } 463 }; 464 465 pidTextField.addActionListener(attacher); 466 panel.add(pidTextField); 467 attachDialog.getContentPane().add(panel, BorderLayout.NORTH); 468 469 Box vbox = Box.createVerticalBox(); 470 panel = new JPanel(); 471 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 472 panel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); 473 JTextArea ta = new JTextArea( 474 "Enter the process ID of a currently-running HotSpot process. On " + 475 "most Unix operating systems, this can be determined by " + 476 "typing \"ps -u <your username> | grep java\"; the process ID is the " + 477 "first number which appears on the resulting line. On Windows, the " + 478 "process ID is present in the Task Manager, which can be brought up " + 479 "while logged on to the desktop by pressing Ctrl-Alt-Delete."); 480 ta.setLineWrap(true); 481 ta.setWrapStyleWord(true); 482 ta.setEditable(false); 483 ta.setBackground(panel.getBackground()); 484 panel.add(ta); 485 vbox.add(panel); 486 487 Box hbox = Box.createHorizontalBox(); 488 hbox.add(Box.createGlue()); 489 JButton button = new JButton("OK"); 490 button.addActionListener(attacher); 491 hbox.add(button); 492 hbox.add(Box.createHorizontalStrut(20)); 493 button = new JButton("Cancel"); 494 button.addActionListener(new ActionListener() { 495 public void actionPerformed(ActionEvent e) { 496 attachDialog.setVisible(false); 497 desktop.remove(attachDialog); 498 setMenuItemsEnabled(attachMenuItems, true); 499 } 500 }); 501 hbox.add(button); 502 hbox.add(Box.createGlue()); 503 panel = new JPanel(); 504 panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 505 panel.add(hbox); 506 vbox.add(panel); 507 508 attachDialog.getContentPane().add(vbox, BorderLayout.SOUTH); 509 510 desktop.add(attachDialog); 511 attachDialog.setSize(400, 300); 512 GraphicsUtilities.centerInContainer(attachDialog); 513 attachDialog.show(); 514 pidTextField.requestFocus(); 515 } 516 517 // FIXME: merge showAttachDialog, showOpenCoreFileDialog, showConnectDialog showOpenCoreFileDialog()518 private void showOpenCoreFileDialog() { 519 setMenuItemsEnabled(attachMenuItems, false); 520 final JInternalFrame dialog = new JInternalFrame("Open Core File"); 521 dialog.getContentPane().setLayout(new BorderLayout()); 522 523 JPanel panel = new JPanel(); 524 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 525 panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 526 dialog.setBackground(panel.getBackground()); 527 528 Box hbox = Box.createHorizontalBox(); 529 Box vbox = Box.createVerticalBox(); 530 vbox.add(new JLabel("Path to core file:")); 531 vbox.add(new JLabel("Path to Java executable:")); 532 hbox.add(vbox); 533 534 vbox = Box.createVerticalBox(); 535 final JTextField corePathField = new JTextField(40); 536 final JTextField execPathField = new JTextField(40); 537 vbox.add(corePathField); 538 vbox.add(execPathField); 539 hbox.add(vbox); 540 541 final JButton browseCorePath = new JButton("Browse .."); 542 final JButton browseExecPath = new JButton("Browse .."); 543 browseCorePath.addActionListener(new ActionListener() { 544 public void actionPerformed(ActionEvent e) { 545 JFileChooser fileChooser = new JFileChooser(new File(".")); 546 int retVal = fileChooser.showOpenDialog(dialog); 547 if (retVal == JFileChooser.APPROVE_OPTION) { 548 corePathField.setText(fileChooser.getSelectedFile().getPath()); 549 } 550 } 551 }); 552 browseExecPath.addActionListener(new ActionListener() { 553 public void actionPerformed(ActionEvent e) { 554 JFileChooser fileChooser = new JFileChooser(new File(".")); 555 int retVal = fileChooser.showOpenDialog(dialog); 556 if (retVal == JFileChooser.APPROVE_OPTION) { 557 execPathField.setText(fileChooser.getSelectedFile().getPath()); 558 } 559 } 560 }); 561 vbox = Box.createVerticalBox(); 562 vbox.add(browseCorePath); 563 vbox.add(browseExecPath); 564 hbox.add(vbox); 565 566 panel.add(hbox); 567 dialog.getContentPane().add(panel, BorderLayout.NORTH); 568 569 ActionListener attacher = new ActionListener() { 570 public void actionPerformed(ActionEvent e) { 571 dialog.setVisible(false); 572 desktop.remove(dialog); 573 workerThread.invokeLater(new Runnable() { 574 public void run() { 575 attach(execPathField.getText(), corePathField.getText()); 576 } 577 }); 578 } 579 }; 580 corePathField.addActionListener(attacher); 581 execPathField.addActionListener(attacher); 582 583 vbox = Box.createVerticalBox(); 584 panel = new JPanel(); 585 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 586 panel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); 587 JTextArea ta = new JTextArea( 588 "Enter the full path names to the core file from a HotSpot process " + 589 "and the Java executable from which it came. The latter is typically " + 590 "located in the JDK/JRE directory under the directory " + 591 "jre/bin/<arch>/native_threads."); 592 ta.setLineWrap(true); 593 ta.setWrapStyleWord(true); 594 ta.setEditable(false); 595 ta.setBackground(panel.getBackground()); 596 panel.add(ta); 597 vbox.add(panel); 598 599 hbox = Box.createHorizontalBox(); 600 hbox.add(Box.createGlue()); 601 JButton button = new JButton("OK"); 602 button.addActionListener(attacher); 603 hbox.add(button); 604 hbox.add(Box.createHorizontalStrut(20)); 605 button = new JButton("Cancel"); 606 button.addActionListener(new ActionListener() { 607 public void actionPerformed(ActionEvent e) { 608 dialog.setVisible(false); 609 desktop.remove(dialog); 610 setMenuItemsEnabled(attachMenuItems, true); 611 } 612 }); 613 hbox.add(button); 614 hbox.add(Box.createGlue()); 615 panel = new JPanel(); 616 panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 617 panel.add(hbox); 618 vbox.add(panel); 619 620 dialog.getContentPane().add(vbox, BorderLayout.SOUTH); 621 622 desktop.add(dialog); 623 dialog.setSize(500, 300); 624 GraphicsUtilities.centerInContainer(dialog); 625 dialog.show(); 626 corePathField.requestFocus(); 627 } 628 629 // FIXME: merge showAttachDialog, showOpenCoreFileDialog, showConnectDialog showConnectDialog()630 private void showConnectDialog() { 631 // FIXME: create filtered text field which only accepts numbers 632 setMenuItemsEnabled(attachMenuItems, false); 633 final JInternalFrame dialog = new JInternalFrame("Connect to HotSpot Debug Server"); 634 dialog.getContentPane().setLayout(new BorderLayout()); 635 636 JPanel panel = new JPanel(); 637 panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); 638 panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 639 dialog.setBackground(panel.getBackground()); 640 641 panel.add(new JLabel("Enter machine name:")); 642 final JTextField pidTextField = new JTextField(40); 643 ActionListener attacher = new ActionListener() { 644 public void actionPerformed(ActionEvent e) { 645 dialog.setVisible(false); 646 desktop.remove(dialog); 647 workerThread.invokeLater(new Runnable() { 648 public void run() { 649 connect(pidTextField.getText()); 650 } 651 }); 652 } 653 }; 654 655 pidTextField.addActionListener(attacher); 656 panel.add(pidTextField); 657 dialog.getContentPane().add(panel, BorderLayout.NORTH); 658 659 Box vbox = Box.createVerticalBox(); 660 panel = new JPanel(); 661 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 662 panel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); 663 JTextArea ta = new JTextArea( 664 "Enter the name of a machine on which the HotSpot \"Debug Server\" is " + 665 "running and is attached to a process or core file."); 666 ta.setLineWrap(true); 667 ta.setWrapStyleWord(true); 668 ta.setEditable(false); 669 ta.setBackground(panel.getBackground()); 670 panel.add(ta); 671 vbox.add(panel); 672 673 Box hbox = Box.createHorizontalBox(); 674 hbox.add(Box.createGlue()); 675 JButton button = new JButton("OK"); 676 button.addActionListener(attacher); 677 hbox.add(button); 678 hbox.add(Box.createHorizontalStrut(20)); 679 button = new JButton("Cancel"); 680 button.addActionListener(new ActionListener() { 681 public void actionPerformed(ActionEvent e) { 682 dialog.setVisible(false); 683 desktop.remove(dialog); 684 setMenuItemsEnabled(attachMenuItems, true); 685 } 686 }); 687 hbox.add(button); 688 hbox.add(Box.createGlue()); 689 panel = new JPanel(); 690 panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 691 panel.add(hbox); 692 vbox.add(panel); 693 694 dialog.getContentPane().add(vbox, BorderLayout.SOUTH); 695 696 desktop.add(dialog); 697 dialog.setSize(400, 300); 698 GraphicsUtilities.centerInContainer(dialog); 699 dialog.show(); 700 pidTextField.requestFocus(); 701 } 702 showThreadOopInspector(JavaThread thread)703 public void showThreadOopInspector(JavaThread thread) { 704 showInspector(new OopTreeNodeAdapter(thread.getThreadObj(), null)); 705 } 706 showInspector(SimpleTreeNode adapter)707 public void showInspector(SimpleTreeNode adapter) { 708 showPanel("Inspector", new Inspector(adapter), 1.0f, 0.65f); 709 } 710 showLiveness(Oop oop, LivenessPathList liveness)711 public void showLiveness(Oop oop, LivenessPathList liveness) { 712 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 713 PrintStream tty = new PrintStream(bos); 714 int numPaths = liveness.size(); 715 for (int i = 0; i < numPaths; i++) { 716 tty.println("Path " + (i + 1) + " of " + numPaths + ":"); 717 liveness.get(i).printOn(tty); 718 } 719 JTextArea ta = new JTextArea(bos.toString()); 720 ta.setLineWrap(true); 721 ta.setWrapStyleWord(true); 722 ta.setEditable(false); 723 724 JPanel panel = new JPanel(); 725 panel.setLayout(new BorderLayout()); 726 727 JScrollPane scroller = new JScrollPane(); 728 scroller.getViewport().add(ta); 729 730 panel.add(scroller, BorderLayout.CENTER); 731 732 bos = new ByteArrayOutputStream(); 733 tty = new PrintStream(bos); 734 tty.print("Liveness result for "); 735 Oop.printOopValueOn(oop, tty); 736 737 JInternalFrame frame = new JInternalFrame(bos.toString()); 738 frame.setResizable(true); 739 frame.setClosable(true); 740 frame.setIconifiable(true); 741 frame.getContentPane().setLayout(new BorderLayout()); 742 frame.getContentPane().add(panel, BorderLayout.CENTER); 743 frame.pack(); 744 desktop.add(frame); 745 GraphicsUtilities.reshapeToAspectRatio(frame, 0.5f / 0.2f, 0.5f, frame.getParent().getSize()); 746 frame.show(); 747 } 748 fireComputeReversePtrs()749 private void fireComputeReversePtrs() { 750 // Possible this might have been computed elsewhere 751 if (VM.getVM().getRevPtrs() != null) { 752 computeRevPtrsMenuItem.setEnabled(false); 753 return; 754 } 755 756 workerThread.invokeLater(new Runnable() { 757 public void run() { 758 HeapProgress progress = new HeapProgress("Reverse Pointers Analysis"); 759 try { 760 ReversePtrsAnalysis analysis = new ReversePtrsAnalysis(); 761 analysis.setHeapProgressThunk(progress); 762 analysis.run(); 763 computeRevPtrsMenuItem.setEnabled(false); 764 } catch (OutOfMemoryError e) { 765 final String errMsg = formatMessage(e.toString(), 80); 766 SwingUtilities.invokeLater(new Runnable() { 767 public void run() { 768 JOptionPane.showInternalMessageDialog(desktop, 769 "Error computing reverse pointers:" + errMsg, 770 "Error", 771 JOptionPane.WARNING_MESSAGE); 772 } 773 }); 774 } finally { 775 // make sure the progress bar goes away 776 progress.heapIterationComplete(); 777 } 778 } 779 }); 780 } 781 782 // Simple struct containing signal information 783 class SignalInfo { 784 public int sigNum; 785 public String sigName; 786 } 787 788 // Need to have mutable vframe as well as visible memory panel 789 abstract class StackWalker implements Runnable { 790 protected JavaVFrame vf; 791 protected AnnotatedMemoryPanel annoPanel; 792 StackWalker(JavaVFrame vf, AnnotatedMemoryPanel annoPanel)793 StackWalker(JavaVFrame vf, AnnotatedMemoryPanel annoPanel) { 794 this.vf = vf; 795 this.annoPanel = annoPanel; 796 } 797 } 798 showThreadStackMemory(final JavaThread thread)799 public void showThreadStackMemory(final JavaThread thread) { 800 // dumpStack(thread); 801 JavaVFrame vframe = getLastJavaVFrame(thread); 802 if (vframe == null) { 803 JOptionPane.showInternalMessageDialog(desktop, 804 "Thread \"" + thread.getThreadName() + 805 "\" has no Java frames on its stack", 806 "Show Stack Memory", 807 JOptionPane.INFORMATION_MESSAGE); 808 return; 809 } 810 811 JInternalFrame stackFrame = new JInternalFrame("Stack Memory for " + thread.getThreadName()); 812 stackFrame.getContentPane().setLayout(new BorderLayout()); 813 stackFrame.setResizable(true); 814 stackFrame.setClosable(true); 815 stackFrame.setIconifiable(true); 816 final long addressSize = agent.getTypeDataBase().getAddressSize(); 817 boolean is64Bit = (addressSize == 8); 818 // This is somewhat of a hack to guess a thread's stack limits since the 819 // JavaThread doesn't support this functionality. However it is nice in that 820 // it locks us into the active region of the thread's stack and not its 821 // theoretical limits. 822 // 823 sun.jvm.hotspot.runtime.Frame tmpFrame = thread.getCurrentFrameGuess(); 824 Address sp = tmpFrame.getSP(); 825 Address starting = sp; 826 Address maxSP = starting; 827 Address minSP = starting; 828 RegisterMap tmpMap = thread.newRegisterMap(false); 829 while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) { 830 tmpFrame = tmpFrame.sender(tmpMap); 831 if (tmpFrame != null) { 832 sp = tmpFrame.getSP(); 833 if (sp != null) { 834 maxSP = AddressOps.max(maxSP, sp); 835 minSP = AddressOps.min(minSP, sp); 836 } 837 } 838 839 } 840 // It is useful to be able to see say +/- 8K on the current stack range 841 AnnotatedMemoryPanel annoMemPanel = new AnnotatedMemoryPanel(agent.getDebugger(), is64Bit, starting, 842 minSP.addOffsetTo(-8192), 843 maxSP.addOffsetTo( 8192)); 844 845 stackFrame.getContentPane().add(annoMemPanel, BorderLayout.CENTER); 846 desktop.add(stackFrame); 847 GraphicsUtilities.reshapeToAspectRatio(stackFrame, 4.0f / 3.0f, 0.85f, stackFrame.getParent().getSize()); 848 stackFrame.show(); 849 850 // Stackmap computation for interpreted frames is expensive; do 851 // all stackwalking work in another thread for better GUI 852 // responsiveness 853 workerThread.invokeLater(new StackWalker(vframe, annoMemPanel) { 854 public void run() { 855 Address startAddr = null; 856 857 // As this is a debugger, we want to provide potential crash 858 // information to the user, i.e., by marking signal handler frames 859 // on the stack. Since this system is currently targeted at 860 // annotating the Java frames (interpreted or compiled) on the 861 // stack and not, for example, "external" frames (note the current 862 // absence of a PC-to-symbol lookup mechanism at the Debugger 863 // level), we want to mark any Java frames which were interrupted 864 // by a signal. We do this by making two passes over the stack, 865 // one which finds signal handler frames and puts the parent 866 // frames in a table and one which finds Java frames and if they 867 // are in the table indicates that they were interrupted by a signal. 868 869 Map<sun.jvm.hotspot.runtime.Frame, SignalInfo> interruptedFrameMap = new HashMap<>(); 870 { 871 sun.jvm.hotspot.runtime.Frame tmpFrame = thread.getCurrentFrameGuess(); 872 RegisterMap tmpMap = thread.newRegisterMap(false); 873 while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) { 874 if (tmpFrame.isSignalHandlerFrameDbg()) { 875 // Add some information to the map that we can extract later 876 sun.jvm.hotspot.runtime.Frame interruptedFrame = tmpFrame.sender(tmpMap); 877 SignalInfo info = new SignalInfo(); 878 info.sigNum = tmpFrame.getSignalNumberDbg(); 879 info.sigName = tmpFrame.getSignalNameDbg(); 880 interruptedFrameMap.put(interruptedFrame, info); 881 } 882 tmpFrame = tmpFrame.sender(tmpMap); 883 } 884 } 885 886 while (vf != null) { 887 String anno = null; 888 JavaVFrame curVFrame = vf; 889 sun.jvm.hotspot.runtime.Frame curFrame = curVFrame.getFrame(); 890 Method interpreterFrameMethod = null; 891 892 if (curVFrame.isInterpretedFrame()) { 893 anno = "Interpreted frame"; 894 } else { 895 anno = "Compiled frame"; 896 if (curVFrame.isDeoptimized()) { 897 anno += " (deoptimized)"; 898 } 899 } 900 if (curVFrame.mayBeImpreciseDbg()) { 901 anno += "; information may be imprecise"; 902 } 903 904 if (curVFrame.isInterpretedFrame()) { 905 // Find the codelet 906 InterpreterCodelet codelet = VM.getVM().getInterpreter().getCodeletContaining(curFrame.getPC()); 907 String description = null; 908 if (codelet != null) { 909 description = codelet.getDescription(); 910 } 911 if (description == null) { 912 anno += "\n(Unknown interpreter codelet)"; 913 } else { 914 anno += "\nExecuting in codelet \"" + description + "\" at PC = " + curFrame.getPC(); 915 } 916 } else if (curVFrame.isCompiledFrame()) { 917 anno += "\nExecuting at PC = " + curFrame.getPC(); 918 } 919 920 if (startAddr == null) { 921 startAddr = curFrame.getSP(); 922 } 923 924 // FIXME: some compiled frames with empty oop map sets have been 925 // found (for example, Vector's inner Enumeration class, method 926 // "hasMoreElements"). Not sure yet why these cases are showing 927 // up -- should be possible (though unlikely) for safepoint code 928 // to patch the return instruction of these methods and then 929 // later attempt to get an oop map for that instruction. For 930 // now, we warn if we find such a method. 931 boolean shouldSkipOopMaps = false; 932 if (curVFrame.isCompiledFrame()) { 933 CodeBlob cb = VM.getVM().getCodeCache().findBlob(curFrame.getPC()); 934 ImmutableOopMapSet maps = cb.getOopMaps(); 935 if ((maps == null) || (maps.getCount() == 0)) { 936 shouldSkipOopMaps = true; 937 } 938 } 939 940 // Add signal information to annotation if necessary 941 SignalInfo sigInfo = (SignalInfo) interruptedFrameMap.get(curFrame); 942 if (sigInfo != null) { 943 // This frame took a signal and we need to report it. 944 anno = (anno + "\n*** INTERRUPTED BY SIGNAL " + Integer.toString(sigInfo.sigNum) + 945 " (" + sigInfo.sigName + ")"); 946 } 947 948 JavaVFrame nextVFrame = curVFrame; 949 sun.jvm.hotspot.runtime.Frame nextFrame = curFrame; 950 do { 951 curVFrame = nextVFrame; 952 curFrame = nextFrame; 953 954 try { 955 Method method = curVFrame.getMethod(); 956 if (interpreterFrameMethod == null && curVFrame.isInterpretedFrame()) { 957 interpreterFrameMethod = method; 958 } 959 int bci = curVFrame.getBCI(); 960 String lineNumberAnno = ""; 961 if (method.hasLineNumberTable()) { 962 if ((bci == DebugInformationRecorder.SYNCHRONIZATION_ENTRY_BCI) || 963 (bci >= 0 && bci < method.getCodeSize())) { 964 lineNumberAnno = ", line " + method.getLineNumberFromBCI(bci); 965 } else { 966 lineNumberAnno = " (INVALID BCI)"; 967 } 968 } 969 anno += "\n" + method.getMethodHolder().getName().asString() + "." + 970 method.getName().asString() + method.getSignature().asString() + 971 "\n@bci " + bci + lineNumberAnno; 972 } catch (Exception e) { 973 anno += "\n(ERROR while iterating vframes for frame " + curFrame + ")"; 974 } 975 976 nextVFrame = curVFrame.javaSender(); 977 if (nextVFrame != null) { 978 nextFrame = nextVFrame.getFrame(); 979 } 980 } while (nextVFrame != null && nextFrame.equals(curFrame)); 981 982 if (shouldSkipOopMaps) { 983 anno = anno + "\nNOTE: null or empty ImmutableOopMapSet found for this CodeBlob"; 984 } 985 986 if (curFrame.getFP() != null) { 987 annoPanel.addAnnotation(new Annotation(curFrame.getSP(), 988 curFrame.getFP(), 989 anno)); 990 } else { 991 // For C2, which has null frame pointers on x86/amd64/aarch64 992 CodeBlob cb = VM.getVM().getCodeCache().findBlob(curFrame.getPC()); 993 Address sp = curFrame.getSP(); 994 if (Assert.ASSERTS_ENABLED) { 995 Assert.that(cb.getFrameSize() > 0, "CodeBlob must have non-zero frame size"); 996 } 997 annoPanel.addAnnotation(new Annotation(sp, 998 sp.addOffsetTo(cb.getFrameSize()), 999 anno)); 1000 } 1001 1002 // Add interpreter frame annotations 1003 if (curFrame.isInterpretedFrame()) { 1004 annoPanel.addAnnotation(new Annotation(curFrame.addressOfInterpreterFrameExpressionStack(), 1005 curFrame.addressOfInterpreterFrameTOS(), 1006 "Interpreter expression stack")); 1007 Address monBegin = curFrame.interpreterFrameMonitorBegin().address(); 1008 Address monEnd = curFrame.interpreterFrameMonitorEnd().address(); 1009 if (!monBegin.equals(monEnd)) { 1010 annoPanel.addAnnotation(new Annotation(monBegin, monEnd, 1011 "BasicObjectLocks")); 1012 } 1013 if (interpreterFrameMethod != null) { 1014 // The offset is just to get the right stack slots highlighted in the output 1015 int offset = 1; 1016 annoPanel.addAnnotation(new Annotation(curFrame.addressOfInterpreterFrameLocal(offset), 1017 curFrame.addressOfInterpreterFrameLocal((int) interpreterFrameMethod.getMaxLocals() + offset), 1018 "Interpreter locals area for frame with SP = " + curFrame.getSP())); 1019 } 1020 String methodAnno = "Interpreter frame Method*"; 1021 if (interpreterFrameMethod == null) { 1022 methodAnno += " (BAD OOP)"; 1023 } 1024 Address a = curFrame.addressOfInterpreterFrameMethod(); 1025 annoPanel.addAnnotation(new Annotation(a, a.addOffsetTo(addressSize), methodAnno)); 1026 a = curFrame.addressOfInterpreterFrameCPCache(); 1027 annoPanel.addAnnotation(new Annotation(a, a.addOffsetTo(addressSize), "Interpreter constant pool cache")); 1028 } 1029 1030 RegisterMap rm = (RegisterMap) vf.getRegisterMap().clone(); 1031 if (!shouldSkipOopMaps) { 1032 try { 1033 curFrame.oopsDo(new AddressVisitor() { 1034 public void visitAddress(Address addr) { 1035 if (Assert.ASSERTS_ENABLED) { 1036 Assert.that(addr.andWithMask(VM.getVM().getAddressSize() - 1) == null, 1037 "Address " + addr + "should have been aligned"); 1038 } 1039 OopHandle handle = addr.getOopHandleAt(0); 1040 addAnnotation(addr, handle); 1041 } 1042 1043 public void visitCompOopAddress(Address addr) { 1044 if (Assert.ASSERTS_ENABLED) { 1045 Assert.that(addr.andWithMask(VM.getVM().getAddressSize() - 1) == null, 1046 "Address " + addr + "should have been aligned"); 1047 } 1048 OopHandle handle = addr.getCompOopHandleAt(0); 1049 addAnnotation(addr, handle); 1050 } 1051 1052 public void addAnnotation(Address addr, OopHandle handle) { 1053 // Check contents 1054 String anno = "null oop"; 1055 if (handle != null) { 1056 // Find location 1057 CollectedHeap collHeap = VM.getVM().getUniverse().heap(); 1058 boolean bad = true; 1059 anno = "BAD OOP"; 1060 if (collHeap instanceof GenCollectedHeap) { 1061 GenCollectedHeap heap = (GenCollectedHeap) collHeap; 1062 for (int i = 0; i < heap.nGens(); i++) { 1063 if (heap.getGen(i).isIn(handle)) { 1064 if (i == 0) { 1065 anno = "NewGen "; 1066 } else if (i == 1) { 1067 anno = "OldGen "; 1068 } else { 1069 anno = "Gen " + i + " "; 1070 } 1071 bad = false; 1072 break; 1073 } 1074 } 1075 1076 } else if (collHeap instanceof G1CollectedHeap) { 1077 G1CollectedHeap heap = (G1CollectedHeap)collHeap; 1078 HeapRegion region = heap.hrm().getByAddress(handle); 1079 1080 if (region.isFree()) { 1081 anno = "Free "; 1082 bad = false; 1083 } else if (region.isYoung()) { 1084 anno = "Young "; 1085 bad = false; 1086 } else if (region.isHumongous()) { 1087 anno = "Humongous "; 1088 bad = false; 1089 } else if (region.isPinned()) { 1090 anno = "Pinned "; 1091 bad = false; 1092 } else if (region.isOld()) { 1093 anno = "Old "; 1094 bad = false; 1095 } 1096 } else if (collHeap instanceof ParallelScavengeHeap) { 1097 ParallelScavengeHeap heap = (ParallelScavengeHeap) collHeap; 1098 if (heap.youngGen().isIn(handle)) { 1099 anno = "PSYoungGen "; 1100 bad = false; 1101 } else if (heap.oldGen().isIn(handle)) { 1102 anno = "PSOldGen "; 1103 bad = false; 1104 } 1105 } else if (collHeap instanceof EpsilonHeap) { 1106 anno = "Epsilon "; 1107 bad = false; 1108 } else if (collHeap instanceof ShenandoahHeap) { 1109 ShenandoahHeap heap = (ShenandoahHeap) collHeap; 1110 anno = "ShenandoahHeap "; 1111 bad = false; 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. attach(JVMDebugger d)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 */ attach(String pidText)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 */ attach(final String executablePath, final String corePath)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 */ connect(final String remoteMachineName)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 detachDebugger()1343 private void detachDebugger() { 1344 if (!attached) { 1345 return; 1346 } 1347 agent.detach(); 1348 attached = false; 1349 } 1350 detach()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 */ showThreadsDialog()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 showObjectHistogram()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 ObjectHistogramCleanupThunk(sun.jvm.hotspot.oops.ObjectHistogram histo)1409 ObjectHistogramCleanupThunk(sun.jvm.hotspot.oops.ObjectHistogram histo) { 1410 this.histo = histo; 1411 } 1412 heapIterationComplete()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 showObjectsOfType(Klass type)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 FindObjectByTypeCleanupThunk(FindObjectByType finder)1450 FindObjectByTypeCleanupThunk(FindObjectByType finder) { 1451 this.finder = finder; 1452 } 1453 heapIterationComplete()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 showDebuggerConsole()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 showConsole()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 showFindPanel()1525 private void showFindPanel() { 1526 showPanel("Find Pointer", new FindPanel()); 1527 } 1528 showFindInHeapPanel()1529 private void showFindInHeapPanel() { 1530 showPanel("Find Address In Heap", new FindInHeapPanel()); 1531 } 1532 showFindInCodeCachePanel()1533 private void showFindInCodeCachePanel() { 1534 showPanel("Find Address In Code Cache", new FindInCodeCachePanel()); 1535 } 1536 showHeapParametersPanel()1537 private void showHeapParametersPanel() { 1538 showPanel("Heap Parameters", new HeapParametersPanel()); 1539 } 1540 showThreadInfo(final JavaThread thread)1541 public void showThreadInfo(final JavaThread thread) { 1542 showPanel("Info for " + thread.getThreadName(), new ThreadInfoPanel(thread)); 1543 } 1544 showJavaStackTrace(final JavaThread thread)1545 public void showJavaStackTrace(final JavaThread thread) { 1546 JavaStackTracePanel jstp = new JavaStackTracePanel(); 1547 showPanel("Java stack trace for " + thread.getThreadName(), jstp); 1548 jstp.setJavaThread(thread); 1549 } 1550 showDeadlockDetectionPanel()1551 private void showDeadlockDetectionPanel() { 1552 showPanel("Deadlock Detection", new DeadlockDetectionPanel()); 1553 } 1554 showMonitorCacheDumpPanel()1555 private void showMonitorCacheDumpPanel() { 1556 showPanel("Monitor Cache Dump", new MonitorCacheDumpPanel()); 1557 } 1558 showClassBrowser()1559 public void showClassBrowser() { 1560 final JInternalFrame progressFrame = new JInternalFrame("Class Browser"); 1561 progressFrame.setResizable(true); 1562 progressFrame.setClosable(true); 1563 progressFrame.setIconifiable(true); 1564 progressFrame.getContentPane().setLayout(new BorderLayout()); 1565 final ProgressBarPanel bar = new ProgressBarPanel("Generating class list .."); 1566 bar.setIndeterminate(true); 1567 progressFrame.getContentPane().add(bar, BorderLayout.CENTER); 1568 desktop.add(progressFrame); 1569 progressFrame.pack(); 1570 GraphicsUtilities.centerInContainer(progressFrame); 1571 progressFrame.show(); 1572 1573 workerThread.invokeLater(new Runnable() { 1574 public void run() { 1575 HTMLGenerator htmlGen = new HTMLGenerator(); 1576 InstanceKlass[] klasses = SystemDictionaryHelper.getAllInstanceKlasses(); 1577 final String htmlText = htmlGen.genHTMLForKlassNames(klasses); 1578 SwingUtilities.invokeLater(new Runnable() { 1579 public void run() { 1580 JInternalFrame cbFrame = new JInternalFrame("Class Browser"); 1581 cbFrame.getContentPane().setLayout(new BorderLayout()); 1582 cbFrame.setResizable(true); 1583 cbFrame.setClosable(true); 1584 cbFrame.setIconifiable(true); 1585 ClassBrowserPanel cbPanel = new ClassBrowserPanel(); 1586 cbFrame.getContentPane().add(cbPanel, BorderLayout.CENTER); 1587 desktop.remove(progressFrame); 1588 desktop.repaint(); 1589 desktop.add(cbFrame); 1590 GraphicsUtilities.reshapeToAspectRatio(cbFrame, 1.25f, 0.85f, 1591 cbFrame.getParent().getSize()); 1592 cbFrame.show(); 1593 cbPanel.setClassesText(htmlText); 1594 } 1595 }); 1596 } 1597 }); 1598 } 1599 showCodeViewer()1600 public void showCodeViewer() { 1601 showPanel("Code Viewer", new CodeViewerPanel(), 1.25f, 0.85f); 1602 } 1603 showCodeViewer(final Address address)1604 public void showCodeViewer(final Address address) { 1605 final CodeViewerPanel panel = new CodeViewerPanel(); 1606 showPanel("Code Viewer", panel, 1.25f, 0.85f); 1607 SwingUtilities.invokeLater(new Runnable() { 1608 public void run() { 1609 panel.viewAddress(address); 1610 } 1611 }); 1612 1613 } 1614 showMemoryViewer()1615 public void showMemoryViewer() { 1616 showPanel("Memory Viewer", new MemoryViewer(agent.getDebugger(), agent.getTypeDataBase().getAddressSize() == 8)); 1617 } 1618 showCommandLineFlags()1619 public void showCommandLineFlags() { 1620 showPanel("Command Line Flags", new VMFlagsPanel()); 1621 } 1622 showVMVersion()1623 public void showVMVersion() { 1624 showPanel("VM Version Info", new VMVersionInfoPanel()); 1625 } 1626 showSystemProperties()1627 public void showSystemProperties() { 1628 showPanel("System Properties", new SysPropsPanel()); 1629 } 1630 showPanel(String name, JPanel panel)1631 private void showPanel(String name, JPanel panel) { 1632 showPanel(name, panel, 5.0f / 3.0f, 0.4f); 1633 } 1634 showPanel(String name, JPanel panel, float aspectRatio, float fillRatio)1635 private void showPanel(String name, JPanel panel, float aspectRatio, float fillRatio) { 1636 JInternalFrame frame = new JInternalFrame(name); 1637 frame.getContentPane().setLayout(new BorderLayout()); 1638 frame.setResizable(true); 1639 frame.setClosable(true); 1640 frame.setIconifiable(true); 1641 frame.setMaximizable(true); 1642 frame.getContentPane().add(panel, BorderLayout.CENTER); 1643 desktop.add(frame); 1644 GraphicsUtilities.reshapeToAspectRatio(frame, aspectRatio, fillRatio, frame.getParent().getSize()); 1645 GraphicsUtilities.randomLocation(frame); 1646 frame.show(); 1647 if (panel instanceof SAPanel) { 1648 ((SAPanel)panel).addPanelListener(this); 1649 } 1650 } 1651 1652 //-------------------------------------------------------------------------------- 1653 // Framework for heap iteration with progress bar 1654 // 1655 1656 interface CleanupThunk { heapIterationComplete()1657 public void heapIterationComplete(); 1658 } 1659 1660 class HeapProgress implements HeapProgressThunk { 1661 private JInternalFrame frame; 1662 private ProgressBarPanel bar; 1663 private String windowTitle; 1664 private String progressBarTitle; 1665 private CleanupThunk cleanup; 1666 HeapProgress(String windowTitle)1667 HeapProgress(String windowTitle) { 1668 this(windowTitle, "Percentage of heap visited", null); 1669 } 1670 HeapProgress(String windowTitle, String progressBarTitle)1671 HeapProgress(String windowTitle, String progressBarTitle) { 1672 this(windowTitle, progressBarTitle, null); 1673 } 1674 HeapProgress(String windowTitle, String progressBarTitle, CleanupThunk cleanup)1675 HeapProgress(String windowTitle, String progressBarTitle, CleanupThunk cleanup) { 1676 this.windowTitle = windowTitle; 1677 this.progressBarTitle = progressBarTitle; 1678 this.cleanup = cleanup; 1679 } 1680 heapIterationFractionUpdate(final double fractionOfHeapVisited)1681 public void heapIterationFractionUpdate(final double fractionOfHeapVisited) { 1682 if (frame == null) { 1683 SwingUtilities.invokeLater(new Runnable() { 1684 public void run() { 1685 frame = new JInternalFrame(windowTitle); 1686 frame.setResizable(true); 1687 frame.setIconifiable(true); 1688 frame.getContentPane().setLayout(new BorderLayout()); 1689 bar = new ProgressBarPanel(progressBarTitle); 1690 frame.getContentPane().add(bar, BorderLayout.CENTER); 1691 desktop.add(frame); 1692 frame.pack(); 1693 GraphicsUtilities.constrainToSize(frame, frame.getParent().getSize()); 1694 GraphicsUtilities.centerInContainer(frame); 1695 frame.show(); 1696 } 1697 }); 1698 } 1699 1700 SwingUtilities.invokeLater(new Runnable() { 1701 public void run() { 1702 bar.setValue(fractionOfHeapVisited); 1703 } 1704 }); 1705 } 1706 heapIterationComplete()1707 public void heapIterationComplete() { 1708 SwingUtilities.invokeLater(new Runnable() { 1709 public void run() { 1710 desktop.remove(frame); 1711 desktop.repaint(); 1712 if (VM.getVM().getRevPtrs() != null) { 1713 // Ended up computing reverse pointers as a side-effect 1714 computeRevPtrsMenuItem.setEnabled(false); 1715 } 1716 } 1717 }); 1718 1719 if (cleanup != null) { 1720 cleanup.heapIterationComplete(); 1721 } 1722 } 1723 } 1724 1725 class VisitHeap implements Runnable { 1726 HeapVisitor visitor; 1727 VisitHeap(HeapVisitor visitor)1728 VisitHeap(HeapVisitor visitor) { 1729 this.visitor = visitor; 1730 } 1731 run()1732 public void run() { 1733 VM.getVM().getObjectHeap().iterate(visitor); 1734 } 1735 } 1736 doHeapIteration(String frameTitle, String progressBarText, HeapVisitor visitor, CleanupThunk cleanup)1737 private void doHeapIteration(String frameTitle, 1738 String progressBarText, 1739 HeapVisitor visitor, 1740 CleanupThunk cleanup) { 1741 sun.jvm.hotspot.oops.ObjectHistogram histo = new sun.jvm.hotspot.oops.ObjectHistogram(); 1742 HeapProgress progress = new HeapProgress(frameTitle, 1743 progressBarText, 1744 cleanup); 1745 HeapVisitor progVisitor = new ProgressiveHeapVisitor(visitor, progress); 1746 workerThread.invokeLater(new VisitHeap(progVisitor)); 1747 } 1748 1749 //-------------------------------------------------------------------------------- 1750 // Stack trace helper 1751 // 1752 getLastJavaVFrame(JavaThread cur)1753 private static JavaVFrame getLastJavaVFrame(JavaThread cur) { 1754 RegisterMap regMap = cur.newRegisterMap(true); 1755 sun.jvm.hotspot.runtime.Frame f = cur.getCurrentFrameGuess(); 1756 if (f == null) return null; 1757 boolean imprecise = true; 1758 if (f.isInterpretedFrame() && !f.isInterpretedFrameValid()) { 1759 System.err.println("Correcting for invalid interpreter frame"); 1760 f = f.sender(regMap); 1761 imprecise = false; 1762 } 1763 VFrame vf = VFrame.newVFrame(f, regMap, cur, true, imprecise); 1764 if (vf == null) { 1765 System.err.println(" (Unable to create vframe for topmost frame guess)"); 1766 return null; 1767 } 1768 if (vf.isJavaFrame()) { 1769 return (JavaVFrame) vf; 1770 } 1771 return (JavaVFrame) vf.javaSender(); 1772 } 1773 1774 // Internal routine for debugging dumpStack(JavaThread cur)1775 private static void dumpStack(JavaThread cur) { 1776 RegisterMap regMap = cur.newRegisterMap(true); 1777 sun.jvm.hotspot.runtime.Frame f = cur.getCurrentFrameGuess(); 1778 PrintStream tty = System.err; 1779 while (f != null) { 1780 tty.print("Found "); 1781 if (f.isInterpretedFrame()) { tty.print("interpreted"); } 1782 else if (f.isCompiledFrame()) { tty.print("compiled"); } 1783 else if (f.isEntryFrame()) { tty.print("entry"); } 1784 else if (f.isNativeFrame()) { tty.print("native"); } 1785 else if (f.isRuntimeFrame()) { tty.print("runtime"); } 1786 else { tty.print("external"); } 1787 tty.print(" frame with PC = " + f.getPC() + ", SP = " + f.getSP() + ", FP = " + f.getFP()); 1788 if (f.isSignalHandlerFrameDbg()) { 1789 tty.print(" (SIGNAL HANDLER)"); 1790 } 1791 tty.println(); 1792 1793 if (!f.isFirstFrame()) { 1794 f = f.sender(regMap); 1795 } else { 1796 f = null; 1797 } 1798 } 1799 } 1800 1801 //-------------------------------------------------------------------------------- 1802 // Component utilities 1803 // 1804 createMenuItem(String name, ActionListener l)1805 private static JMenuItem createMenuItem(String name, ActionListener l) { 1806 JMenuItem item = new JMenuItem(name); 1807 item.addActionListener(l); 1808 return item; 1809 } 1810 1811 /** Punctuates the given string with \n's where necessary to not 1812 exceed the given number of characters per line. Strips 1813 extraneous whitespace. */ formatMessage(String message, int charsPerLine)1814 private String formatMessage(String message, int charsPerLine) { 1815 StringBuffer buf = new StringBuffer(message.length()); 1816 StringTokenizer tokenizer = new StringTokenizer(message); 1817 int curLineLength = 0; 1818 while (tokenizer.hasMoreTokens()) { 1819 String tok = tokenizer.nextToken(); 1820 if (curLineLength + tok.length() > charsPerLine) { 1821 buf.append('\n'); 1822 curLineLength = 0; 1823 } else { 1824 if (curLineLength != 0) { 1825 buf.append(' '); 1826 ++curLineLength; 1827 } 1828 } 1829 buf.append(tok); 1830 curLineLength += tok.length(); 1831 } 1832 return buf.toString(); 1833 } 1834 setMenuItemsEnabled(java.util.List<JMenuItem> items, boolean enabled)1835 private void setMenuItemsEnabled(java.util.List<JMenuItem> items, boolean enabled) { 1836 for (Iterator<JMenuItem> iter = items.iterator(); iter.hasNext(); ) { 1837 iter.next().setEnabled(enabled); 1838 } 1839 } 1840 } 1841