0
|
1 /*
|
|
2 * Copyright 2002-2003 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.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 }
|