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