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