comparison agent/src/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCDebugInfoDataBase.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
comparison
equal deleted inserted replaced
-1:000000000000 0:a61af66fc99e
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 }