0
|
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 }
|