1 /*
   2  * Copyright (c) 2001, 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.win32;
  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 Win32CDebugInfoBuilder
  36   implements DebugVC50SubsectionTypes, DebugVC50TypeLeafIndices, DebugVC50TypeEnums, DebugVC50SymbolTypes, DebugVC50MemberAttributes, CVAttributes, AccessControl {
  37   private Win32Debugger 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   Win32CDebugInfoBuilder(Win32Debugger 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 }