1 /*
2  * Copyright (c) 2002, 2003, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * 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 
WindbgCDebugInfoBuilder(WindbgDebugger dbg)62   WindbgCDebugInfoBuilder(WindbgDebugger dbg) {
63     this.dbg = dbg;
64   }
65 
buildDataBase(String dllName, Address base)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 
getDebugVC50(COFFFile file)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 
getSegMap()643   private DebugVC50SSSegMap getSegMap() {
644     return (DebugVC50SSSegMap) findSubsection(SST_SEG_MAP);
645   }
646 
getGlobalTypes()647   private DebugVC50SSGlobalTypes getGlobalTypes() {
648     return (DebugVC50SSGlobalTypes) findSubsection(SST_GLOBAL_TYPES);
649   }
650 
getGlobalSymbols()651   private DebugVC50SSGlobalSym getGlobalSymbols() {
652     return (DebugVC50SSGlobalSym) findSubsection(SST_GLOBAL_SYM);
653   }
654 
findSubsection(short ssType)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 
putType(Type t)666   private void putType(Type t) {
667     db.addType(new Integer(iter.getTypeIndex()), t);
668   }
669 
newAddress(int offset, short segment)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 
getTypeByIndex(int intIndex)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 
addBlock(BlockSym block)783   private void addBlock(BlockSym block) {
784     db.addBlock(new Integer(symIter.getOffset()), block);
785     blockStack.push(block);
786   }
787 
skipEnd()788   private void skipEnd() {
789     ++endsToSkip;
790   }
791 
newLazyBlockSym(int offset)792   private BlockSym newLazyBlockSym(int offset) {
793     if (offset == 0) {
794       return null;
795     }
796 
797     return new LazyBlockSym(new Integer(offset));
798   }
799 
memberAttributeToAccessControl(short memberAttribute)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 
addLocalToCurBlock(LocalSym local)811   private void addLocalToCurBlock(LocalSym local) {
812     ((BasicBlockSym) blockStack.peek()).addLocal(local);
813   }
814 
addGlobalSym(GlobalSym sym)815   private void addGlobalSym(GlobalSym sym) {
816     db.addGlobalSym(sym);
817   }
818 
skipTypeRecord()819   private void skipTypeRecord() {
820     while (!iter.typeStringDone()) {
821       iter.typeStringNext();
822     }
823   }
824 }
825