1 /* 2 * Copyright (c) 2000, 2010, 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.coff; 26 27 import java.io.*; 28 import java.nio.*; 29 import java.nio.channels.*; 30 import java.util.*; 31 32 import sun.jvm.hotspot.utilities.memo.*; 33 import sun.jvm.hotspot.utilities.Assert; 34 import sun.jvm.hotspot.debugger.DataSource; 35 import sun.jvm.hotspot.debugger.MappedByteBufferDataSource; 36 37 /** Top-level factory which parses COFF files, including object files, 38 Portable Executables and DLLs. Returns {@link 39 sun.jvm.hotspot.debugger.win32.coff.COFFFile} objects. This class is a 40 singleton. */ 41 42 public class COFFFileParser { 43 private static COFFFileParser soleInstance; 44 45 // Constants from the file format documentation 46 private static final int COFF_HEADER_SIZE = 20; 47 private static final int SECTION_HEADER_SIZE = 40; 48 private static final int SYMBOL_SIZE = 18; 49 private static final int RELOCATION_SIZE = 10; 50 private static final int LINE_NUMBER_SIZE = 6; 51 52 private static final String US_ASCII = "US-ASCII"; 53 54 private COFFFileParser() {} 55 56 /** This class is a singleton; returns the sole instance. */ 57 public static COFFFileParser getParser() { 58 if (soleInstance == null) { 59 soleInstance = new COFFFileParser(); 60 } 61 return soleInstance; 62 } 63 64 public COFFFile parse(String filename) throws COFFException { 65 try { 66 File file = new File(filename); 67 FileInputStream stream = new FileInputStream(file); 68 MappedByteBuffer buf = stream.getChannel().map(FileChannel.MapMode.READ_ONLY, 69 0, 70 file.length()); 71 72 // This is pretty confusing. The file format is little-endian 73 // and so is the CPU. In order for the multi-byte accessors to 74 // work properly we must NOT change the endianness of the 75 // MappedByteBuffer. Need to think about this some more and file 76 // a bug if there is one. (FIXME) 77 // buf.order(ByteOrder.nativeOrder()); 78 return parse(new MappedByteBufferDataSource(buf)); 79 } catch (FileNotFoundException e) { 80 throw new COFFException(e); 81 } catch (IOException e) { 82 throw new COFFException(e); 83 } 84 } 85 86 public COFFFile parse(DataSource source) throws COFFException { 87 return new COFFFileImpl(source); 88 } 89 90 class COFFFileImpl implements COFFFile { 91 private DataSource file; 92 private long filePos; 93 private boolean isImage; 94 private long imageHeaderOffset; 95 private MemoizedObject header = new MemoizedObject() { 96 public Object computeValue() { 97 return new COFFHeaderImpl(); 98 } 99 }; 100 101 COFFFileImpl(DataSource file) throws COFFException { 102 this.file = file; 103 initialize(); 104 } 105 106 public boolean isImage() { 107 return isImage; 108 } 109 110 public COFFHeader getHeader() { 111 return (COFFHeaderImpl) header.getValue(); 112 } 113 114 class COFFHeaderImpl implements COFFHeader { 115 private short machine; 116 private short numberOfSections; 117 private int timeDateStamp; 118 private int pointerToSymbolTable; 119 private int numberOfSymbols; 120 private short sizeOfOptionalHeader; 121 private short characteristics; 122 private MemoizedObject[] sectionHeaders; 123 private MemoizedObject[] symbols; 124 125 // Init stringTable at decl time since other fields init'ed in the 126 // constructor need the String Table. 127 private MemoizedObject stringTable = new MemoizedObject() { 128 public Object computeValue() { 129 // the String Table follows the Symbol Table 130 int ptr = getPointerToSymbolTable(); 131 if (ptr == 0) { 132 // no Symbol Table so no String Table 133 return new StringTable(0); 134 } else { 135 return new StringTable(ptr + SYMBOL_SIZE * getNumberOfSymbols()); 136 } 137 } 138 }; 139 140 COFFHeaderImpl() { 141 seek(imageHeaderOffset); 142 machine = readShort(); 143 numberOfSections = readShort(); 144 timeDateStamp = readInt(); 145 pointerToSymbolTable = readInt(); 146 numberOfSymbols = readInt(); 147 // String Table can be accessed at this point because 148 // pointerToSymbolTable and numberOfSymbols fields are set. 149 sizeOfOptionalHeader = readShort(); 150 characteristics = readShort(); 151 152 // Set up section headers 153 sectionHeaders = new MemoizedObject[numberOfSections]; 154 for (int i = 0; i < numberOfSections; i++) { 155 final int secHdrOffset = (int) 156 (imageHeaderOffset + COFF_HEADER_SIZE + sizeOfOptionalHeader + i * SECTION_HEADER_SIZE); 157 sectionHeaders[i] = new MemoizedObject() { 158 public Object computeValue() { 159 return new SectionHeaderImpl(secHdrOffset); 160 } 161 }; 162 } 163 164 // Set up symbols 165 symbols = new MemoizedObject[numberOfSymbols]; 166 for (int i = 0; i < numberOfSymbols; i++) { 167 final int symbolOffset = pointerToSymbolTable + i * SYMBOL_SIZE; 168 symbols[i] = new MemoizedObject() { 169 public Object computeValue() { 170 return new COFFSymbolImpl(symbolOffset); 171 } 172 }; 173 } 174 } 175 176 public short getMachineType() { return machine; } 177 public short getNumberOfSections() { return numberOfSections; } 178 public int getTimeDateStamp() { return timeDateStamp; } 179 public int getPointerToSymbolTable() { return pointerToSymbolTable; } 180 public int getNumberOfSymbols() { return numberOfSymbols; } 181 public short getSizeOfOptionalHeader() { return sizeOfOptionalHeader; } 182 public OptionalHeader getOptionalHeader() throws COFFException { 183 if (getSizeOfOptionalHeader() == 0) { 184 return null; 185 } 186 return new OptionalHeaderImpl((int) (imageHeaderOffset + COFF_HEADER_SIZE)); 187 } 188 public short getCharacteristics() { return characteristics; } 189 public boolean hasCharacteristic(short characteristic) { 190 return ((characteristics & characteristic) != 0); 191 } 192 public SectionHeader getSectionHeader(int index) { 193 // NOTE zero-basing of index 194 return (SectionHeader) sectionHeaders[index - 1].getValue(); 195 } 196 public COFFSymbol getCOFFSymbol(int index) { 197 return (COFFSymbol) symbols[index].getValue(); 198 } 199 public int getNumberOfStrings() { 200 return getStringTable().getNum(); 201 } 202 public String getString(int i) { 203 return getStringTable().get(i); 204 } 205 206 StringTable getStringTable() { return (StringTable) stringTable.getValue(); } 207 208 // NOTE: can destroy current seek() position! 209 int rvaToFileOffset(int rva) { 210 if (rva == 0) return 0; 211 // Search for section containing RVA 212 for (int i = 1; i <= getNumberOfSections(); i++) { 213 SectionHeader sec = getSectionHeader(i); 214 int va = sec.getVirtualAddress(); 215 int sz = sec.getSize(); 216 if ((va <= rva) && (rva < (va + sz))) { 217 return sec.getPointerToRawData() + (rva - va); 218 } 219 } 220 throw new COFFException("Unable to find RVA 0x" + 221 Integer.toHexString(rva) + 222 " in any section"); 223 } 224 225 class OptionalHeaderImpl implements OptionalHeader { 226 private short magic; 227 private MemoizedObject standardFields; 228 private MemoizedObject windowsSpecificFields; 229 private MemoizedObject dataDirectories; 230 231 // We use an offset of 2 because OptionalHeaderStandardFieldsImpl doesn't 232 // include the 'magic' field. 233 private static final int STANDARD_FIELDS_OFFSET = 2; 234 private static final int PE32_WINDOWS_SPECIFIC_FIELDS_OFFSET = 28; 235 private static final int PE32_DATA_DIRECTORIES_OFFSET = 96; 236 private static final int PE32_PLUS_WINDOWS_SPECIFIC_FIELDS_OFFSET = 24; 237 private static final int PE32_PLUS_DATA_DIRECTORIES_OFFSET = 112; 238 239 OptionalHeaderImpl(final int offset) { 240 seek(offset); 241 magic = readShort(); 242 243 final boolean isPE32Plus = (magic == MAGIC_PE32_PLUS); 244 final int standardFieldsOffset = offset + STANDARD_FIELDS_OFFSET; 245 final int windowsSpecificFieldsOffset = offset + 246 (isPE32Plus 247 ? PE32_PLUS_WINDOWS_SPECIFIC_FIELDS_OFFSET 248 : PE32_WINDOWS_SPECIFIC_FIELDS_OFFSET); 249 final int dataDirectoriesOffset = offset + 250 (isPE32Plus 251 ? PE32_PLUS_DATA_DIRECTORIES_OFFSET 252 : PE32_DATA_DIRECTORIES_OFFSET); 253 254 standardFields = new MemoizedObject() { 255 public Object computeValue() { 256 return new OptionalHeaderStandardFieldsImpl(standardFieldsOffset, 257 isPE32Plus); 258 } 259 }; 260 windowsSpecificFields = new MemoizedObject() { 261 public Object computeValue() { 262 return new OptionalHeaderWindowsSpecificFieldsImpl(windowsSpecificFieldsOffset, 263 isPE32Plus); 264 } 265 }; 266 dataDirectories = new MemoizedObject() { 267 public Object computeValue() { 268 return new OptionalHeaderDataDirectoriesImpl(dataDirectoriesOffset, 269 getWindowsSpecificFields().getNumberOfRvaAndSizes()); 270 } 271 }; 272 } 273 274 public short getMagicNumber() { 275 return magic; 276 } 277 278 public OptionalHeaderStandardFields getStandardFields() { 279 return (OptionalHeaderStandardFields) standardFields.getValue(); 280 } 281 282 public OptionalHeaderWindowsSpecificFields getWindowsSpecificFields() { 283 return (OptionalHeaderWindowsSpecificFields) windowsSpecificFields.getValue(); 284 } 285 public OptionalHeaderDataDirectories getDataDirectories() { 286 return (OptionalHeaderDataDirectories) dataDirectories.getValue(); 287 } 288 } 289 290 class OptionalHeaderStandardFieldsImpl implements OptionalHeaderStandardFields { 291 private boolean isPE32Plus; 292 private byte majorLinkerVersion; 293 private byte minorLinkerVersion; 294 private int sizeOfCode; 295 private int sizeOfInitializedData; 296 private int sizeOfUninitializedData; 297 private int addressOfEntryPoint; 298 private int baseOfCode; 299 private int baseOfData; // only set in PE32 300 301 OptionalHeaderStandardFieldsImpl(int offset, 302 boolean isPE32Plus) { 303 this.isPE32Plus = isPE32Plus; 304 seek(offset); 305 majorLinkerVersion = readByte(); 306 minorLinkerVersion = readByte(); 307 sizeOfCode = readInt(); 308 sizeOfInitializedData = readInt(); 309 sizeOfUninitializedData = readInt(); 310 addressOfEntryPoint = readInt(); 311 baseOfCode = readInt(); 312 if (!isPE32Plus) { 313 // only available in PE32 314 baseOfData = readInt(); 315 } 316 } 317 318 public byte getMajorLinkerVersion() { return majorLinkerVersion; } 319 public byte getMinorLinkerVersion() { return minorLinkerVersion; } 320 public int getSizeOfCode() { return sizeOfCode; } 321 public int getSizeOfInitializedData() { return sizeOfInitializedData; } 322 public int getSizeOfUninitializedData() { return sizeOfUninitializedData; } 323 public int getAddressOfEntryPoint() { return addressOfEntryPoint; } 324 public int getBaseOfCode() { return baseOfCode; } 325 public int getBaseOfData() throws COFFException { 326 if (isPE32Plus) { 327 throw new COFFException("Not present in PE32+ files"); 328 } 329 return baseOfData; 330 } 331 } 332 333 class OptionalHeaderWindowsSpecificFieldsImpl implements OptionalHeaderWindowsSpecificFields { 334 private long imageBase; 335 private int sectionAlignment; 336 private int fileAlignment; 337 private short majorOperatingSystemVersion; 338 private short minorOperatingSystemVersion; 339 private short majorImageVersion; 340 private short minorImageVersion; 341 private short majorSubsystemVersion; 342 private short minorSubsystemVersion; 343 private int sizeOfImage; 344 private int sizeOfHeaders; 345 private int checkSum; 346 private short subsystem; 347 private short dllCharacteristics; 348 private long sizeOfStackReserve; 349 private long sizeOfStackCommit; 350 private long sizeOfHeapReserve; 351 private long sizeOfHeapCommit; 352 private int loaderFlags; 353 private int numberOfRvaAndSizes; 354 355 OptionalHeaderWindowsSpecificFieldsImpl(int offset, boolean isPE32Plus) { 356 seek(offset); 357 358 if (!isPE32Plus) { 359 imageBase = maskInt(readInt()); 360 } else { 361 imageBase = readLong(); 362 } 363 sectionAlignment = readInt(); 364 fileAlignment = readInt(); 365 majorOperatingSystemVersion = readShort(); 366 minorOperatingSystemVersion = readShort(); 367 majorImageVersion = readShort(); 368 minorImageVersion = readShort(); 369 majorSubsystemVersion = readShort(); 370 minorSubsystemVersion = readShort(); 371 readInt(); // Reserved 372 sizeOfImage = readInt(); 373 sizeOfHeaders = readInt(); 374 checkSum = readInt(); 375 subsystem = readShort(); 376 dllCharacteristics = readShort(); 377 if (!isPE32Plus) { 378 sizeOfStackReserve = maskInt(readInt()); 379 sizeOfStackCommit = maskInt(readInt()); 380 sizeOfHeapReserve = maskInt(readInt()); 381 sizeOfHeapCommit = maskInt(readInt()); 382 } else { 383 sizeOfStackReserve = readLong(); 384 sizeOfStackCommit = readLong(); 385 sizeOfHeapReserve = readLong(); 386 sizeOfHeapCommit = readLong(); 387 } 388 loaderFlags = readInt(); 389 numberOfRvaAndSizes = readInt(); 390 } 391 392 public long getImageBase() { return imageBase; } 393 public int getSectionAlignment() { return sectionAlignment; } 394 public int getFileAlignment() { return fileAlignment; } 395 public short getMajorOperatingSystemVersion() { return majorOperatingSystemVersion; } 396 public short getMinorOperatingSystemVersion() { return minorOperatingSystemVersion; } 397 public short getMajorImageVersion() { return majorImageVersion; } 398 public short getMinorImageVersion() { return minorImageVersion; } 399 public short getMajorSubsystemVersion() { return majorSubsystemVersion; } 400 public short getMinorSubsystemVersion() { return minorSubsystemVersion; } 401 public int getSizeOfImage() { return sizeOfImage; } 402 public int getSizeOfHeaders() { return sizeOfHeaders; } 403 public int getCheckSum() { return checkSum; } 404 public short getSubsystem() { return subsystem; } 405 public short getDLLCharacteristics() { return dllCharacteristics; } 406 public long getSizeOfStackReserve() { return sizeOfStackReserve; } 407 public long getSizeOfStackCommit() { return sizeOfStackCommit; } 408 public long getSizeOfHeapReserve() { return sizeOfHeapReserve; } 409 public long getSizeOfHeapCommit() { return sizeOfHeapCommit; } 410 public int getLoaderFlags() { return loaderFlags; } 411 public int getNumberOfRvaAndSizes() { return numberOfRvaAndSizes; } 412 413 private long maskInt(long arg) { 414 return (arg & 0x00000000FFFFFFFFL); 415 } 416 } 417 418 class OptionalHeaderDataDirectoriesImpl implements OptionalHeaderDataDirectories { 419 private int numberOfRvaAndSizes; 420 private MemoizedObject[] dataDirectories; 421 private MemoizedObject exportDirectoryTable; 422 private MemoizedObject debugDirectory; 423 424 private static final int DATA_DIRECTORY_SIZE = 8; 425 426 OptionalHeaderDataDirectoriesImpl(int offset, 427 int numberOfRvaAndSizes) { 428 this.numberOfRvaAndSizes = numberOfRvaAndSizes; 429 dataDirectories = new MemoizedObject[numberOfRvaAndSizes]; 430 for (int i = 0; i < numberOfRvaAndSizes; i++) { 431 final int dirOffset = offset + (i * DATA_DIRECTORY_SIZE); 432 dataDirectories[i] = new MemoizedObject() { 433 public Object computeValue() { 434 return new DataDirectoryImpl(dirOffset); 435 } 436 }; 437 } 438 439 exportDirectoryTable = new MemoizedObject() { 440 public Object computeValue() { 441 DataDirectory dir = getExportTable(); 442 if (dir.getRVA() == 0 || dir.getSize() == 0) { 443 return null; 444 } 445 // ExportDirectoryTableImpl needs both the RVA and the 446 // RVA converted to a file offset. 447 return new 448 ExportDirectoryTableImpl(dir.getRVA(), dir.getSize()); 449 } 450 }; 451 452 debugDirectory = new MemoizedObject() { 453 public Object computeValue() { 454 DataDirectory dir = getDebug(); 455 if (dir.getRVA() == 0 || dir.getSize() == 0) { 456 return null; 457 } 458 return new DebugDirectoryImpl(rvaToFileOffset(dir.getRVA()), dir.getSize()); 459 } 460 }; 461 } 462 463 public DataDirectory getExportTable() throws COFFException { 464 return (DataDirectory) dataDirectories[checkIndex(0)].getValue(); 465 } 466 public DataDirectory getImportTable() throws COFFException { 467 return (DataDirectory) dataDirectories[checkIndex(1)].getValue(); 468 } 469 public DataDirectory getResourceTable() throws COFFException { 470 return (DataDirectory) dataDirectories[checkIndex(2)].getValue(); 471 } 472 public DataDirectory getExceptionTable() throws COFFException { 473 return (DataDirectory) dataDirectories[checkIndex(3)].getValue(); 474 } 475 public DataDirectory getCertificateTable() throws COFFException { 476 return (DataDirectory) dataDirectories[checkIndex(4)].getValue(); 477 } 478 public DataDirectory getBaseRelocationTable() throws COFFException { 479 return (DataDirectory) dataDirectories[checkIndex(5)].getValue(); 480 } 481 public DataDirectory getDebug() throws COFFException { 482 return (DataDirectory) dataDirectories[checkIndex(6)].getValue(); 483 } 484 public DataDirectory getArchitecture() throws COFFException { 485 return (DataDirectory) dataDirectories[checkIndex(7)].getValue(); 486 } 487 public DataDirectory getGlobalPtr() throws COFFException { 488 return (DataDirectory) dataDirectories[checkIndex(8)].getValue(); 489 } 490 public DataDirectory getTLSTable() throws COFFException { 491 return (DataDirectory) dataDirectories[checkIndex(9)].getValue(); 492 } 493 public DataDirectory getLoadConfigTable() throws COFFException { 494 return (DataDirectory) dataDirectories[checkIndex(10)].getValue(); 495 } 496 public DataDirectory getBoundImportTable() throws COFFException { 497 return (DataDirectory) dataDirectories[checkIndex(11)].getValue(); 498 } 499 public DataDirectory getImportAddressTable() throws COFFException { 500 return (DataDirectory) dataDirectories[checkIndex(12)].getValue(); 501 } 502 public DataDirectory getDelayImportDescriptor() throws COFFException { 503 return (DataDirectory) dataDirectories[checkIndex(13)].getValue(); 504 } 505 public DataDirectory getCOMPlusRuntimeHeader() throws COFFException { 506 return (DataDirectory) dataDirectories[checkIndex(14)].getValue(); 507 } 508 509 public ExportDirectoryTable getExportDirectoryTable() throws COFFException { 510 return (ExportDirectoryTable) exportDirectoryTable.getValue(); 511 } 512 513 public DebugDirectory getDebugDirectory() throws COFFException { 514 return (DebugDirectory) debugDirectory.getValue(); 515 } 516 517 private int checkIndex(int index) throws COFFException { 518 if ((index < 0) || (index >= dataDirectories.length)) { 519 throw new COFFException("Directory " + index + " unavailable (only " + 520 numberOfRvaAndSizes + " tables present)"); 521 } 522 return index; 523 } 524 } 525 526 class DataDirectoryImpl implements DataDirectory { 527 int rva; 528 int size; 529 530 DataDirectoryImpl(int offset) { 531 seek(offset); 532 rva = readInt(); 533 size = readInt(); 534 } 535 536 public int getRVA() { return rva; } 537 public int getSize() { return size; } 538 } 539 540 class ExportDirectoryTableImpl implements ExportDirectoryTable { 541 private int exportDataDirRVA; 542 private int offset; 543 private int size; 544 545 private int exportFlags; 546 private int timeDateStamp; 547 private short majorVersion; 548 private short minorVersion; 549 private int nameRVA; 550 private int ordinalBase; 551 private int addressTableEntries; 552 private int numberOfNamePointers; 553 private int exportAddressTableRVA; 554 private int namePointerTableRVA; 555 private int ordinalTableRVA; 556 557 private MemoizedObject dllName; 558 559 private MemoizedObject exportNameTable; 560 private MemoizedObject exportNamePointerTable; 561 private MemoizedObject exportOrdinalTable; 562 private MemoizedObject exportAddressTable; 563 564 ExportDirectoryTableImpl(int exportDataDirRVA, int size) { 565 this.exportDataDirRVA = exportDataDirRVA; 566 offset = rvaToFileOffset(exportDataDirRVA); 567 this.size = size; 568 seek(offset); 569 exportFlags = readInt(); 570 timeDateStamp = readInt(); 571 majorVersion = readShort(); 572 minorVersion = readShort(); 573 nameRVA = readInt(); 574 ordinalBase = readInt(); 575 addressTableEntries = readInt(); 576 numberOfNamePointers = readInt(); 577 exportAddressTableRVA = readInt(); 578 namePointerTableRVA = readInt(); 579 ordinalTableRVA = readInt(); 580 581 dllName = new MemoizedObject() { 582 public Object computeValue() { 583 seek(rvaToFileOffset(getNameRVA())); 584 return readCString(); 585 } 586 }; 587 588 exportNamePointerTable = new MemoizedObject() { 589 public Object computeValue() { 590 int[] pointers = new int[getNumberOfNamePointers()]; 591 seek(rvaToFileOffset(getNamePointerTableRVA())); 592 // Must make two passes to avoid rvaToFileOffset 593 // destroying seek() position 594 for (int i = 0; i < pointers.length; i++) { 595 pointers[i] = readInt(); 596 } 597 for (int i = 0; i < pointers.length; i++) { 598 pointers[i] = rvaToFileOffset(pointers[i]); 599 } 600 return pointers; 601 } 602 }; 603 604 exportNameTable = new MemoizedObject() { 605 public Object computeValue() { 606 return new ExportNameTable(getExportNamePointerTable()); 607 } 608 }; 609 610 exportOrdinalTable = new MemoizedObject() { 611 public Object computeValue() { 612 // number of ordinals is same as the number of name pointers 613 short[] ordinals = new short[getNumberOfNamePointers()]; 614 seek(rvaToFileOffset(getOrdinalTableRVA())); 615 for (int i = 0; i < ordinals.length; i++) { 616 ordinals[i] = readShort(); 617 } 618 return ordinals; 619 } 620 }; 621 622 exportAddressTable = new MemoizedObject() { 623 public Object computeValue() { 624 int[] addresses = new int[getNumberOfAddressTableEntries()]; 625 seek(rvaToFileOffset(getExportAddressTableRVA())); 626 // The Export Address Table values are a union of two 627 // possible values: 628 // Export RVA - The address of the exported symbol when 629 // loaded into memory, relative to the image base. 630 // This value doesn't get converted into a file offset. 631 // Forwarder RVA - The pointer to a null-terminated ASCII 632 // string in the export section. This value gets 633 // converted into a file offset because we have to 634 // fetch the string. 635 for (int i = 0; i < addresses.length; i++) { 636 addresses[i] = readInt(); 637 } 638 return addresses; 639 } 640 }; 641 } 642 643 public int getExportFlags() { return exportFlags; } 644 public int getTimeDateStamp() { return timeDateStamp; } 645 public short getMajorVersion() { return majorVersion; } 646 public short getMinorVersion() { return minorVersion; } 647 public int getNameRVA() { return nameRVA; } 648 649 public String getDLLName() { 650 return (String) dllName.getValue(); 651 } 652 653 public int getOrdinalBase() { return ordinalBase; } 654 public int getNumberOfAddressTableEntries() { return addressTableEntries; } 655 public int getNumberOfNamePointers() { return numberOfNamePointers; } 656 public int getExportAddressTableRVA() { return exportAddressTableRVA; } 657 public int getNamePointerTableRVA() { return namePointerTableRVA; } 658 public int getOrdinalTableRVA() { return ordinalTableRVA; } 659 660 public String getExportName(int i) { 661 return getExportNameTable().get(i); 662 } 663 664 public short getExportOrdinal(int i) { 665 return getExportOrdinalTable()[i]; 666 } 667 668 public boolean isExportAddressForwarder(short ordinal) { 669 int addr = getExportAddress(ordinal); 670 return ((exportDataDirRVA <= addr) && 671 (addr < (exportDataDirRVA + size))); 672 } 673 674 public String getExportAddressForwarder(short ordinal) { 675 seek(rvaToFileOffset(getExportAddress(ordinal))); 676 return readCString(); 677 } 678 679 public int getExportAddress(short ordinal) { 680 681 /////////////////////// 682 // FIXME: MAJOR HACK // 683 /////////////////////// 684 685 // According to the documentation, the first line here is 686 // correct. However, it doesn't seem to work. The second 687 // one, however, does. 688 689 // OK, it's probably due to using negative indices in the 690 // export address table in "real life"...need to rethink 691 // this when I'm more awake 692 693 // return getExportAddressTable()[ordinal - ordinalBase]; 694 return getExportAddressTable()[ordinal]; 695 } 696 697 private ExportNameTable getExportNameTable() { 698 return (ExportNameTable) exportNameTable.getValue(); 699 } 700 701 private int[] getExportNamePointerTable() { 702 return (int[]) exportNamePointerTable.getValue(); 703 } 704 705 private short[] getExportOrdinalTable() { 706 return (short[]) exportOrdinalTable.getValue(); 707 } 708 709 private int[] getExportAddressTable() { 710 return (int[]) exportAddressTable.getValue(); 711 } 712 } 713 714 class ExportNameTable { 715 private MemoizedObject[] names; 716 717 ExportNameTable(final int[] exportNamePointerTable) { 718 names = new MemoizedObject[exportNamePointerTable.length]; 719 for (int i = 0; i < exportNamePointerTable.length; i++) { 720 final int idx = i; 721 names[idx] = new MemoizedObject() { 722 public Object computeValue() { 723 seek(exportNamePointerTable[idx]); 724 return readCString(); 725 } 726 }; 727 }; 728 } 729 730 String get(int i) { 731 return (String) names[i].getValue(); 732 } 733 } 734 735 class DebugDirectoryImpl implements DebugDirectory { 736 private int offset; 737 private int size; 738 private int numEntries; 739 740 private static final int DEBUG_DIRECTORY_ENTRY_SIZE = 28; 741 742 DebugDirectoryImpl(int offset, int size) { 743 this.offset = offset; 744 this.size = size; 745 746 if ((size % DEBUG_DIRECTORY_ENTRY_SIZE) != 0) { 747 throw new COFFException("Corrupt DebugDirectory at offset 0x" + 748 Integer.toHexString(offset)); 749 } 750 751 numEntries = size / DEBUG_DIRECTORY_ENTRY_SIZE; 752 } 753 754 public int getNumEntries() { return numEntries; } 755 public DebugDirectoryEntry getEntry(int i) { 756 if ((i < 0) || (i >= getNumEntries())) throw new IndexOutOfBoundsException(); 757 return new DebugDirectoryEntryImpl(offset + i * DEBUG_DIRECTORY_ENTRY_SIZE); 758 } 759 } 760 761 class DebugDirectoryEntryImpl implements DebugDirectoryEntry, DebugTypes { 762 private int characteristics; 763 private int timeDateStamp; 764 private short majorVersion; 765 private short minorVersion; 766 private int type; 767 private int sizeOfData; 768 private int addressOfRawData; 769 private int pointerToRawData; 770 771 DebugDirectoryEntryImpl(int offset) { 772 seek(offset); 773 characteristics = readInt(); 774 timeDateStamp = readInt(); 775 majorVersion = readShort(); 776 minorVersion = readShort(); 777 type = readInt(); 778 sizeOfData = readInt(); 779 addressOfRawData = readInt(); 780 pointerToRawData = readInt(); 781 } 782 783 public int getCharacteristics() { return characteristics; } 784 public int getTimeDateStamp() { return timeDateStamp; } 785 public short getMajorVersion() { return majorVersion; } 786 public short getMinorVersion() { return minorVersion; } 787 public int getType() { return type; } 788 public int getSizeOfData() { return sizeOfData; } 789 public int getAddressOfRawData() { return addressOfRawData; } 790 public int getPointerToRawData() { return pointerToRawData; } 791 792 public DebugVC50 getDebugVC50() { 793 // See whether we can recognize VC++ 5.0 debug information. 794 try { 795 if (getType() != IMAGE_DEBUG_TYPE_CODEVIEW) return null; 796 797 int offset = getPointerToRawData(); 798 seek(offset); 799 if (readByte() == 'N' && 800 readByte() == 'B' && 801 readByte() == '1' && 802 readByte() == '1') { 803 return new DebugVC50Impl(offset); 804 } 805 } catch (COFFException e) { 806 e.printStackTrace(); 807 } 808 return null; 809 } 810 811 public byte getRawDataByte(int i) { 812 if (i < 0 || i >= getSizeOfData()) { 813 throw new IndexOutOfBoundsException(); 814 } 815 seek(getPointerToRawData() + i); 816 return readByte(); 817 } 818 } 819 820 class DebugVC50Impl implements DebugVC50, DebugVC50TypeLeafIndices { 821 private int lfaBase; 822 823 private int subsectionDirectoryOffset; 824 private MemoizedObject subsectionDirectory; 825 826 DebugVC50Impl(int offset) { 827 lfaBase = offset; 828 seek(offset); 829 readInt(); // Discard NB11 830 subsectionDirectoryOffset = globalOffset(readInt()); 831 832 // Ensure information is complete 833 verify(); 834 835 subsectionDirectory = new MemoizedObject() { 836 public Object computeValue() { 837 return new DebugVC50SubsectionDirectoryImpl(getSubsectionDirectoryOffset()); 838 } 839 }; 840 } 841 842 public int getSubsectionDirectoryOffset() { 843 return subsectionDirectoryOffset; 844 } 845 846 public DebugVC50SubsectionDirectory getSubsectionDirectory() { 847 return (DebugVC50SubsectionDirectory) subsectionDirectory.getValue(); 848 } 849 850 private int globalOffset(int offset) { 851 return offset + lfaBase; 852 } 853 854 private void verify() { 855 // Seek to subsection directory manually and look for 856 // signature following it. This finishes validating that we 857 // have VC++ 5.0 debug info. Throw COFFException if not 858 // found; will cause caller to return null. 859 seek(subsectionDirectoryOffset); 860 int headerLength = readShort(); 861 int entryLength = readShort(); 862 int numEntries = readInt(); 863 int endOffset = subsectionDirectoryOffset + headerLength + numEntries * entryLength; 864 seek(endOffset); 865 866 if (readByte() == 'N' && 867 readByte() == 'B' && 868 readByte() == '1' && 869 readByte() == '1') { 870 return; 871 } 872 873 throw new COFFException("Did not find NB11 signature at end of debug info"); 874 } 875 876 class DebugVC50SubsectionDirectoryImpl 877 implements DebugVC50SubsectionDirectory, 878 DebugVC50SubsectionTypes { 879 private int offset; 880 private short dirHeaderLength; 881 private short dirEntryLength; 882 private int numEntries; 883 884 DebugVC50SubsectionDirectoryImpl(int offset) { 885 this.offset = offset; 886 // Read header 887 seek(offset); 888 dirHeaderLength = readShort(); 889 dirEntryLength = readShort(); 890 numEntries = readInt(); 891 } 892 893 public short getHeaderLength() { return dirHeaderLength; } 894 public short getEntryLength() { return dirEntryLength; } 895 public int getNumEntries() { return numEntries; } 896 897 public DebugVC50Subsection getSubsection(int i) { 898 // Fetch the subsection type and instantiate the correct 899 // type of subsection based on it 900 seek(offset + dirHeaderLength + (i * dirEntryLength)); 901 short ssType = readShort(); 902 short iMod = readShort(); // Unneeded? 903 int lfo = globalOffset(readInt()); 904 int cb = readInt(); 905 switch (ssType) { 906 case SST_MODULE: 907 return new DebugVC50SSModuleImpl(ssType, iMod, cb, lfo); 908 case SST_TYPES: 909 return new DebugVC50SSTypesImpl(ssType, iMod, cb, lfo); 910 case SST_PUBLIC: 911 return new DebugVC50SSPublicImpl(ssType, iMod, cb, lfo); 912 case SST_PUBLIC_SYM: 913 return new DebugVC50SSPublicSymImpl(ssType, iMod, cb, lfo); 914 case SST_SYMBOLS: 915 return new DebugVC50SSSymbolsImpl(ssType, iMod, cb, lfo); 916 case SST_ALIGN_SYM: 917 return new DebugVC50SSAlignSymImpl(ssType, iMod, cb, lfo); 918 case SST_SRC_LN_SEG: 919 return new DebugVC50SSSrcLnSegImpl(ssType, iMod, cb, lfo); 920 case SST_SRC_MODULE: 921 return new DebugVC50SSSrcModuleImpl(ssType, iMod, cb, lfo); 922 case SST_LIBRARIES: 923 return new DebugVC50SSLibrariesImpl(ssType, iMod, cb, lfo); 924 case SST_GLOBAL_SYM: 925 return new DebugVC50SSGlobalSymImpl(ssType, iMod, cb, lfo); 926 case SST_GLOBAL_PUB: 927 return new DebugVC50SSGlobalPubImpl(ssType, iMod, cb, lfo); 928 case SST_GLOBAL_TYPES: 929 return new DebugVC50SSGlobalTypesImpl(ssType, iMod, cb, lfo); 930 case SST_MPC: 931 return new DebugVC50SSMPCImpl(ssType, iMod, cb, lfo); 932 case SST_SEG_MAP: 933 return new DebugVC50SSSegMapImpl(ssType, iMod, cb, lfo); 934 case SST_SEG_NAME: 935 return new DebugVC50SSSegNameImpl(ssType, iMod, cb, lfo); 936 case SST_PRE_COMP: 937 return new DebugVC50SSPreCompImpl(ssType, iMod, cb, lfo); 938 case SST_UNUSED: 939 return null; 940 case SST_OFFSET_MAP_16: 941 return new DebugVC50SSOffsetMap16Impl(ssType, iMod, cb, lfo); 942 case SST_OFFSET_MAP_32: 943 return new DebugVC50SSOffsetMap32Impl(ssType, iMod, cb, lfo); 944 case SST_FILE_INDEX: 945 return new DebugVC50SSFileIndexImpl(ssType, iMod, cb, lfo); 946 case SST_STATIC_SYM: 947 return new DebugVC50SSStaticSymImpl(ssType, iMod, cb, lfo); 948 default: 949 throw new COFFException("Unknown section type " + ssType); 950 } 951 } 952 } 953 954 //////////////////////////////////// 955 // // 956 // Implementations of subsections // 957 // // 958 //////////////////////////////////// 959 960 class DebugVC50SubsectionImpl implements DebugVC50Subsection { 961 private short ssType; 962 private short iMod; 963 private int ssSize; 964 965 DebugVC50SubsectionImpl(short ssType, short iMod, int ssSize, int offset) { 966 this.ssType = ssType; 967 this.iMod = iMod; 968 this.ssSize = ssSize; 969 } 970 971 public short getSubsectionType() { return ssType; } 972 public short getSubsectionModuleIndex() { return iMod; } 973 public int getSubsectionSize() { return ssSize; } 974 } 975 976 class DebugVC50SSModuleImpl extends DebugVC50SubsectionImpl implements DebugVC50SSModule { 977 private int offset; 978 private short ovlNumber; 979 private short iLib; 980 private short cSeg; 981 private short style; 982 private MemoizedObject segInfo; 983 private MemoizedObject name; 984 985 private static final int HEADER_SIZE = 8; 986 private static final int SEG_INFO_SIZE = 12; 987 988 DebugVC50SSModuleImpl(short ssType, short iMod, int ssSize, final int offset) { 989 super(ssType, iMod, ssSize, offset); 990 this.offset = offset; 991 seek(offset); 992 ovlNumber = readShort(); 993 iLib = readShort(); 994 cSeg = readShort(); 995 style = readShort(); 996 segInfo = new MemoizedObject() { 997 public Object computeValue() { 998 int base = offset + HEADER_SIZE; 999 DebugVC50SegInfo[] res = new DebugVC50SegInfo[cSeg]; 1000 for (int i = 0; i < cSeg; i++) { 1001 res[i] = new DebugVC50SegInfoImpl(base); 1002 base += SEG_INFO_SIZE; 1003 } 1004 return res; 1005 } 1006 }; 1007 name = new MemoizedObject() { 1008 public Object computeValue() { 1009 return readLengthPrefixedStringAt(offset + (HEADER_SIZE + cSeg * SEG_INFO_SIZE)); 1010 } 1011 }; 1012 } 1013 1014 public short getOverlayNumber() { return ovlNumber; } 1015 public short getLibrariesIndex() { return iLib; } 1016 public short getNumCodeSegments() { return cSeg; } 1017 public short getDebuggingStyle() { return style; } 1018 public DebugVC50SegInfo getSegInfo(int i) { return ((DebugVC50SegInfo[]) segInfo.getValue())[i]; } 1019 public String getName() { return (String) name.getValue(); } 1020 } 1021 1022 class DebugVC50SegInfoImpl implements DebugVC50SegInfo { 1023 private short seg; 1024 private int offset; 1025 private int cbSeg; 1026 1027 DebugVC50SegInfoImpl(int offset) { 1028 seek(offset); 1029 seg = readShort(); 1030 readShort(); // pad 1031 offset = readInt(); 1032 cbSeg = readInt(); 1033 } 1034 1035 public short getSegment() { return seg; } 1036 public int getOffset() { return offset; } 1037 public int getSegmentCodeSize() { return cbSeg; } 1038 } 1039 1040 class DebugVC50SSTypesImpl extends DebugVC50SubsectionImpl implements DebugVC50SSTypes { 1041 DebugVC50SSTypesImpl(short ssType, short iMod, int ssSize, int offset) { 1042 super(ssType, iMod, ssSize, offset); 1043 } 1044 } 1045 1046 class DebugVC50SSPublicImpl extends DebugVC50SubsectionImpl implements DebugVC50SSPublic { 1047 DebugVC50SSPublicImpl(short ssType, short iMod, int ssSize, int offset) { 1048 super(ssType, iMod, ssSize, offset); 1049 } 1050 } 1051 1052 class DebugVC50SSPublicSymImpl extends DebugVC50SubsectionImpl implements DebugVC50SSPublicSym { 1053 DebugVC50SSPublicSymImpl(short ssType, short iMod, int ssSize, int offset) { 1054 super(ssType, iMod, ssSize, offset); 1055 } 1056 } 1057 1058 class DebugVC50SSSymbolsImpl extends DebugVC50SubsectionImpl implements DebugVC50SSSymbols { 1059 DebugVC50SSSymbolsImpl(short ssType, short iMod, int ssSize, int offset) { 1060 super(ssType, iMod, ssSize, offset); 1061 } 1062 } 1063 1064 class DebugVC50SSAlignSymImpl extends DebugVC50SubsectionImpl implements DebugVC50SSAlignSym { 1065 private int offset; 1066 1067 DebugVC50SSAlignSymImpl(short ssType, short iMod, int ssSize, int offset) { 1068 super(ssType, iMod, ssSize, offset); 1069 this.offset = offset; 1070 } 1071 1072 public DebugVC50SymbolIterator getSymbolIterator() { 1073 return new DebugVC50SymbolIteratorImpl(offset, getSubsectionSize()); 1074 } 1075 } 1076 1077 class DebugVC50SSSrcLnSegImpl extends DebugVC50SubsectionImpl implements DebugVC50SSSrcLnSeg { 1078 DebugVC50SSSrcLnSegImpl(short ssType, short iMod, int ssSize, int offset) { 1079 super(ssType, iMod, ssSize, offset); 1080 } 1081 } 1082 1083 class DebugVC50SSSrcModuleImpl extends DebugVC50SubsectionImpl implements DebugVC50SSSrcModule { 1084 private int offset; 1085 private short cFile; 1086 private short cSeg; 1087 private MemoizedObject baseSrcFiles; 1088 private MemoizedObject segOffsets; 1089 private MemoizedObject segs; 1090 1091 DebugVC50SSSrcModuleImpl(short ssType, short iMod, int ssSize, final int offset) { 1092 super(ssType, iMod, ssSize, offset); 1093 1094 this.offset = offset; 1095 seek(offset); 1096 cFile = readShort(); 1097 cSeg = readShort(); 1098 1099 baseSrcFiles = new MemoizedObject() { 1100 public Object computeValue() { 1101 int[] offsets = new int[getNumSourceFiles()]; 1102 seek(offset + 4); 1103 for (int i = 0; i < getNumSourceFiles(); i++) { 1104 offsets[i] = offset + readInt(); 1105 } 1106 DebugVC50SrcModFileDescImpl[] res = new DebugVC50SrcModFileDescImpl[offsets.length]; 1107 for (int i = 0; i < res.length; i++) { 1108 res[i] = new DebugVC50SrcModFileDescImpl(offsets[i], offset); 1109 } 1110 return res; 1111 } 1112 }; 1113 1114 segOffsets = new MemoizedObject() { 1115 public Object computeValue() { 1116 seek(offset + 4 * (getNumSourceFiles() + 1)); 1117 int[] res = new int[2 * getNumCodeSegments()]; 1118 for (int i = 0; i < 2 * getNumCodeSegments(); i++) { 1119 res[i] = readInt(); 1120 } 1121 return res; 1122 } 1123 }; 1124 1125 segs = new MemoizedObject() { 1126 public Object computeValue() { 1127 seek(offset + 4 * (getNumSourceFiles() + 1) + 8 * getNumCodeSegments()); 1128 short[] res = new short[getNumCodeSegments()]; 1129 for (int i = 0; i < getNumCodeSegments(); i++) { 1130 res[i] = readShort(); 1131 } 1132 return res; 1133 } 1134 }; 1135 } 1136 1137 public int getNumSourceFiles() { return cFile & 0xFFFF; } 1138 public int getNumCodeSegments() { return cSeg & 0xFFFF; } 1139 public DebugVC50SrcModFileDesc getSourceFileDesc(int i) { 1140 return ((DebugVC50SrcModFileDescImpl[]) baseSrcFiles.getValue())[i]; 1141 } 1142 1143 public int getSegmentStartOffset(int i) { 1144 return ((int[]) segOffsets.getValue())[2*i]; 1145 } 1146 1147 public int getSegmentEndOffset(int i) { 1148 return ((int[]) segOffsets.getValue())[2*i+1]; 1149 } 1150 1151 public int getSegment(int i) { 1152 return ((short[]) segs.getValue())[i] & 0xFFFF; 1153 } 1154 } 1155 1156 class DebugVC50SrcModFileDescImpl implements DebugVC50SrcModFileDesc { 1157 private short cSeg; 1158 private MemoizedObject baseSrcLn; 1159 private MemoizedObject segOffsets; 1160 private MemoizedObject name; 1161 1162 DebugVC50SrcModFileDescImpl(final int offset, final int baseOffset) { 1163 seek(offset); 1164 cSeg = readShort(); 1165 1166 baseSrcLn = new MemoizedObject() { 1167 public Object computeValue() { 1168 seek(offset + 4); 1169 int[] offsets = new int[getNumCodeSegments()]; 1170 for (int i = 0; i < getNumCodeSegments(); i++) { 1171 offsets[i] = baseOffset + readInt(); 1172 } 1173 DebugVC50SrcModLineNumberMapImpl[] res = 1174 new DebugVC50SrcModLineNumberMapImpl[getNumCodeSegments()]; 1175 for (int i = 0; i < getNumCodeSegments(); i++) { 1176 res[i] = new DebugVC50SrcModLineNumberMapImpl(offsets[i]); 1177 } 1178 return res; 1179 } 1180 }; 1181 1182 segOffsets = new MemoizedObject() { 1183 public Object computeValue() { 1184 seek(offset + 4 * (getNumCodeSegments() + 1)); 1185 int[] res = new int[2 * getNumCodeSegments()]; 1186 for (int i = 0; i < 2 * getNumCodeSegments(); i++) { 1187 res[i] = readInt(); 1188 } 1189 return res; 1190 } 1191 }; 1192 1193 name = new MemoizedObject() { 1194 public Object computeValue() { 1195 seek(offset + 4 + 12 * getNumCodeSegments()); 1196 // NOTE: spec says name length is two bytes, but it's really one 1197 int cbName = readByte() & 0xFF; 1198 byte[] res = new byte[cbName]; 1199 readBytes(res); 1200 try { 1201 return new String(res, US_ASCII); 1202 } catch (UnsupportedEncodingException e) { 1203 throw new COFFException(e); 1204 } 1205 } 1206 }; 1207 } 1208 1209 public int getNumCodeSegments() { return cSeg & 0xFFFF; } 1210 1211 public DebugVC50SrcModLineNumberMap getLineNumberMap(int i) { 1212 return ((DebugVC50SrcModLineNumberMapImpl[]) baseSrcLn.getValue())[i]; 1213 } 1214 1215 public int getSegmentStartOffset(int i) { 1216 return ((int[]) segOffsets.getValue())[2*i]; 1217 } 1218 1219 public int getSegmentEndOffset(int i) { 1220 return ((int[]) segOffsets.getValue())[2*i+1]; 1221 } 1222 1223 public String getSourceFileName() { 1224 return (String) name.getValue(); 1225 } 1226 } 1227 1228 class DebugVC50SrcModLineNumberMapImpl implements DebugVC50SrcModLineNumberMap { 1229 private short seg; 1230 private short cPair; 1231 private MemoizedObject offsets; 1232 private MemoizedObject lineNumbers; 1233 1234 DebugVC50SrcModLineNumberMapImpl(final int offset) { 1235 seek(offset); 1236 seg = readShort(); 1237 cPair = readShort(); 1238 offsets = new MemoizedObject() { 1239 public Object computeValue() { 1240 seek(offset + 4); 1241 int[] res = new int[getNumSourceLinePairs()]; 1242 for (int i = 0; i < getNumSourceLinePairs(); i++) { 1243 res[i] = readInt(); 1244 } 1245 return res; 1246 } 1247 }; 1248 1249 lineNumbers = new MemoizedObject() { 1250 public Object computeValue() { 1251 seek(offset + 4 * (getNumSourceLinePairs() + 1)); 1252 short[] res = new short[getNumSourceLinePairs()]; 1253 for (int i = 0; i < getNumSourceLinePairs(); i++) { 1254 res[i] = readShort(); 1255 } 1256 return res; 1257 } 1258 }; 1259 } 1260 1261 public int getSegment() { return seg; } 1262 public int getNumSourceLinePairs() { return cPair; } 1263 public int getCodeOffset(int i) { 1264 return ((int[]) offsets.getValue())[i]; 1265 } 1266 public int getLineNumber(int i) { 1267 return ((short[]) lineNumbers.getValue())[i] & 0xFFFF; 1268 } 1269 } 1270 1271 class DebugVC50SSLibrariesImpl extends DebugVC50SubsectionImpl implements DebugVC50SSLibraries { 1272 DebugVC50SSLibrariesImpl(short ssType, short iMod, int ssSize, int offset) { 1273 super(ssType, iMod, ssSize, offset); 1274 } 1275 1276 // FIXME: NOT FINISHED 1277 } 1278 1279 class DebugVC50SSSymbolBaseImpl extends DebugVC50SubsectionImpl implements DebugVC50SSSymbolBase { 1280 private int offset; 1281 private short symHash; 1282 private short addrHash; 1283 private int cbSymbol; 1284 private int cbSymHash; 1285 private int cbAddrHash; 1286 1287 private static final int HEADER_SIZE = 16; 1288 1289 DebugVC50SSSymbolBaseImpl(short ssType, short iMod, int ssSize, int offset) { 1290 super(ssType, iMod, ssSize, offset); 1291 this.offset = offset; 1292 seek(offset); 1293 symHash = readShort(); 1294 addrHash = readShort(); 1295 cbSymbol = readInt(); 1296 cbSymHash = readInt(); 1297 cbAddrHash = readInt(); 1298 } 1299 1300 public short getSymHashIndex() { return symHash; } 1301 public short getAddrHashIndex() { return addrHash; } 1302 public int getSymTabSize() { return cbSymbol; } 1303 public int getSymHashSize() { return cbSymHash; } 1304 public int getAddrHashSize() { return cbAddrHash; } 1305 1306 public DebugVC50SymbolIterator getSymbolIterator() { 1307 return new DebugVC50SymbolIteratorImpl(offset + HEADER_SIZE, cbSymbol); 1308 } 1309 } 1310 1311 class DebugVC50SSGlobalSymImpl extends DebugVC50SSSymbolBaseImpl implements DebugVC50SSGlobalSym { 1312 DebugVC50SSGlobalSymImpl(short ssType, short iMod, int ssSize, int offset) { 1313 super(ssType, iMod, ssSize, offset); 1314 } 1315 } 1316 class DebugVC50SSGlobalPubImpl extends DebugVC50SSSymbolBaseImpl implements DebugVC50SSGlobalPub { 1317 DebugVC50SSGlobalPubImpl(short ssType, short iMod, int ssSize, int offset) { 1318 super(ssType, iMod, ssSize, offset); 1319 } 1320 } 1321 1322 class DebugVC50SSGlobalTypesImpl extends DebugVC50SubsectionImpl implements DebugVC50SSGlobalTypes { 1323 private int offset; 1324 private int cType; 1325 1326 DebugVC50SSGlobalTypesImpl(short ssType, short iMod, int ssSize, int offset) { 1327 super(ssType, iMod, ssSize, offset); 1328 this.offset = offset; 1329 seek(offset); 1330 readInt(); // Discard "flags" 1331 cType = readInt(); 1332 } 1333 1334 public int getNumTypes() { return cType; } 1335 // FIXME: should memoize these 1336 public int getTypeOffset(int i) { 1337 seek(offset + 4 * (i + 2)); 1338 return readInt() + offsetOfFirstType(); 1339 } 1340 1341 public DebugVC50TypeIterator getTypeIterator() { 1342 return new DebugVC50TypeIteratorImpl(this, 1343 offsetOfFirstType(), 1344 cType); 1345 } 1346 1347 private int offsetOfFirstType() { 1348 return offset + 4 * (getNumTypes() + 2); 1349 } 1350 } 1351 1352 class DebugVC50SSMPCImpl extends DebugVC50SubsectionImpl implements DebugVC50SSMPC { 1353 DebugVC50SSMPCImpl(short ssType, short iMod, int ssSize, int offset) { 1354 super(ssType, iMod, ssSize, offset); 1355 } 1356 } 1357 1358 class DebugVC50SSSegMapImpl extends DebugVC50SubsectionImpl implements DebugVC50SSSegMap { 1359 private short cSeg; 1360 private short cSegLog; 1361 private MemoizedObject segDescs; 1362 1363 DebugVC50SSSegMapImpl(short ssType, short iMod, int ssSize, final int offset) { 1364 super(ssType, iMod, ssSize, offset); 1365 seek(offset); 1366 cSeg = readShort(); 1367 cSegLog = readShort(); 1368 segDescs = new MemoizedObject() { 1369 public Object computeValue() { 1370 DebugVC50SegDesc[] descs = new DebugVC50SegDesc[cSeg]; 1371 for (int i = 0; i < cSeg; i++) { 1372 descs[i] = new DebugVC50SegDescImpl(offset + 4 + (20 * i)); 1373 } 1374 return descs; 1375 } 1376 }; 1377 } 1378 1379 public short getNumSegDesc() { return cSeg; } 1380 public short getNumLogicalSegDesc() { return cSegLog; } 1381 public DebugVC50SegDesc getSegDesc(int i) { return ((DebugVC50SegDesc[]) segDescs.getValue())[i]; } 1382 } 1383 1384 class DebugVC50SegDescImpl implements DebugVC50SegDesc { 1385 private short flags; 1386 private short ovl; 1387 private short group; 1388 private short frame; 1389 private short iSegName; 1390 private short iClassName; 1391 private int offset; 1392 private int cbSeg; 1393 1394 DebugVC50SegDescImpl(int offset) { 1395 seek(offset); 1396 flags = readShort(); 1397 ovl = readShort(); 1398 group = readShort(); 1399 frame = readShort(); 1400 iSegName = readShort(); 1401 iClassName = readShort(); 1402 offset = readInt(); 1403 cbSeg = readInt(); 1404 } 1405 1406 public short getFlags() { return flags; } 1407 public short getOverlayNum() { return ovl; } 1408 public short getGroup() { return group; } 1409 public short getFrame() { return frame; } 1410 public short getName() { return iSegName; } 1411 public short getClassName() { return iClassName; } 1412 public int getOffset() { return offset; } 1413 public int getSize() { return cbSeg; } 1414 } 1415 1416 1417 class DebugVC50SSSegNameImpl extends DebugVC50SubsectionImpl implements DebugVC50SSSegName { 1418 private int offset; 1419 private int size; 1420 private MemoizedObject names; 1421 1422 DebugVC50SSSegNameImpl(short ssType, short iMod, int ssSize, int offset) { 1423 super(ssType, iMod, ssSize, offset); 1424 this.offset = offset; 1425 this.size = ssSize; 1426 seek(offset); 1427 names = new MemoizedObject() { 1428 public Object computeValue() { 1429 int i = 0; 1430 List data = new ArrayList(); 1431 while (i < size) { 1432 String s = readCString(); 1433 data.add(s); 1434 i += s.length(); 1435 } 1436 String[] res = new String[data.size()]; 1437 res = (String[]) data.toArray(res); 1438 return res; 1439 } 1440 }; 1441 } 1442 1443 public String getSegName(int i) { 1444 return ((String[]) names.getValue())[i]; 1445 } 1446 } 1447 1448 class DebugVC50SSPreCompImpl extends DebugVC50SubsectionImpl implements DebugVC50SSPreComp { 1449 DebugVC50SSPreCompImpl(short ssType, short iMod, int ssSize, int offset) { 1450 super(ssType, iMod, ssSize, offset); 1451 } 1452 } 1453 1454 class DebugVC50SSOffsetMap16Impl extends DebugVC50SubsectionImpl implements DebugVC50SSOffsetMap16 { 1455 DebugVC50SSOffsetMap16Impl(short ssType, short iMod, int ssSize, int offset) { 1456 super(ssType, iMod, ssSize, offset); 1457 } 1458 } 1459 1460 class DebugVC50SSOffsetMap32Impl extends DebugVC50SubsectionImpl implements DebugVC50SSOffsetMap32 { 1461 DebugVC50SSOffsetMap32Impl(short ssType, short iMod, int ssSize, int offset) { 1462 super(ssType, iMod, ssSize, offset); 1463 } 1464 } 1465 1466 class DebugVC50SSFileIndexImpl extends DebugVC50SubsectionImpl implements DebugVC50SSFileIndex { 1467 private int offset; 1468 private short cMod; // Number of modules in the executable 1469 private short cRef; // Total number of file name references 1470 private MemoizedObject modStart; 1471 private MemoizedObject cRefCnt; 1472 // FIXME: probably useless; needs fixup to be converted into 1473 // indices rather than offsets 1474 private MemoizedObject nameRef; 1475 private MemoizedObject names; 1476 1477 DebugVC50SSFileIndexImpl(short ssType, short iMod, int ssSize, final int offset) { 1478 super(ssType, iMod, ssSize, offset); 1479 this.offset = offset; 1480 seek(offset); 1481 cMod = readShort(); 1482 cRef = readShort(); 1483 modStart = new MemoizedObject() { 1484 public Object computeValue() { 1485 short[] vals = new short[cMod]; 1486 seek(4 + offset); 1487 for (int i = 0; i < cMod; i++) { 1488 vals[i] = readShort(); 1489 } 1490 return vals; 1491 } 1492 }; 1493 cRefCnt = new MemoizedObject() { 1494 public Object computeValue() { 1495 short[] vals = new short[cMod]; 1496 seek(4 + offset + (2 * cMod)); 1497 for (int i = 0; i < cMod; i++) { 1498 vals[i] = readShort(); 1499 } 1500 return vals; 1501 } 1502 }; 1503 nameRef = new MemoizedObject() { 1504 public Object computeValue() { 1505 int[] vals = new int[cRef]; 1506 seek(4 + offset + (4 * cMod)); 1507 for (int i = 0; i < cMod; i++) { 1508 vals[i] = readInt(); 1509 } 1510 return vals; 1511 } 1512 }; 1513 names = new MemoizedObject() { 1514 public Object computeValue() { 1515 String[] vals = new String[cRef]; 1516 for (int i = 0; i < cRef; i++) { 1517 vals[i] = readCString(); 1518 } 1519 return vals; 1520 } 1521 }; 1522 } 1523 1524 public short getNumModules() { return cMod; } 1525 public short getNumReferences() { return cRef; } 1526 public short[] getModStart() { return (short[]) modStart.getValue(); } 1527 public short[] getRefCount() { return (short[]) cRefCnt.getValue(); } 1528 public int[] getNameRef() { return (int[]) nameRef.getValue(); } 1529 public String[] getNames() { return (String[]) names.getValue(); } 1530 } 1531 1532 class DebugVC50SSStaticSymImpl extends DebugVC50SSSymbolBaseImpl implements DebugVC50SSStaticSym { 1533 DebugVC50SSStaticSymImpl(short ssType, short iMod, int ssSize, int offset) { 1534 super(ssType, iMod, ssSize, offset); 1535 } 1536 } 1537 1538 ////////////////////////////////////////////////// 1539 // // 1540 // Implementations of symbol and type iterators // 1541 // // 1542 ////////////////////////////////////////////////// 1543 1544 class DebugVC50SymbolIteratorImpl implements DebugVC50SymbolIterator { 1545 private int base; 1546 private int size; 1547 private int pos; 1548 private int curSymSize; 1549 private int curSymType; 1550 1551 private static final int HEADER_SIZE = 4; 1552 1553 DebugVC50SymbolIteratorImpl(int base, int size) { 1554 this(base, size, base); 1555 } 1556 1557 private DebugVC50SymbolIteratorImpl(int base, int size, int pos) { 1558 this.base = base; 1559 this.size = size; 1560 this.pos = pos; 1561 seek(pos); 1562 curSymSize = readShort() & 0xFFFF; 1563 curSymType = readShort() & 0xFFFF; 1564 } 1565 1566 public boolean done() { 1567 return (pos == (base + size)); 1568 } 1569 1570 public void next() throws NoSuchElementException { 1571 if (done()) throw new NoSuchElementException("No more symbols"); 1572 pos += curSymSize + 2; 1573 seek(pos); 1574 curSymSize = readShort() & 0xFFFF; 1575 curSymType = readShort() & 0xFFFF; 1576 } 1577 1578 public short getLength() { 1579 return (short) curSymSize; 1580 } 1581 1582 public int getType() { 1583 return curSymType; 1584 } 1585 1586 public int getOffset() { 1587 return pos + HEADER_SIZE; 1588 } 1589 1590 ///////////////////////// 1591 // S_COMPILE accessors // 1592 ///////////////////////// 1593 1594 public byte getCompilerTargetProcessor() { 1595 symSeek(0); 1596 return readByte(); 1597 } 1598 1599 public int getCompilerFlags() { 1600 symSeek(1); 1601 int res = 0; 1602 for (int i = 0; i < 3; i++) { 1603 int b = readByte() & 0xFF; 1604 res = (res << 8) | b; 1605 } 1606 return res; 1607 } 1608 1609 public String getComplierVersion() { 1610 return readLengthPrefixedStringAt(4); 1611 } 1612 1613 ////////////////////////// 1614 // S_REGISTER accessors // 1615 ////////////////////////// 1616 1617 public int getRegisterSymbolType() { 1618 symSeek(0); 1619 return readInt(); 1620 } 1621 1622 public short getRegisterEnum() { 1623 symSeek(4); 1624 return readShort(); 1625 } 1626 1627 public String getRegisterSymbolName() { 1628 return readLengthPrefixedStringAt(6); 1629 } 1630 1631 ////////////////////////// 1632 // S_CONSTANT accessors // 1633 ////////////////////////// 1634 1635 public int getConstantType() { 1636 symSeek(0); 1637 return readInt(); 1638 } 1639 1640 public int getConstantValueAsInt() throws DebugVC50WrongNumericTypeException { 1641 return readIntNumericLeafAt(4); 1642 } 1643 1644 public long getConstantValueAsLong() throws DebugVC50WrongNumericTypeException { 1645 return readLongNumericLeafAt(4); 1646 } 1647 1648 public float getConstantValueAsFloat() throws DebugVC50WrongNumericTypeException { 1649 return readFloatNumericLeafAt(4); 1650 } 1651 1652 public double getConstantValueAsDouble() throws DebugVC50WrongNumericTypeException { 1653 return readDoubleNumericLeafAt(4); 1654 } 1655 1656 public String getConstantName() { 1657 return readLengthPrefixedStringAt(4 + numericLeafLengthAt(4)); 1658 } 1659 1660 ///////////////////// 1661 // S_UDT accessors // 1662 ///////////////////// 1663 1664 public int getUDTType() { 1665 symSeek(0); 1666 return readInt(); 1667 } 1668 1669 public String getUDTName() { 1670 return readLengthPrefixedStringAt(4); 1671 } 1672 1673 ///////////////////////// 1674 // S_SSEARCH accessors // 1675 ///////////////////////// 1676 1677 public int getSearchSymbolOffset() { 1678 symSeek(0); 1679 return readInt(); 1680 } 1681 1682 public short getSearchSegment() { 1683 symSeek(4); 1684 return readShort(); 1685 } 1686 1687 ///////////////////// 1688 // S_END accessors // 1689 ///////////////////// 1690 1691 // (No accessors) 1692 1693 ////////////////////// 1694 // S_SKIP accessors // 1695 ////////////////////// 1696 1697 // (No accessors) 1698 1699 /////////////////////////// 1700 // S_CVRESERVE accessors // 1701 /////////////////////////// 1702 1703 // (No accessors) 1704 1705 ///////////////////////// 1706 // S_OBJNAME accessors // 1707 ///////////////////////// 1708 1709 public int getObjectCodeViewSignature() { 1710 symSeek(0); 1711 return readInt(); 1712 } 1713 1714 public String getObjectName() { 1715 return readLengthPrefixedStringAt(4); 1716 } 1717 1718 //////////////////////// 1719 // S_ENDARG accessors // 1720 //////////////////////// 1721 1722 // (No accessors) 1723 1724 ////////////////////////// 1725 // S_COBOLUDT accessors // 1726 ////////////////////////// 1727 1728 // (Elided as they are irrelevant) 1729 1730 ///////////////////////// 1731 // S_MANYREG accessors // 1732 ///////////////////////// 1733 1734 public int getManyRegType() { 1735 symSeek(0); 1736 return readInt(); 1737 } 1738 1739 public byte getManyRegCount() { 1740 symSeek(4); 1741 return readByte(); 1742 } 1743 1744 public byte getManyRegRegister(int i) { 1745 symSeek(5 + i); 1746 return readByte(); 1747 } 1748 1749 public String getManyRegName() { 1750 return readLengthPrefixedStringAt(5 + getManyRegCount()); 1751 } 1752 1753 //////////////////////// 1754 // S_RETURN accessors // 1755 //////////////////////// 1756 1757 public short getReturnFlags() { 1758 symSeek(0); 1759 return readShort(); 1760 } 1761 1762 public byte getReturnStyle() { 1763 symSeek(2); 1764 return readByte(); 1765 } 1766 1767 public byte getReturnRegisterCount() { 1768 symSeek(3); 1769 return readByte(); 1770 } 1771 1772 public byte getReturnRegister(int i) { 1773 symSeek(4 + i); 1774 return readByte(); 1775 } 1776 1777 /////////////////////////// 1778 // S_ENTRYTHIS accessors // 1779 /////////////////////////// 1780 1781 public void advanceToEntryThisSymbol() { 1782 seek(pos + 4); 1783 int tmpSymSize = readShort(); 1784 int tmpSymType = readShort(); 1785 if (Assert.ASSERTS_ENABLED) { 1786 // Make sure that ends of inner and outer symbols line 1787 // up, otherwise need more work 1788 Assert.that(pos + curSymSize + 2 == pos + 4 + tmpSymSize, 1789 "advanceToEntryThisSymbol needs more work"); 1790 } 1791 pos += 4; 1792 curSymSize = tmpSymSize; 1793 curSymType = tmpSymType; 1794 } 1795 1796 /////////////////////////////////////////////////////////////////////// 1797 // // 1798 // // 1799 // Symbols for (Intel) 16:32 Segmented and 32-bit Flat Architectures // 1800 // // 1801 // // 1802 /////////////////////////////////////////////////////////////////////// 1803 1804 ///////////////////////// 1805 // S_BPREL32 accessors // 1806 ///////////////////////// 1807 1808 public int getBPRelOffset() { 1809 symSeek(0); 1810 return readInt(); 1811 } 1812 1813 public int getBPRelType() { 1814 symSeek(4); 1815 return readInt(); 1816 } 1817 1818 public String getBPRelName() { 1819 return readLengthPrefixedStringAt(8); 1820 } 1821 1822 /////////////////////////////////////// 1823 // S_LDATA32 and S_GDATA32 accessors // 1824 /////////////////////////////////////// 1825 1826 public int getLGDataType() { 1827 symSeek(0); 1828 return readInt(); 1829 } 1830 1831 public int getLGDataOffset() { 1832 symSeek(4); 1833 return readInt(); 1834 } 1835 1836 public short getLGDataSegment() { 1837 symSeek(8); 1838 return readShort(); 1839 } 1840 1841 public String getLGDataName() { 1842 return readLengthPrefixedStringAt(10); 1843 } 1844 1845 /////////////////////// 1846 // S_PUB32 accessors // 1847 /////////////////////// 1848 1849 // FIXME: has the same format as the above; consider updating 1850 // documentation. No separate accessors provided. 1851 1852 /////////////////////////////////////// 1853 // S_LPROC32 and S_GPROC32 accessors // 1854 /////////////////////////////////////// 1855 1856 public DebugVC50SymbolIterator getLGProcParent() { 1857 int offs = getLGProcParentOffset(); 1858 if (offs == 0) return null; 1859 return new DebugVC50SymbolIteratorImpl(base, size, offs); 1860 } 1861 1862 public int getLGProcParentOffset() { 1863 symSeek(0); 1864 int offs = readInt(); 1865 if (offs == 0) return 0; 1866 return base + offs; 1867 } 1868 1869 public DebugVC50SymbolIterator getLGProcEnd() { 1870 int offs = getLGProcEndOffset(); 1871 return new DebugVC50SymbolIteratorImpl(base, size, offs); 1872 } 1873 1874 public int getLGProcEndOffset() { 1875 symSeek(4); 1876 int offs = readInt(); 1877 if (Assert.ASSERTS_ENABLED) { 1878 Assert.that(offs != 0, "should not have null end offset for procedure symbols"); 1879 } 1880 return base + offs; 1881 } 1882 1883 public DebugVC50SymbolIterator getLGProcNext() { 1884 int offs = getLGProcNextOffset(); 1885 if (offs == 0) return null; 1886 return new DebugVC50SymbolIteratorImpl(base, size, offs); 1887 } 1888 1889 public int getLGProcNextOffset() { 1890 symSeek(8); 1891 int offs = readInt(); 1892 if (offs == 0) return 0; 1893 return base + offs; 1894 } 1895 1896 public int getLGProcLength() { 1897 symSeek(12); 1898 return readInt(); 1899 } 1900 1901 public int getLGProcDebugStart() { 1902 symSeek(16); 1903 return readInt(); 1904 } 1905 1906 public int getLGProcDebugEnd() { 1907 symSeek(20); 1908 return readInt(); 1909 } 1910 1911 public int getLGProcType() { 1912 symSeek(24); 1913 return readInt(); 1914 } 1915 1916 public int getLGProcOffset() { 1917 symSeek(28); 1918 return readInt(); 1919 } 1920 1921 public short getLGProcSegment() { 1922 symSeek(32); 1923 return readShort(); 1924 } 1925 1926 public byte getLGProcFlags() { 1927 symSeek(34); 1928 return readByte(); 1929 } 1930 1931 public String getLGProcName() { 1932 return readLengthPrefixedStringAt(35); 1933 } 1934 1935 ///////////////////////// 1936 // S_THUNK32 accessors // 1937 ///////////////////////// 1938 1939 public DebugVC50SymbolIterator getThunkParent() { 1940 int offs = getThunkParentOffset(); 1941 if (offs == 0) return null; 1942 return new DebugVC50SymbolIteratorImpl(base, size, offs); 1943 } 1944 1945 public int getThunkParentOffset() { 1946 symSeek(0); 1947 int offs = readInt(); 1948 if (offs == 0) return 0; 1949 return base + offs; 1950 } 1951 1952 public DebugVC50SymbolIterator getThunkEnd() { 1953 symSeek(4); 1954 int offs = readInt(); 1955 return new DebugVC50SymbolIteratorImpl(base, size, offs); 1956 } 1957 1958 public int getThunkEndOffset() { 1959 symSeek(4); 1960 int offs = readInt(); 1961 if (Assert.ASSERTS_ENABLED) { 1962 Assert.that(offs != 0, "should not have null end offset for thunk symbols"); 1963 } 1964 return base + offs; 1965 } 1966 1967 public DebugVC50SymbolIterator getThunkNext() { 1968 int offs = getThunkNextOffset(); 1969 if (offs == 0) return null; 1970 return new DebugVC50SymbolIteratorImpl(base, size, base + offs); 1971 } 1972 1973 public int getThunkNextOffset() { 1974 symSeek(8); 1975 int offs = readInt(); 1976 if (offs == 0) return 0; 1977 return base + offs; 1978 } 1979 1980 public int getThunkOffset() { 1981 symSeek(12); 1982 return readInt(); 1983 } 1984 1985 public short getThunkSegment() { 1986 symSeek(16); 1987 return readShort(); 1988 } 1989 1990 public short getThunkLength() { 1991 symSeek(18); 1992 return readShort(); 1993 } 1994 1995 public byte getThunkType() { 1996 symSeek(20); 1997 return readByte(); 1998 } 1999 2000 public String getThunkName() { 2001 return readLengthPrefixedStringAt(21); 2002 } 2003 2004 public short getThunkAdjustorThisDelta() { 2005 symSeek(21 + lengthPrefixedStringLengthAt(21)); 2006 return readShort(); 2007 } 2008 2009 public String getThunkAdjustorTargetName() { 2010 return readLengthPrefixedStringAt(23 + lengthPrefixedStringLengthAt(21)); 2011 } 2012 2013 public short getThunkVCallDisplacement() { 2014 symSeek(21 + lengthPrefixedStringLengthAt(21)); 2015 return readShort(); 2016 } 2017 2018 public int getThunkPCodeOffset() { 2019 symSeek(21 + lengthPrefixedStringLengthAt(21)); 2020 return readInt(); 2021 } 2022 2023 public short getThunkPCodeSegment() { 2024 symSeek(25 + lengthPrefixedStringLengthAt(21)); 2025 return readShort(); 2026 } 2027 2028 ///////////////////////// 2029 // S_BLOCK32 accessors // 2030 ///////////////////////// 2031 2032 public DebugVC50SymbolIterator getBlockParent() { 2033 int offs = getBlockParentOffset(); 2034 if (offs == 0) return null; 2035 return new DebugVC50SymbolIteratorImpl(base, size, offs); 2036 } 2037 2038 public int getBlockParentOffset() { 2039 symSeek(0); 2040 int offs = readInt(); 2041 if (offs == 0) return 0; 2042 return base + offs; 2043 } 2044 2045 public DebugVC50SymbolIterator getBlockEnd() { 2046 symSeek(4); 2047 int offs = readInt(); 2048 return new DebugVC50SymbolIteratorImpl(base, size, offs); 2049 } 2050 2051 public int getBlockEndOffset() { 2052 symSeek(4); 2053 int offs = readInt(); 2054 if (Assert.ASSERTS_ENABLED) { 2055 Assert.that(offs != 0, "should not have null end offset for block symbols"); 2056 } 2057 return base + offs; 2058 } 2059 2060 public int getBlockLength() { 2061 symSeek(8); 2062 return readInt(); 2063 } 2064 2065 public int getBlockOffset() { 2066 symSeek(12); 2067 return readInt(); 2068 } 2069 2070 public short getBlockSegment() { 2071 symSeek(16); 2072 return readShort(); 2073 } 2074 2075 public String getBlockName() { 2076 return readLengthPrefixedStringAt(18); 2077 } 2078 2079 //////////////////////// 2080 // S_WITH32 accessors // 2081 //////////////////////// 2082 2083 // FIXME: this is a Pascal construct; ignored for now 2084 2085 ///////////////////////// 2086 // S_LABEL32 accessors // 2087 ///////////////////////// 2088 2089 public int getLabelOffset() { 2090 symSeek(0); 2091 return readInt(); 2092 } 2093 2094 public short getLabelSegment() { 2095 symSeek(4); 2096 return readShort(); 2097 } 2098 2099 public byte getLabelFlags() { 2100 symSeek(6); 2101 return readByte(); 2102 } 2103 2104 public String getLabelName() { 2105 return readLengthPrefixedStringAt(7); 2106 } 2107 2108 //////////////////////////// 2109 // S_CEXMODEL32 accessors // 2110 //////////////////////////// 2111 2112 public int getChangeOffset() { 2113 symSeek(0); 2114 return readInt(); 2115 } 2116 2117 public short getChangeSegment() { 2118 symSeek(4); 2119 return readShort(); 2120 } 2121 2122 public short getChangeModel() { 2123 symSeek(6); 2124 return readShort(); 2125 } 2126 2127 //////////////////////////// 2128 // S_VFTTABLE32 accessors // 2129 //////////////////////////// 2130 2131 public int getVTableRoot() { 2132 symSeek(0); 2133 return readInt(); 2134 } 2135 2136 public int getVTablePath() { 2137 symSeek(4); 2138 return readInt(); 2139 } 2140 2141 public int getVTableOffset() { 2142 symSeek(8); 2143 return readInt(); 2144 } 2145 2146 public short getVTableSegment() { 2147 symSeek(12); 2148 return readShort(); 2149 } 2150 2151 ////////////////////////// 2152 // S_REGREL32 accessors // 2153 ////////////////////////// 2154 2155 public int getRegRelOffset() { 2156 symSeek(0); 2157 return readInt(); 2158 } 2159 2160 public int getRegRelType() { 2161 symSeek(4); 2162 return readInt(); 2163 } 2164 2165 public short getRegRelRegister() { 2166 symSeek(8); 2167 return readShort(); 2168 } 2169 2170 public String getRegRelName() { 2171 return readLengthPrefixedStringAt(10); 2172 } 2173 2174 /////////////////////////////////////////// 2175 // S_LTHREAD32 and S_GTHREAD32 accessors // 2176 /////////////////////////////////////////// 2177 2178 public int getLThreadType() { 2179 symSeek(0); 2180 return readInt(); 2181 } 2182 2183 public int getLThreadOffset() { 2184 symSeek(4); 2185 return readInt(); 2186 } 2187 2188 public short getLThreadSegment() { 2189 symSeek(8); 2190 return readShort(); 2191 } 2192 2193 public String getLThreadName() { 2194 return readLengthPrefixedStringAt(10); 2195 } 2196 2197 //---------------------------------------------------------------------- 2198 // Internals only below this point 2199 // 2200 2201 private void symSeek(int offsetInSym) { 2202 seek(pos + HEADER_SIZE + offsetInSym); 2203 } 2204 2205 private int numericLeafLengthAt(int offsetInSym) { 2206 return DebugVC50Impl.this.numericLeafLengthAt(pos + HEADER_SIZE + offsetInSym); 2207 } 2208 2209 private int readIntNumericLeafAt(int offsetInSym) { 2210 return DebugVC50Impl.this.readIntNumericLeafAt(pos + HEADER_SIZE + offsetInSym); 2211 } 2212 2213 private long readLongNumericLeafAt(int offsetInSym) { 2214 return DebugVC50Impl.this.readLongNumericLeafAt(pos + HEADER_SIZE + offsetInSym); 2215 } 2216 2217 private float readFloatNumericLeafAt(int offsetInSym) { 2218 return DebugVC50Impl.this.readFloatNumericLeafAt(pos + HEADER_SIZE + offsetInSym); 2219 } 2220 2221 private double readDoubleNumericLeafAt(int offsetInSym) { 2222 return DebugVC50Impl.this.readDoubleNumericLeafAt(pos + HEADER_SIZE + offsetInSym); 2223 } 2224 2225 private int lengthPrefixedStringLengthAt(int offsetInSym) { 2226 return DebugVC50Impl.this.lengthPrefixedStringLengthAt(pos + HEADER_SIZE + offsetInSym); 2227 } 2228 2229 private String readLengthPrefixedStringAt(int offsetInSym) { 2230 return DebugVC50Impl.this.readLengthPrefixedStringAt(pos + HEADER_SIZE + offsetInSym); 2231 } 2232 } 2233 2234 class DebugVC50TypeIteratorImpl implements DebugVC50TypeIterator, 2235 DebugVC50TypeLeafIndices, DebugVC50MemberAttributes, DebugVC50TypeEnums { 2236 private DebugVC50SSGlobalTypes parent; 2237 private int base; 2238 private int numTypes; 2239 private int typeIndex; 2240 private int typeRecordOffset; 2241 private int typeStringOffset; 2242 private int typeRecordSize; 2243 private int typeStringLeaf; 2244 2245 DebugVC50TypeIteratorImpl(DebugVC50SSGlobalTypes parent, int base, int numTypes) { 2246 this(parent, base, numTypes, 0, base); 2247 } 2248 2249 private DebugVC50TypeIteratorImpl(DebugVC50SSGlobalTypes parent, int base, int numTypes, int curType, int offset) { 2250 this.parent = parent; 2251 this.base = base; 2252 this.numTypes = numTypes; 2253 this.typeIndex = curType; 2254 if (!done()) { 2255 typeRecordOffset = offset; 2256 loadTypeRecord(); 2257 } 2258 } 2259 2260 public boolean done() { 2261 return (typeIndex == numTypes); 2262 } 2263 2264 public void next() throws NoSuchElementException { 2265 if (done()) throw new NoSuchElementException(); 2266 ++typeIndex; 2267 if (!done()) { 2268 typeRecordOffset = parent.getTypeOffset(typeIndex); 2269 loadTypeRecord(); 2270 } 2271 } 2272 2273 public short getLength() { 2274 return (short) typeRecordSize; 2275 } 2276 2277 public int getTypeIndex() { 2278 return biasTypeIndex(typeIndex); 2279 } 2280 2281 public int getNumTypes() { 2282 return numTypes; 2283 } 2284 2285 public boolean typeStringDone() { 2286 return (typeStringOffset - typeRecordOffset - 2) >= typeRecordSize; 2287 } 2288 2289 public void typeStringNext() throws NoSuchElementException { 2290 if (typeStringDone()) throw new NoSuchElementException(); 2291 typeStringOffset += typeStringLength(); 2292 loadTypeString(); 2293 } 2294 2295 public int typeStringLeaf() { 2296 return typeStringLeaf; 2297 } 2298 2299 public int typeStringOffset() { 2300 return typeStringOffset; 2301 } 2302 2303 /////////////////////////// 2304 // LF_MODIFIER accessors // 2305 /////////////////////////// 2306 2307 public int getModifierIndex() { 2308 typeSeek(2); 2309 return readInt(); 2310 } 2311 2312 public short getModifierAttribute() { 2313 typeSeek(6); 2314 return readShort(); 2315 } 2316 2317 ////////////////////////// 2318 // LF_POINTER accessors // 2319 ////////////////////////// 2320 2321 public int getPointerType() { 2322 typeSeek(2); 2323 return readInt(); 2324 } 2325 2326 public int getPointerAttributes() { 2327 typeSeek(6); 2328 return readInt(); 2329 } 2330 2331 public int getPointerBasedOnTypeIndex() { 2332 typeSeek(10); 2333 return readInt(); 2334 } 2335 2336 public String getPointerBasedOnTypeName() { 2337 return readLengthPrefixedStringAt(14); 2338 } 2339 2340 public int getPointerToMemberClass() { 2341 typeSeek(10); 2342 return readInt(); 2343 } 2344 2345 public short getPointerToMemberFormat() { 2346 typeSeek(14); 2347 return readShort(); 2348 } 2349 2350 //////////////////////// 2351 // LF_ARRAY accessors // 2352 //////////////////////// 2353 2354 public int getArrayElementType() { 2355 typeSeek(2); 2356 return readInt(); 2357 } 2358 2359 public int getArrayIndexType() { 2360 typeSeek(6); 2361 return readInt(); 2362 } 2363 2364 public int getArrayLength() throws DebugVC50WrongNumericTypeException { 2365 return readIntNumericLeafAt(10); 2366 } 2367 2368 public String getArrayName() { 2369 return readLengthPrefixedStringAt(10 + numericLeafLengthAt(10)); 2370 } 2371 2372 ///////////////////////////////////////// 2373 // LF_CLASS and LF_STRUCTURE accessors // 2374 ///////////////////////////////////////// 2375 2376 public short getClassCount() { 2377 typeSeek(2); 2378 return readShort(); 2379 } 2380 2381 public short getClassProperty() { 2382 typeSeek(4); 2383 return readShort(); 2384 } 2385 2386 public int getClassFieldList() { 2387 typeSeek(6); 2388 return readInt(); 2389 } 2390 2391 public DebugVC50TypeIterator getClassFieldListIterator() { 2392 int index = unbiasTypeIndex(getClassFieldList()); 2393 int offset = parent.getTypeOffset(index); 2394 return new DebugVC50TypeIteratorImpl(parent, base, numTypes, index, offset); 2395 } 2396 2397 public int getClassDerivationList() { 2398 typeSeek(10); 2399 return readInt(); 2400 } 2401 2402 public int getClassVShape() { 2403 typeSeek(14); 2404 return readInt(); 2405 } 2406 2407 public int getClassSize() throws DebugVC50WrongNumericTypeException { 2408 return readIntNumericLeafAt(18); 2409 } 2410 2411 public String getClassName() { 2412 return readLengthPrefixedStringAt(18 + numericLeafLengthAt(18)); 2413 } 2414 2415 //////////////////////// 2416 // LF_UNION accessors // 2417 //////////////////////// 2418 2419 public short getUnionCount() { 2420 typeSeek(2); 2421 return readShort(); 2422 } 2423 2424 public short getUnionProperty() { 2425 typeSeek(4); 2426 return readShort(); 2427 } 2428 2429 public int getUnionFieldList() { 2430 typeSeek(6); 2431 return readInt(); 2432 } 2433 2434 public DebugVC50TypeIterator getUnionFieldListIterator() { 2435 int index = unbiasTypeIndex(getUnionFieldList()); 2436 int offset = parent.getTypeOffset(index); 2437 return new DebugVC50TypeIteratorImpl(parent, base, numTypes, index, offset); 2438 } 2439 2440 public int getUnionSize() throws DebugVC50WrongNumericTypeException { 2441 return readIntNumericLeafAt(10); 2442 } 2443 2444 public String getUnionName() { 2445 return readLengthPrefixedStringAt(10 + numericLeafLengthAt(10)); 2446 } 2447 2448 /////////////////////// 2449 // LF_ENUM accessors // 2450 /////////////////////// 2451 2452 public short getEnumCount() { 2453 typeSeek(2); 2454 return readShort(); 2455 } 2456 2457 public short getEnumProperty() { 2458 typeSeek(4); 2459 return readShort(); 2460 } 2461 2462 public int getEnumType() { 2463 typeSeek(6); 2464 return readInt(); 2465 } 2466 2467 public int getEnumFieldList() { 2468 typeSeek(10); 2469 return readInt(); 2470 } 2471 2472 public DebugVC50TypeIterator getEnumFieldListIterator() { 2473 int index = unbiasTypeIndex(getEnumFieldList()); 2474 int offset = parent.getTypeOffset(index); 2475 return new DebugVC50TypeIteratorImpl(parent, base, numTypes, index, offset); 2476 } 2477 2478 public String getEnumName() { 2479 return readLengthPrefixedStringAt(14); 2480 } 2481 2482 //////////////////////////// 2483 // LF_PROCEDURE accessors // 2484 //////////////////////////// 2485 2486 public int getProcedureReturnType() { 2487 typeSeek(2); 2488 return readInt(); 2489 } 2490 2491 public byte getProcedureCallingConvention() { 2492 typeSeek(6); 2493 return readByte(); 2494 } 2495 2496 public short getProcedureNumberOfParameters() { 2497 typeSeek(8); 2498 return readShort(); 2499 } 2500 2501 public int getProcedureArgumentList() { 2502 typeSeek(10); 2503 return readInt(); 2504 } 2505 2506 public DebugVC50TypeIterator getProcedureArgumentListIterator() { 2507 int index = unbiasTypeIndex(getProcedureArgumentList()); 2508 int offset = parent.getTypeOffset(index); 2509 return new DebugVC50TypeIteratorImpl(parent, base, numTypes, index, offset); 2510 } 2511 2512 //////////////////////////// 2513 // LF_MFUNCTION accessors // 2514 //////////////////////////// 2515 2516 public int getMFunctionReturnType() { 2517 typeSeek(2); 2518 return readInt(); 2519 } 2520 2521 public int getMFunctionContainingClass() { 2522 typeSeek(6); 2523 return readInt(); 2524 } 2525 2526 public int getMFunctionThis() { 2527 typeSeek(10); 2528 return readInt(); 2529 } 2530 2531 public byte getMFunctionCallingConvention() { 2532 typeSeek(14); 2533 return readByte(); 2534 } 2535 2536 public short getMFunctionNumberOfParameters() { 2537 typeSeek(16); 2538 return readShort(); 2539 } 2540 2541 public int getMFunctionArgumentList() { 2542 typeSeek(18); 2543 return readInt(); 2544 } 2545 2546 public DebugVC50TypeIterator getMFunctionArgumentListIterator() { 2547 int index = unbiasTypeIndex(getMFunctionArgumentList()); 2548 int offset = parent.getTypeOffset(index); 2549 return new DebugVC50TypeIteratorImpl(parent, base, numTypes, index, offset); 2550 } 2551 2552 public int getMFunctionThisAdjust() { 2553 typeSeek(22); 2554 return readInt(); 2555 } 2556 2557 ////////////////////////// 2558 // LF_VTSHAPE accessors // 2559 ////////////////////////// 2560 2561 public short getVTShapeCount() { 2562 typeSeek(2); 2563 return readShort(); 2564 } 2565 2566 public int getVTShapeDescriptor(int i) { 2567 typeSeek(4 + (i / 2)); 2568 int val = readByte() & 0xFF; 2569 if ((i % 2) != 0) { 2570 val = val >> 4; 2571 } 2572 return val; 2573 } 2574 2575 ///////////////////////// 2576 // LF_BARRAY accessors // 2577 ///////////////////////// 2578 2579 public int getBasicArrayType() { 2580 typeSeek(2); 2581 return readInt(); 2582 } 2583 2584 //////////////////////// 2585 // LF_LABEL accessors // 2586 //////////////////////// 2587 2588 public short getLabelAddressMode() { 2589 typeSeek(2); 2590 return readShort(); 2591 } 2592 2593 /////////////////////////// 2594 // LF_DIMARRAY accessors // 2595 /////////////////////////// 2596 2597 public int getDimArrayType() { 2598 typeSeek(2); 2599 return readInt(); 2600 } 2601 2602 public int getDimArrayDimInfo() { 2603 typeSeek(6); 2604 return readInt(); 2605 } 2606 2607 public String getDimArrayName() { 2608 return readLengthPrefixedStringAt(10); 2609 } 2610 2611 ////////////////////////// 2612 // LF_VFTPATH accessors // 2613 ////////////////////////// 2614 2615 public int getVFTPathCount() { 2616 typeSeek(2); 2617 return readInt(); 2618 } 2619 2620 public int getVFTPathBase(int i) { 2621 typeSeek(6 + (4 * i)); 2622 return readInt(); 2623 } 2624 2625 /////////////////////// 2626 // LF_SKIP accessors // 2627 /////////////////////// 2628 2629 public int getSkipIndex() { 2630 typeSeek(2); 2631 return readInt(); 2632 } 2633 2634 ////////////////////////// 2635 // LF_ARGLIST accessors // 2636 ////////////////////////// 2637 2638 public int getArgListCount() { 2639 typeSeek(2); 2640 return readInt(); 2641 } 2642 2643 public int getArgListType(int i) { 2644 typeSeek(6 + (4 * i)); 2645 return readInt(); 2646 } 2647 2648 ///////////////////////// 2649 // LF_DEFARG accessors // 2650 ///////////////////////// 2651 2652 public int getDefaultArgType() { 2653 typeSeek(2); 2654 return readInt(); 2655 } 2656 2657 public String getDefaultArgExpression() { 2658 return readLengthPrefixedStringAt(6); 2659 } 2660 2661 ////////////////////////// 2662 // LF_DERIVED accessors // 2663 ////////////////////////// 2664 2665 public int getDerivedCount() { 2666 typeSeek(2); 2667 return readInt(); 2668 } 2669 2670 public int getDerivedType(int i) { 2671 typeSeek(6); 2672 return readInt(); 2673 } 2674 2675 /////////////////////////// 2676 // LF_BITFIELD accessors // 2677 /////////////////////////// 2678 2679 public int getBitfieldFieldType() { 2680 typeSeek(2); 2681 return readInt(); 2682 } 2683 2684 public byte getBitfieldLength() { 2685 typeSeek(6); 2686 return readByte(); 2687 } 2688 2689 public byte getBitfieldPosition() { 2690 typeSeek(7); 2691 return readByte(); 2692 } 2693 2694 //////////////////////// 2695 // LF_MLIST accessors // 2696 //////////////////////// 2697 2698 public short getMListAttribute() { 2699 typeSeek(2); 2700 return readShort(); 2701 } 2702 2703 public int getMListLength() { 2704 return (getLength() - 6 - (isMListIntroducingVirtual() ? 4 : 0)) / 4; 2705 } 2706 2707 public int getMListType(int i) { 2708 typeSeek(6 + 4 * i); 2709 return readInt(); 2710 } 2711 2712 public boolean isMListIntroducingVirtual() { 2713 return isIntroducingVirtual(getMListAttribute()); 2714 } 2715 2716 public int getMListVtabOffset() { 2717 typeSeek(6 + 4 * getMListLength()); 2718 return readInt(); 2719 } 2720 2721 ///////////////////////// 2722 // LF_REFSYM accessors // 2723 ///////////////////////// 2724 2725 public DebugVC50SymbolIterator getRefSym() { 2726 typeSeek(2); 2727 int len = readShort() & 0xFFFF; 2728 return new DebugVC50SymbolIteratorImpl(typeStringOffset + 2, len); 2729 } 2730 2731 ///////////////////////// 2732 // LF_BCLASS accessors // 2733 ///////////////////////// 2734 2735 public short getBClassAttribute() { 2736 typeSeek(2); 2737 return readShort(); 2738 } 2739 2740 public int getBClassType() { 2741 typeSeek(4); 2742 return readInt(); 2743 } 2744 2745 public int getBClassOffset() throws DebugVC50WrongNumericTypeException { 2746 return readIntNumericLeafAt(8); 2747 } 2748 2749 ////////////////////////// 2750 // LF_VBCLASS accessors // 2751 ////////////////////////// 2752 2753 public short getVBClassAttribute() { 2754 typeSeek(2); 2755 return readShort(); 2756 } 2757 2758 public int getVBClassBaseClassType() { 2759 typeSeek(4); 2760 return readInt(); 2761 } 2762 2763 public int getVBClassVirtualBaseClassType() { 2764 typeSeek(8); 2765 return readInt(); 2766 } 2767 2768 public int getVBClassVBPOff() throws DebugVC50WrongNumericTypeException { 2769 return readIntNumericLeafAt(12); 2770 } 2771 2772 public int getVBClassVBOff() throws DebugVC50WrongNumericTypeException { 2773 return readIntNumericLeafAt(12 + numericLeafLengthAt(12)); 2774 } 2775 2776 /////////////////////////// 2777 // LF_IVBCLASS accessors // 2778 /////////////////////////// 2779 2780 public short getIVBClassAttribute() { 2781 typeSeek(2); 2782 return readShort(); 2783 } 2784 2785 public int getIVBClassBType() { 2786 typeSeek(4); 2787 return readInt(); 2788 } 2789 2790 public int getIVBClassVBPType() { 2791 typeSeek(8); 2792 return readInt(); 2793 } 2794 2795 public int getIVBClassVBPOff() throws DebugVC50WrongNumericTypeException { 2796 return readIntNumericLeafAt(12); 2797 } 2798 2799 public int getIVBClassVBOff() throws DebugVC50WrongNumericTypeException { 2800 return readIntNumericLeafAt(12 + numericLeafLengthAt(12)); 2801 } 2802 2803 //////////////////////////// 2804 // LF_ENUMERATE accessors // 2805 //////////////////////////// 2806 2807 public short getEnumerateAttribute() { 2808 typeSeek(2); 2809 return readShort(); 2810 } 2811 2812 public long getEnumerateValue() { 2813 return readIntNumericLeafAt(4); 2814 } 2815 2816 public String getEnumerateName() { 2817 return readLengthPrefixedStringAt(4 + numericLeafLengthAt(4)); 2818 } 2819 2820 //////////////////////////// 2821 // LF_FRIENDFCN accessors // 2822 //////////////////////////// 2823 2824 public int getFriendFcnType() { 2825 typeSeek(4); 2826 return readInt(); 2827 } 2828 2829 public String getFriendFcnName() { 2830 return readLengthPrefixedStringAt(8); 2831 } 2832 2833 //////////////////////// 2834 // LF_INDEX accessors // 2835 //////////////////////// 2836 2837 public int getIndexValue() { 2838 typeSeek(4); 2839 return readInt(); 2840 } 2841 2842 public DebugVC50TypeIterator getIndexIterator() { 2843 int index = unbiasTypeIndex(getIndexValue()); 2844 int offset = parent.getTypeOffset(index); 2845 return new DebugVC50TypeIteratorImpl(parent, base, numTypes, index, offset); 2846 } 2847 2848 ///////////////////////// 2849 // LF_MEMBER accessors // 2850 ///////////////////////// 2851 2852 public short getMemberAttribute() { 2853 typeSeek(2); 2854 return readShort(); 2855 } 2856 2857 public int getMemberType() { 2858 typeSeek(4); 2859 return readInt(); 2860 } 2861 2862 public int getMemberOffset() throws DebugVC50WrongNumericTypeException { 2863 return readIntNumericLeafAt(8); 2864 } 2865 2866 public String getMemberName() { 2867 return readLengthPrefixedStringAt(8 + numericLeafLengthAt(8)); 2868 } 2869 2870 /////////////////////////// 2871 // LF_STMEMBER accessors // 2872 /////////////////////////// 2873 2874 public short getStaticAttribute() { 2875 typeSeek(2); 2876 return readShort(); 2877 } 2878 2879 public int getStaticType() { 2880 typeSeek(4); 2881 return readInt(); 2882 } 2883 2884 public String getStaticName() { 2885 return readLengthPrefixedStringAt(8); 2886 } 2887 2888 ///////////////////////// 2889 // LF_METHOD accessors // 2890 ///////////////////////// 2891 2892 public short getMethodCount() { 2893 typeSeek(2); 2894 return readShort(); 2895 } 2896 2897 public int getMethodList() { 2898 typeSeek(4); 2899 return readInt(); 2900 } 2901 2902 public String getMethodName() { 2903 return readLengthPrefixedStringAt(8); 2904 } 2905 2906 ///////////////////////////// 2907 // LF_NESTEDTYPE accessors // 2908 ///////////////////////////// 2909 2910 public int getNestedType() { 2911 typeSeek(4); 2912 return readInt(); 2913 } 2914 2915 public String getNestedName() { 2916 return readLengthPrefixedStringAt(8); 2917 } 2918 2919 /////////////////////////// 2920 // LF_VFUNCTAB accessors // 2921 /////////////////////////// 2922 2923 public int getVFuncTabType() { 2924 typeSeek(4); 2925 return readInt(); 2926 } 2927 2928 //////////////////////////// 2929 // LF_FRIENDCLS accessors // 2930 //////////////////////////// 2931 2932 public int getFriendClsType() { 2933 typeSeek(4); 2934 return readInt(); 2935 } 2936 2937 //////////////////////////// 2938 // LF_ONEMETHOD accessors // 2939 //////////////////////////// 2940 2941 public short getOneMethodAttribute() { 2942 typeSeek(2); 2943 return readShort(); 2944 } 2945 2946 public int getOneMethodType() { 2947 typeSeek(4); 2948 return readInt(); 2949 } 2950 2951 public boolean isOneMethodIntroducingVirtual() { 2952 return isIntroducingVirtual(getOneMethodAttribute()); 2953 } 2954 2955 public int getOneMethodVBaseOff() { 2956 typeSeek(8); 2957 return readInt(); 2958 } 2959 2960 public String getOneMethodName() { 2961 int baseLen = 8 + (isOneMethodIntroducingVirtual() ? 4 : 0); 2962 return readLengthPrefixedStringAt(baseLen); 2963 } 2964 2965 /////////////////////////// 2966 // LF_VFUNCOFF accessors // 2967 /////////////////////////// 2968 2969 public int getVFuncOffType() { 2970 typeSeek(4); 2971 return readInt(); 2972 } 2973 2974 public int getVFuncOffOffset() { 2975 typeSeek(8); 2976 return readInt(); 2977 } 2978 2979 /////////////////////////////// 2980 // LF_NESTEDTYPEEX accessors // 2981 /////////////////////////////// 2982 2983 public short getNestedExAttribute() { 2984 typeSeek(2); 2985 return readShort(); 2986 } 2987 2988 public int getNestedExType() { 2989 typeSeek(4); 2990 return readInt(); 2991 } 2992 2993 public String getNestedExName() { 2994 return readLengthPrefixedStringAt(8); 2995 } 2996 2997 /////////////////////////////// 2998 // LF_MEMBERMODIFY accessors // 2999 /////////////////////////////// 3000 3001 public short getMemberModifyAttribute() { 3002 typeSeek(2); 3003 return readShort(); 3004 } 3005 3006 public int getMemberModifyType() { 3007 typeSeek(4); 3008 return readInt(); 3009 } 3010 3011 public String getMemberModifyName() { 3012 return readLengthPrefixedStringAt(8); 3013 } 3014 3015 //////////////////////////// 3016 // Numeric Leaf accessors // 3017 //////////////////////////// 3018 3019 public short getNumericTypeAt(int byteOffset) { 3020 typeSeek(byteOffset); 3021 return readShort(); 3022 } 3023 3024 public int getNumericLengthAt(int byteOffset) 3025 throws DebugVC50WrongNumericTypeException { 3026 return numericLeafLengthAt(byteOffset); 3027 } 3028 3029 public int getNumericIntAt(int byteOffset) 3030 throws DebugVC50WrongNumericTypeException { 3031 return readIntNumericLeafAt(byteOffset); 3032 } 3033 3034 public long getNumericLongAt(int byteOffset) 3035 throws DebugVC50WrongNumericTypeException { 3036 // FIXME 3037 throw new RuntimeException("Unimplemented"); 3038 } 3039 3040 public float getNumericFloatAt(int byteOffset) 3041 throws DebugVC50WrongNumericTypeException { 3042 // FIXME 3043 throw new RuntimeException("Unimplemented"); 3044 } 3045 3046 public double getNumericDoubleAt(int byteOffset) 3047 throws DebugVC50WrongNumericTypeException { 3048 // FIXME 3049 throw new RuntimeException("Unimplemented"); 3050 } 3051 3052 public byte[] getNumericDataAt(int byteOffset) 3053 throws DebugVC50WrongNumericTypeException { 3054 // FIXME 3055 throw new RuntimeException("Unimplemented"); 3056 } 3057 3058 //---------------------------------------------------------------------- 3059 // Internals only below this point 3060 // 3061 3062 private void loadTypeRecord() { 3063 seek(typeRecordOffset); 3064 typeRecordSize = readShort() & 0xFFFF; 3065 typeStringOffset = typeRecordOffset + 2; 3066 loadTypeString(); 3067 } 3068 3069 private void loadTypeString() { 3070 seek(typeStringOffset); 3071 int lo = readByte() & 0xFF; 3072 // See if it is one of the single-byte leaves 3073 if (lo >= LF_PAD0) { 3074 typeStringLeaf = lo; 3075 } else { 3076 int hi = readByte() & 0xFF; 3077 typeStringLeaf = (hi << 8) | lo; 3078 } 3079 } 3080 3081 private void typeSeek(int offset) { 3082 seek(typeStringOffset + offset); 3083 } 3084 3085 private int typeStringLength() { 3086 // LF_PAD 3087 if (typeStringLeaf >= 0xF0 && typeStringLeaf <= 0xFF) { 3088 return (typeStringLeaf - 0xF0); 3089 } 3090 3091 switch (typeStringLeaf) { 3092 3093 // Leaf indices for type records that can be referenced 3094 // from symbols: 3095 case LF_MODIFIER: return 8; 3096 case LF_POINTER: { 3097 int extraLen = 0; 3098 int attr = (getPointerAttributes() & POINTER_PTRTYPE_MASK) >> POINTER_PTRTYPE_SHIFT; 3099 int mode = (getPointerAttributes() & POINTER_PTRMODE_MASK) >> POINTER_PTRMODE_SHIFT; 3100 if (attr == POINTER_PTRTYPE_BASED_ON_TYPE) { 3101 extraLen = 4 + numericLeafLengthAt(typeStringOffset + 14); 3102 } else if (mode == POINTER_PTRMODE_PTR_TO_DATA_MEMBER || 3103 mode == POINTER_PTRMODE_PTR_TO_METHOD) { 3104 extraLen = 6; 3105 } 3106 return 10 + extraLen; 3107 } 3108 case LF_ARRAY: { 3109 int temp = 10 + numericLeafLengthAt(10); 3110 return temp + lengthPrefixedStringLengthAt(temp); 3111 } 3112 case LF_CLASS: 3113 case LF_STRUCTURE: { 3114 int temp = 18 + numericLeafLengthAt(18); 3115 return temp + lengthPrefixedStringLengthAt(temp); 3116 } 3117 case LF_UNION: { 3118 int temp = 10 + numericLeafLengthAt(10); 3119 return temp + lengthPrefixedStringLengthAt(temp); 3120 } 3121 case LF_ENUM: { 3122 return 14 + lengthPrefixedStringLengthAt(14); 3123 } 3124 case LF_PROCEDURE: return 14; 3125 case LF_MFUNCTION: return 26; 3126 case LF_VTSHAPE: return 4 + ((getVTShapeCount() + 1) / 2); 3127 case LF_COBOL0: 3128 case LF_COBOL1: throw new COFFException("COBOL symbols unimplemented"); 3129 case LF_BARRAY: return 6; 3130 case LF_LABEL: return 4; 3131 case LF_NULL: return 2; 3132 case LF_NOTTRAN: return 2; 3133 case LF_DIMARRAY: return 10 + lengthPrefixedStringLengthAt(10); 3134 case LF_VFTPATH: return 6 + 4 * getVFTPathCount(); 3135 case LF_PRECOMP: return 14 + lengthPrefixedStringLengthAt(14); 3136 case LF_ENDPRECOMP: return 6; 3137 case LF_OEM: throw new COFFException("OEM symbols unimplemented"); 3138 case LF_TYPESERVER: return 10 + lengthPrefixedStringLengthAt(10); 3139 3140 case LF_SKIP: return 6 + numericLeafLengthAt(6); 3141 case LF_ARGLIST: return 6 + 4 * getArgListCount(); 3142 case LF_DEFARG: return 6 + lengthPrefixedStringLengthAt(6); 3143 // case LF_FIELDLIST: throw new COFFException("Should not see LF_FIELDLIST leaf"); 3144 case LF_FIELDLIST: return 2; 3145 case LF_DERIVED: return 6 + 4 * getDerivedCount(); 3146 case LF_BITFIELD: return 8; 3147 case LF_METHODLIST: { 3148 return 6 + 4 * getMListLength() + (isMListIntroducingVirtual() ? 4 : 0); 3149 } 3150 case LF_DIMCONU: 3151 case LF_DIMCONLU: 3152 case LF_DIMVARU: 3153 case LF_DIMVARLU: throw new COFFException("LF_DIMCONU, LF_DIMCONLU, LF_DIMVARU, and LF_DIMVARLU unsupported"); 3154 case LF_REFSYM: { 3155 seek(typeStringOffset + 2); 3156 return 4 + readShort(); 3157 } 3158 3159 case LF_BCLASS: return 8 + numericLeafLengthAt(8); 3160 case LF_VBCLASS: 3161 case LF_IVBCLASS: { 3162 int temp = 12 + numericLeafLengthAt(12); 3163 return temp + numericLeafLengthAt(temp); 3164 } 3165 case LF_ENUMERATE: { 3166 int temp = 4 + numericLeafLengthAt(4); 3167 return temp + lengthPrefixedStringLengthAt(temp); 3168 } 3169 case LF_FRIENDFCN: return 8 + lengthPrefixedStringLengthAt(8); 3170 case LF_INDEX: return 8; 3171 case LF_MEMBER: { 3172 int temp = 8 + numericLeafLengthAt(8); 3173 return temp + lengthPrefixedStringLengthAt(temp); 3174 } 3175 case LF_STMEMBER: return 8 + lengthPrefixedStringLengthAt(8); 3176 case LF_METHOD: return 8 + lengthPrefixedStringLengthAt(8); 3177 case LF_NESTTYPE: return 8 + lengthPrefixedStringLengthAt(8); 3178 case LF_VFUNCTAB: return 8; 3179 case LF_FRIENDCLS: return 8; 3180 case LF_ONEMETHOD: { 3181 int baseLen = 8 + (isOneMethodIntroducingVirtual() ? 4 : 0); 3182 return baseLen + lengthPrefixedStringLengthAt(baseLen); 3183 } 3184 case LF_VFUNCOFF: return 12; 3185 case LF_NESTTYPEEX: return 8 + lengthPrefixedStringLengthAt(8); 3186 case LF_MEMBERMODIFY: return 8 + lengthPrefixedStringLengthAt(8); 3187 3188 // Should not encounter numeric leaves with this routine 3189 case LF_CHAR: 3190 case LF_SHORT: 3191 case LF_USHORT: 3192 case LF_LONG: 3193 case LF_ULONG: 3194 case LF_REAL32: 3195 case LF_REAL64: 3196 case LF_REAL80: 3197 case LF_REAL128: 3198 case LF_QUADWORD: 3199 case LF_UQUADWORD: 3200 case LF_REAL48: 3201 case LF_COMPLEX32: 3202 case LF_COMPLEX64: 3203 case LF_COMPLEX80: 3204 case LF_COMPLEX128: 3205 case LF_VARSTRING: throw new RuntimeException("Unexpected numeric leaf " + typeStringLeaf + 3206 "in type string"); 3207 default: 3208 throw new COFFException("Unrecognized leaf " + typeStringLeaf + " in type string at offset " + 3209 typeStringOffset); 3210 } 3211 } 3212 3213 private boolean isIntroducingVirtual(int mprop) { 3214 int masked = mprop & MEMATTR_MPROP_MASK; 3215 return ((masked == MEMATTR_MPROP_INTRODUCING_VIRTUAL) || 3216 (masked == MEMATTR_MPROP_PURE_INTRODUCING_VIRTUAL)); 3217 } 3218 3219 private int numericLeafLengthAt(int offset) { 3220 return DebugVC50Impl.this.numericLeafLengthAt(typeStringOffset + offset); 3221 } 3222 3223 private int readIntNumericLeafAt(int offset) { 3224 return DebugVC50Impl.this.readIntNumericLeafAt(typeStringOffset + offset); 3225 } 3226 3227 private int lengthPrefixedStringLengthAt(int offset) { 3228 return DebugVC50Impl.this.lengthPrefixedStringLengthAt(typeStringOffset + offset); 3229 } 3230 3231 private String readLengthPrefixedStringAt(int offset) { 3232 return DebugVC50Impl.this.readLengthPrefixedStringAt(typeStringOffset + offset); 3233 } 3234 } 3235 3236 private int numericLeafLengthAt(int absoluteOffset) throws DebugVC50WrongNumericTypeException { 3237 seek(absoluteOffset); 3238 int leaf = readShort() & 0xFFFF; 3239 if (leaf < 0x8000) return 2; 3240 switch (leaf) { 3241 case LF_CHAR: return 3; 3242 case LF_SHORT: 3243 case LF_USHORT: return 4; 3244 case LF_LONG: 3245 case LF_ULONG: return 6; 3246 case LF_REAL32: return 6; 3247 case LF_REAL64: return 10; 3248 case LF_REAL80: return 12; 3249 case LF_REAL128: return 18; 3250 case LF_QUADWORD: 3251 case LF_UQUADWORD: return 18; 3252 case LF_REAL48: return 8; 3253 case LF_COMPLEX32: return 10; 3254 case LF_COMPLEX64: return 18; 3255 case LF_COMPLEX80: return 26; 3256 case LF_COMPLEX128: return 66; 3257 // FIXME: figure out format of variable-length strings 3258 case LF_VARSTRING: return 4 + readIntNumericLeafAt(absoluteOffset + 2); 3259 3260 default: 3261 throw new DebugVC50WrongNumericTypeException("Illegal numeric leaf index " + leaf + 3262 " at offset " + absoluteOffset); 3263 } 3264 } 3265 3266 private int readIntNumericLeafAt(int absoluteOffset) throws DebugVC50WrongNumericTypeException { 3267 seek(absoluteOffset); 3268 int leaf = readShort() & 0xFFFF; 3269 if (leaf < 0x8000) return leaf; 3270 switch (leaf) { 3271 case LF_CHAR: return readByte() & 0xFF; 3272 case LF_SHORT: 3273 case LF_USHORT: return readShort() & 0xFFFF; 3274 case LF_LONG: 3275 case LF_ULONG: return readInt(); 3276 3277 default: 3278 throw new DebugVC50WrongNumericTypeException("Illegal numeric leaf index " + leaf); 3279 } 3280 } 3281 3282 private long readLongNumericLeafAt(int absoluteOffset) throws DebugVC50WrongNumericTypeException { 3283 seek(absoluteOffset); 3284 int leaf = readShort() & 0xFFFF; 3285 if (leaf < 0x8000) return leaf; 3286 switch (leaf) { 3287 case LF_CHAR: return readByte() & 0xFF; 3288 case LF_SHORT: 3289 case LF_USHORT: return readShort() & 0xFFFF; 3290 case LF_LONG: 3291 case LF_ULONG: return readInt() & 0xFFFFFFFF; 3292 case LF_QUADWORD: 3293 case LF_UQUADWORD: return readLong(); 3294 3295 default: 3296 throw new DebugVC50WrongNumericTypeException("Illegal numeric leaf index " + leaf); 3297 } 3298 } 3299 3300 private float readFloatNumericLeafAt(int absoluteOffset) throws DebugVC50WrongNumericTypeException { 3301 seek(absoluteOffset); 3302 int leaf = readShort() & 0xFFFF; 3303 if (leaf != LF_REAL32) { 3304 throw new DebugVC50WrongNumericTypeException("Illegal numeric leaf index " + leaf); 3305 } 3306 return readFloat(); 3307 } 3308 3309 private double readDoubleNumericLeafAt(int absoluteOffset) throws DebugVC50WrongNumericTypeException { 3310 seek(absoluteOffset); 3311 int leaf = readShort() & 0xFFFF; 3312 if (leaf != LF_REAL64) { 3313 throw new DebugVC50WrongNumericTypeException("Illegal numeric leaf index " + leaf); 3314 } 3315 return readDouble(); 3316 } 3317 3318 private int lengthPrefixedStringLengthAt(int absoluteOffset) { 3319 // NOTE: the format of length-prefixed strings is not well 3320 // specified. There is a LF_VARSTRING numeric leaf (the 3321 // format of which is also not specified), but it seems that 3322 // most length-prefixed strings are comprised of a single 3323 // byte length followed by that many bytes of data. 3324 seek(absoluteOffset); 3325 int len = readByte() & 0xFF; 3326 return 1 + len; 3327 } 3328 3329 private String readLengthPrefixedStringAt(int absoluteOffset) { 3330 // NOTE: it isn't clear whether LF_VARSTRING numeric leaves 3331 // ever show up, or in general what happens when the length 3332 // of the string is > 255 (FIXME) 3333 seek(absoluteOffset); 3334 int len = readByte() & 0xFF; 3335 byte[] res = new byte[len]; 3336 int numRead = readBytes(res); 3337 if (numRead != len) { 3338 throw new COFFException("Error reading length prefixed string in symbol at offset " + 3339 absoluteOffset); 3340 } 3341 try { 3342 return new String(res, US_ASCII); 3343 } catch (UnsupportedEncodingException e) { 3344 throw new COFFException(e); 3345 } 3346 } 3347 3348 private int unbiasTypeIndex(int index) { 3349 return index - 0x1000; 3350 } 3351 3352 private int biasTypeIndex(int index) { 3353 return index + 0x1000; 3354 } 3355 } // Class DebugVC50Impl 3356 3357 class SectionHeaderImpl implements SectionHeader { 3358 private String name; 3359 private int virtualSize; 3360 private int virtualAddress; 3361 private int sizeOfRawData; 3362 private int pointerToRawData; 3363 private int pointerToRelocations; 3364 private int pointerToLineNumbers; 3365 private short numberOfRelocations; 3366 private short numberOfLineNumbers; 3367 private int characteristics; 3368 private MemoizedObject[] relocations; 3369 private MemoizedObject[] lineNumbers; 3370 3371 public SectionHeaderImpl(int offset) throws COFFException { 3372 seek(offset); 3373 3374 // FIXME: compute name lazily 3375 3376 // Read name 3377 byte[] tmpName = new byte[8]; 3378 int numRead = readBytes(tmpName); 3379 if (numRead != 8) { 3380 throw new COFFException("Error reading name of section header at offset " + offset); 3381 } 3382 if (tmpName[0] == (byte) '/') { 3383 // Long name; must find real value in string table 3384 int index = 0; 3385 try { 3386 index = Integer.parseInt(new String(tmpName, 1, tmpName.length - 1, US_ASCII)); 3387 } catch (NumberFormatException e) { 3388 throw new COFFException("Error parsing string table index of name of section header " + 3389 "at offset " + offset); 3390 } catch (UnsupportedEncodingException e) { 3391 throw new COFFException(e); 3392 } 3393 // Look up in string table 3394 // FIXME: this index value is assumed to be in the valid range 3395 name = getStringTable().get(index); 3396 } else { 3397 try { 3398 int length = 0; 3399 // find last non-NULL 3400 for (; length < tmpName.length && tmpName[length] != '\0';) { 3401 length++; 3402 } 3403 // don't include NULL chars in returned name String 3404 name = new String(tmpName, 0, length, US_ASCII); 3405 } catch (UnsupportedEncodingException e) { 3406 throw new COFFException(e); 3407 } 3408 } 3409 virtualSize = readInt(); 3410 virtualAddress = readInt(); 3411 sizeOfRawData = readInt(); 3412 pointerToRawData = readInt(); 3413 pointerToRelocations = readInt(); 3414 pointerToLineNumbers = readInt(); 3415 numberOfRelocations = readShort(); 3416 numberOfLineNumbers = readShort(); 3417 characteristics = readInt(); 3418 3419 // Set up relocations 3420 relocations = new MemoizedObject[numberOfRelocations]; 3421 for (int i = 0; i < numberOfRelocations; i++) { 3422 final int relocOffset = pointerToRelocations + i * RELOCATION_SIZE; 3423 relocations[i] = new MemoizedObject() { 3424 public Object computeValue() { 3425 return new COFFRelocationImpl(relocOffset); 3426 } 3427 }; 3428 } 3429 3430 // Set up line numbers 3431 lineNumbers = new MemoizedObject[numberOfLineNumbers]; 3432 for (int i = 0; i < numberOfLineNumbers; i++) { 3433 final int lineNoOffset = pointerToLineNumbers + i * LINE_NUMBER_SIZE; 3434 lineNumbers[i] = new MemoizedObject() { 3435 public Object computeValue() { 3436 return new COFFLineNumberImpl(lineNoOffset); 3437 } 3438 }; 3439 } 3440 } 3441 3442 public String getName() { return name; } 3443 public int getSize() { return virtualSize; } 3444 public int getVirtualAddress() { return virtualAddress; } 3445 public int getSizeOfRawData() { return sizeOfRawData; } 3446 public int getPointerToRawData() { return pointerToRawData; } 3447 public int getPointerToRelocations() { return pointerToRelocations; } 3448 public int getPointerToLineNumbers() { return pointerToLineNumbers; } 3449 public short getNumberOfRelocations() { return numberOfRelocations; } 3450 public short getNumberOfLineNumbers() { return numberOfLineNumbers; } 3451 public int getSectionFlags() { return characteristics; } 3452 public boolean hasSectionFlag(int flag ) { 3453 return ((characteristics & flag) != 0); 3454 } 3455 public COFFRelocation getCOFFRelocation(int index) { 3456 return (COFFRelocation) relocations[index].getValue(); 3457 } 3458 public COFFLineNumber getCOFFLineNumber(int index) { 3459 return (COFFLineNumber) lineNumbers[index]; 3460 } 3461 } 3462 3463 class COFFSymbolImpl implements COFFSymbol, COFFSymbolConstants { 3464 private int offset; 3465 private String name; 3466 private int value; 3467 private short sectionNumber; 3468 private short type; 3469 private byte storageClass; 3470 private byte numberOfAuxSymbols; 3471 private MemoizedObject auxFunctionDefinitionRecord = new MemoizedObject() { 3472 public Object computeValue() { 3473 return new AuxFunctionDefinitionRecordImpl(offset + SYMBOL_SIZE); 3474 } 3475 }; 3476 private MemoizedObject auxBfEfRecord = new MemoizedObject() { 3477 public Object computeValue() { 3478 return new AuxBfEfRecordImpl(offset + SYMBOL_SIZE); 3479 } 3480 }; 3481 private MemoizedObject auxWeakExternalRecord = new MemoizedObject() { 3482 public Object computeValue() { 3483 return new AuxWeakExternalRecordImpl(offset + SYMBOL_SIZE); 3484 } 3485 }; 3486 private MemoizedObject auxFileRecord = new MemoizedObject() { 3487 public Object computeValue() { 3488 return new AuxFileRecordImpl(offset + SYMBOL_SIZE); 3489 } 3490 }; 3491 private MemoizedObject auxSectionDefinitionsRecord = new MemoizedObject() { 3492 public Object computeValue() { 3493 return new AuxSectionDefinitionsRecordImpl(offset + SYMBOL_SIZE); 3494 } 3495 }; 3496 3497 public COFFSymbolImpl(int offset) throws COFFException { 3498 this.offset = offset; 3499 seek(offset); 3500 3501 // Parse name 3502 byte[] tmpName = new byte[8]; 3503 int numRead = readBytes(tmpName); 3504 if (numRead != 8) { 3505 throw new COFFException("Error reading name of symbol at offset " + offset); 3506 } 3507 if ((tmpName[0] == 0) && 3508 (tmpName[1] == 0) && 3509 (tmpName[2] == 0) && 3510 (tmpName[3] == 0)) { 3511 // It's an offset into the string table. 3512 // FIXME: not sure about byte ordering... 3513 int stringOffset = (tmpName[4] << 24 | 3514 tmpName[5] << 16 | 3515 tmpName[6] << 8 | 3516 tmpName[7]); 3517 // FIXME: stringOffset is assumed to be in the valid range 3518 name = getStringTable().getAtOffset(stringOffset); 3519 } 3520 3521 value = readInt(); 3522 sectionNumber = readShort(); 3523 type = readShort(); 3524 storageClass = readByte(); 3525 numberOfAuxSymbols = readByte(); 3526 } 3527 3528 public int getOffset() { return offset; } 3529 public String getName() { return name; } 3530 public int getValue() { return value; } 3531 public short getSectionNumber() { return sectionNumber; } 3532 public short getType() { return type; } 3533 public byte getStorageClass() { return storageClass; } 3534 public byte getNumberOfAuxSymbols() { return numberOfAuxSymbols; } 3535 public boolean isFunctionDefinition() { 3536 return ((getStorageClass() == IMAGE_SYM_CLASS_EXTERNAL) && 3537 ((getType() >>> 8) == IMAGE_SYM_DTYPE_FUNCTION) && 3538 (getSectionNumber() > 0)); 3539 } 3540 public AuxFunctionDefinitionRecord getAuxFunctionDefinitionRecord() { 3541 return (AuxFunctionDefinitionRecord) auxFunctionDefinitionRecord.getValue(); 3542 } 3543 public boolean isBfOrEfSymbol() { 3544 return ((getName().equals(".bf") || getName().equals(".ef")) && 3545 (getStorageClass() == IMAGE_SYM_CLASS_FUNCTION)); 3546 } 3547 public AuxBfEfRecord getAuxBfEfRecord() { 3548 return (AuxBfEfRecord) auxBfEfRecord.getValue(); 3549 } 3550 public boolean isWeakExternal() { 3551 return ((getStorageClass() == IMAGE_SYM_CLASS_EXTERNAL) && 3552 (getSectionNumber() == IMAGE_SYM_UNDEFINED) && 3553 (getValue() == 0)); 3554 } 3555 public AuxWeakExternalRecord getAuxWeakExternalRecord() { 3556 return (AuxWeakExternalRecord) auxWeakExternalRecord.getValue(); 3557 } 3558 public boolean isFile() { 3559 return ((getName().equals(".file")) && 3560 (getStorageClass() == IMAGE_SYM_CLASS_FILE)); 3561 } 3562 public AuxFileRecord getAuxFileRecord() { 3563 return (AuxFileRecord) auxFileRecord.getValue(); 3564 } 3565 public boolean isSectionDefinition() { 3566 // FIXME: not sure how to ensure that symbol name is the 3567 // name of a section. 3568 return ((getName().charAt(0) == '.') && 3569 (getStorageClass() == IMAGE_SYM_CLASS_STATIC)); 3570 } 3571 public AuxSectionDefinitionsRecord getAuxSectionDefinitionsRecord() { 3572 return (AuxSectionDefinitionsRecord) auxSectionDefinitionsRecord.getValue(); 3573 } 3574 } 3575 3576 class AuxFunctionDefinitionRecordImpl implements AuxFunctionDefinitionRecord { 3577 private int tagIndex; 3578 private int totalSize; 3579 private int pointerToLineNumber; 3580 private int pointerToNextFunction; 3581 3582 AuxFunctionDefinitionRecordImpl(int offset) { 3583 seek(offset); 3584 tagIndex = readInt(); 3585 totalSize = readInt(); 3586 // NOTE zero-basing of this index 3587 pointerToLineNumber = readInt() - 1; 3588 pointerToNextFunction = readInt(); 3589 } 3590 3591 public int getTagIndex() { return tagIndex; } 3592 public int getTotalSize() { return totalSize; } 3593 public int getPointerToLineNumber() { return pointerToLineNumber; } 3594 public int getPointerToNextFunction() { return pointerToNextFunction; } 3595 public int getType() { return FUNCTION_DEFINITION; } 3596 } 3597 3598 class AuxBfEfRecordImpl implements AuxBfEfRecord { 3599 private short lineNumber; 3600 private int pointerToNextFunction; 3601 3602 AuxBfEfRecordImpl(int offset) { 3603 seek(offset); 3604 readInt(); 3605 lineNumber = readShort(); 3606 readInt(); 3607 readShort(); 3608 pointerToNextFunction = readInt(); 3609 } 3610 3611 public short getLineNumber() { return lineNumber; } 3612 public int getPointerToNextFunction() { return pointerToNextFunction; } 3613 public int getType() { return BF_EF_RECORD; } 3614 } 3615 3616 class AuxWeakExternalRecordImpl implements AuxWeakExternalRecord { 3617 private int tagIndex; 3618 private int characteristics; 3619 3620 AuxWeakExternalRecordImpl(int offset) { 3621 seek(offset); 3622 tagIndex = readInt(); 3623 characteristics = readInt(); 3624 } 3625 3626 public int getTagIndex() { return tagIndex; } 3627 public int getCharacteristics() { return characteristics; } 3628 public int getType() { return WEAK_EXTERNAL; } 3629 } 3630 3631 class AuxFileRecordImpl implements AuxFileRecord { 3632 private String name; 3633 3634 AuxFileRecordImpl(int offset) { 3635 seek(offset); 3636 byte[] tmpName = new byte[18]; 3637 int numRead = readBytes(tmpName); 3638 if (numRead != 18) { 3639 throw new COFFException("Error reading auxiliary file record at offset " + offset); 3640 } 3641 try { 3642 name = new String(tmpName, US_ASCII); 3643 } catch (UnsupportedEncodingException e) { 3644 throw new COFFException(e); 3645 } 3646 } 3647 3648 public String getName() { return name; } 3649 public int getType() { return FILE; } 3650 } 3651 3652 class AuxSectionDefinitionsRecordImpl implements AuxSectionDefinitionsRecord { 3653 private int length; 3654 private short numberOfRelocations; 3655 private short numberOfLineNumbers; 3656 private int checkSum; 3657 private short number; 3658 private byte selection; 3659 3660 AuxSectionDefinitionsRecordImpl(int offset) { 3661 seek(offset); 3662 length = readInt(); 3663 numberOfRelocations = readShort(); 3664 numberOfLineNumbers = readShort(); 3665 checkSum = readInt(); 3666 number = readShort(); 3667 selection = readByte(); 3668 } 3669 3670 public int getLength() { return length; } 3671 public short getNumberOfRelocations() { return numberOfRelocations; } 3672 public short getNumberOfLineNumbers() { return numberOfLineNumbers; } 3673 public int getCheckSum() { return checkSum; } 3674 public short getNumber() { return number; } 3675 public byte getSelection() { return selection; } 3676 public int getType() { return SECTION_DEFINITION; } 3677 } 3678 3679 class COFFRelocationImpl implements COFFRelocation { 3680 private int virtualAddress; 3681 private int symbolTableIndex; 3682 private short type; 3683 3684 COFFRelocationImpl(int offset) { 3685 seek(offset); 3686 virtualAddress = readInt(); 3687 symbolTableIndex = readInt(); 3688 type = readShort(); 3689 } 3690 3691 public int getVirtualAddress() { return virtualAddress; } 3692 public int getSymbolTableIndex() { return symbolTableIndex; } 3693 public short getType() { return type; } 3694 } 3695 3696 class COFFLineNumberImpl implements COFFLineNumber { 3697 private int type; 3698 private short lineNumber; 3699 3700 COFFLineNumberImpl(int offset) { 3701 seek(offset); 3702 type = readInt(); 3703 lineNumber = readShort(); 3704 } 3705 3706 public int getType() { 3707 return type; 3708 } 3709 3710 public short getLineNumber() { 3711 return lineNumber; 3712 } 3713 } 3714 3715 class StringTable { 3716 class COFFString { 3717 String str; 3718 int offset; 3719 3720 COFFString(String str, int offset) { 3721 this.str = str; this.offset = offset; 3722 } 3723 } 3724 3725 COFFString[] strings; 3726 3727 StringTable(int offset) { 3728 if (offset == 0) { 3729 // no String Table 3730 strings = new COFFString[0]; 3731 return; 3732 } 3733 3734 seek(offset); 3735 int length = readInt(); // length includes itself 3736 byte[] data = new byte[length - 4]; 3737 int numBytesRead = readBytes(data); 3738 if (numBytesRead != data.length) { 3739 throw new COFFException("Error reading string table (read " + 3740 numBytesRead + " bytes, expected to read " + data.length + ")"); 3741 } 3742 int numStrings = 0; 3743 int ptr = 0; 3744 for (ptr = 0; ptr < data.length; ptr++) { 3745 if (data[ptr] == 0) { 3746 numStrings++; 3747 } 3748 } 3749 strings = new COFFString[numStrings]; 3750 int lastPtr = 0; 3751 ptr = 0; 3752 for (int i = 0; i < numStrings; i++) { 3753 while (data[ptr] != 0) { 3754 ptr++; 3755 } 3756 try { 3757 strings[i] = new COFFString(new String(data, lastPtr, ptr - lastPtr, US_ASCII), 3758 offset + ptr + 4); 3759 } catch (UnsupportedEncodingException e) { 3760 throw new COFFException(e); 3761 } 3762 ptr++; 3763 lastPtr = ptr; 3764 } 3765 } 3766 3767 int getNum() { 3768 return strings.length; 3769 } 3770 3771 String get(int i) { 3772 return strings[i].str; 3773 } 3774 3775 /** This version takes an absolute offset in the file */ 3776 String getAtOffset(int offset) { 3777 int i = Arrays.binarySearch(strings, new COFFString(null, offset), 3778 new Comparator() { 3779 public int compare(Object o1, Object o2) { 3780 COFFString s1 = (COFFString) o1; 3781 COFFString s2 = (COFFString) o2; 3782 if (s1.offset == s2.offset) { 3783 return 0; 3784 } else if (s1.offset < s2.offset) { 3785 return -1; 3786 } else { 3787 return 1; 3788 } 3789 } 3790 }); 3791 if (i < 0) { 3792 throw new COFFException("No string found at file offset " + offset); 3793 } 3794 return strings[i].str; 3795 } 3796 } 3797 } 3798 3799 void initialize() throws COFFException { 3800 // Figure out whether this file is an object file or an image 3801 // (either executable or DLL). 3802 seek(0x3c); // Error here probably indicates file format error 3803 try { 3804 int peOffset = readInt(); 3805 seek(peOffset); 3806 if ((readByte() == (byte) 'P') && 3807 (readByte() == (byte) 'E') && 3808 (readByte() == (byte) 0) && 3809 (readByte() == (byte) 0)) { 3810 isImage = true; 3811 imageHeaderOffset = getFilePointer(); 3812 } 3813 } 3814 catch (COFFException e) { 3815 // Expect failures here if not image file. 3816 } 3817 } 3818 3819 byte readByteAt(long offset) throws COFFException { 3820 seek(offset); 3821 return readByte(); 3822 } 3823 3824 byte readByte() throws COFFException { 3825 try { 3826 return file.readByte(); 3827 } catch (IOException e) { 3828 throw new COFFException(e.toString() + " at offset 0x" + 3829 Long.toHexString(filePos), e); 3830 } 3831 } 3832 3833 int readBytesAt(long offset, byte[] b) throws COFFException { 3834 seek(offset); 3835 return readBytes(b); 3836 } 3837 3838 int readBytes(byte[] b) throws COFFException { 3839 try { 3840 return file.read(b); 3841 } catch (IOException e) { 3842 throw new COFFException(e.toString() + " at offset 0x" + 3843 Long.toHexString(filePos), e); 3844 } 3845 } 3846 3847 /** NOTE: reads little-endian short */ 3848 short readShortAt(long offset) throws COFFException { 3849 seek(offset); 3850 return readShort(); 3851 } 3852 3853 /** NOTE: reads little-endian short */ 3854 short readShort() throws COFFException { 3855 try { 3856 return byteSwap(file.readShort()); 3857 } catch (IOException e) { 3858 throw new COFFException(e.toString() + " at offset 0x" + 3859 Long.toHexString(filePos), e); 3860 } 3861 } 3862 3863 /** NOTE: reads little-endian int */ 3864 int readIntAt(long offset) throws COFFException { 3865 seek(offset); 3866 return readInt(); 3867 } 3868 3869 /** NOTE: reads little-endian int */ 3870 int readInt() throws COFFException { 3871 try { 3872 return byteSwap(file.readInt()); 3873 } catch (IOException e) { 3874 throw new COFFException(e.toString() + " at offset 0x" + 3875 Long.toHexString(filePos), e); 3876 } 3877 } 3878 3879 /** NOTE: reads little-endian long */ 3880 long readLongAt(long offset) throws COFFException { 3881 seek(offset); 3882 return readLong(); 3883 } 3884 3885 /** NOTE: reads little-endian long */ 3886 long readLong() throws COFFException { 3887 try { 3888 return byteSwap(file.readLong()); 3889 } catch (IOException e) { 3890 throw new COFFException(e.toString() + " at offset 0x" + 3891 Long.toHexString(filePos), e); 3892 } 3893 } 3894 3895 /** NOTE: reads little-endian float */ 3896 float readFloat() throws COFFException { 3897 int i = readInt(); 3898 return Float.intBitsToFloat(i); 3899 } 3900 3901 /** NOTE: reads little-endian double */ 3902 double readDouble() throws COFFException { 3903 long l = readLong(); 3904 return Double.longBitsToDouble(l); 3905 } 3906 3907 String readCString() throws COFFException { 3908 List data = new ArrayList(); 3909 byte b = 0; 3910 while ((b = readByte()) != 0) { 3911 data.add(new Byte(b)); 3912 } 3913 byte[] bytes = new byte[data.size()]; 3914 for (int i = 0; i < data.size(); i++) { 3915 bytes[i] = ((Byte) data.get(i)).byteValue(); 3916 } 3917 try { 3918 return new String(bytes, US_ASCII); 3919 } catch (UnsupportedEncodingException e) { 3920 throw new COFFException(e); 3921 } 3922 } 3923 3924 void seek(long offset) throws COFFException { 3925 try { 3926 filePos = offset; 3927 file.seek(offset); 3928 } catch (IOException e) { 3929 throw new COFFException(e.toString() + " at offset 0x" + 3930 Long.toHexString(offset), e); 3931 } 3932 } 3933 3934 long getFilePointer() throws COFFException { 3935 try { 3936 return file.getFilePointer(); 3937 } catch (IOException e) { 3938 throw new COFFException(e); 3939 } 3940 } 3941 3942 short byteSwap(short arg) { 3943 return (short) ((arg << 8) | ((arg >>> 8) & 0xFF)); 3944 } 3945 3946 int byteSwap(int arg) { 3947 return (((int) byteSwap((short) arg)) << 16) | (((int) (byteSwap((short) (arg >>> 16)))) & 0xFFFF); 3948 } 3949 3950 long byteSwap(long arg) { 3951 return ((((long) byteSwap((int) arg)) << 32) | (((long) byteSwap((int) (arg >>> 32))) & 0xFFFFFFFF)); 3952 } 3953 3954 public void close() throws COFFException { 3955 try { 3956 file.close(); 3957 } catch (IOException e) { 3958 throw new COFFException(e); 3959 } 3960 } 3961 } 3962 }