Mercurial > hg > truffle
annotate agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgCDebugInfoBuilder.java @ 1913:3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
Summary: Allow CONSTANT_InvokeDynamic nodes to have any number of extra operands.
Reviewed-by: twisti
author | jrose |
---|---|
date | Sat, 30 Oct 2010 13:08:23 -0700 |
parents | c18cbe5936b8 |
children |
rev | line source |
---|---|
0 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
2 * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
25 package sun.jvm.hotspot.debugger.windbg; | |
26 | |
27 import java.util.*; | |
28 | |
29 import sun.jvm.hotspot.debugger.*; | |
30 import sun.jvm.hotspot.debugger.win32.coff.*; | |
31 import sun.jvm.hotspot.debugger.cdbg.*; | |
32 import sun.jvm.hotspot.debugger.cdbg.basic.*; | |
33 import sun.jvm.hotspot.utilities.Assert; | |
34 | |
35 class WindbgCDebugInfoBuilder | |
36 implements DebugVC50SubsectionTypes, DebugVC50TypeLeafIndices, DebugVC50TypeEnums, DebugVC50SymbolTypes, DebugVC50MemberAttributes, CVAttributes, AccessControl { | |
37 private WindbgDebugger dbg; | |
38 private Address base; | |
39 | |
40 private DebugVC50 vc50; | |
41 private BasicCDebugInfoDataBase db; | |
42 private DebugVC50TypeIterator iter; | |
43 | |
44 private DebugVC50SymbolIterator symIter; | |
45 | |
46 // Logical->physical segment mapping | |
47 private COFFFile file; | |
48 private DebugVC50SSSegMap segMap; | |
49 | |
50 // Canonicalization of primitive types | |
51 private Map primIndexToTypeMap; | |
52 | |
53 // Global unnamed enumeration | |
54 // (FIXME: must figure out how to handle nested type descriptions) | |
55 private BasicEnumType unnamedEnum; | |
56 | |
57 private Stack blockStack; | |
58 private int endsToSkip; | |
59 | |
60 private static final int POINTER_SIZE = 4; | |
61 | |
62 WindbgCDebugInfoBuilder(WindbgDebugger dbg) { | |
63 this.dbg = dbg; | |
64 } | |
65 | |
66 CDebugInfoDataBase buildDataBase(String dllName, Address base) { | |
67 this.base = base; | |
68 file = COFFFileParser.getParser().parse(dllName); | |
69 vc50 = getDebugVC50(file); | |
70 | |
71 if (vc50 == null) return null; | |
72 | |
73 segMap = getSegMap(); | |
74 | |
75 primIndexToTypeMap = new HashMap(); | |
76 blockStack = new Stack(); | |
77 endsToSkip = 0; | |
78 | |
79 db = new BasicCDebugInfoDataBase(); | |
80 db.beginConstruction(); | |
81 | |
82 // Get global types and add them to the database | |
83 DebugVC50SSGlobalTypes types = getGlobalTypes(); | |
84 for (iter = types.getTypeIterator(); !iter.done(); iter.next()) { | |
85 while (!iter.typeStringDone()) { | |
86 switch (iter.typeStringLeaf()) { | |
87 case LF_MODIFIER: { | |
88 int idx = iter.getModifierIndex(); | |
89 BasicType target = getTypeByIndex(idx); | |
90 short windowsMods = iter.getModifierAttribute(); | |
91 short mods = 0; | |
92 if ((windowsMods & MODIFIER_CONST_MASK) != 0) mods |= CONST; | |
93 if ((windowsMods & MODIFIER_VOLATILE_MASK) != 0) mods |= VOLATILE; | |
94 putType(target.getCVVariant(mods)); | |
95 break; | |
96 } | |
97 case LF_POINTER: { | |
98 int idx = iter.getPointerType(); | |
99 BasicType target = getTypeByIndex(idx); | |
100 short windowsMods = iter.getModifierAttribute(); | |
101 short mods = 0; | |
102 if ((windowsMods & POINTER_CONST_MASK) != 0) mods |= CONST; | |
103 if ((windowsMods & POINTER_VOLATILE_MASK) != 0) mods |= VOLATILE; | |
104 BasicPointerType ptrType = new BasicPointerType(POINTER_SIZE, target); | |
105 if (mods != 0) { | |
106 ptrType = (BasicPointerType) ptrType.getCVVariant(mods); | |
107 } | |
108 | |
109 putType(ptrType); | |
110 break; | |
111 } | |
112 case LF_ARRAY: { | |
113 BasicType elemType = getTypeByIndex(iter.getArrayElementType()); | |
114 putType(new BasicArrayType(iter.getArrayName(), elemType, iter.getArrayLength())); | |
115 break; | |
116 } | |
117 case LF_CLASS: | |
118 case LF_STRUCTURE: { | |
119 CompoundTypeKind kind = ((iter.typeStringLeaf() == LF_CLASS) ? CompoundTypeKind.CLASS | |
120 : CompoundTypeKind.STRUCT); | |
121 BasicCompoundType type = new BasicCompoundType(iter.getClassName(), | |
122 iter.getClassSize(), | |
123 kind); | |
124 // Skip parsing of forward references to types | |
125 // FIXME: do we have to resolve these later? | |
126 if ((iter.getClassProperty() & PROPERTY_FWDREF) == 0) { | |
127 DebugVC50TypeIterator fieldIter = iter.getClassFieldListIterator(); | |
128 if (Assert.ASSERTS_ENABLED) { | |
129 Assert.that(fieldIter.typeStringLeaf() == LF_FIELDLIST, "Expected field list"); | |
130 } | |
131 boolean advance = false; | |
132 while (!fieldIter.typeStringDone()) { | |
133 advance = true; | |
134 switch (fieldIter.typeStringLeaf()) { | |
135 case LF_FIELDLIST: break; | |
136 case LF_BCLASS: { | |
137 int accessControl = memberAttributeToAccessControl(fieldIter.getBClassAttribute()); | |
138 Type baseType = getTypeByIndex(fieldIter.getBClassType()); | |
139 // FIXME: take offset into account | |
140 type.addBaseClass(new BasicBaseClass(accessControl, false, baseType)); | |
141 break; | |
142 } | |
143 case LF_VBCLASS: { | |
144 int accessControl = memberAttributeToAccessControl(fieldIter.getVBClassAttribute()); | |
145 Type baseType = getTypeByIndex(fieldIter.getVBClassBaseClassType()); | |
146 // FIXME: take offset and virtual base offset into account | |
147 type.addBaseClass(new BasicBaseClass(accessControl, true, baseType)); | |
148 break; | |
149 } | |
150 // I don't think we need to handle indirect virtual base | |
151 // classes since they should be handled indirectly through | |
152 // the modeling of the type hierarchy | |
153 case LF_IVBCLASS: break; | |
154 case LF_INDEX: { | |
155 fieldIter = fieldIter.getIndexIterator(); | |
156 advance = false; | |
157 break; | |
158 } | |
159 case LF_MEMBER: { | |
160 BasicField field = new BasicField(fieldIter.getMemberName(), | |
161 getTypeByIndex(fieldIter.getMemberType()), | |
162 memberAttributeToAccessControl(fieldIter.getMemberAttribute()), | |
163 false); | |
164 field.setOffset(fieldIter.getMemberOffset()); | |
165 type.addField(field); | |
166 break; | |
167 } | |
168 case LF_STMEMBER: { | |
169 BasicField field = new BasicField(fieldIter.getStaticName(), | |
170 getTypeByIndex(fieldIter.getStaticType()), | |
171 memberAttributeToAccessControl(fieldIter.getStaticAttribute()), | |
172 true); | |
173 // The field's address will be found during resolution | |
174 // of the debug info database | |
175 type.addField(field); | |
176 break; | |
177 } | |
178 // FIXME: handle methods | |
179 case LF_METHOD: break; | |
180 case LF_ONEMETHOD: break; | |
181 // FIXME: handle nested types | |
182 case LF_NESTTYPE: break; | |
183 case LF_NESTTYPEEX: break; | |
184 // NOTE: virtual functions not needed/handled yet for | |
185 // this debugging system (because we are not planning to | |
186 // handle calling methods in the target process at | |
187 // runtime) | |
188 case LF_VFUNCTAB: break; | |
189 case LF_FRIENDCLS: break; | |
190 case LF_VFUNCOFF: break; | |
191 case LF_MEMBERMODIFY: break; | |
192 case LF_PAD0: case LF_PAD1: case LF_PAD2: case LF_PAD3: | |
193 case LF_PAD4: case LF_PAD5: case LF_PAD6: case LF_PAD7: | |
194 case LF_PAD8: case LF_PAD9: case LF_PAD10: case LF_PAD11: | |
195 case LF_PAD12: case LF_PAD13: case LF_PAD14: case LF_PAD15: break; | |
196 default: System.err.println("WARNING: unexpected leaf index " + | |
197 fieldIter.typeStringLeaf() + | |
198 " in field list for type " + iter.getTypeIndex()); | |
199 } | |
200 if (advance) { | |
201 fieldIter.typeStringNext(); | |
202 } | |
203 } | |
204 } | |
205 putType(type); | |
206 break; | |
207 } | |
208 case LF_UNION: { | |
209 BasicCompoundType type = new BasicCompoundType(iter.getUnionName(), | |
210 iter.getUnionSize(), | |
211 CompoundTypeKind.UNION); | |
212 // Skip parsing of forward references to types | |
213 // FIXME: do we have to resolve these later? | |
214 if ((iter.getClassProperty() & PROPERTY_FWDREF) == 0) { | |
215 DebugVC50TypeIterator fieldIter = iter.getUnionFieldListIterator(); | |
216 if (Assert.ASSERTS_ENABLED) { | |
217 Assert.that(fieldIter.typeStringLeaf() == LF_FIELDLIST, "Expected field list"); | |
218 } | |
219 boolean advance = false; | |
220 while (!fieldIter.typeStringDone()) { | |
221 advance = true; | |
222 switch (fieldIter.typeStringLeaf()) { | |
223 case LF_FIELDLIST: break; | |
224 case LF_BCLASS: break; | |
225 case LF_VBCLASS: break; | |
226 case LF_IVBCLASS: break; | |
227 case LF_INDEX: { | |
228 fieldIter = fieldIter.getIndexIterator(); | |
229 advance = false; | |
230 break; | |
231 } | |
232 case LF_MEMBER: { | |
233 BasicField field = new BasicField(fieldIter.getMemberName(), | |
234 getTypeByIndex(fieldIter.getMemberType()), | |
235 memberAttributeToAccessControl(fieldIter.getMemberAttribute()), | |
236 false); | |
237 field.setOffset(fieldIter.getMemberOffset()); | |
238 type.addField(field); | |
239 break; | |
240 } | |
241 case LF_STMEMBER: { | |
242 System.err.println("WARNING: I didn't think unions could contain static fields..."); | |
243 BasicField field = new BasicField(fieldIter.getStaticName(), | |
244 getTypeByIndex(fieldIter.getStaticType()), | |
245 memberAttributeToAccessControl(fieldIter.getStaticAttribute()), | |
246 true); | |
247 // The field's address will be found during resolution | |
248 // of the debug info database | |
249 type.addField(field); | |
250 break; | |
251 } | |
252 case LF_METHOD: break; | |
253 case LF_ONEMETHOD: break; | |
254 // FIXME: handle nested types | |
255 case LF_NESTTYPE: break; | |
256 case LF_NESTTYPEEX: break; | |
257 case LF_VFUNCTAB: break; | |
258 case LF_FRIENDCLS: break; | |
259 case LF_VFUNCOFF: break; | |
260 case LF_MEMBERMODIFY: break; | |
261 case LF_PAD0: case LF_PAD1: case LF_PAD2: case LF_PAD3: | |
262 case LF_PAD4: case LF_PAD5: case LF_PAD6: case LF_PAD7: | |
263 case LF_PAD8: case LF_PAD9: case LF_PAD10: case LF_PAD11: | |
264 case LF_PAD12: case LF_PAD13: case LF_PAD14: case LF_PAD15: break; | |
265 | |
266 default: System.err.println("WARNING: unexpected leaf index " + | |
267 fieldIter.typeStringLeaf() + | |
268 " in field list for union of type " + iter.getTypeIndex()); | |
269 } | |
270 if (advance) { | |
271 fieldIter.typeStringNext(); | |
272 } | |
273 } | |
274 } | |
275 putType(type); | |
276 break; | |
277 } | |
278 case LF_ENUM: { | |
279 String name = iter.getEnumName(); | |
280 BasicEnumType enumType = null; | |
281 if ((name == null) || (name.equals(""))) { | |
282 if (unnamedEnum == null) { | |
283 unnamedEnum = new BasicEnumType(null, getTypeByIndex(iter.getEnumType())); | |
284 } | |
285 enumType = unnamedEnum; | |
286 } else { | |
287 enumType = new BasicEnumType(name, getTypeByIndex(iter.getEnumType())); | |
288 } | |
289 DebugVC50TypeIterator fieldIter = iter.getEnumFieldListIterator(); | |
290 if (Assert.ASSERTS_ENABLED) { | |
291 Assert.that(fieldIter.typeStringLeaf() == LF_FIELDLIST, "Expected field list"); | |
292 } | |
293 boolean advance = false; | |
294 while (!fieldIter.typeStringDone()) { | |
295 advance = true; | |
296 switch (fieldIter.typeStringLeaf()) { | |
297 case LF_FIELDLIST: break; | |
298 case LF_ENUMERATE: { | |
299 String enumName = fieldIter.getEnumerateName(); | |
300 long enumVal = fieldIter.getEnumerateValue(); | |
301 enumType.addEnum(enumName, enumVal); | |
302 break; | |
303 } | |
304 case LF_INDEX: { | |
305 fieldIter = fieldIter.getIndexIterator(); | |
306 advance = false; | |
307 break; | |
308 } | |
309 | |
310 case LF_PAD0: case LF_PAD1: case LF_PAD2: case LF_PAD3: | |
311 case LF_PAD4: case LF_PAD5: case LF_PAD6: case LF_PAD7: | |
312 case LF_PAD8: case LF_PAD9: case LF_PAD10: case LF_PAD11: | |
313 case LF_PAD12: case LF_PAD13: case LF_PAD14: case LF_PAD15: break; | |
314 | |
315 default: System.err.println("WARNING: unexpected leaf index " + | |
316 fieldIter.typeStringLeaf() + | |
317 " in field list for enum of type " + iter.getTypeIndex()); | |
318 } | |
319 | |
320 if (advance) { | |
321 fieldIter.typeStringNext(); | |
322 } | |
323 } | |
324 | |
325 putType(enumType); | |
326 break; | |
327 } | |
328 case LF_PROCEDURE: { | |
329 Type retType = getTypeByIndex(iter.getProcedureReturnType()); | |
330 BasicFunctionType func = new BasicFunctionType(null, POINTER_SIZE, retType); | |
331 DebugVC50TypeIterator argIter = iter.getProcedureArgumentListIterator(); | |
332 if (Assert.ASSERTS_ENABLED) { | |
333 Assert.that(argIter.typeStringLeaf() == LF_ARGLIST, "Expected argument list"); | |
334 } | |
335 for (int i = 0; i < argIter.getArgListCount(); i++) { | |
336 func.addArgumentType(getTypeByIndex(argIter.getArgListType(i))); | |
337 } | |
338 putType(func); | |
339 break; | |
340 } | |
341 case LF_MFUNCTION: { | |
342 Type retType = getTypeByIndex(iter.getMFunctionReturnType()); | |
343 Type container = getTypeByIndex(iter.getMFunctionContainingClass()); | |
344 Type thisType = getTypeByIndex(iter.getMFunctionThis()); | |
345 long thisAdjust = iter.getMFunctionThisAdjust(); | |
346 BasicMemberFunctionType func = new BasicMemberFunctionType(null, | |
347 POINTER_SIZE, | |
348 retType, | |
349 container, | |
350 thisType, | |
351 thisAdjust); | |
352 DebugVC50TypeIterator argIter = iter.getMFunctionArgumentListIterator(); | |
353 for (int i = 0; i < argIter.getArgListCount(); i++) { | |
354 func.addArgumentType(getTypeByIndex(argIter.getArgListType(i))); | |
355 } | |
356 putType(func); | |
357 break; | |
358 } | |
359 // FIXME: handle virtual function table shape description | |
360 case LF_VTSHAPE: break; | |
361 case LF_BARRAY: System.err.println("FIXME: don't know what to do with LF_BARRAY leaves (convert to pointers?"); break; | |
362 case LF_LABEL: break; | |
363 case LF_NULL: break; // FIXME: do we need to handle this? With what? | |
364 case LF_DIMARRAY: System.err.println("FIXME: don't know what to do with LF_DIMARRAY leaves yet"); break; | |
365 case LF_VFTPATH: break; | |
366 case LF_PRECOMP: break; | |
367 case LF_ENDPRECOMP: break; | |
368 case LF_OEM: break; | |
369 case LF_TYPESERVER: break; | |
370 | |
371 // Type records referenced from other type records | |
372 | |
373 case LF_SKIP: break; | |
374 case LF_ARGLIST: skipTypeRecord(); break; | |
375 case LF_DEFARG: System.err.println("FIXME: handle default arguments (dereference the type)"); break; | |
376 case LF_FIELDLIST: skipTypeRecord(); break; | |
377 case LF_DERIVED: break; | |
378 case LF_BITFIELD: { | |
379 Type underlyingType = getTypeByIndex(iter.getBitfieldFieldType()); | |
380 BasicBitType bit = new BasicBitType(underlyingType, | |
381 (iter.getBitfieldLength() & 0xFF), | |
382 (iter.getBitfieldPosition() & 0xFF)); | |
383 putType(bit); | |
384 break; | |
385 } | |
386 case LF_METHODLIST: break; | |
387 case LF_DIMCONU: | |
388 case LF_DIMCONLU: | |
389 case LF_DIMVARU: | |
390 case LF_DIMVARLU: break; | |
391 case LF_REFSYM: break; | |
392 | |
393 case LF_PAD0: case LF_PAD1: case LF_PAD2: case LF_PAD3: | |
394 case LF_PAD4: case LF_PAD5: case LF_PAD6: case LF_PAD7: | |
395 case LF_PAD8: case LF_PAD9: case LF_PAD10: case LF_PAD11: | |
396 case LF_PAD12: case LF_PAD13: case LF_PAD14: case LF_PAD15: break; | |
397 | |
398 default: { | |
399 System.err.println("Unexpected leaf index " + | |
400 iter.typeStringLeaf() + " at offset 0x" + | |
401 Integer.toHexString(iter.typeStringOffset())); | |
402 break; | |
403 } | |
404 } | |
405 | |
406 | |
407 if (!iter.typeStringDone()) { | |
408 iter.typeStringNext(); | |
409 } | |
410 } | |
411 } | |
412 | |
413 // Add all symbol directories to debug info | |
414 // (FIXME: must figure out how to handle module-by-module | |
415 // arrangement of at least the static symbols to have proper | |
416 // lookup -- should probably also take advantage of the PROCREF | |
417 // and UDT references to understand how to build the global | |
418 // database vs. the module-by-module one) | |
419 DebugVC50SubsectionDirectory dir = vc50.getSubsectionDirectory(); | |
420 int moduleNumber = 0; // Debugging | |
421 for (int i = 0; i < dir.getNumEntries(); i++) { | |
422 DebugVC50Subsection ss = dir.getSubsection(i); | |
423 int ssType = ss.getSubsectionType(); | |
424 boolean process = false; | |
425 | |
426 if ((ssType == SST_GLOBAL_SYM) || | |
427 (ssType == SST_GLOBAL_PUB) || | |
428 (ssType == SST_STATIC_SYM)) { | |
429 DebugVC50SSSymbolBase syms = (DebugVC50SSSymbolBase) ss; | |
430 symIter = syms.getSymbolIterator(); | |
431 process = true; | |
432 } | |
433 | |
434 if (ssType == SST_ALIGN_SYM) { | |
435 DebugVC50SSAlignSym syms = (DebugVC50SSAlignSym) ss; | |
436 symIter = syms.getSymbolIterator(); | |
437 process = true; | |
438 } | |
439 | |
440 if (process) { | |
441 for (; !symIter.done(); symIter.next()) { | |
442 switch (symIter.getType()) { | |
443 case S_COMPILE: break; | |
444 case S_SSEARCH: break; // FIXME: may need this later | |
445 case S_END: { | |
446 try { | |
447 // FIXME: workaround for warnings until we figure out | |
448 // what to do with THUNK32 symbols | |
449 if (endsToSkip == 0) { | |
450 blockStack.pop(); | |
451 } else { | |
452 --endsToSkip; | |
453 } | |
454 } catch (EmptyStackException e) { | |
455 System.err.println("WARNING: mismatched block begins/ends in debug information"); | |
456 } | |
457 break; | |
458 } | |
459 case S_SKIP: break; | |
460 case S_CVRESERVE: break; | |
461 case S_OBJNAME: break; // FIXME: may need this later | |
462 case S_ENDARG: break; | |
463 case S_COBOLUDT: break; | |
464 case S_MANYREG: break; // FIXME: may need to add support for this | |
465 case S_RETURN: break; // NOTE: would need this if adding support for calling functions | |
466 case S_ENTRYTHIS: break; // FIXME: may need to add support for this | |
467 case S_REGISTER: break; // FIXME: may need to add support for this | |
468 case S_CONSTANT: break; // FIXME: will need to add support for this | |
469 case S_UDT: break; // FIXME: need to see how these are used; are | |
470 // they redundant, or are they used to describe | |
471 // global variables as opposed to types? | |
472 case S_COBOLUDT2: break; | |
473 case S_MANYREG2: break; | |
474 case S_BPREL32: { | |
475 LocalSym sym = new BasicLocalSym(symIter.getBPRelName(), | |
476 getTypeByIndex(symIter.getBPRelType()), | |
477 symIter.getBPRelOffset()); | |
478 addLocalToCurBlock(sym); | |
479 break; | |
480 } | |
481 case S_LDATA32: | |
482 case S_GDATA32: { | |
483 // FIXME: must handle these separately from global data (have | |
484 // module scoping and only add these at the module level) | |
485 boolean isModuleLocal = (symIter.getType() == S_LDATA32); | |
486 | |
487 GlobalSym sym = new BasicGlobalSym(symIter.getLGDataName(), | |
488 getTypeByIndex(symIter.getLGDataType()), | |
489 newAddress(symIter.getLGDataOffset(), symIter.getLGDataSegment()), | |
490 isModuleLocal); | |
491 // FIXME: must handle module-local symbols differently | |
492 addGlobalSym(sym); | |
493 break; | |
494 } | |
495 case S_PUB32: break; // FIXME: figure out how these differ from | |
496 // above and how they are used | |
497 case S_LPROC32: | |
498 case S_GPROC32: { | |
499 BasicFunctionSym sym = new BasicFunctionSym(newLazyBlockSym(symIter.getLGProcParentOffset()), | |
500 symIter.getLGProcLength(), | |
501 newAddress(symIter.getLGProcOffset(), symIter.getLGProcSegment()), | |
502 symIter.getLGProcName(), | |
503 getTypeByIndex(symIter.getLGProcType()), | |
504 (symIter.getType() == S_LPROC32)); | |
505 | |
506 // FIXME: have to handle local procedures differently (have | |
507 // notion of modules and only add those procedures to the | |
508 // module they are defined in) | |
509 addBlock(sym); | |
510 break; | |
511 } | |
512 case S_THUNK32: { | |
513 // FIXME: see whether we need to handle these | |
514 skipEnd(); | |
515 break; | |
516 } | |
517 case S_BLOCK32: { | |
518 BasicBlockSym sym = new BasicBlockSym(newLazyBlockSym(symIter.getBlockParentOffset()), | |
519 symIter.getBlockLength(), | |
520 newAddress(symIter.getBlockOffset(), symIter.getBlockSegment()), | |
521 symIter.getBlockName()); | |
522 addBlock(sym); | |
523 break; | |
524 } | |
525 case S_WITH32: break; | |
526 case S_LABEL32: break; | |
527 case S_CEXMODEL32: break; | |
528 case S_VFTTABLE32: break; // FIXME: may need to handle this | |
529 // (most likely for run-time type determination) | |
530 case S_REGREL32: break; // FIXME: may need to add support for this | |
531 case S_LTHREAD32: break; | |
532 case S_GTHREAD32: break; // FIXME: may need to add support for these | |
533 case S_PROCREF: break; | |
534 case S_DATAREF: break; | |
535 case S_ALIGN: break; | |
536 default: | |
537 // These two unknown symbol types show up very frequently. | |
538 // Symbol type 0 appears to always be a no-op symbol of | |
539 // length 2 (i.e., length just covers the symbol type.) | |
540 // Symbol type 4115 appears to be a copyright notice for | |
541 // the Microsoft linker. | |
542 if ((symIter.getType() != 0) && (symIter.getType() != 4115)) { | |
543 System.err.println(" NOTE: Unexpected symbol of type " + | |
544 symIter.getType() + " at offset 0x" + | |
545 Integer.toHexString(symIter.getOffset())); | |
546 } | |
547 break; | |
548 } | |
549 } | |
550 } | |
551 } | |
552 | |
553 // Add line number information for all modules | |
554 for (int i = 0; i < dir.getNumEntries(); i++) { | |
555 DebugVC50Subsection ss = dir.getSubsection(i); | |
556 if (ss.getSubsectionType() == SST_SRC_MODULE) { | |
557 DebugVC50SSSrcModule srcMod = (DebugVC50SSSrcModule) ss; | |
558 for (int sf = 0; sf < srcMod.getNumSourceFiles(); sf++) { | |
559 DebugVC50SrcModFileDesc desc = srcMod.getSourceFileDesc(sf); | |
560 // Uniquify these to save space | |
561 String name = desc.getSourceFileName().intern(); | |
562 for (int cs = 0; cs < desc.getNumCodeSegments(); cs++) { | |
563 DebugVC50SrcModLineNumberMap map = desc.getLineNumberMap(cs); | |
564 SectionHeader seg = file.getHeader().getSectionHeader(map.getSegment()); | |
565 for (int lp = 0; lp < map.getNumSourceLinePairs(); lp++) { | |
566 Address startPC = base.addOffsetTo(seg.getVirtualAddress() + map.getCodeOffset(lp)); | |
567 // Fake address for endPC -- will be filled in by BasicLineNumberMapping | |
568 Address endPC = base.addOffsetTo(seg.getSize()); | |
569 db.addLineNumberInfo(new BasicLineNumberInfo(name, map.getLineNumber(lp), startPC, endPC)); | |
570 } | |
571 } | |
572 } | |
573 } | |
574 } | |
575 | |
576 // Finish assembly of database | |
577 db.resolve(new ResolveListener() { | |
578 public void resolveFailed(Type containingType, LazyType failedResolve, String detail) { | |
579 System.err.println("WARNING: failed to resolve type of index " + | |
580 ((Integer) failedResolve.getKey()).intValue() + | |
581 " in type " + containingType.getName() + " (class " + | |
582 containingType.getClass().getName() + ") while " + detail); | |
583 } | |
584 | |
585 public void resolveFailed(Type containingType, String staticFieldName) { | |
586 System.err.println("WARNING: failed to resolve address of static field \"" + | |
587 staticFieldName + "\" in type " + containingType.getName()); | |
588 } | |
589 | |
590 public void resolveFailed(Sym containingSymbol, LazyType failedResolve, String detail) { | |
591 System.err.println("WARNING: failed to resolve type of index " + | |
592 ((Integer) failedResolve.getKey()).intValue() + | |
593 " in symbol of type " + containingSymbol.getClass().getName() + | |
594 " while " + detail); | |
595 } | |
596 | |
597 public void resolveFailed(Sym containingSymbol, LazyBlockSym failedResolve, String detail) { | |
598 System.err.println("WARNING: failed to resolve block at offset 0x" + | |
599 Integer.toHexString(((Integer) failedResolve.getKey()).intValue()) + | |
600 " in symbol of type " + containingSymbol.getClass().getName() + | |
601 " while " + detail); | |
602 } | |
603 }); | |
604 | |
605 db.endConstruction(); | |
606 | |
607 return db; | |
608 } | |
609 | |
610 | |
611 //---------------------------------------------------------------------- | |
612 // Internals only below this point | |
613 // | |
614 | |
615 private static DebugVC50 getDebugVC50(COFFFile file) { | |
616 COFFHeader header = file.getHeader(); | |
617 OptionalHeader opt = header.getOptionalHeader(); | |
618 if (opt == null) { | |
619 // Optional header not found | |
620 return null; | |
621 } | |
622 OptionalHeaderDataDirectories dd = opt.getDataDirectories(); | |
623 if (dd == null) { | |
624 // Optional header data directories not found | |
625 return null; | |
626 } | |
627 DebugDirectory debug = dd.getDebugDirectory(); | |
628 if (debug == null) { | |
629 // Debug directory not found | |
630 return null; | |
631 } | |
632 for (int i = 0; i < debug.getNumEntries(); i++) { | |
633 DebugDirectoryEntry entry = debug.getEntry(i); | |
634 if (entry.getType() == DebugTypes.IMAGE_DEBUG_TYPE_CODEVIEW) { | |
635 return entry.getDebugVC50(); | |
636 } | |
637 } | |
638 | |
639 // CodeView information not found in debug directory | |
640 return null; | |
641 } | |
642 | |
643 private DebugVC50SSSegMap getSegMap() { | |
644 return (DebugVC50SSSegMap) findSubsection(SST_SEG_MAP); | |
645 } | |
646 | |
647 private DebugVC50SSGlobalTypes getGlobalTypes() { | |
648 return (DebugVC50SSGlobalTypes) findSubsection(SST_GLOBAL_TYPES); | |
649 } | |
650 | |
651 private DebugVC50SSGlobalSym getGlobalSymbols() { | |
652 return (DebugVC50SSGlobalSym) findSubsection(SST_GLOBAL_SYM); | |
653 } | |
654 | |
655 private DebugVC50Subsection findSubsection(short ssType) { | |
656 DebugVC50SubsectionDirectory dir = vc50.getSubsectionDirectory(); | |
657 for (int i = 0; i < dir.getNumEntries(); i++) { | |
658 DebugVC50Subsection ss = dir.getSubsection(i); | |
659 if (ss.getSubsectionType() == ssType) { | |
660 return ss; | |
661 } | |
662 } | |
663 throw new DebuggerException("Unable to find subsection of type " + ssType); | |
664 } | |
665 | |
666 private void putType(Type t) { | |
667 db.addType(new Integer(iter.getTypeIndex()), t); | |
668 } | |
669 | |
670 private Address newAddress(int offset, short segment) { | |
671 int seg = segment & 0xFFFF; | |
672 // NOTE: it isn't clear how to use the segMap to map from logical | |
673 // to physical segments. It seems it would make more sense if the | |
674 // SegDescs contained a physical segment number in addition to the | |
675 // offset within the physical segment of the logical one. | |
676 | |
677 // Get the section header corresponding to this segment | |
678 SectionHeader section = file.getHeader().getSectionHeader(seg); | |
679 | |
680 // Result is relative to image base | |
681 return base.addOffsetTo(section.getVirtualAddress() + offset); | |
682 } | |
683 | |
684 private BasicType getTypeByIndex(int intIndex) { | |
685 Integer index = new Integer(intIndex); | |
686 | |
687 // Handle primitive types here. | |
688 if (intIndex <= 0x0FFF) { | |
689 BasicType type = (BasicType) primIndexToTypeMap.get(index); | |
690 if (type != null) { | |
691 return type; | |
692 } | |
693 // Construct appropriate new primitive type | |
694 int primMode = intIndex & RESERVED_MODE_MASK; | |
695 if (primMode == RESERVED_MODE_DIRECT) { | |
696 int primType = intIndex & RESERVED_TYPE_MASK; | |
697 switch (primType) { | |
698 case RESERVED_TYPE_SIGNED_INT: | |
699 case RESERVED_TYPE_UNSIGNED_INT: { | |
700 boolean unsigned = (primType == RESERVED_TYPE_UNSIGNED_INT); | |
701 int size = 0; | |
702 String name = null; | |
703 switch (intIndex & RESERVED_SIZE_MASK) { | |
704 case RESERVED_SIZE_INT_1_BYTE: size = 1; name = "char"; break; | |
705 case RESERVED_SIZE_INT_2_BYTE: size = 2; name = "short"; break; | |
706 case RESERVED_SIZE_INT_4_BYTE: size = 4; name = "int"; break; | |
707 case RESERVED_SIZE_INT_8_BYTE: size = 8; name = "__int64"; break; | |
708 default: throw new DebuggerException("Illegal size of integer type " + intIndex); | |
709 } | |
710 type = new BasicIntType(name, size, unsigned); | |
711 break; | |
712 } | |
713 case RESERVED_TYPE_BOOLEAN: { | |
714 int size = 0; | |
715 switch (intIndex & RESERVED_SIZE_MASK) { | |
716 case RESERVED_SIZE_INT_1_BYTE: size = 1; break; | |
717 case RESERVED_SIZE_INT_2_BYTE: size = 2; break; | |
718 case RESERVED_SIZE_INT_4_BYTE: size = 4; break; | |
719 case RESERVED_SIZE_INT_8_BYTE: size = 8; break; | |
720 default: throw new DebuggerException("Illegal size of boolean type " + intIndex); | |
721 } | |
722 type = new BasicIntType("bool", size, false); | |
723 break; | |
724 } | |
725 case RESERVED_TYPE_REAL: { | |
726 switch (intIndex & RESERVED_SIZE_MASK) { | |
727 case RESERVED_SIZE_REAL_32_BIT: | |
728 type = new BasicFloatType("float", 4); | |
729 break; | |
730 case RESERVED_SIZE_REAL_64_BIT: | |
731 type = new BasicDoubleType("double", 8); | |
732 break; | |
733 default: | |
734 throw new DebuggerException("Unsupported floating-point size in type " + intIndex); | |
735 } | |
736 break; | |
737 } | |
738 case RESERVED_TYPE_REALLY_INT: { | |
739 switch (intIndex & RESERVED_SIZE_MASK) { | |
740 case RESERVED_SIZE_REALLY_INT_CHAR: type = new BasicIntType("char", 1, false); break; | |
741 case RESERVED_SIZE_REALLY_INT_WCHAR: type = new BasicIntType("wchar", 2, false); break; | |
742 case RESERVED_SIZE_REALLY_INT_2_BYTE: type = new BasicIntType("short", 2, false); break; | |
743 case RESERVED_SIZE_REALLY_INT_2_BYTE_U: type = new BasicIntType("short", 2, true); break; | |
744 case RESERVED_SIZE_REALLY_INT_4_BYTE: type = new BasicIntType("int", 4, false); break; | |
745 case RESERVED_SIZE_REALLY_INT_4_BYTE_U: type = new BasicIntType("int", 4, true); break; | |
746 case RESERVED_SIZE_REALLY_INT_8_BYTE: type = new BasicIntType("__int64", 8, false); break; | |
747 case RESERVED_SIZE_REALLY_INT_8_BYTE_U: type = new BasicIntType("__int64", 8, true); break; | |
748 default: throw new DebuggerException("Illegal REALLY_INT size in type " + intIndex); | |
749 } | |
750 break; | |
751 } | |
752 case RESERVED_TYPE_SPECIAL: { | |
753 switch (intIndex & RESERVED_SIZE_MASK) { | |
754 case RESERVED_SIZE_SPECIAL_NO_TYPE: | |
755 case RESERVED_SIZE_SPECIAL_VOID: type = new BasicVoidType(); break; | |
756 default: throw new DebuggerException("Don't know how to handle reserved special type " + intIndex); | |
757 } | |
758 break; | |
759 } | |
760 | |
761 default: | |
762 throw new DebuggerException("Don't know how to handle reserved type " + intIndex); | |
763 } | |
764 } else { | |
765 // Fold all pointer types together since we only support | |
766 // flat-mode addressing anyway | |
767 Type targetType = getTypeByIndex(intIndex & (~RESERVED_MODE_MASK)); | |
768 | |
769 type = new BasicPointerType(POINTER_SIZE, targetType); | |
770 } | |
771 if (Assert.ASSERTS_ENABLED) { | |
772 Assert.that(type != null, "Got null Type for primitive type " + intIndex); | |
773 } | |
774 primIndexToTypeMap.put(index, type); | |
775 return type; | |
776 } | |
777 | |
778 // Not primitive type. Construct lazy reference to target type. | |
779 // (Is it worth canonicalizing these as well to save space?) | |
780 return new LazyType(index); | |
781 } | |
782 | |
783 private void addBlock(BlockSym block) { | |
784 db.addBlock(new Integer(symIter.getOffset()), block); | |
785 blockStack.push(block); | |
786 } | |
787 | |
788 private void skipEnd() { | |
789 ++endsToSkip; | |
790 } | |
791 | |
792 private BlockSym newLazyBlockSym(int offset) { | |
793 if (offset == 0) { | |
794 return null; | |
795 } | |
796 | |
797 return new LazyBlockSym(new Integer(offset)); | |
798 } | |
799 | |
800 private int memberAttributeToAccessControl(short memberAttribute) { | |
801 int acc = memberAttribute & MEMATTR_ACCESS_MASK; | |
802 switch (acc) { | |
803 case MEMATTR_ACCESS_NO_PROTECTION: return NO_PROTECTION; | |
804 case MEMATTR_ACCESS_PRIVATE: return PRIVATE; | |
805 case MEMATTR_ACCESS_PROTECTED: return PROTECTED; | |
806 case MEMATTR_ACCESS_PUBLIC: return PUBLIC; | |
807 default: throw new RuntimeException("Should not reach here"); | |
808 } | |
809 } | |
810 | |
811 private void addLocalToCurBlock(LocalSym local) { | |
812 ((BasicBlockSym) blockStack.peek()).addLocal(local); | |
813 } | |
814 | |
815 private void addGlobalSym(GlobalSym sym) { | |
816 db.addGlobalSym(sym); | |
817 } | |
818 | |
819 private void skipTypeRecord() { | |
820 while (!iter.typeStringDone()) { | |
821 iter.typeStringNext(); | |
822 } | |
823 } | |
824 } |