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