1 /* 2 * Copyright 2001 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 20 * CA 95054 USA or visit www.sun.com if you need additional information or 21 * have any questions. 22 * 23 */ 24 25 package sun.jvm.hotspot.bugspot; 26 27 import java.awt.*; 28 import java.awt.event.*; 29 import java.util.*; 30 import javax.swing.*; 31 import javax.swing.table.*; 32 33 import sun.jvm.hotspot.debugger.*; 34 import sun.jvm.hotspot.debugger.cdbg.*; 35 import sun.jvm.hotspot.runtime.*; 36 import sun.jvm.hotspot.ui.*; 37 38 // NOTE: this class was not placed in sun.jvm.hotspot.ui to prevent 39 // mixing components designed for C and C++ debugging with the ones 40 // that work with the core serviceability agent functionality (which 41 // does not require that the CDebugger interface be implemented). 42 43 /** The ThreadListPanel is used for C and C++ debugging and can 44 visualize all threads in the target process. The caller passes in 45 a CDebugger attached to the target process and can request that 46 JavaThreads' associations with these underlying threads be 47 displayed; this option is only valid when attached to a HotSpot 48 JVM and when the {@link sun.jvm.hotspot.runtime.VM} has been 49 initialized. */ 50 51 public class ThreadListPanel extends JPanel { 52 /** Listener which can be added to receive "Set Focus" events */ 53 public static interface Listener { 54 /** ThreadProxy will always be provided; JavaThread will only be 55 present if displayJavaThreads was specified in the constructor 56 for the panel and the thread was a JavaThread. */ 57 public void setFocus(ThreadProxy thread, JavaThread jthread); 58 } 59 60 static class ThreadInfo { 61 private ThreadProxy thread; 62 // Distinguish between PC == null and no top frame 63 private boolean gotPC; 64 private Address pc; 65 private String location; 66 private JavaThread javaThread; 67 private String javaThreadName; 68 69 public ThreadInfo(ThreadProxy thread, CDebugger dbg, JavaThread jthread) { 70 this.thread = thread; 71 this.location = "<unknown>"; 72 CFrame fr = dbg.topFrameForThread(thread); 73 if (fr != null) { 74 gotPC = true; 75 pc = fr.pc(); 76 PCFinder.Info info = PCFinder.findPC(pc, fr.loadObjectForPC(), dbg); 77 if (info.getName() != null) { 78 location = info.getName(); 79 if (info.getConfidence() == PCFinder.LOW_CONFIDENCE) { 80 location = location + " (?)"; 81 } 82 if (info.getOffset() < 0) { 83 location = location + " + 0x" + Long.toHexString(info.getOffset()); 84 } 85 } 86 } 87 if (jthread != null) { 88 javaThread = jthread; 89 javaThreadName = jthread.getThreadName(); 90 } 91 } 92 93 public ThreadProxy getThread() { return thread; } 94 public boolean hasPC() { return gotPC; } 95 public Address getPC() { return pc; } 96 public String getLocation() { return location; } 97 public boolean isJavaThread() { return (javaThread != null); } 98 public JavaThread getJavaThread() { return javaThread; } 99 public String getJavaThreadName() { return javaThreadName; } 100 } 101 102 // List<ThreadInfo> 103 private java.util.List threadList; 104 private JTable table; 105 private AbstractTableModel dataModel; 106 // List<Listener> 107 private java.util.List listeners; 108 109 /** Takes a CDebugger from which the thread list is queried. 110 displayJavaThreads must only be set to true if the debugger is 111 attached to a HotSpot JVM and if the VM has already been 112 initialized. */ 113 public ThreadListPanel(CDebugger dbg, final boolean displayJavaThreads) { 114 super(); 115 116 Map threadToJavaThreadMap = null; 117 if (displayJavaThreads) { 118 // Collect Java threads from virtual machine and insert them in 119 // table for later querying 120 threadToJavaThreadMap = new HashMap(); 121 Threads threads = VM.getVM().getThreads(); 122 for (JavaThread thr = threads.first(); thr != null; thr = thr.next()) { 123 threadToJavaThreadMap.put(thr.getThreadProxy(), thr); 124 } 125 } 126 127 java.util.List/*<ThreadProxy>*/ threads = dbg.getThreadList(); 128 threadList = new ArrayList(threads.size()); 129 for (Iterator iter = threads.iterator(); iter.hasNext(); ) { 130 ThreadProxy thr = (ThreadProxy) iter.next(); 131 JavaThread jthr = null; 132 if (displayJavaThreads) { 133 jthr = (JavaThread) threadToJavaThreadMap.get(thr); 134 } 135 threadList.add(new ThreadInfo(thr, dbg, jthr)); 136 } 137 138 // Thread ID, current PC, current symbol, Java Thread, [Java thread name] 139 dataModel = new AbstractTableModel() { 140 public int getColumnCount() { return (displayJavaThreads ? 5 : 3); } 141 public int getRowCount() { return threadList.size(); } 142 public String getColumnName(int col) { 143 switch (col) { 144 case 0: 145 return "Thread ID"; 146 case 1: 147 return "PC"; 148 case 2: 149 return "Location"; 150 case 3: 151 return "Java?"; 152 case 4: 153 return "Java Thread Name"; 154 default: 155 throw new RuntimeException("Index " + col + " out of bounds"); 156 } 157 } 158 public Object getValueAt(int row, int col) { 159 ThreadInfo info = (ThreadInfo) threadList.get(row); 160 161 switch (col) { 162 case 0: 163 return info.getThread(); 164 case 1: 165 { 166 if (info.hasPC()) { 167 return info.getPC(); 168 } 169 return "<no frames on stack>"; 170 } 171 case 2: 172 return info.getLocation(); 173 case 3: 174 if (info.isJavaThread()) { 175 return "Yes"; 176 } else { 177 return ""; 178 } 179 case 4: 180 if (info.isJavaThread()) { 181 return info.getJavaThreadName(); 182 } else { 183 return ""; 184 } 185 default: 186 throw new RuntimeException("Index (" + col + ", " + row + ") out of bounds"); 187 } 188 } 189 }; 190 191 // Build user interface 192 setLayout(new BorderLayout()); 193 table = new JTable(dataModel); 194 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 195 JTableHeader header = table.getTableHeader(); 196 header.setReorderingAllowed(false); 197 table.setRowSelectionAllowed(true); 198 table.setColumnSelectionAllowed(false); 199 JScrollPane scrollPane = new JScrollPane(table); 200 add(scrollPane, BorderLayout.CENTER); 201 if (threadList.size() > 0) { 202 table.setRowSelectionInterval(0, 0); 203 } 204 205 JButton button = new JButton("Set Focus"); 206 button.addActionListener(new ActionListener() { 207 public void actionPerformed(ActionEvent e) { 208 int i = table.getSelectedRow(); 209 if (i < 0) { 210 return; 211 } 212 ThreadInfo info = (ThreadInfo) threadList.get(i); 213 for (Iterator iter = listeners.iterator(); iter.hasNext(); ) { 214 ((Listener) iter.next()).setFocus(info.getThread(), info.getJavaThread()); 215 } 216 } 217 }); 218 JPanel focusPanel = new JPanel(); 219 focusPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0)); 220 focusPanel.setLayout(new BoxLayout(focusPanel, BoxLayout.Y_AXIS)); 221 focusPanel.add(Box.createGlue()); 222 focusPanel.add(button); 223 focusPanel.add(Box.createGlue()); 224 add(focusPanel, BorderLayout.EAST); 225 226 // FIXME: make listener model for the debugger so if the user 227 // specifies a mapfile for or path to a given DSO later we can 228 // update our state 229 } 230 231 public void addListener(Listener l) { 232 if (listeners == null) { 233 listeners = new ArrayList(); 234 } 235 listeners.add(l); 236 } 237 }