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.debugger.cdbg.basic;
|
|
26
|
|
27 import java.util.*;
|
|
28 import sun.jvm.hotspot.debugger.*;
|
|
29 import sun.jvm.hotspot.debugger.cdbg.*;
|
|
30 import sun.jvm.hotspot.utilities.AddressOps;
|
|
31 import sun.jvm.hotspot.utilities.Assert;
|
|
32
|
|
33 public class BasicCDebugInfoDataBase implements CDebugInfoDataBase {
|
|
34 private static final int INITIALIZED_STATE = 0;
|
|
35 private static final int CONSTRUCTION_STATE = 1;
|
|
36 private static final int RESOLVED_STATE = 2;
|
|
37 private static final int COMPLETE_STATE = 3;
|
|
38
|
|
39 private int state = INITIALIZED_STATE;
|
|
40
|
|
41 ///////////
|
|
42 // Types //
|
|
43 ///////////
|
|
44
|
|
45 // Used only during construction
|
|
46 private Map lazyTypeMap;
|
|
47
|
|
48 // Used during construction and at run time for iteration
|
|
49 private List types;
|
|
50
|
|
51 // Used only during runtime
|
|
52 private Map nameToTypeMap;
|
|
53
|
|
54 /////////////
|
|
55 // Symbols //
|
|
56 /////////////
|
|
57
|
|
58 // Used only during construction
|
|
59 private Map lazySymMap;
|
|
60
|
|
61 // List of blocks in increasing order by starting address. These can
|
|
62 // then be binary searched.
|
|
63 private List blocks;
|
|
64
|
|
65 // Name-to-global symbol table
|
|
66 private Map nameToSymMap;
|
|
67
|
|
68 //////////////////
|
|
69 // Line numbers //
|
|
70 //////////////////
|
|
71
|
|
72 private BasicLineNumberMapping lineNumbers;
|
|
73
|
|
74 /** Supports lazy instantiation and references between types and
|
|
75 symbols via insertion using arbitrary Object keys that are
|
|
76 wrapped by LazyTypes. Once the database has been fully
|
|
77 constructed and all types are present, one should call
|
|
78 resolveTypes(), which will resolve all LazyTypes down to
|
|
79 concrete types (and signal an error if some lazy types were
|
|
80 unresolved). */
|
|
81 public void beginConstruction() {
|
|
82 if (Assert.ASSERTS_ENABLED) {
|
|
83 Assert.that(state == INITIALIZED_STATE, "wrong state");
|
|
84 }
|
|
85 state = CONSTRUCTION_STATE;
|
|
86
|
|
87 // Types
|
|
88 lazyTypeMap = new HashMap();
|
|
89 types = new ArrayList();
|
|
90
|
|
91 // Symbols
|
|
92 lazySymMap = new HashMap();
|
|
93 blocks = new ArrayList();
|
|
94 nameToSymMap = new HashMap();
|
|
95
|
|
96 // Line numbers
|
|
97 lineNumbers = new BasicLineNumberMapping();
|
|
98 }
|
|
99
|
|
100 /** Add a type which may later in construction be referred to via a
|
|
101 LazyType with this key. lazyKey may be null. */
|
|
102 public void addType(Object lazyKey, Type type) {
|
|
103 if (Assert.ASSERTS_ENABLED) {
|
|
104 Assert.that(state == CONSTRUCTION_STATE, "wrong state");
|
|
105 }
|
|
106 if (lazyKey != null) {
|
|
107 if (lazyTypeMap.put(lazyKey, type) != null) {
|
|
108 throw new RuntimeException("Type redefined for lazy key " + lazyKey);
|
|
109 }
|
|
110 } else {
|
|
111 types.add(type);
|
|
112 }
|
|
113 }
|
|
114
|
|
115 public void resolve(ResolveListener listener) {
|
|
116 if (Assert.ASSERTS_ENABLED) {
|
|
117 Assert.that(state == CONSTRUCTION_STATE, "wrong state");
|
|
118 }
|
|
119 // Go through all types in lazyTypeMap and types.
|
|
120 // Resolve all LazyTypes.
|
|
121 resolveLazyMap(listener);
|
|
122 for (ListIterator iter = types.listIterator(); iter.hasNext(); ) {
|
|
123 BasicType t = (BasicType) iter.next();
|
|
124 BasicType t2 = (BasicType) t.resolveTypes(this, listener);
|
|
125 if (t != t2) {
|
|
126 iter.set(t2);
|
|
127 }
|
|
128 }
|
|
129 // Go through all symbols and resolve references to types and
|
|
130 // references to other symbols
|
|
131 for (Iterator iter = blocks.iterator(); iter.hasNext(); ) {
|
|
132 ((BasicSym) iter.next()).resolve(this, listener);
|
|
133 }
|
|
134 for (Iterator iter = nameToSymMap.values().iterator(); iter.hasNext(); ) {
|
|
135 ((BasicSym) iter.next()).resolve(this, listener);
|
|
136 }
|
|
137
|
|
138 // Sort blocks in ascending order of starting address (but do not
|
|
139 // change ordering among blocks with the same starting address)
|
|
140 Collections.sort(blocks, new Comparator() {
|
|
141 public int compare(Object o1, Object o2) {
|
|
142 BlockSym b1 = (BlockSym) o1;
|
|
143 BlockSym b2 = (BlockSym) o2;
|
|
144 Address a1 = b1.getAddress();
|
|
145 Address a2 = b2.getAddress();
|
|
146 if (AddressOps.lt(a1, a2)) { return -1; }
|
|
147 if (AddressOps.gt(a1, a2)) { return 1; }
|
|
148 return 0;
|
|
149 }
|
|
150 });
|
|
151
|
|
152 state = RESOLVED_STATE;
|
|
153 }
|
|
154
|
|
155 public void endConstruction() {
|
|
156 if (Assert.ASSERTS_ENABLED) {
|
|
157 Assert.that(state == RESOLVED_STATE, "wrong state");
|
|
158 }
|
|
159 // Move all types to type list
|
|
160 for (Iterator iter = lazyTypeMap.values().iterator(); iter.hasNext(); ) {
|
|
161 types.add(iter.next());
|
|
162 }
|
|
163 // Build name-to-type map
|
|
164 nameToTypeMap = new HashMap();
|
|
165 for (Iterator iter = types.iterator(); iter.hasNext(); ) {
|
|
166 Type t = (Type) iter.next();
|
|
167 if (!t.isConst() && !t.isVolatile()) {
|
|
168 nameToTypeMap.put(t.getName(), t);
|
|
169 }
|
|
170 }
|
|
171 // Lose lazy maps
|
|
172 lazyTypeMap = null;
|
|
173 lazySymMap = null;
|
|
174 // Sort and finish line number information
|
|
175 lineNumbers.sort();
|
|
176 // FIXME: on some platforms it might not be necessary to call
|
|
177 // recomputeEndPCs(). Will have to see what stabs information
|
|
178 // looks like. Should make configurable whether we make this call
|
|
179 // or not.
|
|
180 lineNumbers.recomputeEndPCs();
|
|
181
|
|
182 state = COMPLETE_STATE;
|
|
183 }
|
|
184
|
|
185 public Type lookupType(String name) {
|
|
186 return lookupType(name, 0);
|
|
187 }
|
|
188
|
|
189 public Type lookupType(String name, int cvAttributes) {
|
|
190 if (Assert.ASSERTS_ENABLED) {
|
|
191 Assert.that(state == COMPLETE_STATE, "wrong state");
|
|
192 }
|
|
193 BasicType t = (BasicType) nameToTypeMap.get(name);
|
|
194 if (t != null) {
|
|
195 if (cvAttributes != 0) {
|
|
196 t = (BasicType) t.getCVVariant(cvAttributes);
|
|
197 }
|
|
198 }
|
|
199 return t;
|
|
200 }
|
|
201
|
|
202 public void iterate(TypeVisitor v) {
|
|
203 if (Assert.ASSERTS_ENABLED) {
|
|
204 Assert.that(state == COMPLETE_STATE, "wrong state");
|
|
205 }
|
|
206 for (Iterator iter = types.iterator(); iter.hasNext(); ) {
|
|
207 BasicType t = (BasicType) iter.next();
|
|
208 t.visit(v);
|
|
209 }
|
|
210 }
|
|
211
|
|
212 /** Add a BlockSym to the debug information database. The given
|
|
213 BlockSym may be referred to by a LazyBlockSym wrapping the given
|
|
214 Object key, which must be non-null. Any references to other
|
|
215 blocks (for example, the parent scope) should be made with
|
|
216 LazyBlockSyms. These references will be resolved after the
|
|
217 database is built. */
|
|
218 public void addBlock(Object key, BlockSym block) {
|
|
219 if (Assert.ASSERTS_ENABLED) {
|
|
220 Assert.that(key != null, "key must be non-null");
|
|
221 }
|
|
222 lazySymMap.put(key, block);
|
|
223 blocks.add(block);
|
|
224 }
|
|
225
|
|
226 public void addGlobalSym(GlobalSym sym) {
|
|
227 nameToSymMap.put(sym.getName(), sym);
|
|
228 }
|
|
229
|
|
230 public BlockSym debugInfoForPC(Address pc) {
|
|
231 return searchBlocks(pc, 0, blocks.size() - 1);
|
|
232 }
|
|
233
|
|
234 public GlobalSym lookupSym(String name) {
|
|
235 return (GlobalSym) nameToSymMap.get(name);
|
|
236 }
|
|
237
|
|
238 public void addLineNumberInfo(BasicLineNumberInfo info) {
|
|
239 lineNumbers.addLineNumberInfo(info);
|
|
240 }
|
|
241
|
|
242 public LineNumberInfo lineNumberForPC(Address pc) throws DebuggerException {
|
|
243 return lineNumbers.lineNumberForPC(pc);
|
|
244 }
|
|
245
|
|
246 public void iterate(LineNumberVisitor v) {
|
|
247 lineNumbers.iterate(v);
|
|
248 }
|
|
249
|
|
250 //----------------------------------------------------------------------
|
|
251 // Internals only below this point
|
|
252 //
|
|
253
|
|
254 /** Intended only to be used by the BasicType implementation. */
|
|
255 public Type resolveType(Type containingType, Type targetType, ResolveListener listener, String detail) {
|
|
256 BasicType basicTargetType = (BasicType) targetType;
|
|
257 if (Assert.ASSERTS_ENABLED) {
|
|
258 Assert.that(state == CONSTRUCTION_STATE, "wrong state");
|
|
259 }
|
|
260 if (basicTargetType.isLazy()) {
|
|
261 BasicType resolved = (BasicType) lazyTypeMap.get(((LazyType) targetType).getKey());
|
|
262 // FIXME: would like to have an assert here that the target is
|
|
263 // non-null, but apparently have bugs here with forward
|
|
264 // references of pointer types
|
|
265 if (resolved == null) {
|
|
266 listener.resolveFailed(containingType, (LazyType) targetType, detail + " because target type was not found");
|
|
267 return targetType;
|
|
268 }
|
|
269 if (resolved.isLazy()) {
|
|
270 // Might happen for const/var variants for forward references
|
|
271 if (resolved.isConst() || resolved.isVolatile()) {
|
|
272 resolved = (BasicType) resolved.resolveTypes(this, listener);
|
|
273 }
|
|
274 if (resolved.isLazy()) {
|
|
275 listener.resolveFailed(containingType, (LazyType) targetType,
|
|
276 detail + " because target type (with key " +
|
|
277 ((Integer) ((LazyType) resolved).getKey()).intValue() +
|
|
278 (resolved.isConst() ? ", const" : ", not const") +
|
|
279 (resolved.isVolatile() ? ", volatile" : ", not volatile") +
|
|
280 ") was lazy");
|
|
281 }
|
|
282 }
|
|
283 return resolved;
|
|
284 }
|
|
285 return targetType;
|
|
286 }
|
|
287
|
|
288 /** Intended only to be usd by the BasicSym implementation. */
|
|
289 public Type resolveType(Sym containingSymbol, Type targetType, ResolveListener listener, String detail) {
|
|
290 BasicType basicTargetType = (BasicType) targetType;
|
|
291 if (Assert.ASSERTS_ENABLED) {
|
|
292 Assert.that(state == CONSTRUCTION_STATE, "wrong state");
|
|
293 }
|
|
294 if (basicTargetType.isLazy()) {
|
|
295 BasicType resolved = (BasicType) lazyTypeMap.get(((LazyType) targetType).getKey());
|
|
296 // FIXME: would like to have an assert here that the target is
|
|
297 // non-null, but apparently have bugs here
|
|
298 if (resolved == null) {
|
|
299 listener.resolveFailed(containingSymbol, (LazyType) targetType, detail);
|
|
300 return targetType;
|
|
301 }
|
|
302 if (resolved.isLazy()) {
|
|
303 // Might happen for const/var variants for forward references
|
|
304 if (resolved.isConst() || resolved.isVolatile()) {
|
|
305 resolved = (BasicType) resolved.resolveTypes(this, listener);
|
|
306 }
|
|
307 if (resolved.isLazy()) {
|
|
308 listener.resolveFailed(containingSymbol, (LazyType) targetType, detail);
|
|
309 }
|
|
310 }
|
|
311 return resolved;
|
|
312 }
|
|
313 return targetType;
|
|
314 }
|
|
315
|
|
316 /** Intended only to be usd by the BasicSym implementation. */
|
|
317 public Sym resolveSym(Sym containingSymbol, Sym targetSym, ResolveListener listener, String detail) {
|
|
318 if (targetSym == null) return null;
|
|
319 BasicSym basicTargetSym = (BasicSym) targetSym;
|
|
320 if (Assert.ASSERTS_ENABLED) {
|
|
321 Assert.that(state == CONSTRUCTION_STATE, "wrong state");
|
|
322 }
|
|
323 if (basicTargetSym.isLazy()) {
|
|
324 BasicSym resolved = (BasicSym) lazySymMap.get(((LazyBlockSym) targetSym).getKey());
|
|
325 // FIXME: would like to have an assert here that the target is
|
|
326 // non-null, but apparently have bugs here
|
|
327 if (resolved == null) {
|
|
328 listener.resolveFailed(containingSymbol, (LazyBlockSym) targetSym, detail);
|
|
329 return targetSym;
|
|
330 }
|
|
331 if (resolved.isLazy()) {
|
|
332 listener.resolveFailed(containingSymbol, (LazyBlockSym) targetSym, detail);
|
|
333 }
|
|
334 return resolved;
|
|
335 }
|
|
336 return targetSym;
|
|
337 }
|
|
338
|
|
339 private void resolveLazyMap(ResolveListener listener) {
|
|
340 for (Iterator iter = lazyTypeMap.entrySet().iterator(); iter.hasNext(); ) {
|
|
341 Map.Entry entry = (Map.Entry) iter.next();
|
|
342 BasicType t = (BasicType) entry.getValue();
|
|
343 BasicType t2 = (BasicType) t.resolveTypes(this, listener);
|
|
344 if (t2 != t) {
|
|
345 entry.setValue(t2);
|
|
346 }
|
|
347 }
|
|
348 }
|
|
349
|
|
350 /** Find the block whose starting address is closest to but less
|
|
351 than the given address. */
|
|
352 private BlockSym searchBlocks(Address addr, int lowIdx, int highIdx) {
|
|
353 if (highIdx < lowIdx) return null;
|
|
354 if ((lowIdx == highIdx) || (lowIdx == highIdx - 1)) {
|
|
355 // Base case: start with highIdx and walk backward. See whether
|
|
356 // addr is greater than any of the blocks' starting addresses,
|
|
357 // and if so, return that block.
|
|
358 Address lastAddr = null;
|
|
359 BlockSym ret = null;
|
|
360 for (int i = highIdx; i >= 0; --i) {
|
|
361 BlockSym block = (BlockSym) blocks.get(i);
|
|
362 if (AddressOps.lte(block.getAddress(), addr)) {
|
|
363 if ((lastAddr == null) || (AddressOps.equal(block.getAddress(), lastAddr))) {
|
|
364 lastAddr = block.getAddress();
|
|
365 ret = block;
|
|
366 } else {
|
|
367 break;
|
|
368 }
|
|
369 }
|
|
370 }
|
|
371 return ret;
|
|
372 }
|
|
373 int midIdx = (lowIdx + highIdx) >> 1;
|
|
374 BlockSym block = (BlockSym) blocks.get(midIdx);
|
|
375 // See address relationship
|
|
376 if (AddressOps.lte(block.getAddress(), addr)) {
|
|
377 // Always move search up
|
|
378 return searchBlocks(addr, midIdx, highIdx);
|
|
379 } else {
|
|
380 // Always move search down
|
|
381 return searchBlocks(addr, lowIdx, midIdx);
|
|
382 }
|
|
383 }
|
|
384 }
|