diff --git a/Ghidra/Features/PDB/developer_scripts/pdbquery/PdbQuery.java b/Ghidra/Features/PDB/developer_scripts/pdbquery/PdbQuery.java index 50b472f59a..41778c89af 100644 --- a/Ghidra/Features/PDB/developer_scripts/pdbquery/PdbQuery.java +++ b/Ghidra/Features/PDB/developer_scripts/pdbquery/PdbQuery.java @@ -15,13 +15,12 @@ */ package pdbquery; -import java.util.Map; - import ghidra.app.script.GhidraScript; import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.app.util.bin.format.pdb2.pdbreader.type.PrimitiveMsType; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup; import ghidra.util.Msg; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; @@ -184,9 +183,10 @@ public class PdbQuery { * @param pdb the PDB to search * @param searchString the search string * @throws CancelledException upon user cancellation + * @throws PdbException upon issue creating an iterator */ public static void searchSymbols(GhidraScript script, AbstractPdb pdb, String searchString) - throws CancelledException { + throws CancelledException, PdbException { PdbDebugInfo debugInfo = pdb.getDebugInfo(); if (debugInfo == null) { @@ -198,40 +198,25 @@ public class PdbQuery { int numModules = debugInfo.getNumModules(); TaskMonitor monitor = script.getMonitor(); - int numSymbols = 0; - for (int module = 0; module <= numModules; module++) { - monitor.checkCancelled(); - try { - Map symbols = debugInfo.getModuleSymbolsByOffset(module); - numSymbols += symbols.size(); - } - catch (PdbException e) { - // just skip the module... logging this in the next loop. - } - } - monitor.initialize(numSymbols); - println(script, "Searching " + numSymbols + " PDB symbol components..."); + monitor.initialize(numModules); + println(script, "Searching " + numModules + "PDB modules' symbol components..."); for (int module = 0; module <= numModules; module++) { monitor.checkCancelled(); - try { - Map symbols = debugInfo.getModuleSymbolsByOffset(module); - numSymbols += symbols.size(); - for (Map.Entry entry : symbols.entrySet()) { - monitor.checkCancelled(); - AbstractMsSymbol symbol = entry.getValue(); - String symbolString = symbol.toString(); - if (symbolString.contains(searchString)) { - results.append("Module " + module + ", Offset " + entry.getKey() + ":\n"); - results.append(symbolString); - results.append('\n'); - } - monitor.incrementProgress(1); + SymbolGroup symbolGroup = new SymbolGroup(pdb, module); + MsSymbolIterator iter = symbolGroup.getSymbolIterator(); + while (iter.hasNext()) { + monitor.checkCancelled(); + AbstractMsSymbol symbol = iter.next(); + String symbolString = symbol.toString(); + if (symbolString.contains(searchString)) { + results.append( + "Module " + module + ", Offset " + iter.getCurrentOffset() + ":\n"); + results.append(symbolString); + results.append('\n'); } } - catch (PdbException e) { - Msg.debug(PdbQuery.class, "Skipping module " + module + " due to exception."); - } + monitor.incrementProgress(1); } println(script, results.toString()); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/AbstractPdb.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/AbstractPdb.java index b62901398d..547abf4fbb 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/AbstractPdb.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/AbstractPdb.java @@ -149,7 +149,7 @@ public abstract class AbstractPdb implements AutoCloseable { if (debugInfo != null) { try { // dbiAge and targetProcessor set during deserialization of new DBI header - debugInfo.deserialize(true); + debugInfo.initialize(true); } catch (CancelledException e) { throw new AssertException(e); // unexpected @@ -328,9 +328,7 @@ public abstract class AbstractPdb implements AutoCloseable { Class typeClass) { recordNumber = fixupTypeIndex(recordNumber, typeClass); AbstractMsType msType = - getTPI(recordNumber.getCategory()).getRecord(recordNumber.getNumber()); -// AbstractMsType msType = -// getTPI(recordNumber.getCategory()).getRandomAccessRecord(recordNumber.getNumber()); + getTPI(recordNumber.getCategory()).getRandomAccessRecord(recordNumber.getNumber()); if (!typeClass.isInstance(msType)) { if (!recordNumber.isNoType()) { PdbLog.logGetTypeClassMismatch(msType, typeClass); @@ -505,7 +503,7 @@ public abstract class AbstractPdb implements AutoCloseable { typeProgramInterface = tpiParser.parse(this); if (typeProgramInterface != null) { - typeProgramInterface.deserialize(); + typeProgramInterface.initialize(); } boolean ipiStreamHasNoName = ItemProgramInterfaceParser.hackCheckNoNameForStream(nameTable); @@ -514,7 +512,7 @@ public abstract class AbstractPdb implements AutoCloseable { ItemProgramInterfaceParser ipiParser = new ItemProgramInterfaceParser(); itemProgramInterface = ipiParser.parse(this); if (itemProgramInterface != null) { - itemProgramInterface.deserialize(); + itemProgramInterface.initialize(); } //processDependencyIndexPairList(); //dumpDependencyGraph(); @@ -522,7 +520,7 @@ public abstract class AbstractPdb implements AutoCloseable { parseDBI(); if (debugInfo != null) { - debugInfo.deserialize(false); + debugInfo.initialize(false); } substreamsDeserialized = true; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/AbstractSymbolInformation.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/AbstractSymbolInformation.java index 047ad5778e..b01e5164b1 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/AbstractSymbolInformation.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/AbstractSymbolInformation.java @@ -19,7 +19,8 @@ import java.io.IOException; import java.io.Writer; import java.util.*; -import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; +import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream; +import ghidra.util.Msg; import ghidra.util.exception.CancelledException; /** @@ -37,25 +38,31 @@ public abstract class AbstractSymbolInformation { public static final int GSI70 = 0xeffe0000 + 19990810; // 0xf12f091a = -248575718 + public static final int HASH_PRE70_HEADER_LENGTH = 0; + public static final int HASH_70_HEADER_LENGTH = 16; + public static final int HASH_HEADER_MIN_READ_LENGTH = + Integer.max(HASH_PRE70_HEADER_LENGTH, HASH_70_HEADER_LENGTH); + //============================================================================================== // Internals //============================================================================================== protected AbstractPdb pdb; - protected int numHashRecords; - protected int numExtraBytes; - protected int hashRecordsBitMapLength; + protected int streamNumber; + protected int symbolHashLength; + protected int symbolHashOffset; + + protected int hashHeaderLength; protected int headerSignature; protected int versionNumber; protected int hashRecordsLength; protected int bucketsLength; + protected int hashRecordsOffset; + protected int bucketsOffset; - // These are read from "buckets." - protected List hashBucketOffsets = new ArrayList<>(); - protected Set hashRecords = new TreeSet<>(); - protected List modifiedHashRecordSymbolOffsets = new ArrayList<>(); - - protected List symbols = new ArrayList<>(); + protected int numHashRecords; + protected int numExtraBytes; + protected int hashRecordsBitMapLength; //============================================================================================== // API @@ -63,41 +70,84 @@ public abstract class AbstractSymbolInformation { /** * Constructor * @param pdbIn {@link AbstractPdb} that owns the Abstract Symbol Information to process + * @param streamNumber the stream number containing the symbol information */ - public AbstractSymbolInformation(AbstractPdb pdbIn) { + public AbstractSymbolInformation(AbstractPdb pdbIn, int streamNumber) { pdb = pdbIn; - } - - /** - * Returns the list of symbols for this {@link AbstractSymbolInformation} - * @return the symbols - */ - public List getSymbols() { - return symbols; + this.streamNumber = streamNumber; } /** * Returns the Offsets of symbols within the symbol table; these are gotten from the * HashRecords and modified to point to the size field of the symbols in the symbol table * @return offsets + * @throws PdbException upon not enough data left to parse + * @throws CancelledException upon user cancellation */ - public List getModifiedHashRecordSymbolOffsets() { - return modifiedHashRecordSymbolOffsets; + public List getModifiedHashRecordSymbolOffsets() throws CancelledException, PdbException { + return generateModifiedSymbolOffsets(); } //============================================================================================== // Package-Protected Internals //============================================================================================== /** - * Deserialize the {@link AbstractSymbolInformation} from the appropriate stream in the Pdb - * @param streamNumber the stream number containing the information to deserialize + * Parses and returns the hash bucket offsets + * @return the offsets + * @throws PdbException upon not enough data left to parse + * @throws CancelledException upon user cancellation + */ + List getHashBucketOffsets() throws CancelledException, PdbException { + try { + PdbByteReader reader = + pdb.getReaderForStreamNumber(streamNumber, bucketsOffset, bucketsLength); + if (headerSignature == HEADER_SIGNATURE) { + return deserializedCompressedHashBuckets(reader); + } + return deserializedHashBuckets(reader); + } + catch (IOException e) { + Msg.error(this, String.format( + "PDB: Error creating hash buckets while reading stream %d offset %d and length %d", + streamNumber, bucketsOffset, bucketsLength)); + return new ArrayList<>(); + } + } + + /** + * Parses and returns the hash records + * @return the hash records + * @throws PdbException upon not enough data left to parse + * @throws CancelledException upon user cancellation + */ + Set getHashRecords() throws CancelledException, PdbException { + try { + PdbByteReader reader = + pdb.getReaderForStreamNumber(streamNumber, hashRecordsOffset, hashRecordsLength); + return deserializeHashRecords(reader); + } + catch (IOException e) { + Msg.error(this, String.format( + "PDB: Error creating hash records while reading stream %d offset %d and length %d", + streamNumber, hashRecordsOffset, hashRecordsLength)); + return new TreeSet<>(); + } + } + + /** + * Deserialize basic {@link AbstractSymbolInformation} from the appropriate stream in the Pdb + * so that later queries can be made * @throws IOException on file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes * @throws PdbException upon not enough data left to parse * @throws CancelledException upon user cancellation */ - void deserialize(int streamNumber) - throws IOException, PdbException, CancelledException { + abstract void initialize() throws IOException, PdbException, CancelledException; + + /** + * Initializes values such as offset, lengths, and numbers + */ + void initializeValues() { if (pdb.hasMinimalDebugInfo()) { hashRecordsBitMapLength = 0x8000; numExtraBytes = 0; // I believe; @@ -113,10 +163,11 @@ public abstract class AbstractSymbolInformation { /** * Debug method for dumping information from this {@link AbstractSymbolInformation} * @param writer {@link Writer} to which to dump the information - * @throws IOException upon IOException writing to the {@link Writer} + * @throws IOException issue reading PDB or upon issue writing to the {@link Writer} * @throws CancelledException upon user cancellation + * @throws PdbException upon not enough data left to parse */ - void dump(Writer writer) throws IOException, CancelledException { + void dump(Writer writer) throws IOException, CancelledException, PdbException { StringBuilder builder = new StringBuilder(); builder.append("AbstractSymbolInformation-----------------------------------\n"); dumpHashHeader(builder); @@ -160,35 +211,34 @@ public abstract class AbstractSymbolInformation { /** * Generates a list of symbols from the information that we have - * @throws PdbException upon PDB corruption + * @return the offsets + * @throws PdbException upon not enough data left to parse * @throws CancelledException upon user cancellation */ - protected void generateSymbolsList() - throws PdbException, CancelledException { - symbols = new ArrayList<>(); + protected List generateModifiedSymbolOffsets() throws PdbException, CancelledException { + List modifiedHashRecordSymbolOffsets = new ArrayList<>(); PdbDebugInfo debugInfo = pdb.getDebugInfo(); if (debugInfo == null) { - return; + return modifiedHashRecordSymbolOffsets; } - Map symbolsByOffset = debugInfo.getSymbolsByOffset(); + Set hashRecords = getHashRecords(); for (SymbolHashRecord record : hashRecords) { pdb.checkCancelled(); long offset = record.getOffset() - 2; // Modified offset - AbstractMsSymbol symbol = symbolsByOffset.get(offset); modifiedHashRecordSymbolOffsets.add(offset); - if (symbol == null) { - throw new PdbException("PDB corrupted"); - } - symbols.add(symbol); } + return modifiedHashRecordSymbolOffsets; } /** * Debug method for dumping hash records from this {@link AbstractSymbolInformation} * @param builder {@link StringBuilder} to which to dump the information + * @throws PdbException upon not enough data left to parse * @throws CancelledException upon user cancellation */ - protected void dumpHashRecords(StringBuilder builder) throws CancelledException { + protected void dumpHashRecords(StringBuilder builder) + throws CancelledException, PdbException { + Set hashRecords = getHashRecords(); builder.append("HashRecords-------------------------------------------------\n"); builder.append("numHashRecords: " + hashRecords.size() + "\n"); for (SymbolHashRecord record : hashRecords) { @@ -199,31 +249,12 @@ public abstract class AbstractSymbolInformation { builder.append("\nEnd HashRecords---------------------------------------------\n"); } - /** - * Deserializes the hash table for the symbols - * @param reader {@link PdbByteReader} containing the data buffer to process - * @throws PdbException upon not enough data left to parse - * @throws CancelledException upon user cancellation - */ - protected void deserializeHashTable(PdbByteReader reader) - throws PdbException, CancelledException { - - deserializeHashHeader(reader); - - if (headerSignature == HEADER_SIGNATURE) { - switch (versionNumber) { - case GSI70: - deserializeGsi70HashTable(reader); - break; - default: - throw new PdbException("Unknown GSI Version Number"); - } - } - else { - reader.reset(); // There was no header - deserializeGsiPre70HashTable(reader); - } - + protected void deserializeHashHeader() throws PdbException, CancelledException, IOException { + MsfStream stream = pdb.getMsf().getStream(streamNumber); + PdbByteReader reader = + pdb.getReaderForStreamNumber(streamNumber, symbolHashOffset, + HASH_HEADER_MIN_READ_LENGTH); + deserializeHashHeader(reader, stream.getLength()); } /** @@ -231,81 +262,28 @@ public abstract class AbstractSymbolInformation { * @param reader {@link PdbByteReader} containing the data buffer to process * @throws PdbException upon not enough data left to parse */ - private void deserializeHashHeader(PdbByteReader reader) throws PdbException { + private void deserializeHashHeader(PdbByteReader reader, int streamLength) throws PdbException { headerSignature = reader.parseInt(); - versionNumber = reader.parseInt(); - hashRecordsLength = reader.parseInt(); - bucketsLength = reader.parseInt(); - } - - /** - * Deserialize the body of the {@link AbstractSymbolInformation} according to the GSI versions - * prior to 7.00 specification - * @param reader {@link PdbByteReader} containing the data buffer to process - * @throws PdbException upon unexpected fields - * @throws CancelledException upon user cancellation - */ - private void deserializeGsiPre70HashTable(PdbByteReader reader) - throws PdbException, CancelledException { - - int numBucketsBytes = 4 * (numHashRecords + 1); - if (reader.numRemaining() < numBucketsBytes) { - throw new PdbException("Not enough data for GSI"); + if (headerSignature == HEADER_SIGNATURE) { + hashHeaderLength = HASH_70_HEADER_LENGTH; + versionNumber = reader.parseInt(); + hashRecordsLength = reader.parseInt(); + bucketsLength = reader.parseInt(); + hashRecordsOffset = symbolHashOffset + reader.getIndex(); + bucketsOffset = hashRecordsOffset + hashRecordsLength; } - int numRecordsBytes = (reader.numRemaining() - numBucketsBytes); - - PdbByteReader hashRecordsReader = reader.getSubPdbByteReader(numRecordsBytes); - PdbByteReader bucketsReader = reader.getSubPdbByteReader(numBucketsBytes); - if (reader.hasMore()) { - throw new PdbException("Unexpected extra information at and of GSI stream"); + else { + hashHeaderLength = HASH_PRE70_HEADER_LENGTH; + reader.reset(); // There was no header + // Calculate the values + bucketsLength = 4 * (numHashRecords + 1); + if (streamLength < bucketsLength) { + throw new PdbException("Not enough data for symbol hash buckets."); + } + hashRecordsLength = streamLength - bucketsLength; + hashRecordsOffset = symbolHashOffset + 0; + bucketsOffset = hashRecordsOffset + hashRecordsLength; } - - hashBucketOffsets = new ArrayList<>(); - while (bucketsReader.hasMore()) { - pdb.checkCancelled(); - hashBucketOffsets.add(bucketsReader.parseInt()); - } - - // Note: each offset value is into an array of structures that are 12 bytes in length, but - // whose on-disk size is 8 bytes. These are the structures in the hashRecordsReader. So - // take the offset and multiple by 2/3 to get the byte offset into the reader for the - // actual record. Still need to deal with the collision logic after that. - - deserializeHashRecords(hashRecordsReader); - } - - /** - * Deserialize the body of the {@link AbstractSymbolInformation} according to the GSI 7.00 - * specification - * @param reader {@link PdbByteReader} containing the data buffer to process - * @throws PdbException upon unexpected fields - * @throws CancelledException upon user cancellation - */ - private void deserializeGsi70HashTable(PdbByteReader reader) - throws PdbException, CancelledException { - - if (reader.numRemaining() != hashRecordsLength + bucketsLength) { - throw new PdbException("Data count mismatch in GSI stream"); - } - if (hashRecordsLength == 0 || bucketsLength == 0) { - return; - } - - PdbByteReader hashRecordsReader = reader.getSubPdbByteReader(hashRecordsLength); - PdbByteReader bucketsReader = reader.getSubPdbByteReader(bucketsLength); - - deserializedCompressedHashBuckets(bucketsReader); - -// int i = 0; -// for (int x : hashBucketOffsets) { -// System.out.println(String.format("0x%04x: 0x%08x", i++, x)); -// } - // Note: each offset value is into an array of structures that are 12 bytes in length, but - // whose on-disk size is 8 bytes. These are the structures in the hashRecordsReader. So - // take the offset and multiple by 2/3 to get the byte offset into the reader for the - // actual record. Still need to deal with the collision logic after that. - - deserializeHashRecords(hashRecordsReader); } /** @@ -316,9 +294,11 @@ public abstract class AbstractSymbolInformation { * @throws PdbException upon not enough data left to parse * @throws CancelledException upon user cancellation */ - private void deserializedCompressedHashBuckets(PdbByteReader reader) + private List deserializedCompressedHashBuckets(PdbByteReader reader) throws PdbException, CancelledException { + List hashBucketOffsets = new ArrayList<>(); + PdbByteReader bitEncoderReader = reader.getSubPdbByteReader(hashRecordsBitMapLength); // Throw away extra bytes between bit map and buckets. reader.getSubPdbByteReader(numExtraBytes); @@ -349,24 +329,154 @@ public abstract class AbstractSymbolInformation { throw new PdbException("Compressed GSI Hash Buckets corrupt"); } } + return hashBucketOffsets; } /** - * Deserializes the hash records + * Deserializes a normal/non-compressed set of hash buckets from the {@link PdbByteReader} + * provided. * @param reader {@link PdbByteReader} containing the data buffer to process * @throws PdbException upon not enough data left to parse * @throws CancelledException upon user cancellation */ - private void deserializeHashRecords(PdbByteReader reader) + private List deserializedHashBuckets(PdbByteReader reader) throws PdbException, CancelledException { - hashRecords = new TreeSet<>(); + List hashBucketOffsets = new ArrayList<>(); + while (reader.hasMore()) { + pdb.checkCancelled(); + hashBucketOffsets.add(reader.parseInt()); + } + return hashBucketOffsets; + } + + // The following note is from previous incantation of this code (before changing to on-demand + // reading of components). It still might be applicable here or elsewhere. + // + // Note: each offset value is into an array of structures that are 12 bytes in length, but + // whose on-disk size is 8 bytes. These are the structures in the hashRecordsReader. So + // take the offset and multiple by 2/3 to get the byte offset into the reader for the + // actual record. Still need to deal with the collision logic after that. + /** + * Deserializes and returns the hash records + * @param reader {@link PdbByteReader} containing the data buffer to process + * @throws PdbException upon not enough data left to parse + * @throws CancelledException upon user cancellation + */ + private Set deserializeHashRecords(PdbByteReader reader) + throws PdbException, CancelledException { + Set hashRecords = new TreeSet<>(); while (reader.hasMore()) { pdb.checkCancelled(); SymbolHashRecord record = new SymbolHashRecord(); record.parse(reader); hashRecords.add(record); } + return hashRecords; } + // NOTE Iterator below is not good at this point in time, as we had been working with + // a TreeSet, which is ordered. The iterator below is acting on hash bins which are + // as random as the hash key makes them. TODO: consider other options. For now going back + // to creating the whole TreeSet. + +// public ModifiedOffsetIterator iterator() { +// return new ModifiedOffsetIterator(); +// } +// +// //============================================================================================== +// /** +// * Iterator for {@link SymbolGroup} that iterates through {@link AbstractMsSymbol +// * AbstractMsSymbols} +// */ +// public class ModifiedOffsetIterator implements Iterator { +// +// private int streamOffset; +// private int streamOffsetLimit; +// private float factor; +// +// private Long value; +// +// public ModifiedOffsetIterator() { +// initGet(); +// } +// +// @Override +// public boolean hasNext() { +// return (value != null); +// } +// +// /** +// * Peeks at and returns the next symbol without incrementing to the next. If none are +// * left, then throws NoSuchElementException and reinitializes the state for a new +// * iteration. +// * @see #initGet() +// * @return the next symbol +// * @throws NoSuchElementException if there are no more elements +// */ +// public Long peek() throws NoSuchElementException { +// if (value == null) { +// throw new NoSuchElementException(); +// } +// return value; +// } +// +// @Override +// public Long next() { +// if (value == null) { +// throw new NoSuchElementException(); +// } +// Long offer = value; +// value = retrieveNext(); +// return offer; +// } +// +// private Long retrieveNext() { +// if (streamNumber == MsfStream.NIL_STREAM_NUMBER) { +// return null; +// } +// if (streamOffset >= streamOffsetLimit) { +// return null; +// } +// try { +// PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, streamOffset, +// SymbolHashRecord.RECORD_SIZE); +// SymbolHashRecord record = new SymbolHashRecord(); +// record.parse(reader); +// streamOffset += SymbolHashRecord.RECORD_SIZE; +// // Minus 2 for the "modified" offset points to the length field in the "other" +// // stream +// return record.getOffset() - 2; +// } +// catch (CancelledException | PdbException | IOException e) { +// return null; +// } +// } +// +// /** +// * Initialized the mechanism for requesting the symbols in sequence. +// * @see #hasNext() +// */ +// void initGet() { +// if (streamNumber == MsfStream.NIL_STREAM_NUMBER) { +// streamOffset = 0; +// streamOffsetLimit = 0; +// return; +// } +// streamOffset = hashRecordsOffset; +// streamOffsetLimit = hashRecordsLength; +// value = retrieveNext(); +// long num = streamOffsetLimit - hashRecordsOffset; +// float factor = num <= 0 ? 0.0F : 1.0F / (num); +// } +// +// /** +// * Returns value from 0 to 100 as a rough percentage of having iterated through all records +// * @return the percentage +// */ +// public long getPercentageDone() { +// long num = streamOffset - hashRecordsOffset; +// return (long) (factor * num); +// } +// } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/DebugData.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/DebugData.java index 27e5f73b17..8debd154be 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/DebugData.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/DebugData.java @@ -66,17 +66,6 @@ public class DebugData { private AbstractPdb pdb; private List debugStreams = new ArrayList<>(); - private List framePointerOmissionData; - // private SortedMap omapToSource; - private SortedMap omapFromSource; - private List imageSectionHeaders; - private List imageSectionHeadersOrig; - - private List pData; - - private RvaVaDebugHeader xDataHeader; - private PdbByteReader xDataReader; - //============================================================================================== // API //============================================================================================== @@ -92,9 +81,18 @@ public class DebugData { /** * Returns the Frame Pointer Omission data * @return the framePointerOmissionData or null if does not exist + * @throws PdbException PdbException upon error in processing components + * @throws CancelledException upon user cancellation + * @throws IOException on file seek or read, invalid parameters, bad file configuration, or + * inability to read required bytes */ - public List getFramePointerOmissionData() { - return framePointerOmissionData; + public List getFramePointerOmissionData() + throws CancelledException, PdbException, IOException { + int streamNum = debugStreams.get(DebugType.FRAME_POINTER_OMISSION.getValue()); + if (streamNum == MsfStream.NIL_STREAM_NUMBER) { + return null; + } + return deserializeFramePointerOmissionData(streamNum); } // /** @@ -108,17 +106,74 @@ public class DebugData { /** * Returns the OMAP_FROM_SOURCE mapping of RVA to RVA * @return the omapFromSource or null if does not exist. + * @throws PdbException PdbException upon error in processing components + * @throws CancelledException upon user cancellation + * @throws IOException on file seek or read, invalid parameters, bad file configuration, or + * inability to read required bytes */ - public SortedMap getOmapFromSource() { - return omapFromSource; + public SortedMap getOmapFromSource() + throws CancelledException, PdbException, IOException { + int streamNum = debugStreams.get(DebugType.OMAP_FROM_SOURCE.getValue()); + if (streamNum == MsfStream.NIL_STREAM_NUMBER) { + return null; + } + return deserializeOMap(streamNum); } /** * Returns the {@link List}<{@link ImageSectionHeader}> * @return the imageSectionHeaders or null if does not exist + * @throws PdbException PdbException upon error in processing components + * @throws CancelledException upon user cancellation + * @throws IOException on file seek or read, invalid parameters, bad file configuration, or + * inability to read required bytes */ - public List getImageSectionHeaders() { - return imageSectionHeaders; + public List getImageSectionHeaders() + throws CancelledException, PdbException, IOException { + int streamNum = debugStreams.get(DebugType.SECTION_HEADER.getValue()); + if (streamNum == MsfStream.NIL_STREAM_NUMBER) { + return null; + } + return deserializeSectionHeaders(streamNum); + } + + /** + * Returns XData + * When this returns a non-null list the OMAP_FROM_SRC should be + * used for remapping global symbols + * @return the imageSectionHeadersOrig or null if does not exist + * @throws PdbException PdbException upon error in processing components + * @throws CancelledException upon user cancellation + * @throws IOException on file seek or read, invalid parameters, bad file configuration, or + * inability to read required bytes + */ + // TODO: just put a return of null Integer for now until figured out. + public Integer getXData() + throws CancelledException, PdbException, IOException { + int streamNum = debugStreams.get(DebugType.SECTION_HEADER_ORIG.getValue()); + if (streamNum == MsfStream.NIL_STREAM_NUMBER) { + return null; + } + return deserializeXData(streamNum); + } + + /** + * Returns PData + * When this returns a non-null list the OMAP_FROM_SRC should be + * used for remapping global symbols + * @return the imageSectionHeadersOrig or null if does not exist + * @throws PdbException PdbException upon error in processing components + * @throws CancelledException upon user cancellation + * @throws IOException on file seek or read, invalid parameters, bad file configuration, or + * inability to read required bytes + */ + public List getPData() + throws CancelledException, PdbException, IOException { + int streamNum = debugStreams.get(DebugType.SECTION_HEADER_ORIG.getValue()); + if (streamNum == MsfStream.NIL_STREAM_NUMBER) { + return null; + } + return deserializePData(streamNum); } /** @@ -126,9 +181,18 @@ public class DebugData { * When this returns a non-null list the OMAP_FROM_SRC should be * used for remapping global symbols * @return the imageSectionHeadersOrig or null if does not exist + * @throws PdbException PdbException upon error in processing components + * @throws CancelledException upon user cancellation + * @throws IOException on file seek or read, invalid parameters, bad file configuration, or + * inability to read required bytes */ - public List getImageSectionHeadersOrig() { - return imageSectionHeadersOrig; + public List getImageSectionHeadersOrig() + throws CancelledException, PdbException, IOException { + int streamNum = debugStreams.get(DebugType.SECTION_HEADER_ORIG.getValue()); + if (streamNum == MsfStream.NIL_STREAM_NUMBER) { + return null; + } + return deserializeSectionHeaders(streamNum); } /** @@ -165,6 +229,7 @@ public class DebugData { * @throws IOException on file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes */ + @Deprecated public void deserialize() throws PdbException, CancelledException, IOException { if (debugStreams.isEmpty()) { @@ -178,7 +243,7 @@ public class DebugData { } switch (dbg) { case FRAME_POINTER_OMISSION: - deserializeFramePointerOmissionData(streamNum); + // framePointerOmissionData = deserializeFramePointerOmissionData(streamNum); break; case EXCEPTION: // TODO: implement. @@ -190,42 +255,44 @@ public class DebugData { // omapToSource = deserializeOMap(streamNum); break; case OMAP_FROM_SOURCE: - omapFromSource = deserializeOMap(streamNum); + // omapFromSource = deserializeOMap(streamNum); break; case SECTION_HEADER: - imageSectionHeaders = deserializeSectionHeaders(streamNum); + // imageSectionHeaders = deserializeSectionHeaders(streamNum); break; case TOKEN_RID_MAP: // TODO: implement. break; case X_DATA: - deserializeXData(streamNum); + // DUMMY Integer return value for now + // Integer xData = deserializeXData(streamNum); break; case P_DATA: - deserializePData(streamNum); + // pData = deserializePData(streamNum); break; case NEW_FRAME_POINTER_OMISSION: // TODO: implement. break; case SECTION_HEADER_ORIG: - imageSectionHeadersOrig = deserializeSectionHeaders(streamNum); + // imageSectionHeadersOrig = deserializeSectionHeaders(streamNum); break; } } } - private void deserializeFramePointerOmissionData(int streamNum) + private List deserializeFramePointerOmissionData(int streamNum) throws PdbException, CancelledException, IOException { // TODO: check implementation for completeness. PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); - framePointerOmissionData = new ArrayList<>(); + List fpOmissionData = new ArrayList<>(); while (reader.hasMore()) { pdb.checkCancelled(); FramePointerOmissionRecord framePointerOmissionRecord = new FramePointerOmissionRecord(); framePointerOmissionRecord.parse(reader); - framePointerOmissionData.add(framePointerOmissionRecord); + fpOmissionData.add(framePointerOmissionRecord); } + return fpOmissionData; } private SortedMap deserializeOMap(int streamNum) @@ -259,17 +326,18 @@ public class DebugData { * See the {@link LinkerUnwindInfo} class that was built for and is pertinent to * processing XData */ - private void deserializeXData(int streamNum) + // TODO: just put a return of null Integer for now until figured out. + private Integer deserializeXData(int streamNum) throws PdbException, CancelledException, IOException { PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); int streamLength = reader.getLimit(); //System.out.println(reader.dump(0x20)); RvaVaDebugHeader header = new RvaVaDebugHeader(); - xDataHeader = header; + header.deserialize(reader); //System.out.println(header.dump()); if (header.getHeaderVersion() != 1) { - return; // Silent... TODO: add logging event. + return null; // Silent... TODO: add logging event. } long headerLength = header.getHeaderLength(); long dataLength = header.getDataLength(); @@ -278,25 +346,27 @@ public class DebugData { } reader.setIndex((int) headerLength); //System.out.println(reader.dump()); - xDataReader = reader.getSubPdbByteReader(reader.numRemaining()); + PdbByteReader xDataReader = reader.getSubPdbByteReader(reader.numRemaining()); // TODO: This is a partial implementation. We need to figure out more to know // how to deal with it. The only API information regarding the XData is with // regard to processing PData when the "machine" is IA64 or AMD64. The interpretation // for these machines is not real clear (or a bit of work), and there is no other // interpretation available when the machine is different. + + return null; } // TODO: This is incomplete. - private void deserializePData(int streamNum) + private List deserializePData(int streamNum) throws PdbException, CancelledException, IOException { PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); - pData = new ArrayList<>(); + List myPData = new ArrayList<>(); int streamLength = reader.getLimit(); RvaVaDebugHeader header = new RvaVaDebugHeader(); header.deserialize(reader); //System.out.println(header.dump()); if (header.getHeaderVersion() != 1) { - return; // Silent... TODO: add logging event. + return myPData; // Silent... TODO: add logging event. } long headerLength = header.getHeaderLength(); long dataLength = header.getDataLength(); @@ -335,6 +405,7 @@ public class DebugData { break; } } + return myPData; } /** @@ -342,12 +413,14 @@ public class DebugData { * @param writer {@link Writer} to which to write the debug dump * @throws IOException on issue writing to the {@link Writer} * @throws CancelledException upon user cancellation + * @throws PdbException upon error in processing components */ - void dump(Writer writer) throws IOException, CancelledException { + void dump(Writer writer) throws IOException, CancelledException, PdbException { writer.write("DebugData---------------------------------------------------\n"); dumpDebugStreamList(writer); writer.write("FramePointerOmissionData------------------------------------\n"); + List framePointerOmissionData = getFramePointerOmissionData(); if (framePointerOmissionData != null) { for (FramePointerOmissionRecord framePointerOmissionRecord : framePointerOmissionData) { pdb.checkCancelled(); @@ -368,6 +441,7 @@ public class DebugData { // writer.write("End OmapToSource--------------------------------------------\n"); // writer.write("OmapFromSource----------------------------------------------\n"); + SortedMap omapFromSource = getOmapFromSource(); if (omapFromSource != null) { int num = 0; for (Map.Entry entry : omapFromSource.entrySet()) { @@ -379,6 +453,7 @@ public class DebugData { writer.write("End OmapFromSource------------------------------------------\n"); writer.write("ImageSectionHeaders-----------------------------------------\n"); + List imageSectionHeaders = getImageSectionHeaders(); if (imageSectionHeaders != null) { int sectionNum = 0; for (ImageSectionHeader imageSectionHeader : imageSectionHeaders) { @@ -389,6 +464,7 @@ public class DebugData { writer.write("End ImageSectionHeaders-------------------------------------\n"); writer.write("ImageSectionHeadersOrig-------------------------------------\n"); + List imageSectionHeadersOrig = getImageSectionHeadersOrig(); if (imageSectionHeadersOrig != null) { int sectionNum = 0; for (ImageSectionHeader imageSectionHeader : imageSectionHeadersOrig) { @@ -399,6 +475,7 @@ public class DebugData { writer.write("End ImageSectionHeadersOrig---------------------------------\n"); writer.write("PData-------------------------------------------------------\n"); + List pData = getPData(); if (pData != null) { for (ImageFunctionEntry entry : pData) { pdb.checkCancelled(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/GlobalReferenceIterator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/GlobalReferenceIterator.java index 6907d6685b..91338e4f2d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/GlobalReferenceIterator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/GlobalReferenceIterator.java @@ -15,12 +15,10 @@ */ package ghidra.app.util.bin.format.pdb2.pdbreader; -import java.io.IOException; import java.util.NoSuchElementException; import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; -import ghidra.util.Msg; import ghidra.util.exception.CancelledException; /** @@ -93,17 +91,10 @@ class GlobalReferenceIterator implements ParsingIterator { currentGlobalSymbolIterator = null; return; } - try { - Long offset = offsetIterator.next(); - PdbByteReader reader = - pdb.getReaderForStreamNumber(symbolsStreamNumber, offset.intValue(), - MsfStream.MAX_STREAM_LENGTH); - currentGlobalSymbolIterator = new MsSymbolIterator(pdb, reader); - } - catch (IOException e) { - Msg.error(this, "Problem seen in find()", e); - currentGlobalSymbolIterator = null; - } + Long offset = offsetIterator.next(); + currentGlobalSymbolIterator = + new MsSymbolIterator(pdb, symbolsStreamNumber, offset.intValue(), + MsfStream.MAX_STREAM_LENGTH); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/GlobalSymbolInformation.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/GlobalSymbolInformation.java index 1b198078f9..db0e990298 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/GlobalSymbolInformation.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/GlobalSymbolInformation.java @@ -18,6 +18,7 @@ package ghidra.app.util.bin.format.pdb2.pdbreader; import java.io.IOException; import java.io.Writer; +import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream; import ghidra.util.exception.CancelledException; /** @@ -34,38 +35,42 @@ public class GlobalSymbolInformation extends AbstractSymbolInformation { /** * Constructor. * @param pdbIn {@link AbstractPdb} that owns the Global Symbol Information to process. + * @param streamNumber the stream number containing the symbol information */ - public GlobalSymbolInformation(AbstractPdb pdbIn) { - super(pdbIn); + public GlobalSymbolInformation(AbstractPdb pdbIn, int streamNumber) { + super(pdbIn, streamNumber); } /** - * Deserialize the {@link GlobalSymbolInformation} from the appropriate stream in the Pdb - * @param streamNumber the stream number containing the information to deserialize + * Deserializes and intializes {@link GlobalSymbolInformation} basic information from the + * appropriate stream in the Pdb so that later queries can be made * @throws IOException on file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes * @throws PdbException upon not enough data left to parse * @throws CancelledException upon user cancellation */ @Override - void deserialize(int streamNumber) - throws IOException, PdbException, CancelledException { - super.deserialize(streamNumber); - PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber); - deserializeHashTable(reader); + void initialize() throws IOException, PdbException, CancelledException { + initializeValues(); + initializeGlobalOffsetsAndLengths(); + deserializeHashHeader(); + } - // Organize the information - generateSymbolsList(); + private void initializeGlobalOffsetsAndLengths() { + symbolHashOffset = 0; + MsfStream stream = pdb.getMsf().getStream(streamNumber); + symbolHashLength = (stream == null) ? 0 : stream.getLength(); } /** * Debug method for dumping information from this {@link GlobalSymbolInformation} * @param writer {@link Writer} to which to dump the information - * @throws IOException upon IOException writing to the {@link Writer} + * @throws IOException issue reading PDBor upon issue writing to the {@link Writer} * @throws CancelledException upon user cancellation + * @throws PdbException upon not enough data left to parse */ @Override - void dump(Writer writer) throws IOException, CancelledException { + void dump(Writer writer) throws IOException, CancelledException, PdbException { StringBuilder builder = new StringBuilder(); builder.append("GlobalSymbolInformation-------------------------------------\n"); dumpHashHeader(builder); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/Module.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/Module.java index d09f41b2a6..727e1c6a38 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/Module.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/Module.java @@ -126,13 +126,13 @@ public class Module { * Returns an MsSymbolIterator for the symbols of this module * @return the iterator * @throws CancelledException upon user cancellation + * @throws IOException upon error reading stream * @throws PdbException upon invalid cvSignature */ - public MsSymbolIterator getSymbolIterator() throws CancelledException, PdbException { - PdbByteReader symbolsReader = getSymbolsReader(); - parseSignature(symbolsReader); - MsSymbolIterator iterator = new MsSymbolIterator(pdb, symbolsReader); - return iterator; + public MsSymbolIterator iterator() throws CancelledException, IOException, PdbException { + int startingOffset = pdb.getDebugInfo().getSymbolRecords().getCvSigLength(streamNumber); + int lengthSymbols = moduleInformation.getSizeLocalSymbolsDebugInformation(); + return new MsSymbolIterator(pdb, streamNumber, startingOffset, lengthSymbols); } private void parseSignature(PdbByteReader symbolsReader) throws PdbException { @@ -333,13 +333,14 @@ public class Module { private void dumpSymbols(Writer writer) throws IOException, CancelledException, PdbException { - writer.write("Symbols-----------------------------------------------------\n"); - MsSymbolIterator symbolIterator = getSymbolIterator(); - while (symbolIterator.hasNext()) { + writer.write("Symbols-----------------------------------------------------"); + MsSymbolIterator symbolIter = iterator(); + while (symbolIter.hasNext()) { pdb.checkCancelled(); - AbstractMsSymbol symbol = symbolIterator.next(); + AbstractMsSymbol symbol = symbolIter.next(); + writer.append("\n------------------------------------------------------------\n"); + writer.append(String.format("Offset: 0X%08X\n", symbolIter.getCurrentOffset())); writer.append(symbol.toString()); - writer.append("\n"); } writer.write("End Symbols-------------------------------------------------\n"); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/MsSymbolIterator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/MsSymbolIterator.java index 07c77c7c57..d82309502a 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/MsSymbolIterator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/MsSymbolIterator.java @@ -15,71 +15,136 @@ */ package ghidra.app.util.bin.format.pdb2.pdbreader; +import java.util.Iterator; import java.util.NoSuchElementException; +import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; -import ghidra.util.Msg; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup; import ghidra.util.exception.CancelledException; /** - * Iterator for {@link AbstractMsSymbol AbstractMsSymbols} being read from a stream. + * Iterator for {@link SymbolGroup} that iterates through {@link AbstractMsSymbol + * AbstractMsSymbols} */ -class MsSymbolIterator implements ParsingIterator { +public class MsSymbolIterator implements Iterator { - private AbstractPdb pdb; - private PdbByteReader reader; + private int streamNumber; + private int startOffset; + private SymbolRecords symbolRecords; + private int lengthSymbols; + private int nextRetrieveOffset; + private int currentOffset; + private SymbolRecords.SymLen symLen; - private AbstractMsSymbol currentSymbol = null; + public MsSymbolIterator(AbstractPdb pdb, int streamNumber, int startOffset, int lengthSymbols) { + this.streamNumber = streamNumber; + this.startOffset = startOffset; + this.lengthSymbols = lengthSymbols; + symbolRecords = pdb.getDebugInfo().getSymbolRecords(); + if (streamNumber == MsfStream.NIL_STREAM_NUMBER) { + symLen = null; + nextRetrieveOffset = 0; + currentOffset = 0; + } + else { + initGet(); + } + } + + @Override + public boolean hasNext() { + return (symLen != null); + } /** - * Constructor. - * @param pdb {@link AbstractPdb} that owns the Symbols to be parsed - * @param reader for the stream section containing the symbol information - * @throws CancelledException upon user cancellation + * Peeks at and returns the next symbol without incrementing to the next. If none are + * left, then throws NoSuchElementException and reinitializes the state for a new + * iteration. + * @see #initGet() + * @return the next symbol + * @throws NoSuchElementException if there are no more elements */ - public MsSymbolIterator(AbstractPdb pdb, PdbByteReader reader) throws CancelledException { - this.pdb = pdb; - this.reader = reader; + public AbstractMsSymbol peek() throws NoSuchElementException { + if (symLen == null) { + throw new NoSuchElementException(); + } + return symLen.symbol(); } @Override - public boolean hasNext() throws CancelledException { - if (currentSymbol == null) { - find(); + public AbstractMsSymbol next() { + if (symLen == null) { + throw new NoSuchElementException(); } - return (currentSymbol != null); + SymbolRecords.SymLen offer = symLen; + currentOffset = nextRetrieveOffset; + symLen = retrieveRecord(); + return offer.symbol(); } - @Override - public AbstractMsSymbol next() throws CancelledException, NoSuchElementException { - if (hasNext()) { - AbstractMsSymbol returnSymbol = currentSymbol; - currentSymbol = null; - return returnSymbol; + private SymbolRecords.SymLen retrieveRecord() { + if (streamNumber == MsfStream.NIL_STREAM_NUMBER) { + return null; } - throw new NoSuchElementException("next() called with no more elements"); - } - - @Override - public AbstractMsSymbol peek() throws CancelledException, NoSuchElementException { - if (hasNext()) { - return currentSymbol; - } - throw new NoSuchElementException("peek() called with no more elements"); - } - - private void find() throws CancelledException { - if (!reader.hasMore()) { - currentSymbol = null; - return; + if (nextRetrieveOffset >= lengthSymbols) { + return null; } try { - currentSymbol = SymbolParser.parseLengthAndSymbol(pdb, reader); + SymbolRecords.SymLen retrieved = + symbolRecords.getRandomAccessRecord(streamNumber, nextRetrieveOffset); + if (retrieved != null) { + nextRetrieveOffset += retrieved.length(); + } + return retrieved; } - catch (PdbException e) { - Msg.error(this, "Problem seen in find()", e); - currentSymbol = null; + catch (PdbException | CancelledException e) { + return null; } } + /** + * Returns the next symbol. If none are left, then throws NoSuchElementException and + * reinitializes the state for a new iteration. + * @see #initGet() + * @return the next symbol + * @throws NoSuchElementException if there are no more elements + */ + public long getCurrentOffset() { + return currentOffset; + } + + /** + * Initialized the mechanism for requesting the symbols in sequence. + * @see #hasNext() + */ + public void initGet() { + if (streamNumber == MsfStream.NIL_STREAM_NUMBER) { + return; + } + nextRetrieveOffset = startOffset; + currentOffset = nextRetrieveOffset; + symLen = retrieveRecord(); + } + + /** + * Initialized the mechanism for requesting the symbols in sequence. + * @param offset the offset to which to initialize the mechanism. + * @see #hasNext() + */ + public void initGetByOffset(long offset) { + Long l = offset; + nextRetrieveOffset = l.intValue(); + currentOffset = nextRetrieveOffset; + symLen = retrieveRecord(); + } + + /** + * Returns the stream number + * @return the stream number + */ + public int getStreamNumber() { + return streamNumber; + } + } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbDebugInfo.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbDebugInfo.java index 24b8c004f3..263792fbc0 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbDebugInfo.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbDebugInfo.java @@ -69,14 +69,10 @@ public abstract class PdbDebugInfo { protected List sectionContributionList = new ArrayList<>(); protected List segmentMapList = new ArrayList<>(); - protected SymbolRecords symbolRecords; - protected GlobalSymbolInformation globalSymbolInformation; - protected PublicSymbolInformation publicSymbolInformation; + protected SymbolRecords symbolRecords = null; + protected GlobalSymbolInformation globalSymbolInformation = null; + protected PublicSymbolInformation publicSymbolInformation = null; - //============================================================================================== - // NEW STUFF FROM REFACTOR/REWORK (can be duplicative with other stuff)... might be turned off - // during development. - private boolean doNewStuff = false; private List modules = new ArrayList<>(); //============================================================================================== @@ -91,9 +87,6 @@ public abstract class PdbDebugInfo { Objects.requireNonNull(pdb, "pdb cannot be null"); this.pdb = pdb; this.streamNumber = streamNumber; - globalSymbolInformation = new GlobalSymbolInformation(pdb); - publicSymbolInformation = new PublicSymbolInformation(pdb); - symbolRecords = new SymbolRecords(pdb); } /** @@ -105,7 +98,7 @@ public abstract class PdbDebugInfo { } /** - * Deserializes the {@link PdbDebugInfo}-based instance. + * Deserializes and initializes some basic {@link PdbDebugInfo}-based information * The PDB is updated with dbiAge and targetProcessor during deserialization * of new DBI header. * @param headerOnly if true only the DBI header fields will be parsed @@ -115,24 +108,24 @@ public abstract class PdbDebugInfo { * @throws PdbException upon error parsing a field * @throws CancelledException upon user cancellation */ - public long deserialize(boolean headerOnly) + public long initialize(boolean headerOnly) throws IOException, PdbException, CancelledException { if (headerOnly) { - PdbByteReader reader = - pdb.getReaderForStreamNumber(streamNumber, 0, getHeaderLength()); + PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, 0, getHeaderLength()); deserializeHeader(reader); } else { PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber); deserializeHeader(reader); deserializeInternalSubstreams(reader); - deserializeAdditionalSubstreams(); - // BELOW: NEW STUFF FROM REFACTOR/REWORK (can be duplicative with other stuff) - if (doNewStuff) { - parseModules(); - compareSymbols(); //temporary to ensure same results with previous work. - } - // ABOVE: NEW STUFF FROM REFACTOR/REWORK (can be duplicative with other stuff) + globalSymbolInformation = + new GlobalSymbolInformation(pdb, getGlobalSymbolsHashMaybeStreamNumber()); + publicSymbolInformation = + new PublicSymbolInformation(pdb, getPublicStaticSymbolsHashMaybeStreamNumber()); + symbolRecords = new SymbolRecords(pdb); + initializeAdditionalComponentsForSubstreams(); + initializeModules(); + //compareSymbols(); //temporary to ensure same results with previous work. } return versionNumber; } @@ -170,63 +163,6 @@ public abstract class PdbDebugInfo { return moduleInfo; } - /** - * Returns the list of combined global/public symbols - * @return {@link Map}<{@link Long},{@link AbstractMsSymbol}> of buffer offsets to - * symbols - */ - public Map getSymbolsByOffset() { - return symbolRecords.getSymbolsByOffset(); - } - - /** - * Returns the buffer-offset-to-symbol map for the module as specified by moduleNumber - * @param moduleNumber the number ID of the module for which to return the list - * @return {@link Map}<{@link Long},{@link AbstractMsSymbol}> of buffer offsets to - * symbols for the specified module - * @throws PdbException upon moduleNumber out of range or no module information - */ - public Map getModuleSymbolsByOffset(int moduleNumber) - throws PdbException { - if (moduleNumber < 0 || moduleNumber > moduleInformationList.size()) { - throw new PdbException("ModuleNumber out of range: " + moduleNumber); - } - if (moduleNumber == 0) { - return getSymbolsByOffset(); - } - return symbolRecords.getModuleSymbolsByOffset(moduleNumber - 1); - } - - /** - * Returns the {@link AbstractMsSymbol} from the main symbols for the - * actual symbol record offset (which is past the length and symbol type fields) - * @param offset the offset of the symbol (beyond length and symbol type fields); this is the - * offset value specified by many symbol type records - * @return the symbol group for the module or null if not found - */ - public AbstractMsSymbol getSymbolForOffsetOfRecord(long offset) { - return getSymbolsByOffset().get(offset - 4); - } - - /** - * Returns the {@link AbstractMsSymbol} for the module as specified by moduleNumber and - * actual symbol record offset (which is past the length and symbol type fields) - * @param moduleNumber the number ID of the module (1 to {@link #getNumModules()}) for - * which to return the list - * @param offset the offset of the symbol (beyond length and symbol type fields); this is the - * offset value specified by many symbol type records - * @return the symbol group for the module or null if not found - * @throws PdbException upon moduleNumber out of range or no module information - */ - public AbstractMsSymbol getSymbolForModuleAndOffsetOfRecord(int moduleNumber, long offset) - throws PdbException { - Map symbols = getModuleSymbolsByOffset(moduleNumber); - if (symbols == null) { - return null; - } - return symbols.get(offset - 4); - } - /** * Returns list of {@link SectionContribution} for this debug info * @return list of {@link SectionContribution} @@ -278,6 +214,12 @@ public abstract class PdbDebugInfo { //============================================================================================== // Package-Protected Internals //============================================================================================== + + void deserializeHeaderOnly() throws CancelledException, IOException, PdbException { + PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, 0, getHeaderLength()); + deserializeHeader(reader); + } + /** * Returns the stream number for the GlobalSymbols component * @return stream number @@ -326,7 +268,7 @@ public abstract class PdbDebugInfo { * @throws PdbException upon error parsing a field * @throws CancelledException upon user cancellation */ - protected abstract void deserializeAdditionalSubstreams() + protected abstract void initializeAdditionalComponentsForSubstreams() throws IOException, PdbException, CancelledException; /** @@ -351,9 +293,10 @@ public abstract class PdbDebugInfo { * @param writer {@link Writer} to which to write the debug dump * @throws IOException on issue writing to the {@link Writer} * @throws CancelledException upon user cancellation + * @throws PdbException upon not enough data left to parse */ protected abstract void dumpInternalSubstreams(Writer writer) - throws IOException, CancelledException; + throws IOException, CancelledException, PdbException; //============================================================================================== // Internal Data Methods @@ -556,12 +499,10 @@ public abstract class PdbDebugInfo { globalSymbolInformation.dump(writer); writer.write("\n"); publicSymbolInformation.dump(writer); - if (doNewStuff) { - dumpSymbols(writer); - for (Module module : modules) { - pdb.checkCancelled(); - module.dump(writer); - } + dumpSymbols(writer); + for (Module module : modules) { + pdb.checkCancelled(); + module.dump(writer); } } @@ -611,9 +552,11 @@ public abstract class PdbDebugInfo { } //============================================================================================== - // NEW STUFF FROM REFACTOR/REWORK (can be duplicative with other stuff)... might be turned off - // during development. - private void parseModules() throws CancelledException { + /** + * Initializes modules with some basic information, enabling later queries of the modules + * @throws CancelledException upon user cancellation + */ + private void initializeModules() throws CancelledException { for (ModuleInformation moduleInformation : moduleInformationList) { pdb.checkCancelled(); Module module = new Module(pdb, moduleInformation); @@ -634,21 +577,14 @@ public abstract class PdbDebugInfo { return modules.get(moduleNum); } - // NOTE: Designs are not done regarding possibly iterators for iterating only globals or publics /** - * Returns the symbol iterator for general (public and global symbols + * Returns the symbol iterator for main symbols * @return an iterator over all symbols of the module * @throws CancelledException upon user cancellation - * @throws IOException upon issue reading the stream + * @throws PdbException upon not enough data left to parse */ - public MsSymbolIterator getSymbolIterator() - throws CancelledException, IOException { - if (streamNumberSymbolRecords == MsfStream.NIL_STREAM_NUMBER) { - return null; - } - PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumberSymbolRecords); - MsSymbolIterator iterator = new MsSymbolIterator(pdb, reader); - return iterator; + MsSymbolIterator getSymbolIterator() throws CancelledException, PdbException { + return new MsSymbolIterator(pdb, streamNumberSymbolRecords, 0, MsfStream.MAX_STREAM_LENGTH); } /** @@ -657,25 +593,26 @@ public abstract class PdbDebugInfo { * @return an iterator over all symbols of the module * @throws CancelledException upon user cancellation * @throws PdbException upon not enough data left to parse + * @throws IOException upon issue reading the stream */ - MsSymbolIterator getSymbolIterator(int moduleNum) throws CancelledException, PdbException { + MsSymbolIterator getSymbolIterator(int moduleNum) + throws CancelledException, PdbException, IOException { Module module = modules.get(moduleNum); - return module.getSymbolIterator(); + return module.iterator(); } - private void dumpSymbols(Writer writer) throws CancelledException, IOException { - MsSymbolIterator iterator = getSymbolIterator(); + private void dumpSymbols(Writer writer) throws CancelledException, IOException, PdbException { + MsSymbolIterator iteratorx = getSymbolIterator(); List symbols = new ArrayList<>(); - while (iterator.hasNext()) { + while (iteratorx.hasNext()) { pdb.checkCancelled(); - symbols.add(iterator.next()); + symbols.add(iteratorx.next()); } } // This method is temporary. It only exists for ensuring results as we transition processing // mechanisms. - private void compareSymbols() - throws CancelledException, PdbException, IOException { + private void compareSymbols() throws CancelledException, PdbException, IOException { PdbDebugInfo debugInfo = pdb.getDebugInfo(); if (debugInfo == null) { return; @@ -713,7 +650,7 @@ public abstract class PdbDebugInfo { for (int modnum = 0; modnum < numModules(); modnum++) { pdb.checkCancelled(); Module module = modules.get(modnum); - MsSymbolIterator moduleSymbolsIterator = module.getSymbolIterator(); + MsSymbolIterator moduleSymbolsIterator = getSymbolIterator(modnum); cnt = 0; Map map = symbolRecords.getModuleSymbolsByOffset(modnum); List keys = new ArrayList<>(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbNewDebugInfo.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbNewDebugInfo.java index a5ad502c20..bca4302678 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbNewDebugInfo.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbNewDebugInfo.java @@ -146,16 +146,15 @@ public class PdbNewDebugInfo extends PdbDebugInfo { } @Override - protected void deserializeAdditionalSubstreams() + protected void initializeAdditionalComponentsForSubstreams() throws IOException, PdbException, CancelledException { // TODO: evaluate. I don't think we need GlobalSymbolInformation (hash) or the // PublicSymbolInformation (hash), as they are both are search mechanisms. - symbolRecords.deserialize(); - globalSymbolInformation.deserialize(getGlobalSymbolsHashMaybeStreamNumber()); - publicSymbolInformation.deserialize(getPublicStaticSymbolsHashMaybeStreamNumber()); + symbolRecords.initialize(); + globalSymbolInformation.initialize(); + publicSymbolInformation.initialize(); //TODO: Process further information that might be found from ProcessTypeServerMap, // and processEditAndContinueInformation. - debugData.deserialize(); } @Override @@ -229,7 +228,8 @@ public class PdbNewDebugInfo extends PdbDebugInfo { } @Override - protected void dumpInternalSubstreams(Writer writer) throws IOException, CancelledException { + protected void dumpInternalSubstreams(Writer writer) + throws IOException, CancelledException, PdbException { writer.write("ModuleInformationList---------------------------------------\n"); dumpModuleInformation(writer); writer.write("\nEnd ModuleInformationList-----------------------------------\n"); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbOldDebugInfo.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbOldDebugInfo.java index 1112fad321..b992f76d51 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbOldDebugInfo.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbOldDebugInfo.java @@ -70,13 +70,13 @@ public class PdbOldDebugInfo extends PdbDebugInfo { } @Override - protected void deserializeAdditionalSubstreams() + protected void initializeAdditionalComponentsForSubstreams() throws IOException, PdbException, CancelledException { // TODO: evaluate. I don't think we need GlobalSymbolInformation (hash) or the // PublicSymbolInformation (hash), as they are both are search mechanisms. - symbolRecords.deserialize(); - globalSymbolInformation.deserialize(getGlobalSymbolsHashMaybeStreamNumber()); - publicSymbolInformation.deserialize(getPublicStaticSymbolsHashMaybeStreamNumber()); + symbolRecords.initialize(); + globalSymbolInformation.initialize(); + publicSymbolInformation.initialize(); //TODO: SectionContributions has information about code sections and refers to // debug streams for each. } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PublicSymbolInformation.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PublicSymbolInformation.java index 96c77216d5..bccb531368 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PublicSymbolInformation.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PublicSymbolInformation.java @@ -19,6 +19,8 @@ import java.io.IOException; import java.io.Writer; import java.util.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream; +import ghidra.util.Msg; import ghidra.util.exception.CancelledException; /** @@ -32,10 +34,11 @@ import ghidra.util.exception.CancelledException; */ public class PublicSymbolInformation extends AbstractSymbolInformation { + public static final int PUB_HEADER_SIZE = 28; + //============================================================================================== // Internals //============================================================================================== - private int symbolHashLength; private int addressMapLength; private int numThunks; // unsigned int private int thunkSize; @@ -46,10 +49,9 @@ public class PublicSymbolInformation extends AbstractSymbolInformation { private int thunkTableLength; private int sectionMapLength; - // These should correspond with symbolOffsets that come from HashRecords. - private List addressMapSymbolOffsets = new ArrayList<>(); - private Map thunkTargetOffsetsByTableOffset = new HashMap<>(); - private Map absoluteOffsetsBySectionNumber = new HashMap<>(); + private int addressMapOffset; + private int thunkMapOffset; + private int sectionMapOffset; //============================================================================================== // API @@ -57,9 +59,10 @@ public class PublicSymbolInformation extends AbstractSymbolInformation { /** * Constructor * @param pdbIn {@link AbstractPdb} that owns the Public Symbol Information to process + * @param streamNumber the stream number containing the symbol information */ - public PublicSymbolInformation(AbstractPdb pdbIn) { - super(pdbIn); + public PublicSymbolInformation(AbstractPdb pdbIn, int streamNumber) { + super(pdbIn, streamNumber); } /** @@ -114,65 +117,92 @@ public class PublicSymbolInformation extends AbstractSymbolInformation { * Returns the Offsets of symbols within the symbol table gotten from the address map. These * offsets to point to the size field of the symbols in the symbol table * @return offsets + * @throws PdbException upon not enough data left to parse + * @throws CancelledException upon user cancellation */ - public List getAddressMapSymbolOffsets() { - return addressMapSymbolOffsets; + public List getAddressMapSymbolOffsets() throws CancelledException, PdbException { + try { + PdbByteReader reader = + pdb.getReaderForStreamNumber(streamNumber, addressMapOffset, addressMapLength); + return deserializeAddressMap(reader); + } + catch (IOException e) { + Msg.error(this, String.format( + "PDB: Error creating address map symbol offsets while reading stream %d at offset %d and length %d", + streamNumber, addressMapOffset, addressMapLength)); + return new ArrayList<>(); + } + } + + /** + * Returns the Thunk Target Offsets by Table Offset + * @return the map + * @throws PdbException upon not enough data left to parse + * @throws CancelledException upon user cancellation + */ + public Map getThunkTargetOffsetsByTableOffset() + throws CancelledException, PdbException { + try { + PdbByteReader reader = + pdb.getReaderForStreamNumber(streamNumber, thunkMapOffset, thunkMapLength); + return deserializeThunkMap(reader); + } + catch (IOException e) { + Msg.error(this, String.format( + "PDB: Error creating thunk target offsets by table offset while reading stream %d offset %d and length %d", + streamNumber, thunkMapOffset, thunkMapLength)); + return new HashMap<>(); + } + } + + /** + * Returns the Absolute Offsets by Section Number map + * @return the map + * @throws PdbException upon not enough data left to parse + * @throws CancelledException upon user cancellation + */ + public Map getAbsoluteOffsetsBySectionNumber() + throws CancelledException, PdbException { + try { + PdbByteReader reader = + pdb.getReaderForStreamNumber(streamNumber, sectionMapOffset, sectionMapLength); + return deserializeSectionMap(reader); + } + catch (IOException e) { + Msg.error(this, String.format( + "PDB: Error creating absolute offsets by section number while reading stream %d offset %d and length %d", + streamNumber, sectionMapOffset, sectionMapLength)); + return new HashMap<>(); + } } //============================================================================================== // Package-Protected Internals //============================================================================================== /** - * Deserialize the {@link PublicSymbolInformation} from the appropriate stream in the Pdb - * @param streamNumber the stream number containing the information to deserialize + * Deserializes and intializes {@link PublicSymbolInformation} basic information from the + * appropriate stream in the Pdb so that later queries can be made * @throws IOException on file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes * @throws PdbException upon not enough data left to parse * @throws CancelledException upon user cancellation */ @Override - void deserialize(int streamNumber) - throws IOException, PdbException, CancelledException { - super.deserialize(streamNumber); - - PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber); - - deserializePubHeader(reader); - - PdbByteReader hashReader = reader.getSubPdbByteReader(symbolHashLength); - deserializeHashTable(hashReader); - - PdbByteReader addressMapReader = reader.getSubPdbByteReader(addressMapLength); - deserializeAddressMap(addressMapReader); - - PdbByteReader thunkMapReader = reader.getSubPdbByteReader(thunkMapLength); - deserializeThunkMap(thunkMapReader); - - /* - * See note in {@link #deserializePubHeader(PdbByteReader)} regarding spurious data - * for numSections. Because of this, we will assume the rest of the data in the - * reader belongs to the section map and set the appropriate variable values here. - */ - sectionMapLength = reader.numRemaining(); - if (sectionMapLength % 8 != 0) { - throw new PdbException("sectionMapLength size not multiple of 8"); - } - numSections = sectionMapLength / 8; - PdbByteReader sectionMapReader = reader.getSubPdbByteReader(sectionMapLength); - deserializeSectionMap(sectionMapReader); - - // Organize the information - generateSymbolsList(); + void initialize() throws IOException, PdbException, CancelledException { + initializeValues(); + deserializePubHeader(); + deserializeHashHeader(); } /** * Debug method for dumping information from this {@link PublicSymbolInformation} * @param writer {@link Writer} to which to dump the information - * @throws IOException upon IOException writing to the {@link Writer} + * @throws IOException issue reading PDBor upon issue writing to the {@link Writer} * @throws CancelledException upon user cancellation + * @throws PdbException upon not enough data left to parse */ @Override - void dump(Writer writer) throws IOException, CancelledException { + void dump(Writer writer) throws IOException, CancelledException, PdbException { StringBuilder builder = new StringBuilder(); builder.append("PublicSymbolInformation-------------------------------------\n"); dumpPubHeader(builder); @@ -197,23 +227,31 @@ public class PublicSymbolInformation extends AbstractSymbolInformation { * @throws PdbException upon not enough data left to parse * @throws CancelledException upon user cancellation */ - private void deserializeAddressMap(PdbByteReader reader) + private List deserializeAddressMap(PdbByteReader reader) throws PdbException, CancelledException { + List myAddressMapSymbolOffsets = new ArrayList<>(); while (reader.hasMore()) { pdb.checkCancelled(); - addressMapSymbolOffsets.add((long) reader.parseInt()); + myAddressMapSymbolOffsets.add((long) reader.parseInt()); } + return myAddressMapSymbolOffsets; } /** * Debug method for dumping Address Map information from this {@link AbstractSymbolInformation} * @param builder {@link StringBuilder} to which to dump the information + * @throws IOException on file seek or read, invalid parameters, bad file configuration, or + * inability to read required bytes + * @throws PdbException upon not enough data left to parse + * @throws CancelledException upon user cancellation */ - private void dumpAddressMap(StringBuilder builder) { + private void dumpAddressMap(StringBuilder builder) + throws CancelledException, IOException, PdbException { builder.append("AddressMapSymbolOffsets-------------------------------------\n"); - builder.append("numAddressMapSymbolOffsets: " + addressMapSymbolOffsets.size() + "\n"); + List myAddressMapSymbolOffsets = getAddressMapSymbolOffsets(); + builder.append("numAddressMapSymbolOffsets: " + myAddressMapSymbolOffsets.size() + "\n"); int num = 0; - for (Long val : addressMapSymbolOffsets) { + for (Long val : myAddressMapSymbolOffsets) { builder.append(String.format("0X%08X: 0X%012X\n", num++, val)); } builder.append("\nEnd AddressMapSymbolOffsets---------------------------------\n"); @@ -225,26 +263,35 @@ public class PublicSymbolInformation extends AbstractSymbolInformation { * @throws PdbException upon not enough data left to parse * @throws CancelledException upon user cancellation */ - private void deserializeThunkMap(PdbByteReader reader) + private Map deserializeThunkMap(PdbByteReader reader) throws PdbException, CancelledException { int count = 0; + Map myThunkTargetOffsetsByTableOffset = new HashMap<>(); while (reader.hasMore()) { pdb.checkCancelled(); int targetOffset = reader.parseInt(); int mapTableOffset = count * thunkSize + offsetThunkTable; - thunkTargetOffsetsByTableOffset.put(mapTableOffset, targetOffset); + myThunkTargetOffsetsByTableOffset.put(mapTableOffset, targetOffset); } + return myThunkTargetOffsetsByTableOffset; } /** * Debug method for dumping Thunk Map information from this {@link AbstractSymbolInformation} * @param builder {@link StringBuilder} to which to dump the information + * @throws IOException on file seek or read, invalid parameters, bad file configuration, or + * inability to read required bytes + * @throws PdbException upon not enough data left to parse + * @throws CancelledException upon user cancellation */ - private void dumpThunkMap(StringBuilder builder) { + private void dumpThunkMap(StringBuilder builder) + throws CancelledException, IOException, PdbException { + Map myThunkTargetOffsetsByTableOffset = + getThunkTargetOffsetsByTableOffset(); builder.append("ThunkMap----------------------------------------------------\n"); - builder.append( - "numThunkTargetOffsetsByTableOffset: " + thunkTargetOffsetsByTableOffset.size() + "\n"); - for (Map.Entry entry : thunkTargetOffsetsByTableOffset.entrySet()) { + builder.append("numThunkTargetOffsetsByTableOffset: " + + myThunkTargetOffsetsByTableOffset.size() + "\n"); + for (Map.Entry entry : myThunkTargetOffsetsByTableOffset.entrySet()) { builder.append(String.format("0X%08X 0X%08X\n", entry.getKey(), entry.getValue())); } builder.append("\nEnd ThunkMap------------------------------------------------\n"); @@ -256,27 +303,35 @@ public class PublicSymbolInformation extends AbstractSymbolInformation { * @throws PdbException upon not enough data left to parse * @throws CancelledException upon user cancellation */ - private void deserializeSectionMap(PdbByteReader reader) + private Map deserializeSectionMap(PdbByteReader reader) throws PdbException, CancelledException { + Map myAbsoluteOffsetsBySectionNumber = new HashMap<>(); while (reader.hasMore()) { pdb.checkCancelled(); int offset = reader.parseInt(); int section = reader.parseUnsignedShortVal(); reader.skip(2); // padding - absoluteOffsetsBySectionNumber.put(section, offset); + myAbsoluteOffsetsBySectionNumber.put(section, offset); } + return myAbsoluteOffsetsBySectionNumber; } /** * Debug method for dumping Section Map information from this {@link AbstractSymbolInformation} * @param builder {@link StringBuilder} to which to dump the information + * @throws IOException on file seek or read, invalid parameters, bad file configuration, or + * inability to read required bytes + * @throws PdbException upon not enough data left to parse * @throws CancelledException upon user cancellation */ - private void dumpSectionMap(StringBuilder builder) throws CancelledException { + private void dumpSectionMap(StringBuilder builder) + throws CancelledException, IOException, PdbException { + Map myAbsoluteOffsetsBySectionNumber = + getAbsoluteOffsetsBySectionNumber(); builder.append("SectionMap--------------------------------------------------\n"); builder.append( - "numAbsoluteOffsetsBySectionNumber: " + absoluteOffsetsBySectionNumber.size() + "\n"); - for (Map.Entry entry : absoluteOffsetsBySectionNumber.entrySet()) { + "numAbsoluteOffsetsBySectionNumber: " + myAbsoluteOffsetsBySectionNumber.size() + "\n"); + for (Map.Entry entry : myAbsoluteOffsetsBySectionNumber.entrySet()) { pdb.checkCancelled(); builder.append(String.format("0X%08X 0X%08X\n", entry.getKey(), entry.getValue())); } @@ -310,11 +365,17 @@ public class PublicSymbolInformation extends AbstractSymbolInformation { builder.append("\nEnd PublicSymbolInformationHeader---------------------------\n"); } + void deserializePubHeader() throws PdbException, CancelledException, IOException { + MsfStream stream = pdb.getMsf().getStream(streamNumber); + PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, 0, PUB_HEADER_SIZE); + deserializePubHeader(reader, stream.getLength()); + } + // Issue: MSFT does not initialize PSGSIHDR with nSects(0) (our numSections), so spurious // data can be seen for this field. We cannot do sanity checks on the value. The only // effective thing we can do is to check if any data is left in the reader. Whatever amount // is left is what we will use. - private void deserializePubHeader(PdbByteReader reader) throws PdbException { + private void deserializePubHeader(PdbByteReader reader, int streamLength) throws PdbException { symbolHashLength = reader.parseInt(); addressMapLength = reader.parseInt(); long val = reader.parseUnsignedIntVal(); @@ -349,12 +410,21 @@ public class PublicSymbolInformation extends AbstractSymbolInformation { throw new PdbException("Cannot support large unsigned integer for thunk table length"); } thunkTableLength = (int) val; - // See note above regarding MSFT numSections issue - //val = 8 * numSections; - //if (val > Integer.MAX_VALUE) { - // throw new PdbException("Cannot support long value for section map length"); - //} - //sectionMapLength = (int) val; + + // Do some additional calculations + symbolHashOffset = PUB_HEADER_SIZE; // reader.getIndex(); + addressMapOffset = symbolHashOffset + symbolHashLength; + thunkMapOffset = addressMapOffset + addressMapLength; + sectionMapOffset = thunkMapOffset + thunkMapLength; + // Due to the possibility of spurious data for sections (noted above), we will assume + // the rest of the data belongs to the section map and set the appropriate variable + // values here. + sectionMapLength = streamLength - sectionMapOffset; + if (sectionMapLength % 8 != 0) { + throw new PdbException("sectionMapLength size not multiple of 8"); + } + numSections = sectionMapLength / 8; + } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/SymbolHashRecord.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/SymbolHashRecord.java index 04a2e28482..43b44cc1ee 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/SymbolHashRecord.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/SymbolHashRecord.java @@ -25,6 +25,8 @@ public class SymbolHashRecord implements Comparable { private long offsetVal; private int referenceCount; + public static int RECORD_SIZE = 8; + /** * Parses the contents of of this record. * @param reader {@link PdbByteReader} from which to deserialize the data. diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/SymbolRecords.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/SymbolRecords.java index 975f1c51c7..77fa01f537 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/SymbolRecords.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/SymbolRecords.java @@ -34,8 +34,6 @@ import ghidra.util.exception.CancelledException; public class SymbolRecords { private AbstractPdb pdb; - private Map symbolsByOffset; - private List> moduleSymbolsByOffset = new ArrayList<>(); // Used for CvSig part of streams. See methods below. private boolean getSig = true; @@ -59,9 +57,24 @@ public class SymbolRecords { * Returns the list of symbols * @return {@link Map}<{@link Long},{@link AbstractMsSymbol}> of buffer offsets to * symbols + * @throws IOException on file seek or read, invalid parameters, bad file configuration, or + * inability to read required bytes + * @throws PdbException upon not enough data left to parse + * @throws CancelledException upon user cancellation */ - protected Map getSymbolsByOffset() { - return symbolsByOffset; + @Deprecated + protected Map getSymbolsByOffset() + throws CancelledException, PdbException, IOException { + PdbDebugInfo debugInfo = pdb.getDebugInfo(); + if (debugInfo == null) { + return new TreeMap<>(); + } + int streamNumber = debugInfo.getSymbolRecordsStreamNumber(); + if (streamNumber <= 0) { + return new TreeMap<>(); + } + PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber); + return deserializeSymbolRecords(pdb, reader); } /** @@ -69,103 +82,41 @@ public class SymbolRecords { * @param moduleNumber the number ID of the module for which to return the list * @return {@link Map}<{@link Long},{@link AbstractMsSymbol}> of buffer offsets to * symbols for the specified module - */ - protected Map getModuleSymbolsByOffset(int moduleNumber) { - return moduleSymbolsByOffset.get(moduleNumber); - } - - /** - * Deserializes the {@link SymbolRecords} from the stream noted in the DBI header * @throws IOException on file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes * @throws PdbException upon not enough data left to parse * @throws CancelledException upon user cancellation */ - void deserialize() throws IOException, PdbException, CancelledException { - initializeCache(0.001); - determineCvSigValues(); // new method for random-access symbol work - processSymbols(); - processModuleSymbols(); - } - - private void processSymbols() - throws IOException, PdbException, CancelledException { + @Deprecated + protected Map getModuleSymbolsByOffset(int moduleNumber) + throws CancelledException, IOException, PdbException { PdbDebugInfo debugInfo = pdb.getDebugInfo(); if (debugInfo == null) { - return; + return new TreeMap<>(); } - int streamNumber = debugInfo.getSymbolRecordsStreamNumber(); - if (streamNumber <= 0) { - return; + ModuleInformation moduleInfo = debugInfo.moduleInformationList.get(moduleNumber); + int streamNumber = moduleInfo.getStreamNumberDebugInformation(); + if (streamNumber == MsfStream.NIL_STREAM_NUMBER) { + return new TreeMap<>(); } PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber); - symbolsByOffset = deserializeSymbolRecords(pdb, reader); + int sizeSymbolsSection = moduleInfo.getSizeLocalSymbolsDebugInformation(); + PdbByteReader symbolsReader = reader.getSubPdbByteReader(sizeSymbolsSection); + symbolsReader.skip(getCvSigLength(streamNumber)); + return deserializeSymbolRecords(pdb, symbolsReader); } - // Could split this method up into separate methods: one for module symbols and the other for - // Lines processing. Note: would be processing streams more than once; lines would need to - // skip over the symbols. - private void processModuleSymbols() - throws IOException, PdbException, CancelledException { - // cvSignature: - // >64K = C6 - // 1 = C7 - // 2 = C11 (vc5.x) - // 3 = ??? (not specified, and not marked as reserved) - // 4 = C13 (vc7.x) - // 5-64K = RESERVED - // - // Both cvdump (1660 and 1668) and mod.cpp (575) seem to indicate that the first module - // might have the cvSignature of C7 or C11 (when C7/C11), but modules thereafter will not - // or may not have the value. C13 would always have the C13 signature. - boolean getSig = true; - int cvSignature = 0; - PdbDebugInfo debugInfo = pdb.getDebugInfo(); - if (debugInfo == null) { - return; - } - - for (ModuleInformation module : debugInfo.moduleInformationList) { - pdb.checkCancelled(); - int streamNumber = module.getStreamNumberDebugInformation(); - if (streamNumber == MsfStream.NIL_STREAM_NUMBER) { - moduleSymbolsByOffset.add(new TreeMap<>()); - continue; - } - - PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber); - - int sizeSymbolsSection = module.getSizeLocalSymbolsDebugInformation(); - PdbByteReader symbolsReader = reader.getSubPdbByteReader(sizeSymbolsSection); - // See comment above regarding getSig boolean - if (getSig) { - cvSignature = symbolsReader.parseInt(); - } - switch (cvSignature) { - case 1: - case 2: - // We have no 1,2 examples to test this logic for cvSignature. Confirming - // or rejecting this logic is important for simplifying/refactoring this - // method or writing new methods to allow for extraction of information from - // individual modules. The current implementation has cross-module logic - // (setting state in the processing of the first and using this state in the - // processing of follow-on modules). - getSig = false; - break; - case 4: - break; - default: - if (cvSignature < 0x10000) { - throw new PdbException( - "Invalid module CV signature in stream " + streamNumber); - } - break; - } - - Map oneModuleSymbolsByOffset = - deserializeSymbolRecords(pdb, symbolsReader); - moduleSymbolsByOffset.add(oneModuleSymbolsByOffset); - } + /** + * Deserializes and initializes basic {@link SymbolRecords} information from the stream noted + * in the DBI header so that later symbol queries can be done + * @throws IOException on file seek or read, invalid parameters, bad file configuration, or + * inability to read required bytes + * @throws PdbException upon not enough data left to parse + * @throws CancelledException upon user cancellation + */ + void initialize() throws IOException, PdbException, CancelledException { + initializeCache(0.001); + determineCvSigValues(); // new method for random-access symbol work } // These methods are trying to adapt the logic of the previous method here (which attempted @@ -189,7 +140,6 @@ public class SymbolRecords { ModuleInformation moduleInfo = debugInfo.getModuleInformationList().get(0); int streamNumber = moduleInfo.getStreamNumberDebugInformation(); if (streamNumber == MsfStream.NIL_STREAM_NUMBER) { - moduleSymbolsByOffset.add(new TreeMap<>()); return; } PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber); @@ -230,11 +180,11 @@ public class SymbolRecords { */ public int getCvSigLength(int streamNumber) throws CancelledException, IOException, PdbException { - if (cvSignatureCase1and2Stream == MsfStream.NIL_STREAM_NUMBER) { - throw new PdbException("CvSignLength not initialized"); - } +// if (cvSignatureCase1and2Stream == MsfStream.NIL_STREAM_NUMBER) { +// throw new PdbException("CvSigLength not initialized"); +// } if (streamNumber == MsfStream.NIL_STREAM_NUMBER) { - throw new PdbException("Attempting to read unassigned stream"); + return 0; // returning inconsequential value; fact of NIL will be dealt with elsewhere } PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, 0, 4); if (getSig) { @@ -253,7 +203,7 @@ public class SymbolRecords { size = 4; break; default: - throw new PdbException("PDB Error: Bad CvSsigLength state"); + throw new PdbException("PDB Error: Bad CvSigLength state"); } return size; } @@ -306,7 +256,7 @@ public class SymbolRecords { // TODO: consider pre-storing the lengths with one build stream read. However, that would // consume more memory, so only do this if willing to improve process performance at - // cost of memroy. + // cost of memory. //Map recordLengths = new TreeMap<>(); /** @@ -384,13 +334,19 @@ public class SymbolRecords { * @param writer {@link Writer} to which to dump the information * @throws IOException upon issue writing to the {@link Writer} * @throws CancelledException upon user cancellation + * @throws PdbException upon not enough data to parse */ - protected void dump(Writer writer) throws IOException, CancelledException { + protected void dump(Writer writer) throws IOException, CancelledException, PdbException { writer.write("SymbolRecords-----------------------------------------------\n"); + Map symbolsByOffset = getSymbolsByOffset(); dumpSymbolMap(symbolsByOffset, writer); - for (int i = 0; i < moduleSymbolsByOffset.size(); i++) { + PdbDebugInfo debugInfo = pdb.getDebugInfo(); + if (debugInfo == null) { + return; + } + for (int i = 0; i < debugInfo.getNumModules(); i++) { pdb.checkCancelled(); - Map map = moduleSymbolsByOffset.get(i); + Map map = getModuleSymbolsByOffset(i); if (map != null) { writer.write("Module(" + i + ") List:\n"); dumpSymbolMap(map, writer); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TPI.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TPI.java index a40145fade..e4648e3b04 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TPI.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TPI.java @@ -22,8 +22,6 @@ public interface TPI { int getTypeIndexMaxExclusive(); - AbstractMsType getRecord(int recordNumber); - /** * Random access of {@link AbstractMsType} record indicated by {@code recordNumber} * @param recordNumber record number of the record to retrieve diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TypeProgramInterface.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TypeProgramInterface.java index edfc62e840..57f8a80444 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TypeProgramInterface.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TypeProgramInterface.java @@ -120,48 +120,22 @@ public abstract class TypeProgramInterface implements TPI { } /** - * Retrieves the {@link AbstractMsType} record indicated by the recordNumber. The record must - * already have been parsed and inserted into the list + * Retrieves the {@link AbstractMsType} record indicated by the recordNumber * @param recordNumber record number to look up * @return {@link AbstractMsType} pertaining to the record number */ - @Override - public AbstractMsType getRecord(int recordNumber) { - if (recordNumber < 0 || recordNumber - typeIndexMin > typeList.size()) { - // This should not happen, but we have seen it and cannot yet explain it. - // So, for now, we are creating and returning a new BadMsType. - PdbLog.logBadTypeRecordIndex(this, recordNumber); - BadMsType type = new BadMsType(pdb, 0); - type.setRecordNumber(RecordNumber.make(recordCategory, recordNumber)); - return type; - } - if (recordNumber < typeIndexMin) { - PrimitiveMsType primitive = primitiveTypesByRecordNumber.get(recordNumber); - if (primitive == null) { - primitive = new PrimitiveMsType(pdb, recordNumber); - primitiveTypesByRecordNumber.put(recordNumber, primitive); - } - return primitive; - } - return typeList.get(recordNumber - typeIndexMin); - } - @Override public AbstractMsType getRandomAccessRecord(int recordNumber) { - if (recordNumber < 0 || recordNumber - typeIndexMin > typeList.size()) { + if (recordNumber < 0 || recordNumber - typeIndexMin > offLenRecords.size()) { // This should not happen, but we have seen it and cannot yet explain it. // So, for now, we are creating and returning a new BadMsType. PdbLog.logBadTypeRecordIndex(this, recordNumber); - BadMsType type = new BadMsType(pdb, 0); - type.setRecordNumber(RecordNumber.make(recordCategory, recordNumber)); - return type; + BadMsType badType = new BadMsType(pdb, 0); + badType.setRecordNumber(RecordNumber.make(recordCategory, recordNumber)); + return badType; } - if (recordNumber < typeIndexMin) { - PrimitiveMsType primitive = primitiveTypesByRecordNumber.get(recordNumber); - if (primitive == null) { - primitive = new PrimitiveMsType(pdb, recordNumber); - primitiveTypesByRecordNumber.put(recordNumber, primitive); - } + PrimitiveMsType primitive = getPrimitiveRecord(recordNumber); + if (primitive != null) { return primitive; } @@ -171,6 +145,7 @@ public abstract class TypeProgramInterface implements TPI { try { PdbByteReader recordReader = pdb.getReaderForStreamNumber(streamNumber, offLen.offset(), offLen.length()); + recordReader.markAlign(2); return TypeParser.parseRecord(pdb, recordReader, rn); } catch (PdbException | IOException | CancelledException e) { @@ -180,18 +155,31 @@ public abstract class TypeProgramInterface implements TPI { } } + protected PrimitiveMsType getPrimitiveRecord(int recordNumber) { + if (recordNumber >= typeIndexMin) { + return null; + } + PrimitiveMsType primitive = primitiveTypesByRecordNumber.get(recordNumber); + if (primitive == null) { + primitive = new PrimitiveMsType(pdb, recordNumber); + primitiveTypesByRecordNumber.put(recordNumber, primitive); + } + return primitive; + } + //============================================================================================== // Package-Protected Internals //============================================================================================== /** - * Deserializes this {@link TypeProgramInterface} + * Deserializes and initializes {@link TypeProgramInterface} basic information so that later + * queries can be made * @return version number of the {@link TypeProgramInterface} * @throws IOException on file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes * @throws PdbException upon not enough data left to parse * @throws CancelledException upon user cancellation */ - int deserialize() throws IOException, PdbException, CancelledException { + int initialize() throws IOException, PdbException, CancelledException { if (pdb.getMsf() == null) { // Should only be null dummy PDBs used for testing. throw new PdbException("Unexpected null MSF."); @@ -205,10 +193,10 @@ public abstract class TypeProgramInterface implements TPI { // we have this commented out. //hash.deserializeHashStreams(pdb.getMonitor()); + // TODO: consider other mechanisms than offset/length values for use by an iterator. + // Need to be able to access by record number, so might not have much choice. createOffLenRecords(reader); - deserializeTypeRecords(reader); - return versionNumber; } @@ -244,36 +232,6 @@ public abstract class TypeProgramInterface implements TPI { this.typeIndexMaxExclusive = typeIndexMaxExclusive; } - /** - * IMPORTANT: This method is for testing only. It allows us to set a record for a particular - * record number - * @param recordNumber record number for the {@link AbstractMsType} to be inserted - * @param type {@link AbstractMsType} to be inserted - * @return {@code true} if successful - */ - boolean setRecord(int recordNumber, AbstractMsType type) { - if (recordNumber < typeIndexMin) { - return false; - } - for (int i = typeList.size() + typeIndexMin; i <= recordNumber; i++) { - // Add the same record for each index up to the one needed. - typeList.add(type); - } - return true; - } - - /** - * IMPORTANT: This method is for testing only. It allows us to add a record that gets its - * record number automatically assigned - * @param type {@link AbstractMsType} to be inserted - * @return record number assigned - */ - int addRecord(AbstractMsType type) { - int newRecordNum = typeList.size() + typeIndexMin; - typeList.add(type); - return newRecordNum; - } - //============================================================================================== // Abstract Methods //============================================================================================== @@ -308,40 +266,6 @@ public abstract class TypeProgramInterface implements TPI { reader.setIndex(savedIndex); // restore reader to original state } - /** - * Deserializes the Type Records of this class - * @param reader {@link PdbByteReader} from which to deserialize the data - * @throws PdbException upon not enough data left to parse - * @throws CancelledException upon user cancellation - */ - protected void deserializeTypeRecords(PdbByteReader reader) - throws PdbException, CancelledException { - int recordLength; - int recordNumber = typeIndexMin; - - while (reader.hasMore()) { - pdb.checkCancelled(); - - recordLength = reader.parseUnsignedShortVal(); - PdbByteReader recordReader = reader.getSubPdbByteReader(recordLength); - recordReader.markAlign(2); - - // No need to call either of these, because we do not expect the record number - // to have a high bit set here. If we did, we would have to check 'category' to - // know which of the two to call, and we'd have to create an AbstractTypeIndex: - // parseTypeRecordNumber(recordReader, recordNumber); - // parseItemRecordNumber(recordReader, recordNumber); - AbstractMsType type = TypeParser.parseRecord(pdb, recordReader, - RecordNumber.make(recordCategory, recordNumber)); - typeList.add(type); - recordNumber++; - } - if (recordNumber != typeIndexMaxExclusive) { - PdbLog.message(this.getClass().getSimpleName() + ": Header max records: " + - typeIndexMaxExclusive + "; parsed records: " + recordNumber); - } - } - //TODO: more to do for outputting individual records (might want a toString or dump method // on each). /** @@ -350,8 +274,8 @@ public abstract class TypeProgramInterface implements TPI { * @throws IOException on issue writing to the {@link Writer} */ protected void dumpTypeRecords(Writer writer) throws IOException { - int recordNum = typeIndexMin; - for (AbstractMsType type : typeList) { + for (int recordNum = typeIndexMin; recordNum < typeIndexMaxExclusive; recordNum++) { + AbstractMsType type = getRandomAccessRecord(recordNum); StringBuilder builder = new StringBuilder(); builder.append("------------------------------------------------------------\n"); builder.append("Record: "); @@ -367,7 +291,6 @@ public abstract class TypeProgramInterface implements TPI { builder.append("(null)\n"); //Temporary output value. } writer.write(builder.toString()); - recordNum++; } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockSymbolApplier.java index c88b62d4f7..c44d1f6e16 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockSymbolApplier.java @@ -15,10 +15,10 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractBlockMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; @@ -35,7 +35,7 @@ public class BlockSymbolApplier extends MsSymbolApplier { * @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed */ - public BlockSymbolApplier(DefaultPdbApplicator applicator, AbstractMsSymbolIterator iter) { + public BlockSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); if (!(abstractSymbol instanceof AbstractBlockMsSymbol)) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeMapper.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeMapper.java index e59d6a24aa..9b346f106e 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeMapper.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeMapper.java @@ -120,7 +120,7 @@ public class ComplexTypeMapper { // to TYPE as we could get using applicator.getPdb().getTypeRecord(recordNumber) // where recordNumber is a RecordNumber. This is because we are not expecting // a remap for Complex types. - AbstractMsType type = typeProgramInterface.getRecord(indexNumber); + AbstractMsType type = typeProgramInterface.getRandomAccessRecord(indexNumber); if (type instanceof AbstractCompositeMsType compositeType) { mapComplexTypesByPath(compositeFIFOsByPath, indexNumber, compositeType); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java index f6fc4d1b2e..0ca281a163 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java @@ -15,11 +15,9 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; -import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber; +import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractDataMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; import ghidra.program.model.data.*; import ghidra.program.model.listing.*; @@ -40,7 +38,7 @@ public class DataSymbolApplier extends MsSymbolApplier { * @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed */ - public DataSymbolApplier(DefaultPdbApplicator applicator, AbstractMsSymbolIterator iter) { + public DataSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); if (!(abstractSymbol instanceof AbstractDataMsSymbol)) { @@ -170,11 +168,15 @@ public class DataSymbolApplier extends MsSymbolApplier { } if (existingData == null) { try { - applicator.getProgram().getListing().clearCodeUnits(address, - address.add(dataTypeLength - 1), false); + applicator.getProgram() + .getListing() + .clearCodeUnits(address, + address.add(dataTypeLength - 1), false); if (dataType.getLength() == -1) { - applicator.getProgram().getListing().createData(address, dataType, - dataTypeLength); + applicator.getProgram() + .getListing() + .createData(address, dataType, + dataTypeLength); } else { applicator.getProgram().getListing().createData(address, dataType); @@ -187,8 +189,10 @@ public class DataSymbolApplier extends MsSymbolApplier { } else if (isDataReplaceable(existingData)) { try { - applicator.getProgram().getListing().clearCodeUnits(address, - address.add(dataTypeLength - 1), false); + applicator.getProgram() + .getListing() + .clearCodeUnits(address, + address.add(dataTypeLength - 1), false); applicator.getProgram().getListing().createData(address, dataType, dataTypeLength); } catch (CodeUnitInsertionException e) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java index 9a23408f88..a8b3281166 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java @@ -15,6 +15,7 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import java.io.IOException; import java.math.BigInteger; import java.util.*; @@ -33,7 +34,6 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.app.util.bin.format.pe.cli.tables.CliAbstractTableRow; import ghidra.app.util.importer.MessageLog; import ghidra.app.util.pdb.PdbCategories; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.framework.options.Options; import ghidra.graph.*; import ghidra.graph.algo.GraphNavigator; @@ -172,6 +172,9 @@ public class DefaultPdbApplicator implements PdbApplicator { AddressSet disassembleAddresses; List deferredFunctionWorkAppliers; + //============================================================================================== + private int currentModuleNumber = 0; + //============================================================================================== public DefaultPdbApplicator(AbstractPdb pdb) { Objects.requireNonNull(pdb, "pdb cannot be null"); @@ -193,10 +196,12 @@ public class DefaultPdbApplicator implements PdbApplicator { * @param logParam the MessageLog to which to output messages * @throws PdbException if there was a problem processing the data * @throws CancelledException upon user cancellation + * @throws IOException on file seek or read, invalid parameters, bad file configuration, or + * inability to read required bytes */ public void applyTo(Program programParam, DataTypeManager dataTypeManagerParam, Address imageBaseParam, PdbApplicatorOptions applicatorOptionsParam, - MessageLog logParam) throws PdbException, CancelledException { + MessageLog logParam) throws PdbException, CancelledException, IOException { // FIXME: should not support use of DataTypeManager-only since it will not have the correct // data organization if it corresponds to a data type archive. Need to evaluate archive @@ -397,9 +402,16 @@ public class DefaultPdbApplicator implements PdbApplicator { //============================================================================================== //============================================================================================== + /** + * Initializes helper classes and data items used for applying the PDB + * @throws CancelledException upon user cancellation + * @throws PdbException upon error in processing components + * @throws IOException on file seek or read, invalid parameters, bad file configuration, or + * inability to read required bytes + */ private void initializeApplyTo(Program programParam, DataTypeManager dataTypeManagerParam, Address imageBaseParam, PdbApplicatorOptions applicatorOptionsParam, - MessageLog logParam) throws PdbException, CancelledException { + MessageLog logParam) throws PdbException, CancelledException, IOException { validateAndSetParameters(programParam, dataTypeManagerParam, imageBaseParam, applicatorOptionsParam, logParam); @@ -759,8 +771,7 @@ public class DefaultPdbApplicator implements PdbApplicator { throw new PdbException("PDB: DebugInfo is null"); } - for (SectionContribution sectionContribution : debugInfo - .getSectionContributionList()) { + for (SectionContribution sectionContribution : debugInfo.getSectionContributionList()) { int sectionContributionOffset = sectionContribution.getOffset(); int maxSectionContributionOffset = sectionContributionOffset + sectionContribution.getLength(); @@ -781,8 +792,8 @@ public class DefaultPdbApplicator implements PdbApplicator { TaskMonitor monitor = getMonitor(); monitor.initialize(num); monitor.setMessage("PDB: Processing " + num + " data type components..."); - for (int indexNumber = - tpi.getTypeIndexMin(); indexNumber < tpi.getTypeIndexMaxExclusive(); indexNumber++) { + for (int indexNumber = tpi.getTypeIndexMin(); indexNumber < tpi + .getTypeIndexMaxExclusive(); indexNumber++) { monitor.checkCancelled(); //PdbResearch.checkBreak(indexNumber); MsTypeApplier applier = getTypeApplier(RecordNumber.typeRecordNumber(indexNumber)); @@ -849,8 +860,8 @@ public class DefaultPdbApplicator implements PdbApplicator { TaskMonitor monitor = getMonitor(); monitor.initialize(num); monitor.setMessage("PDB: Processing " + num + " item type components..."); - for (int indexNumber = - ipi.getTypeIndexMin(); indexNumber < ipi.getTypeIndexMaxExclusive(); indexNumber++) { + for (int indexNumber = ipi.getTypeIndexMin(); indexNumber < ipi + .getTypeIndexMaxExclusive(); indexNumber++) { monitor.checkCancelled(); MsTypeApplier applier = getTypeApplier(RecordNumber.itemRecordNumber(indexNumber)); applier.apply(); @@ -893,8 +904,8 @@ public class DefaultPdbApplicator implements PdbApplicator { monitor.initialize(num); monitor.setMessage("PDB: Resolving " + num + " data type components..."); long longStart = System.currentTimeMillis(); - for (int indexNumber = - tpi.getTypeIndexMin(); indexNumber < tpi.getTypeIndexMaxExclusive(); indexNumber++) { + for (int indexNumber = tpi.getTypeIndexMin(); indexNumber < tpi + .getTypeIndexMaxExclusive(); indexNumber++) { monitor.checkCancelled(); //PdbResearch.checkBreak(indexNumber); MsTypeApplier applier = getTypeApplier(RecordNumber.typeRecordNumber(indexNumber)); @@ -937,8 +948,7 @@ public class DefaultPdbApplicator implements PdbApplicator { } CreateFunctionCmd funCmd = new CreateFunctionCmd(null, normalizedAddress, - new AddressSet(normalizedAddress, normalizedAddress), - SourceType.DEFAULT); + new AddressSet(normalizedAddress, normalizedAddress), SourceType.DEFAULT); if (!funCmd.applyTo(program, cancelOnlyWrappingMonitor)) { appendLogMsg("Failed to apply function at address " + address.toString() + "; attempting to use possible existing function"); @@ -1154,12 +1164,20 @@ public class DefaultPdbApplicator implements PdbApplicator { TaskMonitor monitor = getMonitor(); monitor.setMessage("PDB: Applying " + totalCount + " main symbol components..."); monitor.initialize(totalCount); - AbstractMsSymbolIterator iter = symbolGroup.iterator(); + MsSymbolIterator iter = symbolGroup.getSymbolIterator(); processSymbolGroup(0, iter); } //============================================================================================== - private void processModuleSymbols() throws CancelledException { + int getCurrentModuleNumber() { + return currentModuleNumber; + } + + private void setCurrentModuleNumber(int moduleNumber) { + currentModuleNumber = moduleNumber; + } + + private void processModuleSymbols() throws CancelledException, PdbException { PdbDebugInfo debugInfo = pdb.getDebugInfo(); if (debugInfo == null) { return; @@ -1184,12 +1202,13 @@ public class DefaultPdbApplicator implements PdbApplicator { // Process symbols list for each module for (int moduleNumber = 1; moduleNumber <= num; moduleNumber++) { monitor.checkCancelled(); + setCurrentModuleNumber(moduleNumber); // Process module symbols list SymbolGroup symbolGroup = getSymbolGroupForModule(moduleNumber); if (symbolGroup == null) { continue; // should not happen } - AbstractMsSymbolIterator iter = symbolGroup.iterator(); + MsSymbolIterator iter = symbolGroup.getSymbolIterator(); processSymbolGroup(moduleNumber, iter); monitor.increment(); // catelogSymbols(index, symbolGroup); @@ -1212,7 +1231,7 @@ public class DefaultPdbApplicator implements PdbApplicator { // } // //============================================================================================== - private void processSymbolGroup(int moduleNumber, AbstractMsSymbolIterator iter) + private void processSymbolGroup(int moduleNumber, MsSymbolIterator iter) throws CancelledException { iter.initGet(); TaskMonitor monitor = getMonitor(); @@ -1244,12 +1263,12 @@ public class DefaultPdbApplicator implements PdbApplicator { } PublicSymbolInformation publicSymbolInformation = debugInfo.getPublicSymbolInformation(); - List offsets = publicSymbolInformation.getModifiedHashRecordSymbolOffsets(); TaskMonitor monitor = getMonitor(); - monitor.setMessage("PDB: Applying " + offsets.size() + " public symbol components..."); - monitor.initialize(offsets.size()); + monitor.setMessage("PDB: Applying public symbols..."); + MsSymbolIterator iter = symbolGroup.getSymbolIterator(); - AbstractMsSymbolIterator iter = symbolGroup.iterator(); + List offsets = publicSymbolInformation.getModifiedHashRecordSymbolOffsets(); + monitor.initialize(offsets.size()); for (long offset : offsets) { monitor.checkCancelled(); iter.initGetByOffset(offset); @@ -1260,6 +1279,26 @@ public class DefaultPdbApplicator implements PdbApplicator { procSym(iter); monitor.incrementProgress(1); } + +// AbstractSymbolInformation.ModifiedOffsetIterator publicsIter = +// publicSymbolInformation.iterator(); +// monitor.initialize(100L); +// long percentDone = 0; +// while (publicsIter.hasNext()) { +// monitor.checkCancelled(); +// Long offset = publicsIter.next(); +// iter.initGetByOffset(offset); +// if (!iter.hasNext()) { +// break; +// } +// pdbApplicatorMetrics.witnessPublicSymbolType(iter.peek()); +// procSym(iter); +// // Increment progress +// long delta = publicsIter.getPercentageDone() - percentDone; +// monitor.incrementProgress(delta); +// percentDone += delta; +// } +// } /** @@ -1281,13 +1320,13 @@ public class DefaultPdbApplicator implements PdbApplicator { return; } - GlobalSymbolInformation globalSymbolInformation = debugInfo.getGlobalSymbolInformation(); - List offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets(); TaskMonitor monitor = getMonitor(); monitor.setMessage("PDB: Applying global symbols..."); - monitor.initialize(offsets.size()); + GlobalSymbolInformation globalSymbolInformation = debugInfo.getGlobalSymbolInformation(); + MsSymbolIterator iter = symbolGroup.getSymbolIterator(); - AbstractMsSymbolIterator iter = symbolGroup.iterator(); + List offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets(); + monitor.initialize(offsets.size()); for (long offset : offsets) { monitor.checkCancelled(); iter.initGetByOffset(offset); @@ -1301,6 +1340,28 @@ public class DefaultPdbApplicator implements PdbApplicator { } monitor.incrementProgress(1); } + +// AbstractSymbolInformation.ModifiedOffsetIterator globalsIter = +// globalSymbolInformation.iterator(); +// monitor.initialize(100L); +// long percentDone = 0; +// while (globalsIter.hasNext()) { +// monitor.checkCancelled(); +// Long offset = globalsIter.next(); +// iter.initGetByOffset(offset); +// if (!iter.hasNext()) { +// break; +// } +// AbstractMsSymbol symbol = iter.peek(); +// pdbApplicatorMetrics.witnessGlobalSymbolType(symbol); +// if (!(symbol instanceof AbstractUserDefinedTypeMsSymbol)) { // Not doing typedefs here +// procSym(iter); +// } +// // Increment progress +// long delta = globalsIter.getPercentageDone() - percentDone; +// monitor.incrementProgress(delta); +// percentDone += delta; +// } } /** @@ -1320,13 +1381,13 @@ public class DefaultPdbApplicator implements PdbApplicator { return; } - GlobalSymbolInformation globalSymbolInformation = debugInfo.getGlobalSymbolInformation(); - List offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets(); TaskMonitor monitor = getMonitor(); monitor.setMessage("PDB: Applying typedefs..."); - monitor.initialize(offsets.size()); + GlobalSymbolInformation globalSymbolInformation = debugInfo.getGlobalSymbolInformation(); + MsSymbolIterator iter = symbolGroup.getSymbolIterator(); - AbstractMsSymbolIterator iter = symbolGroup.iterator(); + List offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets(); + monitor.initialize(offsets.size()); for (long offset : offsets) { monitor.checkCancelled(); iter.initGetByOffset(offset); @@ -1339,6 +1400,28 @@ public class DefaultPdbApplicator implements PdbApplicator { } monitor.incrementProgress(1); } + +// AbstractSymbolInformation.ModifiedOffsetIterator globalsIter = +// globalSymbolInformation.iterator(); +// monitor.initialize(100L); +// long percentDone = 0; +// while (globalsIter.hasNext()) { +// monitor.checkCancelled(); +// Long offset = globalsIter.next(); +// iter.initGetByOffset(offset); +// if (!iter.hasNext()) { +// break; +// } +// AbstractMsSymbol symbol = iter.peek(); +// pdbApplicatorMetrics.witnessGlobalSymbolType(symbol); +// if (symbol instanceof AbstractUserDefinedTypeMsSymbol) { // Doing typedefs here +// procSym(iter); +// } +// // Increment progress +// long delta = globalsIter.getPercentageDone() - percentDone; +// monitor.incrementProgress(delta); +// percentDone += delta; +// } } /** @@ -1378,7 +1461,7 @@ public class DefaultPdbApplicator implements PdbApplicator { monitor.initialize(offsetsRemaining.size()); //getCategoryUtils().setModuleTypedefsCategory(null); - AbstractMsSymbolIterator iter = symbolGroup.iterator(); + MsSymbolIterator iter = symbolGroup.getSymbolIterator(); for (long offset : offsetsRemaining) { monitor.checkCancelled(); iter.initGetByOffset(offset); @@ -1414,7 +1497,7 @@ public class DefaultPdbApplicator implements PdbApplicator { //============================================================================================== @SuppressWarnings("unused") // for method not being called. - private boolean processLinkerSymbols() throws CancelledException { + private boolean processLinkerSymbols() throws CancelledException, PdbException { SymbolGroup symbolGroup = getSymbolGroupForModule(linkerModuleNumber); if (symbolGroup == null) { @@ -1426,7 +1509,7 @@ public class DefaultPdbApplicator implements PdbApplicator { monitor.setMessage("PDB: Applying " + symbolGroup.size() + " linker symbol components..."); monitor.initialize(symbolGroup.size()); - AbstractMsSymbolIterator iter = symbolGroup.iterator(); + MsSymbolIterator iter = symbolGroup.getSymbolIterator(); while (iter.hasNext()) { monitor.checkCancelled(); pdbApplicatorMetrics.witnessLinkerSymbolType(iter.peek()); @@ -1438,20 +1521,21 @@ public class DefaultPdbApplicator implements PdbApplicator { //============================================================================================== @Override - public List getLinkerPeCoffSectionSymbols() throws CancelledException { + public List getLinkerPeCoffSectionSymbols() + throws CancelledException, PdbException { processLinkerModuleSpecialInformation(); return linkerPeCoffSectionSymbols; } //============================================================================================== @Override - public AbstractMsSymbol getLinkerModuleCompileSymbol() throws CancelledException { + public AbstractMsSymbol getLinkerModuleCompileSymbol() throws CancelledException, PdbException { processLinkerModuleSpecialInformation(); return compileSymbolForLinkerModule; } //============================================================================================== - private void processLinkerModuleSpecialInformation() throws CancelledException { + private void processLinkerModuleSpecialInformation() throws CancelledException, PdbException { if (processedLinkerModule) { return; @@ -1465,7 +1549,7 @@ public class DefaultPdbApplicator implements PdbApplicator { TaskMonitor monitor = getMonitor(); monitor.initialize(symbolGroup.size()); - AbstractMsSymbolIterator iter = symbolGroup.iterator(); + MsSymbolIterator iter = symbolGroup.getSymbolIterator(); int numCompileSymbols = 0; int compileSymbolNumForCoffSymbols = -1; while (iter.hasNext()) { @@ -1511,7 +1595,7 @@ public class DefaultPdbApplicator implements PdbApplicator { } //============================================================================================== - private void processThunkSymbolsFromNonLinkerModules() throws CancelledException { + private void processThunkSymbolsFromNonLinkerModules() throws CancelledException, PdbException { PdbDebugInfo debugInfo = pdb.getDebugInfo(); if (debugInfo == null) { @@ -1546,7 +1630,7 @@ public class DefaultPdbApplicator implements PdbApplicator { if (symbolGroup == null) { continue; // should not happen } - AbstractMsSymbolIterator iter = symbolGroup.iterator(); + MsSymbolIterator iter = symbolGroup.getSymbolIterator(); while (iter.hasNext()) { monitor.checkCancelled(); AbstractMsSymbol symbol = iter.peek(); @@ -1566,12 +1650,12 @@ public class DefaultPdbApplicator implements PdbApplicator { //============================================================================================== //============================================================================================== //============================================================================================== - MsSymbolApplier getSymbolApplier(AbstractMsSymbolIterator iter) throws CancelledException { + MsSymbolApplier getSymbolApplier(MsSymbolIterator iter) throws CancelledException { return symbolApplierParser.getSymbolApplier(iter); } //============================================================================================== - void procSym(AbstractMsSymbolIterator iter) throws CancelledException { + void procSym(MsSymbolIterator iter) throws CancelledException { try { MsSymbolApplier applier = getSymbolApplier(iter); applier.apply(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefinedSingleAddressRangeSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefinedSingleAddressRangeSymbolApplier.java index 6e1e2fe02c..41cd8637b6 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefinedSingleAddressRangeSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefinedSingleAddressRangeSymbolApplier.java @@ -15,9 +15,9 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; @@ -34,7 +34,7 @@ public class DefinedSingleAddressRangeSymbolApplier extends MsSymbolApplier { * @param iter the Iterator containing the symbol sequence being processed */ public DefinedSingleAddressRangeSymbolApplier(DefaultPdbApplicator applicator, - AbstractMsSymbolIterator iter) { + MsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); if (!(abstractSymbol instanceof AbstractDefinedSingleAddressRangeMsSymbol)) { @@ -53,7 +53,7 @@ public class DefinedSingleAddressRangeSymbolApplier extends MsSymbolApplier { @Override void applyTo(MsSymbolApplier applyToApplier) throws PdbException, CancelledException { if (applyToApplier instanceof LocalOptimizedSymbolApplier) { -// TODO: eventually apply. +// TODO: eventually apply. // LocalOptimizedSymbolApplier localSymbolApplier = // (LocalOptimizedSymbolApplier) applyToApplier; symbol.getAddressRange(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EndSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EndSymbolApplier.java index f5ccb6eef3..efd90d3f26 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EndSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EndSymbolApplier.java @@ -15,9 +15,9 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.util.exception.AssertException; /** @@ -30,7 +30,7 @@ public class EndSymbolApplier extends MsSymbolApplier { * @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed */ - public EndSymbolApplier(DefaultPdbApplicator applicator, AbstractMsSymbolIterator iter) { + public EndSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); if (!(abstractSymbol instanceof EndMsSymbol || @@ -43,8 +43,8 @@ public class EndSymbolApplier extends MsSymbolApplier { @Override void apply() throws PdbException { pdbLogAndInfoMessage(this, - String.format("Cannot apply %s directly to program (module:0X%04X, offset:0X%08X)", - this.getClass().getSimpleName(), iter.getModuleNumber(), iter.getCurrentOffset())); + String.format("Cannot apply %s directly to program (stream:0X%04X, offset:0X%08X)", + this.getClass().getSimpleName(), iter.getStreamNumber(), iter.getCurrentOffset())); } @Override diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FrameAndProcedureInformationSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FrameAndProcedureInformationSymbolApplier.java index d8f5f0cecf..c925e9e811 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FrameAndProcedureInformationSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FrameAndProcedureInformationSymbolApplier.java @@ -15,10 +15,10 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.ExtraFrameAndProcedureInformationMsSymbol; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; @@ -35,7 +35,7 @@ public class FrameAndProcedureInformationSymbolApplier extends MsSymbolApplier { * @param iter the Iterator containing the symbol sequence being processed */ public FrameAndProcedureInformationSymbolApplier(DefaultPdbApplicator applicator, - AbstractMsSymbolIterator iter) { + MsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); if (!(abstractSymbol instanceof ExtraFrameAndProcedureInformationMsSymbol)) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java index 603116a9d8..2e92a806fd 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java @@ -19,10 +19,8 @@ import java.util.*; import ghidra.app.cmd.function.ApplyFunctionSignatureCmd; import ghidra.app.cmd.function.CallDepthChangeInfo; -import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; -import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber; +import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSet; import ghidra.program.model.data.DataType; @@ -69,7 +67,7 @@ public class FunctionSymbolApplier extends MsSymbolApplier * @param iter the Iterator containing the symbol sequence being processed * @throws CancelledException upon user cancellation */ - public FunctionSymbolApplier(DefaultPdbApplicator applicator, AbstractMsSymbolIterator iter) + public FunctionSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) throws CancelledException { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java index b01528e45c..479b03e3f7 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java @@ -18,10 +18,10 @@ package ghidra.app.util.pdb.pdbapplicator; import java.util.regex.Matcher; import ghidra.app.util.NamespaceUtils; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractLabelMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Function; import ghidra.program.model.symbol.SourceType; @@ -42,7 +42,7 @@ public class LabelSymbolApplier extends MsSymbolApplier implements DeferrableFun * @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed */ - public LabelSymbolApplier(DefaultPdbApplicator applicator, AbstractMsSymbolIterator iter) { + public LabelSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); if (!(abstractSymbol instanceof AbstractLabelMsSymbol)) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LocalOptimizedSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LocalOptimizedSymbolApplier.java index 50206c7d4d..958e100981 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LocalOptimizedSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LocalOptimizedSymbolApplier.java @@ -15,9 +15,9 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; @@ -33,8 +33,7 @@ public class LocalOptimizedSymbolApplier extends MsSymbolApplier { * @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed */ - public LocalOptimizedSymbolApplier(DefaultPdbApplicator applicator, - AbstractMsSymbolIterator iter) { + public LocalOptimizedSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); if (!(abstractSymbol instanceof AbstractLocalSymbolInOptimizedCodeMsSymbol)) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ManagedProcedureSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ManagedProcedureSymbolApplier.java index fd11c4ae3d..036dd54d5d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ManagedProcedureSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ManagedProcedureSymbolApplier.java @@ -18,6 +18,7 @@ package ghidra.app.util.pdb.pdbapplicator; import java.util.*; import ghidra.app.cmd.function.CallDepthChangeInfo; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractManagedProcedureMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; @@ -26,7 +27,6 @@ import ghidra.app.util.bin.format.pe.cli.tables.CliTableMethodDef.CliMethodDefRo import ghidra.app.util.bin.format.pe.cli.tables.CliTableMethodImpl.CliMethodImplRow; import ghidra.app.util.bin.format.pe.cli.tables.CliTableMethodSemantics.CliMethodSemanticsRow; import ghidra.app.util.bin.format.pe.cli.tables.CliTableMethodSpec.CliMethodSpecRow; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSet; import ghidra.program.model.data.DataType; @@ -80,8 +80,8 @@ public class ManagedProcedureSymbolApplier extends MsSymbolApplier * @param iter the Iterator containing the symbol sequence being processed * @throws CancelledException upon user cancellation */ - public ManagedProcedureSymbolApplier(DefaultPdbApplicator applicator, - AbstractMsSymbolIterator iter) throws CancelledException { + public ManagedProcedureSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) + throws CancelledException { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); symbolBlockNestingLevel = 0; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsSymbolApplier.java index 946beef1df..aea5f34f7b 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsSymbolApplier.java @@ -18,10 +18,8 @@ package ghidra.app.util.pdb.pdbapplicator; import java.util.Objects; import ghidra.app.plugin.processors.sleigh.symbol.Symbol; -import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; -import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog; +import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.util.exception.CancelledException; /** @@ -33,7 +31,7 @@ import ghidra.util.exception.CancelledException; */ public abstract class MsSymbolApplier { protected DefaultPdbApplicator applicator; - protected AbstractMsSymbolIterator iter; + protected MsSymbolIterator iter; protected long currentOffset; /** @@ -41,7 +39,7 @@ public abstract class MsSymbolApplier { * @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed */ - public MsSymbolApplier(DefaultPdbApplicator applicator, AbstractMsSymbolIterator iter) { + public MsSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) { Objects.requireNonNull(applicator, "applicator cannot be null"); Objects.requireNonNull(iter, "iter cannot be null"); this.applicator = applicator; @@ -86,7 +84,7 @@ public abstract class MsSymbolApplier { /** * Manages block nesting for symbols/appliers that represent the beginning or end of blocks. * The default is to do nothing. Otherwise the appliers should implement the appropriate - * logic. + * logic. * @param applierParam the applier which is managing blocks, which is typically * {@link FunctionSymbolApplier}. */ diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java index e9a3d498bb..a597cac46d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java @@ -15,8 +15,8 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; /** * A dummy {@link MsSymbolApplier}, which, at a minimum, reads the symbol from the @@ -32,7 +32,7 @@ public class NoSymbolApplier extends MsSymbolApplier { * @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed */ - public NoSymbolApplier(DefaultPdbApplicator applicator, AbstractMsSymbolIterator iter) { + public NoSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) { super(applicator, iter); symbol = iter.next(); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressCalculator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressCalculator.java index 09da627263..fba43adeb1 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressCalculator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressCalculator.java @@ -15,6 +15,7 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import java.io.IOException; import java.util.*; import org.apache.commons.collections4.CollectionUtils; @@ -35,7 +36,7 @@ abstract class PdbAddressCalculator { private int maxSegment; static PdbAddressCalculator chooseAddressCalculator(PdbApplicator applicator, Address imageBase) - throws CancelledException { + throws CancelledException, PdbException, IOException { AbstractPdb pdb = applicator.getPdb(); PdbDebugInfo dbi = pdb.getDebugInfo(); @@ -91,7 +92,7 @@ abstract class PdbAddressCalculator { // We wouldn't have this method if we hadn't found an example where what is supposed to be // an RVA in PeCoffSection is instead a VA. Issue found in one Delphi example. All other // non-Delphi examples seem to have RVA. - static long getCorrection(PdbApplicator applicator) throws CancelledException { + static long getCorrection(PdbApplicator applicator) throws CancelledException, PdbException { AbstractMsSymbol symbol = applicator.getLinkerModuleCompileSymbol(); String name = ""; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java index 9a011f38a0..97e1efadf3 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java @@ -15,6 +15,7 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import java.io.IOException; import java.util.*; import ghidra.app.util.bin.format.pdb2.pdbreader.*; @@ -79,9 +80,11 @@ public class PdbAddressManager { * @param imageBase Address from which all other addresses are based. * @throws PdbException If Program is null; * @throws CancelledException upon user cancellation + * @throws IOException on file seek or read, invalid parameters, bad file configuration, or + * inability to read required bytes */ PdbAddressManager(DefaultPdbApplicator applicator, Address imageBase) - throws PdbException, CancelledException { + throws PdbException, CancelledException, IOException { Objects.requireNonNull(applicator, "applicator may not be null"); Objects.requireNonNull(imageBase, "imageBase may not be null"); this.applicator = applicator; @@ -336,7 +339,14 @@ public class PdbAddressManager { // } // } - private void determineMemoryBlocks() { + /** + * Determines memory blocks + * @throws CancelledException upon user cancellation + * @throws PdbException upon error in processing components + * @throws IOException on file seek or read, invalid parameters, bad file configuration, or + * inability to read required bytes + */ + private void determineMemoryBlocks() throws CancelledException, PdbException, IOException { AbstractPdb pdb = applicator.getPdb(); PdbDebugInfo debugInfo = pdb.getDebugInfo(); segmentMapList = debugInfo.getSegmentMapList(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java index 46f8faa915..d4f4854ef1 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java @@ -18,6 +18,7 @@ package ghidra.app.util.pdb.pdbapplicator; import java.util.List; import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractPdb; +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; import ghidra.program.model.listing.Program; import ghidra.util.exception.CancelledException; @@ -62,15 +63,18 @@ public interface PdbApplicator { * Returns the {@link PeCoffSectionMsSymbol}s from the "Linker" module * @return list of symbols * @throws CancelledException upon user cancellation + * @throws PdbException upon issue creating an iterator */ - public List getLinkerPeCoffSectionSymbols() throws CancelledException; + public List getLinkerPeCoffSectionSymbols() + throws CancelledException, PdbException; /** * Returns the compile symbol seen in the "Linker" module. Should be one of * {@link Compile3MsSymbol} or {@link AbstractCompile2MsSymbol} * @return the compile symbol * @throws CancelledException upon user cancellation + * @throws PdbException upon issue creating an iterator */ - public AbstractMsSymbol getLinkerModuleCompileSymbol() throws CancelledException; + public AbstractMsSymbol getLinkerModuleCompileSymbol() throws CancelledException, PdbException; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java index e9f3ab8f61..187466df1b 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java @@ -22,7 +22,6 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; import ghidra.program.model.data.*; import ghidra.program.model.lang.CompilerSpec; @@ -337,8 +336,7 @@ public class PdbResearch { String nn = applier.getMsType().getName(); if ("std::__1::__map_value_compare,std::__1::__value_type,std::__1::basic_string >,std::__1::less,1>" - .equals( - nn)) { + .equals(nn)) { doNothingSetBreakPointHere(); } if ("class std::__1::__iostream_category".equals(nn)) { @@ -430,7 +428,7 @@ public class PdbResearch { monitor.setMessage("PDB: Applying typedefs..."); monitor.initialize(offsets.size()); - AbstractMsSymbolIterator iter = symbolGroup.iterator(); + MsSymbolIterator iter = symbolGroup.getSymbolIterator(); for (long offset : offsets) { monitor.checkCancelled(); iter.initGetByOffset(offset); @@ -441,8 +439,8 @@ public class PdbResearch { } } - static private boolean childWalkSym(DefaultPdbApplicator applicator, int moduleNumber, - AbstractMsSymbolIterator iter) throws PdbException, CancelledException { + static private boolean childWalkSym(DefaultPdbApplicator applicator, int streamNumber, + MsSymbolIterator iter) throws PdbException, CancelledException { if (!iter.hasNext()) { return false; } @@ -459,18 +457,18 @@ public class PdbResearch { } else if (applier instanceof ReferenceSymbolApplier) { ReferenceSymbolApplier refSymbolApplier = (ReferenceSymbolApplier) applier; - AbstractMsSymbolIterator refIter = + MsSymbolIterator refIter = refSymbolApplier.getInitializedReferencedSymbolGroupIterator(); if (refIter == null) { throw new PdbException("PDB: Referenced Symbol Error - not refIter"); } // recursion - childWalkSym(applicator, refIter.getModuleNumber(), refIter); + childWalkSym(applicator, refIter.getStreamNumber(), refIter); } else if (applier instanceof DataSymbolApplier) { DataSymbolApplier dataSymbolApplier = (DataSymbolApplier) applier; MsTypeApplier typeApplier = dataSymbolApplier.getTypeApplier(); - childWalkType(moduleNumber, typeApplier); + childWalkType(streamNumber, typeApplier); } else if (applier instanceof FunctionSymbolApplier) { FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applier; @@ -620,7 +618,7 @@ public class PdbResearch { * reuse caused by Templates and/or Identical Code Folding. */ static void studyAggregateSymbols(DefaultPdbApplicator applicator, TaskMonitor monitor) - throws CancelledException { + throws CancelledException, PdbException { Map> mapByAddress = new HashMap<>(); processPublicSymbols(applicator, mapByAddress, monitor); processGlobalSymbols(applicator, mapByAddress, monitor); @@ -629,7 +627,8 @@ public class PdbResearch { } private static void processPublicSymbols(DefaultPdbApplicator applicator, - Map> map, TaskMonitor monitor) throws CancelledException { + Map> map, TaskMonitor monitor) + throws CancelledException, PdbException { AbstractPdb pdb = applicator.getPdb(); PdbDebugInfo debugInfo = pdb.getDebugInfo(); @@ -644,11 +643,10 @@ public class PdbResearch { PublicSymbolInformation publicSymbolInformation = debugInfo.getPublicSymbolInformation(); List offsets = publicSymbolInformation.getModifiedHashRecordSymbolOffsets(); - monitor.setMessage( - "PDB: Applying " + offsets.size() + " public symbol components..."); + monitor.setMessage("PDB: Applying " + offsets.size() + " public symbol components..."); monitor.initialize(offsets.size()); - AbstractMsSymbolIterator iter = symbolGroup.iterator(); + MsSymbolIterator iter = symbolGroup.getSymbolIterator(); for (long offset : offsets) { monitor.checkCancelled(); iter.initGetByOffset(offset); @@ -664,7 +662,8 @@ public class PdbResearch { } private static void processGlobalSymbols(DefaultPdbApplicator applicator, - Map> map, TaskMonitor monitor) throws CancelledException { + Map> map, TaskMonitor monitor) + throws CancelledException, PdbException { AbstractPdb pdb = applicator.getPdb(); PdbDebugInfo debugInfo = pdb.getDebugInfo(); @@ -682,7 +681,7 @@ public class PdbResearch { monitor.setMessage("PDB: Applying global symbols..."); monitor.initialize(offsets.size()); - AbstractMsSymbolIterator iter = symbolGroup.iterator(); + MsSymbolIterator iter = symbolGroup.getSymbolIterator(); for (long offset : offsets) { monitor.checkCancelled(); iter.initGetByOffset(offset); @@ -698,7 +697,8 @@ public class PdbResearch { } private static void processModuleSymbols(DefaultPdbApplicator applicator, - Map> map, TaskMonitor monitor) throws CancelledException { + Map> map, TaskMonitor monitor) + throws CancelledException, PdbException { AbstractPdb pdb = applicator.getPdb(); PdbDebugInfo debugInfo = pdb.getDebugInfo(); if (debugInfo == null) { @@ -715,8 +715,7 @@ public class PdbResearch { } totalCount += symbolGroup.size(); } - monitor.setMessage( - "PDB: Applying " + totalCount + " module symbol components..."); + monitor.setMessage("PDB: Applying " + totalCount + " module symbol components..."); monitor.initialize(totalCount); // Process symbols list for each module @@ -731,7 +730,7 @@ public class PdbResearch { if (symbolGroup == null) { continue; } - AbstractMsSymbolIterator iter = symbolGroup.iterator(); + MsSymbolIterator iter = symbolGroup.getSymbolIterator(); processSymbolGroup(applicator, map, moduleNumber, iter, monitor); // do not call monitor.incrementProgress(1) here, as it is updated inside of // processSymbolGroup. @@ -739,7 +738,7 @@ public class PdbResearch { } private static void processSymbolGroup(DefaultPdbApplicator applicator, - Map> map, int moduleNumber, AbstractMsSymbolIterator iter, + Map> map, int moduleNumber, MsSymbolIterator iter, TaskMonitor monitor) throws CancelledException { iter.initGet(); while (iter.hasNext()) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java index 2bc271963f..116c74c6c3 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java @@ -20,7 +20,6 @@ import java.util.*; import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractPublicMsSymbol; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.listing.Program; @@ -50,7 +49,7 @@ public class PdbVbtManager extends VbtManager { // If we find some this way, then need to modify PdbVbtManager to also look // through the loader symbol for them. private static Map findVirtualBaseTableSymbols(DefaultPdbApplicator applicator) - throws CancelledException { + throws CancelledException, PdbException { TaskMonitor monitor = applicator.getMonitor(); Map myAddressByMangledName = new HashMap<>(); @@ -71,7 +70,7 @@ public class PdbVbtManager extends VbtManager { monitor.setMessage("PDB: Searching for virtual base table symbols..."); monitor.initialize(offsets.size()); - AbstractMsSymbolIterator iter = symbolGroup.iterator(); + MsSymbolIterator iter = symbolGroup.getSymbolIterator(); for (long offset : offsets) { monitor.checkCancelled(); iter.initGetByOffset(offset); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java index 17362acd6f..80d715fa90 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java @@ -15,10 +15,10 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.PeCoffGroupMsSymbol; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; @@ -35,8 +35,7 @@ public class PeCoffGroupSymbolApplier extends MsSymbolApplier { * @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed */ - public PeCoffGroupSymbolApplier(DefaultPdbApplicator applicator, - AbstractMsSymbolIterator iter) { + public PeCoffGroupSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); if (!(abstractSymbol instanceof PeCoffGroupMsSymbol)) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffSectionSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffSectionSymbolApplier.java index 3e37b0baf5..b8ab7dac28 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffSectionSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffSectionSymbolApplier.java @@ -15,10 +15,10 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.PeCoffSectionMsSymbol; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; @@ -34,8 +34,7 @@ public class PeCoffSectionSymbolApplier extends MsSymbolApplier { * @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed */ - public PeCoffSectionSymbolApplier(DefaultPdbApplicator applicator, - AbstractMsSymbolIterator iter) { + public PeCoffSectionSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); if (!(abstractSymbol instanceof PeCoffSectionMsSymbol)) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java index d74e2aa75e..54338a00da 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java @@ -15,12 +15,12 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractPublicMsSymbol; import ghidra.app.util.datatype.microsoft.GuidDataType; import ghidra.app.util.datatype.microsoft.GuidUtil; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; import ghidra.program.model.data.DataUtilities; import ghidra.program.model.data.DataUtilities.ClearDataMode; @@ -43,7 +43,7 @@ public class PublicSymbolApplier extends MsSymbolApplier { * @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed */ - public PublicSymbolApplier(DefaultPdbApplicator applicator, AbstractMsSymbolIterator iter) { + public PublicSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); if (!(abstractSymbol instanceof AbstractPublicMsSymbol)) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ReferenceSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ReferenceSymbolApplier.java index 996a59edc9..e472152820 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ReferenceSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ReferenceSymbolApplier.java @@ -15,10 +15,10 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractReferenceMsSymbol; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; @@ -34,7 +34,7 @@ public class ReferenceSymbolApplier extends MsSymbolApplier { * @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed */ - public ReferenceSymbolApplier(DefaultPdbApplicator applicator, AbstractMsSymbolIterator iter) { + public ReferenceSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); if (!(abstractSymbol instanceof AbstractReferenceMsSymbol)) { @@ -52,19 +52,19 @@ public class ReferenceSymbolApplier extends MsSymbolApplier { @Override void apply() throws CancelledException, PdbException { // Potential recursive call via applicator.procSym(). - AbstractMsSymbolIterator refIter = getInitializedReferencedSymbolGroupIterator(); + MsSymbolIterator refIter = getInitializedReferencedSymbolGroupIterator(); if (refIter == null) { throw new PdbException("PDB: Referenced Symbol Error - null refIter"); } applicator.procSym(refIter); } - AbstractMsSymbolIterator getInitializedReferencedSymbolGroupIterator() { + MsSymbolIterator getInitializedReferencedSymbolGroupIterator() throws PdbException { SymbolGroup refSymbolGroup = getReferencedSymbolGroup(); if (refSymbolGroup == null) { return null; } - AbstractMsSymbolIterator refIter = refSymbolGroup.iterator(); + MsSymbolIterator refIter = refSymbolGroup.getSymbolIterator(); refIter.initGetByOffset(getOffsetInReferencedSymbolGroup()); return refIter; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java index fd3c00c169..449351a41a 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java @@ -17,10 +17,10 @@ package ghidra.app.util.pdb.pdbapplicator; import java.util.Objects; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractRegisterRelativeAddressMsSymbol; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.data.DataType; import ghidra.program.model.lang.Register; import ghidra.program.model.listing.*; @@ -40,7 +40,7 @@ public class RegisterRelativeSymbolApplier extends MsSymbolApplier { * @param iter the Iterator containing the symbol sequence being processed */ public RegisterRelativeSymbolApplier(DefaultPdbApplicator applicator, - AbstractMsSymbolIterator iter) { + MsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); if (!(abstractSymbol instanceof AbstractRegisterRelativeAddressMsSymbol)) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java index 42b4d83095..0dcc51f868 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java @@ -19,9 +19,9 @@ import java.util.ArrayList; import java.util.List; import ghidra.app.cmd.comments.SetCommentCmd; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.SeparatedCodeFromCompilerSupportMsSymbol; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; import ghidra.program.model.listing.CodeUnit; import ghidra.util.Msg; @@ -46,7 +46,7 @@ public class SeparatedCodeSymbolApplier extends MsSymbolApplier { private List allAppliers = new ArrayList<>(); - private static AbstractMsSymbolIterator validateSymbol(AbstractMsSymbolIterator iter) { + private static MsSymbolIterator validateSymbol(MsSymbolIterator iter) { if (!(iter.peek() instanceof SeparatedCodeFromCompilerSupportMsSymbol)) { throw new IllegalArgumentException("Not a SeparatedCodeFromCompilerSupportMsSymbol"); } @@ -60,7 +60,7 @@ public class SeparatedCodeSymbolApplier extends MsSymbolApplier { * @throws CancelledException upon user cancellation */ public SeparatedCodeSymbolApplier(DefaultPdbApplicator applicator, - AbstractMsSymbolIterator iter) throws CancelledException { + MsSymbolIterator iter) throws CancelledException { super(applicator, validateSymbol(iter)); symbol = (SeparatedCodeFromCompilerSupportMsSymbol) iter.next(); @@ -111,8 +111,10 @@ public class SeparatedCodeSymbolApplier extends MsSymbolApplier { private void setComments(boolean enabled) { if (enabled) { - String existingComment = applicator.getProgram().getListing().getComment( - CodeUnit.PRE_COMMENT, specifiedAddress); + String existingComment = applicator.getProgram() + .getListing() + .getComment( + CodeUnit.PRE_COMMENT, specifiedAddress); String p = "*************************************************************\n"; String newComment = String.format(p + "* Separated code (from the compiler): %s - %s *\n" + p, diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolApplierFactory.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolApplierFactory.java index be2e8a1b9c..65b97d4742 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolApplierFactory.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolApplierFactory.java @@ -15,8 +15,8 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.util.exception.CancelledException; /** @@ -36,7 +36,7 @@ public class SymbolApplierFactory { // the AbstractMsSymbol (do one for AbstractMsType as well)? Symbols are different in that // we are using SymbolGroup as a member instead of MsType. - MsSymbolApplier getSymbolApplier(AbstractMsSymbolIterator iter) throws CancelledException { + MsSymbolApplier getSymbolApplier(MsSymbolIterator iter) throws CancelledException { AbstractMsSymbol symbol = iter.peek(); if (symbol == null) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolGroup.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolGroup.java index 311e63ba46..cba0848141 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolGroup.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolGroup.java @@ -20,7 +20,6 @@ import java.io.Writer; import java.util.*; import ghidra.app.util.bin.format.pdb2.pdbreader.*; -import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.util.Msg; import ghidra.util.exception.CancelledException; @@ -157,152 +156,38 @@ public class SymbolGroup { writer.write("\nEnd SymbolGroup---------------------------------------------\n"); } - AbstractMsSymbolIterator iterator() { - return new AbstractMsSymbolIterator(); + //============================================================================================== + public MsSymbolIterator getSymbolIterator() throws PdbException { + int streamNumber; + int startingOffset; + int lengthSymbols; + if (moduleNumber == 0) { + streamNumber = pdb.getDebugInfo().getSymbolRecordsStreamNumber(); + startingOffset = 0; + lengthSymbols = Integer.MAX_VALUE; + } + else { + ModuleInformation moduleInfo = + pdb.getDebugInfo().getModuleInformation(moduleNumber); + streamNumber = moduleInfo.getStreamNumberDebugInformation(); + lengthSymbols = moduleInfo.getSizeLocalSymbolsDebugInformation(); + try { + startingOffset = pdb.getDebugInfo().getSymbolRecords().getCvSigLength(streamNumber); + } + catch (IOException e) { + Msg.warn(this, "PDB issue reading stream when initializing iterator for stream " + + streamNumber); + startingOffset = 0; + lengthSymbols = 0; // essentially null out iterator with zero length + } + catch (CancelledException e) { + startingOffset = 0; + lengthSymbols = 0; // essentially null out iterator with zero length + } + } + return new MsSymbolIterator(pdb, streamNumber, startingOffset, lengthSymbols); } //============================================================================================== - /** - * Iterator for {@link SymbolGroup} that iterates through {@link AbstractMsSymbol - * AbstractMsSymbols} - */ - class AbstractMsSymbolIterator implements Iterator { - private SymbolRecords symbolRecords; - private int streamNumber; - private int lengthSymbols; - private int nextRetrieveOffset; - private SymbolRecords.SymLen symLen; - - public AbstractMsSymbolIterator() { - symbolRecords = pdb.getDebugInfo().getSymbolRecords(); - try { - if (moduleNumber == 0) { - streamNumber = pdb.getDebugInfo().getSymbolRecordsStreamNumber(); - lengthSymbols = Integer.MAX_VALUE; - } - else { - ModuleInformation moduleInfo = - pdb.getDebugInfo().getModuleInformation(moduleNumber); - streamNumber = moduleInfo.getStreamNumberDebugInformation(); - lengthSymbols = moduleInfo.getSizeLocalSymbolsDebugInformation(); - - } - if (streamNumber == MsfStream.NIL_STREAM_NUMBER) { - int a = 1; - a = a + 1; - symLen = null; - nextRetrieveOffset = 0; - } - else { - initGet(); - } - } - catch (PdbException e) { - symLen = null; - nextRetrieveOffset = 0; - Msg.warn(this, "Could not retrieve moduleInfo for module number: " + moduleNumber); - } - } - - @Override - public boolean hasNext() { - return (symLen != null); - } - - /** - * Peeks at and returns the next symbol without incrementing to the next. If none are - * left, then throws NoSuchElementException and reinitializes the state for a new - * iteration. - * @see #initGet() - * @return the next symbol - * @throws NoSuchElementException if there are no more elements - */ - public AbstractMsSymbol peek() throws NoSuchElementException { - if (symLen == null) { - throw new NoSuchElementException(); - } - return symLen.symbol(); - } - - @Override - public AbstractMsSymbol next() { - if (symLen == null) { - throw new NoSuchElementException(); - } - SymbolRecords.SymLen offer = symLen; - symLen = retrieveRecord(); - return offer.symbol(); - } - - private SymbolRecords.SymLen retrieveRecord() { - if (streamNumber == MsfStream.NIL_STREAM_NUMBER) { - return null; - } - if (nextRetrieveOffset >= lengthSymbols) { - return null; - } - try { - SymbolRecords.SymLen retrieved = - symbolRecords.getRandomAccessRecord(streamNumber, nextRetrieveOffset); - nextRetrieveOffset += retrieved.length(); - return retrieved; - } - catch (PdbException | CancelledException e) { - return null; - } - } - - /** - * Returns the next symbol. If none are left, then throws NoSuchElementException and - * reinitializes the state for a new iteration. - * @see #initGet() - * @return the next symbol - * @throws NoSuchElementException if there are no more elements - */ - long getCurrentOffset() { - if (symLen == null) { - throw new NoSuchElementException(); - } - return nextRetrieveOffset - symLen.length(); - } - - /** - * Initialized the mechanism for requesting the symbols in sequence. - * @see #hasNext() - */ - void initGet() { - if (streamNumber == MsfStream.NIL_STREAM_NUMBER) { - return; - } - try { - nextRetrieveOffset = symbolRecords.getCvSigLength(streamNumber); - symLen = retrieveRecord(); - } - catch (PdbException | CancelledException | IOException e) { - nextRetrieveOffset = 0; - symLen = null; - } - } - - /** - * Initialized the mechanism for requesting the symbols in sequence. - * @param offset the offset to which to initialize the mechanism. - * @see #hasNext() - */ - void initGetByOffset(long offset) { - Long l = offset; - nextRetrieveOffset = l.intValue(); - symLen = retrieveRecord(); - } - - /** - * Returns the module number. - * @return the module number. - */ - int getModuleNumber() { - return moduleNumber; - } - - } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java index a2d5e64e13..cc6054a701 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java @@ -15,10 +15,10 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.TrampolineMsSymbol; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Function; import ghidra.util.exception.AssertException; @@ -38,7 +38,7 @@ public class TrampolineSymbolApplier extends MsSymbolApplier * @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed */ - public TrampolineSymbolApplier(DefaultPdbApplicator applicator, AbstractMsSymbolIterator iter) { + public TrampolineSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); if (!(abstractSymbol instanceof TrampolineMsSymbol)) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java index 877766f9cb..5cf98b40c6 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java @@ -16,11 +16,9 @@ package ghidra.app.util.pdb.pdbapplicator; import ghidra.app.util.SymbolPath; -import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; -import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber; +import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractUserDefinedTypeMsSymbol; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.data.*; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; @@ -38,7 +36,7 @@ public class TypedefSymbolApplier extends MsSymbolApplier { * @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed */ - public TypedefSymbolApplier(DefaultPdbApplicator applicator, AbstractMsSymbolIterator iter) { + public TypedefSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); if (!(abstractSymbol instanceof AbstractUserDefinedTypeMsSymbol)) { @@ -120,7 +118,7 @@ public class TypedefSymbolApplier extends MsSymbolApplier { SymbolPath symbolPath = new SymbolPath(name); CategoryPath categoryPath = - applicator.getTypedefsCategory(iter.getModuleNumber(), symbolPath); + applicator.getTypedefsCategory(applicator.getCurrentModuleNumber(), symbolPath); DataType typedef = new TypedefDataType(categoryPath.getParent(), categoryPath.getName(), dataType, applicator.getDataTypeManager()); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/WithSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/WithSymbolApplier.java index 9e8ea4885d..298eb1115f 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/WithSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/WithSymbolApplier.java @@ -15,10 +15,10 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractWithMsSymbol; -import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; @@ -37,7 +37,7 @@ public class WithSymbolApplier extends MsSymbolApplier { * @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed */ - public WithSymbolApplier(DefaultPdbApplicator applicator, AbstractMsSymbolIterator iter) { + public WithSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); if (!(abstractSymbol instanceof AbstractWithMsSymbol)) { diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/DummyPdb700.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/DummyPdb700.java index acef5afda9..6bab8bf1d7 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/DummyPdb700.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/DummyPdb700.java @@ -16,6 +16,8 @@ package ghidra.app.util.bin.format.pdb2.pdbreader; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import ghidra.app.util.bin.format.pdb2.pdbreader.msf.StubMsf; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; @@ -29,6 +31,9 @@ public class DummyPdb700 extends Pdb700 { private boolean debugInfoAvailable = true; + private Map dummyTypes = new HashMap<>(); + private Map dummyItems = new HashMap<>(); + //============================================================================================== // API //============================================================================================== @@ -42,8 +47,8 @@ public class DummyPdb700 extends Pdb700 { * @throws IOException upon file IO seek/read issues * @throws PdbException upon unknown value for configuration or error in processing components */ - public DummyPdb700(int tpiIndexMin, int tpiIndexMaxExclusive, - int ipiIndexMin, int ipiIndexMaxExclusive) throws IOException, PdbException { + public DummyPdb700(int tpiIndexMin, int tpiIndexMaxExclusive, int ipiIndexMin, + int ipiIndexMaxExclusive) throws IOException, PdbException { super(new StubMsf(), new PdbReaderOptions()); typeProgramInterface = new DummyTypeProgramInterface800(this, tpiIndexMin, tpiIndexMaxExclusive); @@ -76,7 +81,13 @@ public class DummyPdb700 extends Pdb700 { * @return {@code true} if successful */ public boolean setTypeRecord(int recordNumber, AbstractMsType type) { - return typeProgramInterface.setRecord(recordNumber, type); + int typeIndexMin = typeProgramInterface.getTypeIndexMin(); + if (recordNumber < typeIndexMin) { + return false; + } + RecordNumber record = RecordNumber.typeRecordNumber(recordNumber); + dummyTypes.put(record, type); + return true; } /** @@ -86,7 +97,10 @@ public class DummyPdb700 extends Pdb700 { * @return record number assigned */ public int addTypeRecord(AbstractMsType type) { - return typeProgramInterface.addRecord(type); + int newRecordNum = dummyTypes.size() + typeProgramInterface.getTypeIndexMin(); + RecordNumber record = RecordNumber.typeRecordNumber(newRecordNum); + dummyTypes.put(record, type); + return newRecordNum; } /** @@ -97,7 +111,13 @@ public class DummyPdb700 extends Pdb700 { * @return {@code true} if successful */ public boolean setItemRecord(int recordNumber, AbstractMsType type) { - return itemProgramInterface.setRecord(recordNumber, type); + int typeIndexMin = itemProgramInterface.getTypeIndexMin(); + if (recordNumber < typeIndexMin) { + return false; + } + RecordNumber record = RecordNumber.itemRecordNumber(recordNumber); + dummyItems.put(record, type); + return true; } /** @@ -107,7 +127,48 @@ public class DummyPdb700 extends Pdb700 { * @return record number assigned */ public int addItemRecord(AbstractMsType type) { - return itemProgramInterface.addRecord(type); + int newRecordNum = dummyItems.size() + itemProgramInterface.getTypeIndexMin(); + RecordNumber record = RecordNumber.itemRecordNumber(newRecordNum); + dummyItems.put(record, type); + return newRecordNum; + } + + @Override + public AbstractMsType getTypeRecord(RecordNumber recordNumber) { + return getTypeRecord(recordNumber, AbstractMsType.class); + } + + @Override + public T getTypeRecord(RecordNumber recordNumber, + Class typeClass) { + recordNumber = fixupTypeIndex(recordNumber, typeClass); + AbstractMsType msType = null; + if (recordNumber.getCategory() == RecordCategory.TYPE) { + int typeIndexMin = typeProgramInterface.getTypeIndexMin(); + if (recordNumber.getNumber() < typeIndexMin) { + msType = typeProgramInterface.getPrimitiveRecord(recordNumber.getNumber()); + } + else { + msType = dummyTypes.get(recordNumber); + } + } + else { + int typeIndexMin = itemProgramInterface.getTypeIndexMin(); + if (recordNumber.getNumber() < typeIndexMin) { + // Not sure there is such as thing as an item primitive + msType = itemProgramInterface.getPrimitiveRecord(recordNumber.getNumber()); + } + else { + msType = dummyItems.get(recordNumber); + } + } + if (!typeClass.isInstance(msType)) { + if (!recordNumber.isNoType()) { + PdbLog.logGetTypeClassMismatch(msType, typeClass); + } + return null; + } + return typeClass.cast(msType); } } diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/TypesTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/TypesTest.java index d278cbc5bc..0685a85556 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/TypesTest.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/TypesTest.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -1536,7 +1536,6 @@ public class TypesTest extends AbstractGenericTest { String result = type.toString().trim(); assertEquals("DummyMsType[0:REGISTER: al, Type: DummyMsType, registerSymbolName][0:void]", result); - } @Test