GP-3995 - PDB perf: No long load large components, maps, and lists; use

iterators
This commit is contained in:
ghizard 2023-11-16 15:28:37 -05:00 committed by Ryan Kurtz
parent c225fac124
commit 83ca81140a
47 changed files with 1139 additions and 982 deletions

View file

@ -15,13 +15,12 @@
*/ */
package pdbquery; package pdbquery;
import java.util.Map;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.util.bin.format.pdb2.pdbreader.*; 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.AbstractMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
import ghidra.app.util.bin.format.pdb2.pdbreader.type.PrimitiveMsType; import ghidra.app.util.bin.format.pdb2.pdbreader.type.PrimitiveMsType;
import ghidra.app.util.pdb.pdbapplicator.SymbolGroup;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@ -184,9 +183,10 @@ public class PdbQuery {
* @param pdb the PDB to search * @param pdb the PDB to search
* @param searchString the search string * @param searchString the search string
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
* @throws PdbException upon issue creating an iterator
*/ */
public static void searchSymbols(GhidraScript script, AbstractPdb pdb, String searchString) public static void searchSymbols(GhidraScript script, AbstractPdb pdb, String searchString)
throws CancelledException { throws CancelledException, PdbException {
PdbDebugInfo debugInfo = pdb.getDebugInfo(); PdbDebugInfo debugInfo = pdb.getDebugInfo();
if (debugInfo == null) { if (debugInfo == null) {
@ -198,40 +198,25 @@ public class PdbQuery {
int numModules = debugInfo.getNumModules(); int numModules = debugInfo.getNumModules();
TaskMonitor monitor = script.getMonitor(); TaskMonitor monitor = script.getMonitor();
int numSymbols = 0;
for (int module = 0; module <= numModules; module++) {
monitor.checkCancelled();
try {
Map<Long, AbstractMsSymbol> symbols = debugInfo.getModuleSymbolsByOffset(module);
numSymbols += symbols.size();
}
catch (PdbException e) {
// just skip the module... logging this in the next loop.
}
}
monitor.initialize(numSymbols); monitor.initialize(numModules);
println(script, "Searching " + numSymbols + " PDB symbol components..."); println(script, "Searching " + numModules + "PDB modules' symbol components...");
for (int module = 0; module <= numModules; module++) { for (int module = 0; module <= numModules; module++) {
monitor.checkCancelled(); monitor.checkCancelled();
try { SymbolGroup symbolGroup = new SymbolGroup(pdb, module);
Map<Long, AbstractMsSymbol> symbols = debugInfo.getModuleSymbolsByOffset(module); MsSymbolIterator iter = symbolGroup.getSymbolIterator();
numSymbols += symbols.size(); while (iter.hasNext()) {
for (Map.Entry<Long, AbstractMsSymbol> entry : symbols.entrySet()) { monitor.checkCancelled();
monitor.checkCancelled(); AbstractMsSymbol symbol = iter.next();
AbstractMsSymbol symbol = entry.getValue(); String symbolString = symbol.toString();
String symbolString = symbol.toString(); if (symbolString.contains(searchString)) {
if (symbolString.contains(searchString)) { results.append(
results.append("Module " + module + ", Offset " + entry.getKey() + ":\n"); "Module " + module + ", Offset " + iter.getCurrentOffset() + ":\n");
results.append(symbolString); results.append(symbolString);
results.append('\n'); results.append('\n');
}
monitor.incrementProgress(1);
} }
} }
catch (PdbException e) { monitor.incrementProgress(1);
Msg.debug(PdbQuery.class, "Skipping module " + module + " due to exception.");
}
} }
println(script, results.toString()); println(script, results.toString());
} }

View file

@ -149,7 +149,7 @@ public abstract class AbstractPdb implements AutoCloseable {
if (debugInfo != null) { if (debugInfo != null) {
try { try {
// dbiAge and targetProcessor set during deserialization of new DBI header // dbiAge and targetProcessor set during deserialization of new DBI header
debugInfo.deserialize(true); debugInfo.initialize(true);
} }
catch (CancelledException e) { catch (CancelledException e) {
throw new AssertException(e); // unexpected throw new AssertException(e); // unexpected
@ -328,9 +328,7 @@ public abstract class AbstractPdb implements AutoCloseable {
Class<T> typeClass) { Class<T> typeClass) {
recordNumber = fixupTypeIndex(recordNumber, typeClass); recordNumber = fixupTypeIndex(recordNumber, typeClass);
AbstractMsType msType = AbstractMsType msType =
getTPI(recordNumber.getCategory()).getRecord(recordNumber.getNumber()); getTPI(recordNumber.getCategory()).getRandomAccessRecord(recordNumber.getNumber());
// AbstractMsType msType =
// getTPI(recordNumber.getCategory()).getRandomAccessRecord(recordNumber.getNumber());
if (!typeClass.isInstance(msType)) { if (!typeClass.isInstance(msType)) {
if (!recordNumber.isNoType()) { if (!recordNumber.isNoType()) {
PdbLog.logGetTypeClassMismatch(msType, typeClass); PdbLog.logGetTypeClassMismatch(msType, typeClass);
@ -505,7 +503,7 @@ public abstract class AbstractPdb implements AutoCloseable {
typeProgramInterface = tpiParser.parse(this); typeProgramInterface = tpiParser.parse(this);
if (typeProgramInterface != null) { if (typeProgramInterface != null) {
typeProgramInterface.deserialize(); typeProgramInterface.initialize();
} }
boolean ipiStreamHasNoName = ItemProgramInterfaceParser.hackCheckNoNameForStream(nameTable); boolean ipiStreamHasNoName = ItemProgramInterfaceParser.hackCheckNoNameForStream(nameTable);
@ -514,7 +512,7 @@ public abstract class AbstractPdb implements AutoCloseable {
ItemProgramInterfaceParser ipiParser = new ItemProgramInterfaceParser(); ItemProgramInterfaceParser ipiParser = new ItemProgramInterfaceParser();
itemProgramInterface = ipiParser.parse(this); itemProgramInterface = ipiParser.parse(this);
if (itemProgramInterface != null) { if (itemProgramInterface != null) {
itemProgramInterface.deserialize(); itemProgramInterface.initialize();
} }
//processDependencyIndexPairList(); //processDependencyIndexPairList();
//dumpDependencyGraph(); //dumpDependencyGraph();
@ -522,7 +520,7 @@ public abstract class AbstractPdb implements AutoCloseable {
parseDBI(); parseDBI();
if (debugInfo != null) { if (debugInfo != null) {
debugInfo.deserialize(false); debugInfo.initialize(false);
} }
substreamsDeserialized = true; substreamsDeserialized = true;

View file

@ -19,7 +19,8 @@ import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.util.*; 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; 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 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 // Internals
//============================================================================================== //==============================================================================================
protected AbstractPdb pdb; protected AbstractPdb pdb;
protected int numHashRecords; protected int streamNumber;
protected int numExtraBytes;
protected int hashRecordsBitMapLength;
protected int symbolHashLength;
protected int symbolHashOffset;
protected int hashHeaderLength;
protected int headerSignature; protected int headerSignature;
protected int versionNumber; protected int versionNumber;
protected int hashRecordsLength; protected int hashRecordsLength;
protected int bucketsLength; protected int bucketsLength;
protected int hashRecordsOffset;
protected int bucketsOffset;
// These are read from "buckets." protected int numHashRecords;
protected List<Integer> hashBucketOffsets = new ArrayList<>(); protected int numExtraBytes;
protected Set<SymbolHashRecord> hashRecords = new TreeSet<>(); protected int hashRecordsBitMapLength;
protected List<Long> modifiedHashRecordSymbolOffsets = new ArrayList<>();
protected List<AbstractMsSymbol> symbols = new ArrayList<>();
//============================================================================================== //==============================================================================================
// API // API
@ -63,41 +70,84 @@ public abstract class AbstractSymbolInformation {
/** /**
* Constructor * Constructor
* @param pdbIn {@link AbstractPdb} that owns the Abstract Symbol Information to process * @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; pdb = pdbIn;
} this.streamNumber = streamNumber;
/**
* Returns the list of symbols for this {@link AbstractSymbolInformation}
* @return the symbols
*/
public List<AbstractMsSymbol> getSymbols() {
return symbols;
} }
/** /**
* Returns the Offsets of symbols within the symbol table; these are gotten from the * 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 * HashRecords and modified to point to the size field of the symbols in the symbol table
* @return offsets * @return offsets
* @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation
*/ */
public List<Long> getModifiedHashRecordSymbolOffsets() { public List<Long> getModifiedHashRecordSymbolOffsets() throws CancelledException, PdbException {
return modifiedHashRecordSymbolOffsets; return generateModifiedSymbolOffsets();
} }
//============================================================================================== //==============================================================================================
// Package-Protected Internals // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Deserialize the {@link AbstractSymbolInformation} from the appropriate stream in the Pdb * Parses and returns the hash bucket offsets
* @param streamNumber the stream number containing the information to deserialize * @return the offsets
* @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation
*/
List<Integer> 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<SymbolHashRecord> 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 * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* inability to read required bytes * inability to read required bytes
* @throws PdbException upon not enough data left to parse * @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
void deserialize(int streamNumber) abstract void initialize() throws IOException, PdbException, CancelledException;
throws IOException, PdbException, CancelledException {
/**
* Initializes values such as offset, lengths, and numbers
*/
void initializeValues() {
if (pdb.hasMinimalDebugInfo()) { if (pdb.hasMinimalDebugInfo()) {
hashRecordsBitMapLength = 0x8000; hashRecordsBitMapLength = 0x8000;
numExtraBytes = 0; // I believe; numExtraBytes = 0; // I believe;
@ -113,10 +163,11 @@ public abstract class AbstractSymbolInformation {
/** /**
* Debug method for dumping information from this {@link AbstractSymbolInformation} * Debug method for dumping information from this {@link AbstractSymbolInformation}
* @param writer {@link Writer} to which to dump the information * @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 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(); StringBuilder builder = new StringBuilder();
builder.append("AbstractSymbolInformation-----------------------------------\n"); builder.append("AbstractSymbolInformation-----------------------------------\n");
dumpHashHeader(builder); dumpHashHeader(builder);
@ -160,35 +211,34 @@ public abstract class AbstractSymbolInformation {
/** /**
* Generates a list of symbols from the information that we have * 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 * @throws CancelledException upon user cancellation
*/ */
protected void generateSymbolsList() protected List<Long> generateModifiedSymbolOffsets() throws PdbException, CancelledException {
throws PdbException, CancelledException { List<Long> modifiedHashRecordSymbolOffsets = new ArrayList<>();
symbols = new ArrayList<>();
PdbDebugInfo debugInfo = pdb.getDebugInfo(); PdbDebugInfo debugInfo = pdb.getDebugInfo();
if (debugInfo == null) { if (debugInfo == null) {
return; return modifiedHashRecordSymbolOffsets;
} }
Map<Long, AbstractMsSymbol> symbolsByOffset = debugInfo.getSymbolsByOffset(); Set<SymbolHashRecord> hashRecords = getHashRecords();
for (SymbolHashRecord record : hashRecords) { for (SymbolHashRecord record : hashRecords) {
pdb.checkCancelled(); pdb.checkCancelled();
long offset = record.getOffset() - 2; // Modified offset long offset = record.getOffset() - 2; // Modified offset
AbstractMsSymbol symbol = symbolsByOffset.get(offset);
modifiedHashRecordSymbolOffsets.add(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} * Debug method for dumping hash records from this {@link AbstractSymbolInformation}
* @param builder {@link StringBuilder} to which to dump the information * @param builder {@link StringBuilder} to which to dump the information
* @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
protected void dumpHashRecords(StringBuilder builder) throws CancelledException { protected void dumpHashRecords(StringBuilder builder)
throws CancelledException, PdbException {
Set<SymbolHashRecord> hashRecords = getHashRecords();
builder.append("HashRecords-------------------------------------------------\n"); builder.append("HashRecords-------------------------------------------------\n");
builder.append("numHashRecords: " + hashRecords.size() + "\n"); builder.append("numHashRecords: " + hashRecords.size() + "\n");
for (SymbolHashRecord record : hashRecords) { for (SymbolHashRecord record : hashRecords) {
@ -199,31 +249,12 @@ public abstract class AbstractSymbolInformation {
builder.append("\nEnd HashRecords---------------------------------------------\n"); builder.append("\nEnd HashRecords---------------------------------------------\n");
} }
/** protected void deserializeHashHeader() throws PdbException, CancelledException, IOException {
* Deserializes the hash table for the symbols MsfStream stream = pdb.getMsf().getStream(streamNumber);
* @param reader {@link PdbByteReader} containing the data buffer to process PdbByteReader reader =
* @throws PdbException upon not enough data left to parse pdb.getReaderForStreamNumber(streamNumber, symbolHashOffset,
* @throws CancelledException upon user cancellation HASH_HEADER_MIN_READ_LENGTH);
*/ deserializeHashHeader(reader, stream.getLength());
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);
}
} }
/** /**
@ -231,81 +262,28 @@ public abstract class AbstractSymbolInformation {
* @param reader {@link PdbByteReader} containing the data buffer to process * @param reader {@link PdbByteReader} containing the data buffer to process
* @throws PdbException upon not enough data left to parse * @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(); headerSignature = reader.parseInt();
versionNumber = reader.parseInt(); if (headerSignature == HEADER_SIGNATURE) {
hashRecordsLength = reader.parseInt(); hashHeaderLength = HASH_70_HEADER_LENGTH;
bucketsLength = reader.parseInt(); versionNumber = reader.parseInt();
} hashRecordsLength = reader.parseInt();
bucketsLength = reader.parseInt();
/** hashRecordsOffset = symbolHashOffset + reader.getIndex();
* Deserialize the body of the {@link AbstractSymbolInformation} according to the GSI versions bucketsOffset = hashRecordsOffset + hashRecordsLength;
* 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");
} }
int numRecordsBytes = (reader.numRemaining() - numBucketsBytes); else {
hashHeaderLength = HASH_PRE70_HEADER_LENGTH;
PdbByteReader hashRecordsReader = reader.getSubPdbByteReader(numRecordsBytes); reader.reset(); // There was no header
PdbByteReader bucketsReader = reader.getSubPdbByteReader(numBucketsBytes); // Calculate the values
if (reader.hasMore()) { bucketsLength = 4 * (numHashRecords + 1);
throw new PdbException("Unexpected extra information at and of GSI stream"); 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 PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
private void deserializedCompressedHashBuckets(PdbByteReader reader) private List<Integer> deserializedCompressedHashBuckets(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
List<Integer> hashBucketOffsets = new ArrayList<>();
PdbByteReader bitEncoderReader = reader.getSubPdbByteReader(hashRecordsBitMapLength); PdbByteReader bitEncoderReader = reader.getSubPdbByteReader(hashRecordsBitMapLength);
// Throw away extra bytes between bit map and buckets. // Throw away extra bytes between bit map and buckets.
reader.getSubPdbByteReader(numExtraBytes); reader.getSubPdbByteReader(numExtraBytes);
@ -349,24 +329,154 @@ public abstract class AbstractSymbolInformation {
throw new PdbException("Compressed GSI Hash Buckets corrupt"); 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 * @param reader {@link PdbByteReader} containing the data buffer to process
* @throws PdbException upon not enough data left to parse * @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
private void deserializeHashRecords(PdbByteReader reader) private List<Integer> deserializedHashBuckets(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
hashRecords = new TreeSet<>(); List<Integer> 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<SymbolHashRecord> deserializeHashRecords(PdbByteReader reader)
throws PdbException, CancelledException {
Set<SymbolHashRecord> hashRecords = new TreeSet<>();
while (reader.hasMore()) { while (reader.hasMore()) {
pdb.checkCancelled(); pdb.checkCancelled();
SymbolHashRecord record = new SymbolHashRecord(); SymbolHashRecord record = new SymbolHashRecord();
record.parse(reader); record.parse(reader);
hashRecords.add(record); 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<Long> {
//
// 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);
// }
// }
} }

View file

@ -66,17 +66,6 @@ public class DebugData {
private AbstractPdb pdb; private AbstractPdb pdb;
private List<Integer> debugStreams = new ArrayList<>(); private List<Integer> debugStreams = new ArrayList<>();
private List<FramePointerOmissionRecord> framePointerOmissionData;
// private SortedMap<Long, Long> omapToSource;
private SortedMap<Long, Long> omapFromSource;
private List<ImageSectionHeader> imageSectionHeaders;
private List<ImageSectionHeader> imageSectionHeadersOrig;
private List<ImageFunctionEntry> pData;
private RvaVaDebugHeader xDataHeader;
private PdbByteReader xDataReader;
//============================================================================================== //==============================================================================================
// API // API
//============================================================================================== //==============================================================================================
@ -92,9 +81,18 @@ public class DebugData {
/** /**
* Returns the Frame Pointer Omission data * Returns the Frame Pointer Omission data
* @return the framePointerOmissionData or null if does not exist * @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<FramePointerOmissionRecord> getFramePointerOmissionData() { public List<FramePointerOmissionRecord> getFramePointerOmissionData()
return framePointerOmissionData; 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 * Returns the OMAP_FROM_SOURCE mapping of RVA to RVA
* @return the omapFromSource or null if does not exist. * @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<Long, Long> getOmapFromSource() { public SortedMap<Long, Long> getOmapFromSource()
return omapFromSource; 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}&lt;{@link ImageSectionHeader}&gt; * Returns the {@link List}&lt;{@link ImageSectionHeader}&gt;
* @return the imageSectionHeaders or null if does not exist * @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<ImageSectionHeader> getImageSectionHeaders() { public List<ImageSectionHeader> getImageSectionHeaders()
return imageSectionHeaders; 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<ImageFunctionEntry> 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 * When this returns a non-null list the OMAP_FROM_SRC should be
* used for remapping global symbols * used for remapping global symbols
* @return the imageSectionHeadersOrig or null if does not exist * @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<ImageSectionHeader> getImageSectionHeadersOrig() { public List<ImageSectionHeader> getImageSectionHeadersOrig()
return imageSectionHeadersOrig; 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 * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* inability to read required bytes * inability to read required bytes
*/ */
@Deprecated
public void deserialize() public void deserialize()
throws PdbException, CancelledException, IOException { throws PdbException, CancelledException, IOException {
if (debugStreams.isEmpty()) { if (debugStreams.isEmpty()) {
@ -178,7 +243,7 @@ public class DebugData {
} }
switch (dbg) { switch (dbg) {
case FRAME_POINTER_OMISSION: case FRAME_POINTER_OMISSION:
deserializeFramePointerOmissionData(streamNum); // framePointerOmissionData = deserializeFramePointerOmissionData(streamNum);
break; break;
case EXCEPTION: case EXCEPTION:
// TODO: implement. // TODO: implement.
@ -190,42 +255,44 @@ public class DebugData {
// omapToSource = deserializeOMap(streamNum); // omapToSource = deserializeOMap(streamNum);
break; break;
case OMAP_FROM_SOURCE: case OMAP_FROM_SOURCE:
omapFromSource = deserializeOMap(streamNum); // omapFromSource = deserializeOMap(streamNum);
break; break;
case SECTION_HEADER: case SECTION_HEADER:
imageSectionHeaders = deserializeSectionHeaders(streamNum); // imageSectionHeaders = deserializeSectionHeaders(streamNum);
break; break;
case TOKEN_RID_MAP: case TOKEN_RID_MAP:
// TODO: implement. // TODO: implement.
break; break;
case X_DATA: case X_DATA:
deserializeXData(streamNum); // DUMMY Integer return value for now
// Integer xData = deserializeXData(streamNum);
break; break;
case P_DATA: case P_DATA:
deserializePData(streamNum); // pData = deserializePData(streamNum);
break; break;
case NEW_FRAME_POINTER_OMISSION: case NEW_FRAME_POINTER_OMISSION:
// TODO: implement. // TODO: implement.
break; break;
case SECTION_HEADER_ORIG: case SECTION_HEADER_ORIG:
imageSectionHeadersOrig = deserializeSectionHeaders(streamNum); // imageSectionHeadersOrig = deserializeSectionHeaders(streamNum);
break; break;
} }
} }
} }
private void deserializeFramePointerOmissionData(int streamNum) private List<FramePointerOmissionRecord> deserializeFramePointerOmissionData(int streamNum)
throws PdbException, CancelledException, IOException { throws PdbException, CancelledException, IOException {
// TODO: check implementation for completeness. // TODO: check implementation for completeness.
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
framePointerOmissionData = new ArrayList<>(); List<FramePointerOmissionRecord> fpOmissionData = new ArrayList<>();
while (reader.hasMore()) { while (reader.hasMore()) {
pdb.checkCancelled(); pdb.checkCancelled();
FramePointerOmissionRecord framePointerOmissionRecord = FramePointerOmissionRecord framePointerOmissionRecord =
new FramePointerOmissionRecord(); new FramePointerOmissionRecord();
framePointerOmissionRecord.parse(reader); framePointerOmissionRecord.parse(reader);
framePointerOmissionData.add(framePointerOmissionRecord); fpOmissionData.add(framePointerOmissionRecord);
} }
return fpOmissionData;
} }
private SortedMap<Long, Long> deserializeOMap(int streamNum) private SortedMap<Long, Long> deserializeOMap(int streamNum)
@ -259,17 +326,18 @@ public class DebugData {
* See the {@link LinkerUnwindInfo} class that was built for and is pertinent to * See the {@link LinkerUnwindInfo} class that was built for and is pertinent to
* processing XData * 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 { throws PdbException, CancelledException, IOException {
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
int streamLength = reader.getLimit(); int streamLength = reader.getLimit();
//System.out.println(reader.dump(0x20)); //System.out.println(reader.dump(0x20));
RvaVaDebugHeader header = new RvaVaDebugHeader(); RvaVaDebugHeader header = new RvaVaDebugHeader();
xDataHeader = header;
header.deserialize(reader); header.deserialize(reader);
//System.out.println(header.dump()); //System.out.println(header.dump());
if (header.getHeaderVersion() != 1) { if (header.getHeaderVersion() != 1) {
return; // Silent... TODO: add logging event. return null; // Silent... TODO: add logging event.
} }
long headerLength = header.getHeaderLength(); long headerLength = header.getHeaderLength();
long dataLength = header.getDataLength(); long dataLength = header.getDataLength();
@ -278,25 +346,27 @@ public class DebugData {
} }
reader.setIndex((int) headerLength); reader.setIndex((int) headerLength);
//System.out.println(reader.dump()); //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 // 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 // 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 // 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 // for these machines is not real clear (or a bit of work), and there is no other
// interpretation available when the machine is different. // interpretation available when the machine is different.
return null;
} }
// TODO: This is incomplete. // TODO: This is incomplete.
private void deserializePData(int streamNum) private List<ImageFunctionEntry> deserializePData(int streamNum)
throws PdbException, CancelledException, IOException { throws PdbException, CancelledException, IOException {
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
pData = new ArrayList<>(); List<ImageFunctionEntry> myPData = new ArrayList<>();
int streamLength = reader.getLimit(); int streamLength = reader.getLimit();
RvaVaDebugHeader header = new RvaVaDebugHeader(); RvaVaDebugHeader header = new RvaVaDebugHeader();
header.deserialize(reader); header.deserialize(reader);
//System.out.println(header.dump()); //System.out.println(header.dump());
if (header.getHeaderVersion() != 1) { if (header.getHeaderVersion() != 1) {
return; // Silent... TODO: add logging event. return myPData; // Silent... TODO: add logging event.
} }
long headerLength = header.getHeaderLength(); long headerLength = header.getHeaderLength();
long dataLength = header.getDataLength(); long dataLength = header.getDataLength();
@ -335,6 +405,7 @@ public class DebugData {
break; break;
} }
} }
return myPData;
} }
/** /**
@ -342,12 +413,14 @@ public class DebugData {
* @param writer {@link Writer} to which to write the debug dump * @param writer {@link Writer} to which to write the debug dump
* @throws IOException on issue writing to the {@link Writer} * @throws IOException on issue writing to the {@link Writer}
* @throws CancelledException upon user cancellation * @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"); writer.write("DebugData---------------------------------------------------\n");
dumpDebugStreamList(writer); dumpDebugStreamList(writer);
writer.write("FramePointerOmissionData------------------------------------\n"); writer.write("FramePointerOmissionData------------------------------------\n");
List<FramePointerOmissionRecord> framePointerOmissionData = getFramePointerOmissionData();
if (framePointerOmissionData != null) { if (framePointerOmissionData != null) {
for (FramePointerOmissionRecord framePointerOmissionRecord : framePointerOmissionData) { for (FramePointerOmissionRecord framePointerOmissionRecord : framePointerOmissionData) {
pdb.checkCancelled(); pdb.checkCancelled();
@ -368,6 +441,7 @@ public class DebugData {
// writer.write("End OmapToSource--------------------------------------------\n"); // writer.write("End OmapToSource--------------------------------------------\n");
// //
writer.write("OmapFromSource----------------------------------------------\n"); writer.write("OmapFromSource----------------------------------------------\n");
SortedMap<Long, Long> omapFromSource = getOmapFromSource();
if (omapFromSource != null) { if (omapFromSource != null) {
int num = 0; int num = 0;
for (Map.Entry<Long, Long> entry : omapFromSource.entrySet()) { for (Map.Entry<Long, Long> entry : omapFromSource.entrySet()) {
@ -379,6 +453,7 @@ public class DebugData {
writer.write("End OmapFromSource------------------------------------------\n"); writer.write("End OmapFromSource------------------------------------------\n");
writer.write("ImageSectionHeaders-----------------------------------------\n"); writer.write("ImageSectionHeaders-----------------------------------------\n");
List<ImageSectionHeader> imageSectionHeaders = getImageSectionHeaders();
if (imageSectionHeaders != null) { if (imageSectionHeaders != null) {
int sectionNum = 0; int sectionNum = 0;
for (ImageSectionHeader imageSectionHeader : imageSectionHeaders) { for (ImageSectionHeader imageSectionHeader : imageSectionHeaders) {
@ -389,6 +464,7 @@ public class DebugData {
writer.write("End ImageSectionHeaders-------------------------------------\n"); writer.write("End ImageSectionHeaders-------------------------------------\n");
writer.write("ImageSectionHeadersOrig-------------------------------------\n"); writer.write("ImageSectionHeadersOrig-------------------------------------\n");
List<ImageSectionHeader> imageSectionHeadersOrig = getImageSectionHeadersOrig();
if (imageSectionHeadersOrig != null) { if (imageSectionHeadersOrig != null) {
int sectionNum = 0; int sectionNum = 0;
for (ImageSectionHeader imageSectionHeader : imageSectionHeadersOrig) { for (ImageSectionHeader imageSectionHeader : imageSectionHeadersOrig) {
@ -399,6 +475,7 @@ public class DebugData {
writer.write("End ImageSectionHeadersOrig---------------------------------\n"); writer.write("End ImageSectionHeadersOrig---------------------------------\n");
writer.write("PData-------------------------------------------------------\n"); writer.write("PData-------------------------------------------------------\n");
List<ImageFunctionEntry> pData = getPData();
if (pData != null) { if (pData != null) {
for (ImageFunctionEntry entry : pData) { for (ImageFunctionEntry entry : pData) {
pdb.checkCancelled(); pdb.checkCancelled();

View file

@ -15,12 +15,10 @@
*/ */
package ghidra.app.util.bin.format.pdb2.pdbreader; package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream; import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
/** /**
@ -93,17 +91,10 @@ class GlobalReferenceIterator implements ParsingIterator<MsSymbolIterator> {
currentGlobalSymbolIterator = null; currentGlobalSymbolIterator = null;
return; return;
} }
try { Long offset = offsetIterator.next();
Long offset = offsetIterator.next(); currentGlobalSymbolIterator =
PdbByteReader reader = new MsSymbolIterator(pdb, symbolsStreamNumber, offset.intValue(),
pdb.getReaderForStreamNumber(symbolsStreamNumber, offset.intValue(), MsfStream.MAX_STREAM_LENGTH);
MsfStream.MAX_STREAM_LENGTH);
currentGlobalSymbolIterator = new MsSymbolIterator(pdb, reader);
}
catch (IOException e) {
Msg.error(this, "Problem seen in find()", e);
currentGlobalSymbolIterator = null;
}
} }
} }

View file

@ -18,6 +18,7 @@ package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
/** /**
@ -34,38 +35,42 @@ public class GlobalSymbolInformation extends AbstractSymbolInformation {
/** /**
* Constructor. * Constructor.
* @param pdbIn {@link AbstractPdb} that owns the Global Symbol Information to process. * @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) { public GlobalSymbolInformation(AbstractPdb pdbIn, int streamNumber) {
super(pdbIn); super(pdbIn, streamNumber);
} }
/** /**
* Deserialize the {@link GlobalSymbolInformation} from the appropriate stream in the Pdb * Deserializes and intializes {@link GlobalSymbolInformation} basic information from the
* @param streamNumber the stream number containing the information to deserialize * 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 * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* inability to read required bytes * inability to read required bytes
* @throws PdbException upon not enough data left to parse * @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
@Override @Override
void deserialize(int streamNumber) void initialize() throws IOException, PdbException, CancelledException {
throws IOException, PdbException, CancelledException { initializeValues();
super.deserialize(streamNumber); initializeGlobalOffsetsAndLengths();
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber); deserializeHashHeader();
deserializeHashTable(reader); }
// Organize the information private void initializeGlobalOffsetsAndLengths() {
generateSymbolsList(); symbolHashOffset = 0;
MsfStream stream = pdb.getMsf().getStream(streamNumber);
symbolHashLength = (stream == null) ? 0 : stream.getLength();
} }
/** /**
* Debug method for dumping information from this {@link GlobalSymbolInformation} * Debug method for dumping information from this {@link GlobalSymbolInformation}
* @param writer {@link Writer} to which to dump the information * @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 CancelledException upon user cancellation
* @throws PdbException upon not enough data left to parse
*/ */
@Override @Override
void dump(Writer writer) throws IOException, CancelledException { void dump(Writer writer) throws IOException, CancelledException, PdbException {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("GlobalSymbolInformation-------------------------------------\n"); builder.append("GlobalSymbolInformation-------------------------------------\n");
dumpHashHeader(builder); dumpHashHeader(builder);

View file

@ -126,13 +126,13 @@ public class Module {
* Returns an MsSymbolIterator for the symbols of this module * Returns an MsSymbolIterator for the symbols of this module
* @return the iterator * @return the iterator
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
* @throws IOException upon error reading stream
* @throws PdbException upon invalid cvSignature * @throws PdbException upon invalid cvSignature
*/ */
public MsSymbolIterator getSymbolIterator() throws CancelledException, PdbException { public MsSymbolIterator iterator() throws CancelledException, IOException, PdbException {
PdbByteReader symbolsReader = getSymbolsReader(); int startingOffset = pdb.getDebugInfo().getSymbolRecords().getCvSigLength(streamNumber);
parseSignature(symbolsReader); int lengthSymbols = moduleInformation.getSizeLocalSymbolsDebugInformation();
MsSymbolIterator iterator = new MsSymbolIterator(pdb, symbolsReader); return new MsSymbolIterator(pdb, streamNumber, startingOffset, lengthSymbols);
return iterator;
} }
private void parseSignature(PdbByteReader symbolsReader) throws PdbException { private void parseSignature(PdbByteReader symbolsReader) throws PdbException {
@ -333,13 +333,14 @@ public class Module {
private void dumpSymbols(Writer writer) private void dumpSymbols(Writer writer)
throws IOException, CancelledException, PdbException { throws IOException, CancelledException, PdbException {
writer.write("Symbols-----------------------------------------------------\n"); writer.write("Symbols-----------------------------------------------------");
MsSymbolIterator symbolIterator = getSymbolIterator(); MsSymbolIterator symbolIter = iterator();
while (symbolIterator.hasNext()) { while (symbolIter.hasNext()) {
pdb.checkCancelled(); 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(symbol.toString());
writer.append("\n");
} }
writer.write("End Symbols-------------------------------------------------\n"); writer.write("End Symbols-------------------------------------------------\n");
} }

View file

@ -15,71 +15,136 @@
*/ */
package ghidra.app.util.bin.format.pdb2.pdbreader; package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.util.Iterator;
import java.util.NoSuchElementException; 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.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.util.Msg; import ghidra.app.util.pdb.pdbapplicator.SymbolGroup;
import ghidra.util.exception.CancelledException; 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<AbstractMsSymbol> { public class MsSymbolIterator implements Iterator<AbstractMsSymbol> {
private AbstractPdb pdb; private int streamNumber;
private PdbByteReader reader; 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. * Peeks at and returns the next symbol without incrementing to the next. If none are
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed * left, then throws NoSuchElementException and reinitializes the state for a new
* @param reader for the stream section containing the symbol information * iteration.
* @throws CancelledException upon user cancellation * @see #initGet()
* @return the next symbol
* @throws NoSuchElementException if there are no more elements
*/ */
public MsSymbolIterator(AbstractPdb pdb, PdbByteReader reader) throws CancelledException { public AbstractMsSymbol peek() throws NoSuchElementException {
this.pdb = pdb; if (symLen == null) {
this.reader = reader; throw new NoSuchElementException();
}
return symLen.symbol();
} }
@Override @Override
public boolean hasNext() throws CancelledException { public AbstractMsSymbol next() {
if (currentSymbol == null) { if (symLen == null) {
find(); throw new NoSuchElementException();
} }
return (currentSymbol != null); SymbolRecords.SymLen offer = symLen;
currentOffset = nextRetrieveOffset;
symLen = retrieveRecord();
return offer.symbol();
} }
@Override private SymbolRecords.SymLen retrieveRecord() {
public AbstractMsSymbol next() throws CancelledException, NoSuchElementException { if (streamNumber == MsfStream.NIL_STREAM_NUMBER) {
if (hasNext()) { return null;
AbstractMsSymbol returnSymbol = currentSymbol;
currentSymbol = null;
return returnSymbol;
} }
throw new NoSuchElementException("next() called with no more elements"); if (nextRetrieveOffset >= lengthSymbols) {
} return null;
@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;
} }
try { try {
currentSymbol = SymbolParser.parseLengthAndSymbol(pdb, reader); SymbolRecords.SymLen retrieved =
symbolRecords.getRandomAccessRecord(streamNumber, nextRetrieveOffset);
if (retrieved != null) {
nextRetrieveOffset += retrieved.length();
}
return retrieved;
} }
catch (PdbException e) { catch (PdbException | CancelledException e) {
Msg.error(this, "Problem seen in find()", e); return null;
currentSymbol = 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;
}
} }

View file

@ -69,14 +69,10 @@ public abstract class PdbDebugInfo {
protected List<SectionContribution> sectionContributionList = new ArrayList<>(); protected List<SectionContribution> sectionContributionList = new ArrayList<>();
protected List<SegmentMapDescription> segmentMapList = new ArrayList<>(); protected List<SegmentMapDescription> segmentMapList = new ArrayList<>();
protected SymbolRecords symbolRecords; protected SymbolRecords symbolRecords = null;
protected GlobalSymbolInformation globalSymbolInformation; protected GlobalSymbolInformation globalSymbolInformation = null;
protected PublicSymbolInformation publicSymbolInformation; 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<Module> modules = new ArrayList<>(); private List<Module> modules = new ArrayList<>();
//============================================================================================== //==============================================================================================
@ -91,9 +87,6 @@ public abstract class PdbDebugInfo {
Objects.requireNonNull(pdb, "pdb cannot be null"); Objects.requireNonNull(pdb, "pdb cannot be null");
this.pdb = pdb; this.pdb = pdb;
this.streamNumber = streamNumber; 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 * The PDB is updated with dbiAge and targetProcessor during deserialization
* of new DBI header. * of new DBI header.
* @param headerOnly if true only the DBI header fields will be parsed * @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 PdbException upon error parsing a field
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
public long deserialize(boolean headerOnly) public long initialize(boolean headerOnly)
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
if (headerOnly) { if (headerOnly) {
PdbByteReader reader = PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, 0, getHeaderLength());
pdb.getReaderForStreamNumber(streamNumber, 0, getHeaderLength());
deserializeHeader(reader); deserializeHeader(reader);
} }
else { else {
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber);
deserializeHeader(reader); deserializeHeader(reader);
deserializeInternalSubstreams(reader); deserializeInternalSubstreams(reader);
deserializeAdditionalSubstreams(); globalSymbolInformation =
// BELOW: NEW STUFF FROM REFACTOR/REWORK (can be duplicative with other stuff) new GlobalSymbolInformation(pdb, getGlobalSymbolsHashMaybeStreamNumber());
if (doNewStuff) { publicSymbolInformation =
parseModules(); new PublicSymbolInformation(pdb, getPublicStaticSymbolsHashMaybeStreamNumber());
compareSymbols(); //temporary to ensure same results with previous work. symbolRecords = new SymbolRecords(pdb);
} initializeAdditionalComponentsForSubstreams();
// ABOVE: NEW STUFF FROM REFACTOR/REWORK (can be duplicative with other stuff) initializeModules();
//compareSymbols(); //temporary to ensure same results with previous work.
} }
return versionNumber; return versionNumber;
} }
@ -170,63 +163,6 @@ public abstract class PdbDebugInfo {
return moduleInfo; return moduleInfo;
} }
/**
* Returns the list of combined global/public symbols
* @return {@link Map}&lt;{@link Long},{@link AbstractMsSymbol}&gt; of buffer offsets to
* symbols
*/
public Map<Long, AbstractMsSymbol> 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}&lt;{@link Long},{@link AbstractMsSymbol}&gt; of buffer offsets to
* symbols for the specified module
* @throws PdbException upon moduleNumber out of range or no module information
*/
public Map<Long, AbstractMsSymbol> 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<Long, AbstractMsSymbol> symbols = getModuleSymbolsByOffset(moduleNumber);
if (symbols == null) {
return null;
}
return symbols.get(offset - 4);
}
/** /**
* Returns list of {@link SectionContribution} for this debug info * Returns list of {@link SectionContribution} for this debug info
* @return list of {@link SectionContribution} * @return list of {@link SectionContribution}
@ -278,6 +214,12 @@ public abstract class PdbDebugInfo {
//============================================================================================== //==============================================================================================
// Package-Protected Internals // 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 * Returns the stream number for the GlobalSymbols component
* @return stream number * @return stream number
@ -326,7 +268,7 @@ public abstract class PdbDebugInfo {
* @throws PdbException upon error parsing a field * @throws PdbException upon error parsing a field
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
protected abstract void deserializeAdditionalSubstreams() protected abstract void initializeAdditionalComponentsForSubstreams()
throws IOException, PdbException, CancelledException; throws IOException, PdbException, CancelledException;
/** /**
@ -351,9 +293,10 @@ public abstract class PdbDebugInfo {
* @param writer {@link Writer} to which to write the debug dump * @param writer {@link Writer} to which to write the debug dump
* @throws IOException on issue writing to the {@link Writer} * @throws IOException on issue writing to the {@link Writer}
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
* @throws PdbException upon not enough data left to parse
*/ */
protected abstract void dumpInternalSubstreams(Writer writer) protected abstract void dumpInternalSubstreams(Writer writer)
throws IOException, CancelledException; throws IOException, CancelledException, PdbException;
//============================================================================================== //==============================================================================================
// Internal Data Methods // Internal Data Methods
@ -556,12 +499,10 @@ public abstract class PdbDebugInfo {
globalSymbolInformation.dump(writer); globalSymbolInformation.dump(writer);
writer.write("\n"); writer.write("\n");
publicSymbolInformation.dump(writer); publicSymbolInformation.dump(writer);
if (doNewStuff) { dumpSymbols(writer);
dumpSymbols(writer); for (Module module : modules) {
for (Module module : modules) { pdb.checkCancelled();
pdb.checkCancelled(); module.dump(writer);
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. * Initializes modules with some basic information, enabling later queries of the modules
private void parseModules() throws CancelledException { * @throws CancelledException upon user cancellation
*/
private void initializeModules() throws CancelledException {
for (ModuleInformation moduleInformation : moduleInformationList) { for (ModuleInformation moduleInformation : moduleInformationList) {
pdb.checkCancelled(); pdb.checkCancelled();
Module module = new Module(pdb, moduleInformation); Module module = new Module(pdb, moduleInformation);
@ -634,21 +577,14 @@ public abstract class PdbDebugInfo {
return modules.get(moduleNum); 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 * @return an iterator over all symbols of the module
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
* @throws IOException upon issue reading the stream * @throws PdbException upon not enough data left to parse
*/ */
public MsSymbolIterator getSymbolIterator() MsSymbolIterator getSymbolIterator() throws CancelledException, PdbException {
throws CancelledException, IOException { return new MsSymbolIterator(pdb, streamNumberSymbolRecords, 0, MsfStream.MAX_STREAM_LENGTH);
if (streamNumberSymbolRecords == MsfStream.NIL_STREAM_NUMBER) {
return null;
}
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumberSymbolRecords);
MsSymbolIterator iterator = new MsSymbolIterator(pdb, reader);
return iterator;
} }
/** /**
@ -657,25 +593,26 @@ public abstract class PdbDebugInfo {
* @return an iterator over all symbols of the module * @return an iterator over all symbols of the module
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
* @throws PdbException upon not enough data left to parse * @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); Module module = modules.get(moduleNum);
return module.getSymbolIterator(); return module.iterator();
} }
private void dumpSymbols(Writer writer) throws CancelledException, IOException { private void dumpSymbols(Writer writer) throws CancelledException, IOException, PdbException {
MsSymbolIterator iterator = getSymbolIterator(); MsSymbolIterator iteratorx = getSymbolIterator();
List<AbstractMsSymbol> symbols = new ArrayList<>(); List<AbstractMsSymbol> symbols = new ArrayList<>();
while (iterator.hasNext()) { while (iteratorx.hasNext()) {
pdb.checkCancelled(); pdb.checkCancelled();
symbols.add(iterator.next()); symbols.add(iteratorx.next());
} }
} }
// This method is temporary. It only exists for ensuring results as we transition processing // This method is temporary. It only exists for ensuring results as we transition processing
// mechanisms. // mechanisms.
private void compareSymbols() private void compareSymbols() throws CancelledException, PdbException, IOException {
throws CancelledException, PdbException, IOException {
PdbDebugInfo debugInfo = pdb.getDebugInfo(); PdbDebugInfo debugInfo = pdb.getDebugInfo();
if (debugInfo == null) { if (debugInfo == null) {
return; return;
@ -713,7 +650,7 @@ public abstract class PdbDebugInfo {
for (int modnum = 0; modnum < numModules(); modnum++) { for (int modnum = 0; modnum < numModules(); modnum++) {
pdb.checkCancelled(); pdb.checkCancelled();
Module module = modules.get(modnum); Module module = modules.get(modnum);
MsSymbolIterator moduleSymbolsIterator = module.getSymbolIterator(); MsSymbolIterator moduleSymbolsIterator = getSymbolIterator(modnum);
cnt = 0; cnt = 0;
Map<Long, AbstractMsSymbol> map = symbolRecords.getModuleSymbolsByOffset(modnum); Map<Long, AbstractMsSymbol> map = symbolRecords.getModuleSymbolsByOffset(modnum);
List<Long> keys = new ArrayList<>(); List<Long> keys = new ArrayList<>();

View file

@ -146,16 +146,15 @@ public class PdbNewDebugInfo extends PdbDebugInfo {
} }
@Override @Override
protected void deserializeAdditionalSubstreams() protected void initializeAdditionalComponentsForSubstreams()
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
// TODO: evaluate. I don't think we need GlobalSymbolInformation (hash) or the // TODO: evaluate. I don't think we need GlobalSymbolInformation (hash) or the
// PublicSymbolInformation (hash), as they are both are search mechanisms. // PublicSymbolInformation (hash), as they are both are search mechanisms.
symbolRecords.deserialize(); symbolRecords.initialize();
globalSymbolInformation.deserialize(getGlobalSymbolsHashMaybeStreamNumber()); globalSymbolInformation.initialize();
publicSymbolInformation.deserialize(getPublicStaticSymbolsHashMaybeStreamNumber()); publicSymbolInformation.initialize();
//TODO: Process further information that might be found from ProcessTypeServerMap, //TODO: Process further information that might be found from ProcessTypeServerMap,
// and processEditAndContinueInformation. // and processEditAndContinueInformation.
debugData.deserialize();
} }
@Override @Override
@ -229,7 +228,8 @@ public class PdbNewDebugInfo extends PdbDebugInfo {
} }
@Override @Override
protected void dumpInternalSubstreams(Writer writer) throws IOException, CancelledException { protected void dumpInternalSubstreams(Writer writer)
throws IOException, CancelledException, PdbException {
writer.write("ModuleInformationList---------------------------------------\n"); writer.write("ModuleInformationList---------------------------------------\n");
dumpModuleInformation(writer); dumpModuleInformation(writer);
writer.write("\nEnd ModuleInformationList-----------------------------------\n"); writer.write("\nEnd ModuleInformationList-----------------------------------\n");

View file

@ -70,13 +70,13 @@ public class PdbOldDebugInfo extends PdbDebugInfo {
} }
@Override @Override
protected void deserializeAdditionalSubstreams() protected void initializeAdditionalComponentsForSubstreams()
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
// TODO: evaluate. I don't think we need GlobalSymbolInformation (hash) or the // TODO: evaluate. I don't think we need GlobalSymbolInformation (hash) or the
// PublicSymbolInformation (hash), as they are both are search mechanisms. // PublicSymbolInformation (hash), as they are both are search mechanisms.
symbolRecords.deserialize(); symbolRecords.initialize();
globalSymbolInformation.deserialize(getGlobalSymbolsHashMaybeStreamNumber()); globalSymbolInformation.initialize();
publicSymbolInformation.deserialize(getPublicStaticSymbolsHashMaybeStreamNumber()); publicSymbolInformation.initialize();
//TODO: SectionContributions has information about code sections and refers to //TODO: SectionContributions has information about code sections and refers to
// debug streams for each. // debug streams for each.
} }

View file

@ -19,6 +19,8 @@ import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.util.*; import java.util.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
/** /**
@ -32,10 +34,11 @@ import ghidra.util.exception.CancelledException;
*/ */
public class PublicSymbolInformation extends AbstractSymbolInformation { public class PublicSymbolInformation extends AbstractSymbolInformation {
public static final int PUB_HEADER_SIZE = 28;
//============================================================================================== //==============================================================================================
// Internals // Internals
//============================================================================================== //==============================================================================================
private int symbolHashLength;
private int addressMapLength; private int addressMapLength;
private int numThunks; // unsigned int private int numThunks; // unsigned int
private int thunkSize; private int thunkSize;
@ -46,10 +49,9 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
private int thunkTableLength; private int thunkTableLength;
private int sectionMapLength; private int sectionMapLength;
// These should correspond with symbolOffsets that come from HashRecords. private int addressMapOffset;
private List<Long> addressMapSymbolOffsets = new ArrayList<>(); private int thunkMapOffset;
private Map<Integer, Integer> thunkTargetOffsetsByTableOffset = new HashMap<>(); private int sectionMapOffset;
private Map<Integer, Integer> absoluteOffsetsBySectionNumber = new HashMap<>();
//============================================================================================== //==============================================================================================
// API // API
@ -57,9 +59,10 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
/** /**
* Constructor * Constructor
* @param pdbIn {@link AbstractPdb} that owns the Public Symbol Information to process * @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) { public PublicSymbolInformation(AbstractPdb pdbIn, int streamNumber) {
super(pdbIn); 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 * 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 * offsets to point to the size field of the symbols in the symbol table
* @return offsets * @return offsets
* @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation
*/ */
public List<Long> getAddressMapSymbolOffsets() { public List<Long> getAddressMapSymbolOffsets() throws CancelledException, PdbException {
return addressMapSymbolOffsets; 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<Integer, Integer> 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<Integer, Integer> 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 // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Deserialize the {@link PublicSymbolInformation} from the appropriate stream in the Pdb * Deserializes and intializes {@link PublicSymbolInformation} basic information from the
* @param streamNumber the stream number containing the information to deserialize * 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 * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* inability to read required bytes * inability to read required bytes
* @throws PdbException upon not enough data left to parse * @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
@Override @Override
void deserialize(int streamNumber) void initialize() throws IOException, PdbException, CancelledException {
throws IOException, PdbException, CancelledException { initializeValues();
super.deserialize(streamNumber); deserializePubHeader();
deserializeHashHeader();
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();
} }
/** /**
* Debug method for dumping information from this {@link PublicSymbolInformation} * Debug method for dumping information from this {@link PublicSymbolInformation}
* @param writer {@link Writer} to which to dump the information * @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 CancelledException upon user cancellation
* @throws PdbException upon not enough data left to parse
*/ */
@Override @Override
void dump(Writer writer) throws IOException, CancelledException { void dump(Writer writer) throws IOException, CancelledException, PdbException {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("PublicSymbolInformation-------------------------------------\n"); builder.append("PublicSymbolInformation-------------------------------------\n");
dumpPubHeader(builder); dumpPubHeader(builder);
@ -197,23 +227,31 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
* @throws PdbException upon not enough data left to parse * @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
private void deserializeAddressMap(PdbByteReader reader) private List<Long> deserializeAddressMap(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
List<Long> myAddressMapSymbolOffsets = new ArrayList<>();
while (reader.hasMore()) { while (reader.hasMore()) {
pdb.checkCancelled(); 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} * Debug method for dumping Address Map information from this {@link AbstractSymbolInformation}
* @param builder {@link StringBuilder} to which to dump the information * @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("AddressMapSymbolOffsets-------------------------------------\n");
builder.append("numAddressMapSymbolOffsets: " + addressMapSymbolOffsets.size() + "\n"); List<Long> myAddressMapSymbolOffsets = getAddressMapSymbolOffsets();
builder.append("numAddressMapSymbolOffsets: " + myAddressMapSymbolOffsets.size() + "\n");
int num = 0; int num = 0;
for (Long val : addressMapSymbolOffsets) { for (Long val : myAddressMapSymbolOffsets) {
builder.append(String.format("0X%08X: 0X%012X\n", num++, val)); builder.append(String.format("0X%08X: 0X%012X\n", num++, val));
} }
builder.append("\nEnd AddressMapSymbolOffsets---------------------------------\n"); builder.append("\nEnd AddressMapSymbolOffsets---------------------------------\n");
@ -225,26 +263,35 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
* @throws PdbException upon not enough data left to parse * @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
private void deserializeThunkMap(PdbByteReader reader) private Map<Integer, Integer> deserializeThunkMap(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
int count = 0; int count = 0;
Map<Integer, Integer> myThunkTargetOffsetsByTableOffset = new HashMap<>();
while (reader.hasMore()) { while (reader.hasMore()) {
pdb.checkCancelled(); pdb.checkCancelled();
int targetOffset = reader.parseInt(); int targetOffset = reader.parseInt();
int mapTableOffset = count * thunkSize + offsetThunkTable; 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} * Debug method for dumping Thunk Map information from this {@link AbstractSymbolInformation}
* @param builder {@link StringBuilder} to which to dump the information * @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<Integer, Integer> myThunkTargetOffsetsByTableOffset =
getThunkTargetOffsetsByTableOffset();
builder.append("ThunkMap----------------------------------------------------\n"); builder.append("ThunkMap----------------------------------------------------\n");
builder.append( builder.append("numThunkTargetOffsetsByTableOffset: " +
"numThunkTargetOffsetsByTableOffset: " + thunkTargetOffsetsByTableOffset.size() + "\n"); myThunkTargetOffsetsByTableOffset.size() + "\n");
for (Map.Entry<Integer, Integer> entry : thunkTargetOffsetsByTableOffset.entrySet()) { for (Map.Entry<Integer, Integer> entry : myThunkTargetOffsetsByTableOffset.entrySet()) {
builder.append(String.format("0X%08X 0X%08X\n", entry.getKey(), entry.getValue())); builder.append(String.format("0X%08X 0X%08X\n", entry.getKey(), entry.getValue()));
} }
builder.append("\nEnd ThunkMap------------------------------------------------\n"); builder.append("\nEnd ThunkMap------------------------------------------------\n");
@ -256,27 +303,35 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
* @throws PdbException upon not enough data left to parse * @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
private void deserializeSectionMap(PdbByteReader reader) private Map<Integer, Integer> deserializeSectionMap(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
Map<Integer, Integer> myAbsoluteOffsetsBySectionNumber = new HashMap<>();
while (reader.hasMore()) { while (reader.hasMore()) {
pdb.checkCancelled(); pdb.checkCancelled();
int offset = reader.parseInt(); int offset = reader.parseInt();
int section = reader.parseUnsignedShortVal(); int section = reader.parseUnsignedShortVal();
reader.skip(2); // padding 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} * Debug method for dumping Section Map information from this {@link AbstractSymbolInformation}
* @param builder {@link StringBuilder} to which to dump the information * @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 * @throws CancelledException upon user cancellation
*/ */
private void dumpSectionMap(StringBuilder builder) throws CancelledException { private void dumpSectionMap(StringBuilder builder)
throws CancelledException, IOException, PdbException {
Map<Integer, Integer> myAbsoluteOffsetsBySectionNumber =
getAbsoluteOffsetsBySectionNumber();
builder.append("SectionMap--------------------------------------------------\n"); builder.append("SectionMap--------------------------------------------------\n");
builder.append( builder.append(
"numAbsoluteOffsetsBySectionNumber: " + absoluteOffsetsBySectionNumber.size() + "\n"); "numAbsoluteOffsetsBySectionNumber: " + myAbsoluteOffsetsBySectionNumber.size() + "\n");
for (Map.Entry<Integer, Integer> entry : absoluteOffsetsBySectionNumber.entrySet()) { for (Map.Entry<Integer, Integer> entry : myAbsoluteOffsetsBySectionNumber.entrySet()) {
pdb.checkCancelled(); pdb.checkCancelled();
builder.append(String.format("0X%08X 0X%08X\n", entry.getKey(), entry.getValue())); 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"); 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 // 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 // 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 // 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. // 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(); symbolHashLength = reader.parseInt();
addressMapLength = reader.parseInt(); addressMapLength = reader.parseInt();
long val = reader.parseUnsignedIntVal(); 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"); throw new PdbException("Cannot support large unsigned integer for thunk table length");
} }
thunkTableLength = (int) val; thunkTableLength = (int) val;
// See note above regarding MSFT numSections issue
//val = 8 * numSections; // Do some additional calculations
//if (val > Integer.MAX_VALUE) { symbolHashOffset = PUB_HEADER_SIZE; // reader.getIndex();
// throw new PdbException("Cannot support long value for section map length"); addressMapOffset = symbolHashOffset + symbolHashLength;
//} thunkMapOffset = addressMapOffset + addressMapLength;
//sectionMapLength = (int) val; 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;
} }
} }

View file

@ -25,6 +25,8 @@ public class SymbolHashRecord implements Comparable<SymbolHashRecord> {
private long offsetVal; private long offsetVal;
private int referenceCount; private int referenceCount;
public static int RECORD_SIZE = 8;
/** /**
* Parses the contents of of this record. * Parses the contents of of this record.
* @param reader {@link PdbByteReader} from which to deserialize the data. * @param reader {@link PdbByteReader} from which to deserialize the data.

View file

@ -34,8 +34,6 @@ import ghidra.util.exception.CancelledException;
public class SymbolRecords { public class SymbolRecords {
private AbstractPdb pdb; private AbstractPdb pdb;
private Map<Long, AbstractMsSymbol> symbolsByOffset;
private List<Map<Long, AbstractMsSymbol>> moduleSymbolsByOffset = new ArrayList<>();
// Used for CvSig part of streams. See methods below. // Used for CvSig part of streams. See methods below.
private boolean getSig = true; private boolean getSig = true;
@ -59,9 +57,24 @@ public class SymbolRecords {
* Returns the list of symbols * Returns the list of symbols
* @return {@link Map}&lt;{@link Long},{@link AbstractMsSymbol}&gt; of buffer offsets to * @return {@link Map}&lt;{@link Long},{@link AbstractMsSymbol}&gt; of buffer offsets to
* symbols * 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<Long, AbstractMsSymbol> getSymbolsByOffset() { @Deprecated
return symbolsByOffset; protected Map<Long, AbstractMsSymbol> 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 * @param moduleNumber the number ID of the module for which to return the list
* @return {@link Map}&lt;{@link Long},{@link AbstractMsSymbol}&gt; of buffer offsets to * @return {@link Map}&lt;{@link Long},{@link AbstractMsSymbol}&gt; of buffer offsets to
* symbols for the specified module * symbols for the specified module
*/
protected Map<Long, AbstractMsSymbol> 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 * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* inability to read required bytes * inability to read required bytes
* @throws PdbException upon not enough data left to parse * @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
void deserialize() throws IOException, PdbException, CancelledException { @Deprecated
initializeCache(0.001); protected Map<Long, AbstractMsSymbol> getModuleSymbolsByOffset(int moduleNumber)
determineCvSigValues(); // new method for random-access symbol work throws CancelledException, IOException, PdbException {
processSymbols();
processModuleSymbols();
}
private void processSymbols()
throws IOException, PdbException, CancelledException {
PdbDebugInfo debugInfo = pdb.getDebugInfo(); PdbDebugInfo debugInfo = pdb.getDebugInfo();
if (debugInfo == null) { if (debugInfo == null) {
return; return new TreeMap<>();
} }
int streamNumber = debugInfo.getSymbolRecordsStreamNumber(); ModuleInformation moduleInfo = debugInfo.moduleInformationList.get(moduleNumber);
if (streamNumber <= 0) { int streamNumber = moduleInfo.getStreamNumberDebugInformation();
return; if (streamNumber == MsfStream.NIL_STREAM_NUMBER) {
return new TreeMap<>();
} }
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber); 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 * Deserializes and initializes basic {@link SymbolRecords} information from the stream noted
// skip over the symbols. * in the DBI header so that later symbol queries can be done
private void processModuleSymbols() * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
throws IOException, PdbException, CancelledException { * inability to read required bytes
// cvSignature: * @throws PdbException upon not enough data left to parse
// >64K = C6 * @throws CancelledException upon user cancellation
// 1 = C7 */
// 2 = C11 (vc5.x) void initialize() throws IOException, PdbException, CancelledException {
// 3 = ??? (not specified, and not marked as reserved) initializeCache(0.001);
// 4 = C13 (vc7.x) determineCvSigValues(); // new method for random-access symbol work
// 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<Long, AbstractMsSymbol> oneModuleSymbolsByOffset =
deserializeSymbolRecords(pdb, symbolsReader);
moduleSymbolsByOffset.add(oneModuleSymbolsByOffset);
}
} }
// These methods are trying to adapt the logic of the previous method here (which attempted // 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); ModuleInformation moduleInfo = debugInfo.getModuleInformationList().get(0);
int streamNumber = moduleInfo.getStreamNumberDebugInformation(); int streamNumber = moduleInfo.getStreamNumberDebugInformation();
if (streamNumber == MsfStream.NIL_STREAM_NUMBER) { if (streamNumber == MsfStream.NIL_STREAM_NUMBER) {
moduleSymbolsByOffset.add(new TreeMap<>());
return; return;
} }
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber);
@ -230,11 +180,11 @@ public class SymbolRecords {
*/ */
public int getCvSigLength(int streamNumber) public int getCvSigLength(int streamNumber)
throws CancelledException, IOException, PdbException { throws CancelledException, IOException, PdbException {
if (cvSignatureCase1and2Stream == MsfStream.NIL_STREAM_NUMBER) { // if (cvSignatureCase1and2Stream == MsfStream.NIL_STREAM_NUMBER) {
throw new PdbException("CvSignLength not initialized"); // throw new PdbException("CvSigLength not initialized");
} // }
if (streamNumber == MsfStream.NIL_STREAM_NUMBER) { 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); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, 0, 4);
if (getSig) { if (getSig) {
@ -253,7 +203,7 @@ public class SymbolRecords {
size = 4; size = 4;
break; break;
default: default:
throw new PdbException("PDB Error: Bad CvSsigLength state"); throw new PdbException("PDB Error: Bad CvSigLength state");
} }
return size; return size;
} }
@ -306,7 +256,7 @@ public class SymbolRecords {
// TODO: consider pre-storing the lengths with one build stream read. However, that would // 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 // consume more memory, so only do this if willing to improve process performance at
// cost of memroy. // cost of memory.
//Map<Long, Integer> recordLengths = new TreeMap<>(); //Map<Long, Integer> recordLengths = new TreeMap<>();
/** /**
@ -384,13 +334,19 @@ public class SymbolRecords {
* @param writer {@link Writer} to which to dump the information * @param writer {@link Writer} to which to dump the information
* @throws IOException upon issue writing to the {@link Writer} * @throws IOException upon issue writing to the {@link Writer}
* @throws CancelledException upon user cancellation * @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"); writer.write("SymbolRecords-----------------------------------------------\n");
Map<Long, AbstractMsSymbol> symbolsByOffset = getSymbolsByOffset();
dumpSymbolMap(symbolsByOffset, writer); 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(); pdb.checkCancelled();
Map<Long, AbstractMsSymbol> map = moduleSymbolsByOffset.get(i); Map<Long, AbstractMsSymbol> map = getModuleSymbolsByOffset(i);
if (map != null) { if (map != null) {
writer.write("Module(" + i + ") List:\n"); writer.write("Module(" + i + ") List:\n");
dumpSymbolMap(map, writer); dumpSymbolMap(map, writer);

View file

@ -22,8 +22,6 @@ public interface TPI {
int getTypeIndexMaxExclusive(); int getTypeIndexMaxExclusive();
AbstractMsType getRecord(int recordNumber);
/** /**
* Random access of {@link AbstractMsType} record indicated by {@code recordNumber} * Random access of {@link AbstractMsType} record indicated by {@code recordNumber}
* @param recordNumber record number of the record to retrieve * @param recordNumber record number of the record to retrieve

View file

@ -120,48 +120,22 @@ public abstract class TypeProgramInterface implements TPI {
} }
/** /**
* Retrieves the {@link AbstractMsType} record indicated by the recordNumber. The record must * Retrieves the {@link AbstractMsType} record indicated by the recordNumber
* already have been parsed and inserted into the list
* @param recordNumber record number to look up * @param recordNumber record number to look up
* @return {@link AbstractMsType} pertaining to the record number * @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 @Override
public AbstractMsType getRandomAccessRecord(int recordNumber) { 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. // 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. // So, for now, we are creating and returning a new BadMsType.
PdbLog.logBadTypeRecordIndex(this, recordNumber); PdbLog.logBadTypeRecordIndex(this, recordNumber);
BadMsType type = new BadMsType(pdb, 0); BadMsType badType = new BadMsType(pdb, 0);
type.setRecordNumber(RecordNumber.make(recordCategory, recordNumber)); badType.setRecordNumber(RecordNumber.make(recordCategory, recordNumber));
return type; return badType;
} }
if (recordNumber < typeIndexMin) { PrimitiveMsType primitive = getPrimitiveRecord(recordNumber);
PrimitiveMsType primitive = primitiveTypesByRecordNumber.get(recordNumber); if (primitive != null) {
if (primitive == null) {
primitive = new PrimitiveMsType(pdb, recordNumber);
primitiveTypesByRecordNumber.put(recordNumber, primitive);
}
return primitive; return primitive;
} }
@ -171,6 +145,7 @@ public abstract class TypeProgramInterface implements TPI {
try { try {
PdbByteReader recordReader = PdbByteReader recordReader =
pdb.getReaderForStreamNumber(streamNumber, offLen.offset(), offLen.length()); pdb.getReaderForStreamNumber(streamNumber, offLen.offset(), offLen.length());
recordReader.markAlign(2);
return TypeParser.parseRecord(pdb, recordReader, rn); return TypeParser.parseRecord(pdb, recordReader, rn);
} }
catch (PdbException | IOException | CancelledException e) { 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 // 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} * @return version number of the {@link TypeProgramInterface}
* @throws IOException on file seek or read, invalid parameters, bad file configuration, or * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* inability to read required bytes * inability to read required bytes
* @throws PdbException upon not enough data left to parse * @throws PdbException upon not enough data left to parse
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
int deserialize() throws IOException, PdbException, CancelledException { int initialize() throws IOException, PdbException, CancelledException {
if (pdb.getMsf() == null) { if (pdb.getMsf() == null) {
// Should only be null dummy PDBs used for testing. // Should only be null dummy PDBs used for testing.
throw new PdbException("Unexpected null MSF."); throw new PdbException("Unexpected null MSF.");
@ -205,10 +193,10 @@ public abstract class TypeProgramInterface implements TPI {
// we have this commented out. // we have this commented out.
//hash.deserializeHashStreams(pdb.getMonitor()); //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); createOffLenRecords(reader);
deserializeTypeRecords(reader);
return versionNumber; return versionNumber;
} }
@ -244,36 +232,6 @@ public abstract class TypeProgramInterface implements TPI {
this.typeIndexMaxExclusive = typeIndexMaxExclusive; 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 // Abstract Methods
//============================================================================================== //==============================================================================================
@ -308,40 +266,6 @@ public abstract class TypeProgramInterface implements TPI {
reader.setIndex(savedIndex); // restore reader to original state 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 //TODO: more to do for outputting individual records (might want a toString or dump method
// on each). // on each).
/** /**
@ -350,8 +274,8 @@ public abstract class TypeProgramInterface implements TPI {
* @throws IOException on issue writing to the {@link Writer} * @throws IOException on issue writing to the {@link Writer}
*/ */
protected void dumpTypeRecords(Writer writer) throws IOException { protected void dumpTypeRecords(Writer writer) throws IOException {
int recordNum = typeIndexMin; for (int recordNum = typeIndexMin; recordNum < typeIndexMaxExclusive; recordNum++) {
for (AbstractMsType type : typeList) { AbstractMsType type = getRandomAccessRecord(recordNum);
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("------------------------------------------------------------\n"); builder.append("------------------------------------------------------------\n");
builder.append("Record: "); builder.append("Record: ");
@ -367,7 +291,6 @@ public abstract class TypeProgramInterface implements TPI {
builder.append("(null)\n"); //Temporary output value. builder.append("(null)\n"); //Temporary output value.
} }
writer.write(builder.toString()); writer.write(builder.toString());
recordNum++;
} }
} }

View file

@ -15,10 +15,10 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; 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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractBlockMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractBlockMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; 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.address.Address;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException; 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 applicator the {@link DefaultPdbApplicator} for which we are working.
* @param iter the Iterator containing the symbol sequence being processed * @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); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
if (!(abstractSymbol instanceof AbstractBlockMsSymbol)) { if (!(abstractSymbol instanceof AbstractBlockMsSymbol)) {

View file

@ -120,7 +120,7 @@ public class ComplexTypeMapper {
// to TYPE as we could get using applicator.getPdb().getTypeRecord(recordNumber) // to TYPE as we could get using applicator.getPdb().getTypeRecord(recordNumber)
// where recordNumber is a RecordNumber. This is because we are not expecting // where recordNumber is a RecordNumber. This is because we are not expecting
// a remap for Complex types. // a remap for Complex types.
AbstractMsType type = typeProgramInterface.getRecord(indexNumber); AbstractMsType type = typeProgramInterface.getRandomAccessRecord(indexNumber);
if (type instanceof AbstractCompositeMsType compositeType) { if (type instanceof AbstractCompositeMsType compositeType) {
mapComplexTypesByPath(compositeFIFOsByPath, indexNumber, compositeType); mapComplexTypesByPath(compositeFIFOsByPath, indexNumber, compositeType);
} }

View file

@ -15,11 +15,9 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; package ghidra.app.util.pdb.pdbapplicator;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractDataMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractDataMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; 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.address.Address;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.listing.*; 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 applicator the {@link DefaultPdbApplicator} for which we are working.
* @param iter the Iterator containing the symbol sequence being processed * @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); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
if (!(abstractSymbol instanceof AbstractDataMsSymbol)) { if (!(abstractSymbol instanceof AbstractDataMsSymbol)) {
@ -170,11 +168,15 @@ public class DataSymbolApplier extends MsSymbolApplier {
} }
if (existingData == null) { if (existingData == null) {
try { try {
applicator.getProgram().getListing().clearCodeUnits(address, applicator.getProgram()
address.add(dataTypeLength - 1), false); .getListing()
.clearCodeUnits(address,
address.add(dataTypeLength - 1), false);
if (dataType.getLength() == -1) { if (dataType.getLength() == -1) {
applicator.getProgram().getListing().createData(address, dataType, applicator.getProgram()
dataTypeLength); .getListing()
.createData(address, dataType,
dataTypeLength);
} }
else { else {
applicator.getProgram().getListing().createData(address, dataType); applicator.getProgram().getListing().createData(address, dataType);
@ -187,8 +189,10 @@ public class DataSymbolApplier extends MsSymbolApplier {
} }
else if (isDataReplaceable(existingData)) { else if (isDataReplaceable(existingData)) {
try { try {
applicator.getProgram().getListing().clearCodeUnits(address, applicator.getProgram()
address.add(dataTypeLength - 1), false); .getListing()
.clearCodeUnits(address,
address.add(dataTypeLength - 1), false);
applicator.getProgram().getListing().createData(address, dataType, dataTypeLength); applicator.getProgram().getListing().createData(address, dataType, dataTypeLength);
} }
catch (CodeUnitInsertionException e) { catch (CodeUnitInsertionException e) {

View file

@ -15,6 +15,7 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; package ghidra.app.util.pdb.pdbapplicator;
import java.io.IOException;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.*; 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.bin.format.pe.cli.tables.CliAbstractTableRow;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.pdb.PdbCategories; import ghidra.app.util.pdb.PdbCategories;
import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.graph.*; import ghidra.graph.*;
import ghidra.graph.algo.GraphNavigator; import ghidra.graph.algo.GraphNavigator;
@ -172,6 +172,9 @@ public class DefaultPdbApplicator implements PdbApplicator {
AddressSet disassembleAddresses; AddressSet disassembleAddresses;
List<DeferrableFunctionSymbolApplier> deferredFunctionWorkAppliers; List<DeferrableFunctionSymbolApplier> deferredFunctionWorkAppliers;
//==============================================================================================
private int currentModuleNumber = 0;
//============================================================================================== //==============================================================================================
public DefaultPdbApplicator(AbstractPdb pdb) { public DefaultPdbApplicator(AbstractPdb pdb) {
Objects.requireNonNull(pdb, "pdb cannot be null"); 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 * @param logParam the MessageLog to which to output messages
* @throws PdbException if there was a problem processing the data * @throws PdbException if there was a problem processing the data
* @throws CancelledException upon user cancellation * @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, public void applyTo(Program programParam, DataTypeManager dataTypeManagerParam,
Address imageBaseParam, PdbApplicatorOptions applicatorOptionsParam, 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 // 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 // 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, private void initializeApplyTo(Program programParam, DataTypeManager dataTypeManagerParam,
Address imageBaseParam, PdbApplicatorOptions applicatorOptionsParam, Address imageBaseParam, PdbApplicatorOptions applicatorOptionsParam,
MessageLog logParam) throws PdbException, CancelledException { MessageLog logParam) throws PdbException, CancelledException, IOException {
validateAndSetParameters(programParam, dataTypeManagerParam, imageBaseParam, validateAndSetParameters(programParam, dataTypeManagerParam, imageBaseParam,
applicatorOptionsParam, logParam); applicatorOptionsParam, logParam);
@ -759,8 +771,7 @@ public class DefaultPdbApplicator implements PdbApplicator {
throw new PdbException("PDB: DebugInfo is null"); throw new PdbException("PDB: DebugInfo is null");
} }
for (SectionContribution sectionContribution : debugInfo for (SectionContribution sectionContribution : debugInfo.getSectionContributionList()) {
.getSectionContributionList()) {
int sectionContributionOffset = sectionContribution.getOffset(); int sectionContributionOffset = sectionContribution.getOffset();
int maxSectionContributionOffset = int maxSectionContributionOffset =
sectionContributionOffset + sectionContribution.getLength(); sectionContributionOffset + sectionContribution.getLength();
@ -781,8 +792,8 @@ public class DefaultPdbApplicator implements PdbApplicator {
TaskMonitor monitor = getMonitor(); TaskMonitor monitor = getMonitor();
monitor.initialize(num); monitor.initialize(num);
monitor.setMessage("PDB: Processing " + num + " data type components..."); monitor.setMessage("PDB: Processing " + num + " data type components...");
for (int indexNumber = for (int indexNumber = tpi.getTypeIndexMin(); indexNumber < tpi
tpi.getTypeIndexMin(); indexNumber < tpi.getTypeIndexMaxExclusive(); indexNumber++) { .getTypeIndexMaxExclusive(); indexNumber++) {
monitor.checkCancelled(); monitor.checkCancelled();
//PdbResearch.checkBreak(indexNumber); //PdbResearch.checkBreak(indexNumber);
MsTypeApplier applier = getTypeApplier(RecordNumber.typeRecordNumber(indexNumber)); MsTypeApplier applier = getTypeApplier(RecordNumber.typeRecordNumber(indexNumber));
@ -849,8 +860,8 @@ public class DefaultPdbApplicator implements PdbApplicator {
TaskMonitor monitor = getMonitor(); TaskMonitor monitor = getMonitor();
monitor.initialize(num); monitor.initialize(num);
monitor.setMessage("PDB: Processing " + num + " item type components..."); monitor.setMessage("PDB: Processing " + num + " item type components...");
for (int indexNumber = for (int indexNumber = ipi.getTypeIndexMin(); indexNumber < ipi
ipi.getTypeIndexMin(); indexNumber < ipi.getTypeIndexMaxExclusive(); indexNumber++) { .getTypeIndexMaxExclusive(); indexNumber++) {
monitor.checkCancelled(); monitor.checkCancelled();
MsTypeApplier applier = getTypeApplier(RecordNumber.itemRecordNumber(indexNumber)); MsTypeApplier applier = getTypeApplier(RecordNumber.itemRecordNumber(indexNumber));
applier.apply(); applier.apply();
@ -893,8 +904,8 @@ public class DefaultPdbApplicator implements PdbApplicator {
monitor.initialize(num); monitor.initialize(num);
monitor.setMessage("PDB: Resolving " + num + " data type components..."); monitor.setMessage("PDB: Resolving " + num + " data type components...");
long longStart = System.currentTimeMillis(); long longStart = System.currentTimeMillis();
for (int indexNumber = for (int indexNumber = tpi.getTypeIndexMin(); indexNumber < tpi
tpi.getTypeIndexMin(); indexNumber < tpi.getTypeIndexMaxExclusive(); indexNumber++) { .getTypeIndexMaxExclusive(); indexNumber++) {
monitor.checkCancelled(); monitor.checkCancelled();
//PdbResearch.checkBreak(indexNumber); //PdbResearch.checkBreak(indexNumber);
MsTypeApplier applier = getTypeApplier(RecordNumber.typeRecordNumber(indexNumber)); MsTypeApplier applier = getTypeApplier(RecordNumber.typeRecordNumber(indexNumber));
@ -937,8 +948,7 @@ public class DefaultPdbApplicator implements PdbApplicator {
} }
CreateFunctionCmd funCmd = new CreateFunctionCmd(null, normalizedAddress, CreateFunctionCmd funCmd = new CreateFunctionCmd(null, normalizedAddress,
new AddressSet(normalizedAddress, normalizedAddress), new AddressSet(normalizedAddress, normalizedAddress), SourceType.DEFAULT);
SourceType.DEFAULT);
if (!funCmd.applyTo(program, cancelOnlyWrappingMonitor)) { if (!funCmd.applyTo(program, cancelOnlyWrappingMonitor)) {
appendLogMsg("Failed to apply function at address " + address.toString() + appendLogMsg("Failed to apply function at address " + address.toString() +
"; attempting to use possible existing function"); "; attempting to use possible existing function");
@ -1154,12 +1164,20 @@ public class DefaultPdbApplicator implements PdbApplicator {
TaskMonitor monitor = getMonitor(); TaskMonitor monitor = getMonitor();
monitor.setMessage("PDB: Applying " + totalCount + " main symbol components..."); monitor.setMessage("PDB: Applying " + totalCount + " main symbol components...");
monitor.initialize(totalCount); monitor.initialize(totalCount);
AbstractMsSymbolIterator iter = symbolGroup.iterator(); MsSymbolIterator iter = symbolGroup.getSymbolIterator();
processSymbolGroup(0, iter); 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(); PdbDebugInfo debugInfo = pdb.getDebugInfo();
if (debugInfo == null) { if (debugInfo == null) {
return; return;
@ -1184,12 +1202,13 @@ public class DefaultPdbApplicator implements PdbApplicator {
// Process symbols list for each module // Process symbols list for each module
for (int moduleNumber = 1; moduleNumber <= num; moduleNumber++) { for (int moduleNumber = 1; moduleNumber <= num; moduleNumber++) {
monitor.checkCancelled(); monitor.checkCancelled();
setCurrentModuleNumber(moduleNumber);
// Process module symbols list // Process module symbols list
SymbolGroup symbolGroup = getSymbolGroupForModule(moduleNumber); SymbolGroup symbolGroup = getSymbolGroupForModule(moduleNumber);
if (symbolGroup == null) { if (symbolGroup == null) {
continue; // should not happen continue; // should not happen
} }
AbstractMsSymbolIterator iter = symbolGroup.iterator(); MsSymbolIterator iter = symbolGroup.getSymbolIterator();
processSymbolGroup(moduleNumber, iter); processSymbolGroup(moduleNumber, iter);
monitor.increment(); monitor.increment();
// catelogSymbols(index, symbolGroup); // 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 { throws CancelledException {
iter.initGet(); iter.initGet();
TaskMonitor monitor = getMonitor(); TaskMonitor monitor = getMonitor();
@ -1244,12 +1263,12 @@ public class DefaultPdbApplicator implements PdbApplicator {
} }
PublicSymbolInformation publicSymbolInformation = debugInfo.getPublicSymbolInformation(); PublicSymbolInformation publicSymbolInformation = debugInfo.getPublicSymbolInformation();
List<Long> offsets = publicSymbolInformation.getModifiedHashRecordSymbolOffsets();
TaskMonitor monitor = getMonitor(); TaskMonitor monitor = getMonitor();
monitor.setMessage("PDB: Applying " + offsets.size() + " public symbol components..."); monitor.setMessage("PDB: Applying public symbols...");
monitor.initialize(offsets.size()); MsSymbolIterator iter = symbolGroup.getSymbolIterator();
AbstractMsSymbolIterator iter = symbolGroup.iterator(); List<Long> offsets = publicSymbolInformation.getModifiedHashRecordSymbolOffsets();
monitor.initialize(offsets.size());
for (long offset : offsets) { for (long offset : offsets) {
monitor.checkCancelled(); monitor.checkCancelled();
iter.initGetByOffset(offset); iter.initGetByOffset(offset);
@ -1260,6 +1279,26 @@ public class DefaultPdbApplicator implements PdbApplicator {
procSym(iter); procSym(iter);
monitor.incrementProgress(1); 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; return;
} }
GlobalSymbolInformation globalSymbolInformation = debugInfo.getGlobalSymbolInformation();
List<Long> offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets();
TaskMonitor monitor = getMonitor(); TaskMonitor monitor = getMonitor();
monitor.setMessage("PDB: Applying global symbols..."); monitor.setMessage("PDB: Applying global symbols...");
monitor.initialize(offsets.size()); GlobalSymbolInformation globalSymbolInformation = debugInfo.getGlobalSymbolInformation();
MsSymbolIterator iter = symbolGroup.getSymbolIterator();
AbstractMsSymbolIterator iter = symbolGroup.iterator(); List<Long> offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets();
monitor.initialize(offsets.size());
for (long offset : offsets) { for (long offset : offsets) {
monitor.checkCancelled(); monitor.checkCancelled();
iter.initGetByOffset(offset); iter.initGetByOffset(offset);
@ -1301,6 +1340,28 @@ public class DefaultPdbApplicator implements PdbApplicator {
} }
monitor.incrementProgress(1); 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; return;
} }
GlobalSymbolInformation globalSymbolInformation = debugInfo.getGlobalSymbolInformation();
List<Long> offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets();
TaskMonitor monitor = getMonitor(); TaskMonitor monitor = getMonitor();
monitor.setMessage("PDB: Applying typedefs..."); monitor.setMessage("PDB: Applying typedefs...");
monitor.initialize(offsets.size()); GlobalSymbolInformation globalSymbolInformation = debugInfo.getGlobalSymbolInformation();
MsSymbolIterator iter = symbolGroup.getSymbolIterator();
AbstractMsSymbolIterator iter = symbolGroup.iterator(); List<Long> offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets();
monitor.initialize(offsets.size());
for (long offset : offsets) { for (long offset : offsets) {
monitor.checkCancelled(); monitor.checkCancelled();
iter.initGetByOffset(offset); iter.initGetByOffset(offset);
@ -1339,6 +1400,28 @@ public class DefaultPdbApplicator implements PdbApplicator {
} }
monitor.incrementProgress(1); 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()); monitor.initialize(offsetsRemaining.size());
//getCategoryUtils().setModuleTypedefsCategory(null); //getCategoryUtils().setModuleTypedefsCategory(null);
AbstractMsSymbolIterator iter = symbolGroup.iterator(); MsSymbolIterator iter = symbolGroup.getSymbolIterator();
for (long offset : offsetsRemaining) { for (long offset : offsetsRemaining) {
monitor.checkCancelled(); monitor.checkCancelled();
iter.initGetByOffset(offset); iter.initGetByOffset(offset);
@ -1414,7 +1497,7 @@ public class DefaultPdbApplicator implements PdbApplicator {
//============================================================================================== //==============================================================================================
@SuppressWarnings("unused") // for method not being called. @SuppressWarnings("unused") // for method not being called.
private boolean processLinkerSymbols() throws CancelledException { private boolean processLinkerSymbols() throws CancelledException, PdbException {
SymbolGroup symbolGroup = getSymbolGroupForModule(linkerModuleNumber); SymbolGroup symbolGroup = getSymbolGroupForModule(linkerModuleNumber);
if (symbolGroup == null) { if (symbolGroup == null) {
@ -1426,7 +1509,7 @@ public class DefaultPdbApplicator implements PdbApplicator {
monitor.setMessage("PDB: Applying " + symbolGroup.size() + " linker symbol components..."); monitor.setMessage("PDB: Applying " + symbolGroup.size() + " linker symbol components...");
monitor.initialize(symbolGroup.size()); monitor.initialize(symbolGroup.size());
AbstractMsSymbolIterator iter = symbolGroup.iterator(); MsSymbolIterator iter = symbolGroup.getSymbolIterator();
while (iter.hasNext()) { while (iter.hasNext()) {
monitor.checkCancelled(); monitor.checkCancelled();
pdbApplicatorMetrics.witnessLinkerSymbolType(iter.peek()); pdbApplicatorMetrics.witnessLinkerSymbolType(iter.peek());
@ -1438,20 +1521,21 @@ public class DefaultPdbApplicator implements PdbApplicator {
//============================================================================================== //==============================================================================================
@Override @Override
public List<PeCoffSectionMsSymbol> getLinkerPeCoffSectionSymbols() throws CancelledException { public List<PeCoffSectionMsSymbol> getLinkerPeCoffSectionSymbols()
throws CancelledException, PdbException {
processLinkerModuleSpecialInformation(); processLinkerModuleSpecialInformation();
return linkerPeCoffSectionSymbols; return linkerPeCoffSectionSymbols;
} }
//============================================================================================== //==============================================================================================
@Override @Override
public AbstractMsSymbol getLinkerModuleCompileSymbol() throws CancelledException { public AbstractMsSymbol getLinkerModuleCompileSymbol() throws CancelledException, PdbException {
processLinkerModuleSpecialInformation(); processLinkerModuleSpecialInformation();
return compileSymbolForLinkerModule; return compileSymbolForLinkerModule;
} }
//============================================================================================== //==============================================================================================
private void processLinkerModuleSpecialInformation() throws CancelledException { private void processLinkerModuleSpecialInformation() throws CancelledException, PdbException {
if (processedLinkerModule) { if (processedLinkerModule) {
return; return;
@ -1465,7 +1549,7 @@ public class DefaultPdbApplicator implements PdbApplicator {
TaskMonitor monitor = getMonitor(); TaskMonitor monitor = getMonitor();
monitor.initialize(symbolGroup.size()); monitor.initialize(symbolGroup.size());
AbstractMsSymbolIterator iter = symbolGroup.iterator(); MsSymbolIterator iter = symbolGroup.getSymbolIterator();
int numCompileSymbols = 0; int numCompileSymbols = 0;
int compileSymbolNumForCoffSymbols = -1; int compileSymbolNumForCoffSymbols = -1;
while (iter.hasNext()) { 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(); PdbDebugInfo debugInfo = pdb.getDebugInfo();
if (debugInfo == null) { if (debugInfo == null) {
@ -1546,7 +1630,7 @@ public class DefaultPdbApplicator implements PdbApplicator {
if (symbolGroup == null) { if (symbolGroup == null) {
continue; // should not happen continue; // should not happen
} }
AbstractMsSymbolIterator iter = symbolGroup.iterator(); MsSymbolIterator iter = symbolGroup.getSymbolIterator();
while (iter.hasNext()) { while (iter.hasNext()) {
monitor.checkCancelled(); monitor.checkCancelled();
AbstractMsSymbol symbol = iter.peek(); 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); return symbolApplierParser.getSymbolApplier(iter);
} }
//============================================================================================== //==============================================================================================
void procSym(AbstractMsSymbolIterator iter) throws CancelledException { void procSym(MsSymbolIterator iter) throws CancelledException {
try { try {
MsSymbolApplier applier = getSymbolApplier(iter); MsSymbolApplier applier = getSymbolApplier(iter);
applier.apply(); applier.apply();

View file

@ -15,9 +15,9 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; 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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; 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.AssertException;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
@ -34,7 +34,7 @@ public class DefinedSingleAddressRangeSymbolApplier extends MsSymbolApplier {
* @param iter the Iterator containing the symbol sequence being processed * @param iter the Iterator containing the symbol sequence being processed
*/ */
public DefinedSingleAddressRangeSymbolApplier(DefaultPdbApplicator applicator, public DefinedSingleAddressRangeSymbolApplier(DefaultPdbApplicator applicator,
AbstractMsSymbolIterator iter) { MsSymbolIterator iter) {
super(applicator, iter); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
if (!(abstractSymbol instanceof AbstractDefinedSingleAddressRangeMsSymbol)) { if (!(abstractSymbol instanceof AbstractDefinedSingleAddressRangeMsSymbol)) {
@ -53,7 +53,7 @@ public class DefinedSingleAddressRangeSymbolApplier extends MsSymbolApplier {
@Override @Override
void applyTo(MsSymbolApplier applyToApplier) throws PdbException, CancelledException { void applyTo(MsSymbolApplier applyToApplier) throws PdbException, CancelledException {
if (applyToApplier instanceof LocalOptimizedSymbolApplier) { if (applyToApplier instanceof LocalOptimizedSymbolApplier) {
// TODO: eventually apply. // TODO: eventually apply.
// LocalOptimizedSymbolApplier localSymbolApplier = // LocalOptimizedSymbolApplier localSymbolApplier =
// (LocalOptimizedSymbolApplier) applyToApplier; // (LocalOptimizedSymbolApplier) applyToApplier;
symbol.getAddressRange(); symbol.getAddressRange();

View file

@ -15,9 +15,9 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; 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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; 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.AssertException;
/** /**
@ -30,7 +30,7 @@ public class EndSymbolApplier extends MsSymbolApplier {
* @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param applicator the {@link DefaultPdbApplicator} for which we are working.
* @param iter the Iterator containing the symbol sequence being processed * @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); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
if (!(abstractSymbol instanceof EndMsSymbol || if (!(abstractSymbol instanceof EndMsSymbol ||
@ -43,8 +43,8 @@ public class EndSymbolApplier extends MsSymbolApplier {
@Override @Override
void apply() throws PdbException { void apply() throws PdbException {
pdbLogAndInfoMessage(this, pdbLogAndInfoMessage(this,
String.format("Cannot apply %s directly to program (module:0X%04X, offset:0X%08X)", String.format("Cannot apply %s directly to program (stream:0X%04X, offset:0X%08X)",
this.getClass().getSimpleName(), iter.getModuleNumber(), iter.getCurrentOffset())); this.getClass().getSimpleName(), iter.getStreamNumber(), iter.getCurrentOffset()));
} }
@Override @Override

View file

@ -15,10 +15,10 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; 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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.ExtraFrameAndProcedureInformationMsSymbol; 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.AssertException;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
@ -35,7 +35,7 @@ public class FrameAndProcedureInformationSymbolApplier extends MsSymbolApplier {
* @param iter the Iterator containing the symbol sequence being processed * @param iter the Iterator containing the symbol sequence being processed
*/ */
public FrameAndProcedureInformationSymbolApplier(DefaultPdbApplicator applicator, public FrameAndProcedureInformationSymbolApplier(DefaultPdbApplicator applicator,
AbstractMsSymbolIterator iter) { MsSymbolIterator iter) {
super(applicator, iter); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
if (!(abstractSymbol instanceof ExtraFrameAndProcedureInformationMsSymbol)) { if (!(abstractSymbol instanceof ExtraFrameAndProcedureInformationMsSymbol)) {

View file

@ -19,10 +19,8 @@ import java.util.*;
import ghidra.app.cmd.function.ApplyFunctionSignatureCmd; import ghidra.app.cmd.function.ApplyFunctionSignatureCmd;
import ghidra.app.cmd.function.CallDepthChangeInfo; import ghidra.app.cmd.function.CallDepthChangeInfo;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; 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.Address;
import ghidra.program.model.address.AddressSet; import ghidra.program.model.address.AddressSet;
import ghidra.program.model.data.DataType; 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 * @param iter the Iterator containing the symbol sequence being processed
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
public FunctionSymbolApplier(DefaultPdbApplicator applicator, AbstractMsSymbolIterator iter) public FunctionSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter)
throws CancelledException { throws CancelledException {
super(applicator, iter); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();

View file

@ -18,10 +18,10 @@ package ghidra.app.util.pdb.pdbapplicator;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import ghidra.app.util.NamespaceUtils; 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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractLabelMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractLabelMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; 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.address.Address;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
import ghidra.program.model.symbol.SourceType; 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 applicator the {@link DefaultPdbApplicator} for which we are working.
* @param iter the Iterator containing the symbol sequence being processed * @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); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
if (!(abstractSymbol instanceof AbstractLabelMsSymbol)) { if (!(abstractSymbol instanceof AbstractLabelMsSymbol)) {

View file

@ -15,9 +15,9 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; 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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; 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.AssertException;
import ghidra.util.exception.CancelledException; 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 applicator the {@link DefaultPdbApplicator} for which we are working.
* @param iter the Iterator containing the symbol sequence being processed * @param iter the Iterator containing the symbol sequence being processed
*/ */
public LocalOptimizedSymbolApplier(DefaultPdbApplicator applicator, public LocalOptimizedSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) {
AbstractMsSymbolIterator iter) {
super(applicator, iter); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
if (!(abstractSymbol instanceof AbstractLocalSymbolInOptimizedCodeMsSymbol)) { if (!(abstractSymbol instanceof AbstractLocalSymbolInOptimizedCodeMsSymbol)) {

View file

@ -18,6 +18,7 @@ package ghidra.app.util.pdb.pdbapplicator;
import java.util.*; import java.util.*;
import ghidra.app.cmd.function.CallDepthChangeInfo; 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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractManagedProcedureMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractManagedProcedureMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; 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.CliTableMethodImpl.CliMethodImplRow;
import ghidra.app.util.bin.format.pe.cli.tables.CliTableMethodSemantics.CliMethodSemanticsRow; 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.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.Address;
import ghidra.program.model.address.AddressSet; import ghidra.program.model.address.AddressSet;
import ghidra.program.model.data.DataType; 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 * @param iter the Iterator containing the symbol sequence being processed
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
public ManagedProcedureSymbolApplier(DefaultPdbApplicator applicator, public ManagedProcedureSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter)
AbstractMsSymbolIterator iter) throws CancelledException { throws CancelledException {
super(applicator, iter); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
symbolBlockNestingLevel = 0; symbolBlockNestingLevel = 0;

View file

@ -18,10 +18,8 @@ package ghidra.app.util.pdb.pdbapplicator;
import java.util.Objects; import java.util.Objects;
import ghidra.app.plugin.processors.sleigh.symbol.Symbol; 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.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
/** /**
@ -33,7 +31,7 @@ import ghidra.util.exception.CancelledException;
*/ */
public abstract class MsSymbolApplier { public abstract class MsSymbolApplier {
protected DefaultPdbApplicator applicator; protected DefaultPdbApplicator applicator;
protected AbstractMsSymbolIterator iter; protected MsSymbolIterator iter;
protected long currentOffset; protected long currentOffset;
/** /**
@ -41,7 +39,7 @@ public abstract class MsSymbolApplier {
* @param applicator the {@link DefaultPdbApplicator} for which we are working. * @param applicator the {@link DefaultPdbApplicator} for which we are working.
* @param iter the Iterator containing the symbol sequence being processed * @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(applicator, "applicator cannot be null");
Objects.requireNonNull(iter, "iter cannot be null"); Objects.requireNonNull(iter, "iter cannot be null");
this.applicator = applicator; 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. * 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 * 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 * @param applierParam the applier which is managing blocks, which is typically
* {@link FunctionSymbolApplier}. * {@link FunctionSymbolApplier}.
*/ */

View file

@ -15,8 +15,8 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; 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.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 * 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 applicator the {@link DefaultPdbApplicator} for which we are working.
* @param iter the Iterator containing the symbol sequence being processed * @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); super(applicator, iter);
symbol = iter.next(); symbol = iter.next();
} }

View file

@ -15,6 +15,7 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; package ghidra.app.util.pdb.pdbapplicator;
import java.io.IOException;
import java.util.*; import java.util.*;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
@ -35,7 +36,7 @@ abstract class PdbAddressCalculator {
private int maxSegment; private int maxSegment;
static PdbAddressCalculator chooseAddressCalculator(PdbApplicator applicator, Address imageBase) static PdbAddressCalculator chooseAddressCalculator(PdbApplicator applicator, Address imageBase)
throws CancelledException { throws CancelledException, PdbException, IOException {
AbstractPdb pdb = applicator.getPdb(); AbstractPdb pdb = applicator.getPdb();
PdbDebugInfo dbi = pdb.getDebugInfo(); 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 // 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 // an RVA in PeCoffSection is instead a VA. Issue found in one Delphi example. All other
// non-Delphi examples seem to have RVA. // 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(); AbstractMsSymbol symbol = applicator.getLinkerModuleCompileSymbol();
String name = ""; String name = "";

View file

@ -15,6 +15,7 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; package ghidra.app.util.pdb.pdbapplicator;
import java.io.IOException;
import java.util.*; import java.util.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.*; 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. * @param imageBase Address from which all other addresses are based.
* @throws PdbException If Program is null; * @throws PdbException If Program is null;
* @throws CancelledException upon user cancellation * @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) PdbAddressManager(DefaultPdbApplicator applicator, Address imageBase)
throws PdbException, CancelledException { throws PdbException, CancelledException, IOException {
Objects.requireNonNull(applicator, "applicator may not be null"); Objects.requireNonNull(applicator, "applicator may not be null");
Objects.requireNonNull(imageBase, "imageBase may not be null"); Objects.requireNonNull(imageBase, "imageBase may not be null");
this.applicator = applicator; 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(); AbstractPdb pdb = applicator.getPdb();
PdbDebugInfo debugInfo = pdb.getDebugInfo(); PdbDebugInfo debugInfo = pdb.getDebugInfo();
segmentMapList = debugInfo.getSegmentMapList(); segmentMapList = debugInfo.getSegmentMapList();

View file

@ -18,6 +18,7 @@ package ghidra.app.util.pdb.pdbapplicator;
import java.util.List; import java.util.List;
import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractPdb; 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.app.util.bin.format.pdb2.pdbreader.symbol.*;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
@ -62,15 +63,18 @@ public interface PdbApplicator {
* Returns the {@link PeCoffSectionMsSymbol}s from the "Linker" module * Returns the {@link PeCoffSectionMsSymbol}s from the "Linker" module
* @return list of symbols * @return list of symbols
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
* @throws PdbException upon issue creating an iterator
*/ */
public List<PeCoffSectionMsSymbol> getLinkerPeCoffSectionSymbols() throws CancelledException; public List<PeCoffSectionMsSymbol> getLinkerPeCoffSectionSymbols()
throws CancelledException, PdbException;
/** /**
* Returns the compile symbol seen in the "Linker" module. Should be one of * Returns the compile symbol seen in the "Linker" module. Should be one of
* {@link Compile3MsSymbol} or {@link AbstractCompile2MsSymbol} * {@link Compile3MsSymbol} or {@link AbstractCompile2MsSymbol}
* @return the compile symbol * @return the compile symbol
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
* @throws PdbException upon issue creating an iterator
*/ */
public AbstractMsSymbol getLinkerModuleCompileSymbol() throws CancelledException; public AbstractMsSymbol getLinkerModuleCompileSymbol() throws CancelledException, PdbException;
} }

View file

@ -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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; 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.address.Address;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.lang.CompilerSpec; import ghidra.program.model.lang.CompilerSpec;
@ -337,8 +336,7 @@ public class PdbResearch {
String nn = applier.getMsType().getName(); String nn = applier.getMsType().getName();
if ("std::__1::__map_value_compare<std::__1::basic_string<char>,std::__1::__value_type<std::__1::basic_string<char>,std::__1::basic_string<wchar_t> >,std::__1::less<void>,1>" if ("std::__1::__map_value_compare<std::__1::basic_string<char>,std::__1::__value_type<std::__1::basic_string<char>,std::__1::basic_string<wchar_t> >,std::__1::less<void>,1>"
.equals( .equals(nn)) {
nn)) {
doNothingSetBreakPointHere(); doNothingSetBreakPointHere();
} }
if ("class std::__1::__iostream_category".equals(nn)) { if ("class std::__1::__iostream_category".equals(nn)) {
@ -430,7 +428,7 @@ public class PdbResearch {
monitor.setMessage("PDB: Applying typedefs..."); monitor.setMessage("PDB: Applying typedefs...");
monitor.initialize(offsets.size()); monitor.initialize(offsets.size());
AbstractMsSymbolIterator iter = symbolGroup.iterator(); MsSymbolIterator iter = symbolGroup.getSymbolIterator();
for (long offset : offsets) { for (long offset : offsets) {
monitor.checkCancelled(); monitor.checkCancelled();
iter.initGetByOffset(offset); iter.initGetByOffset(offset);
@ -441,8 +439,8 @@ public class PdbResearch {
} }
} }
static private boolean childWalkSym(DefaultPdbApplicator applicator, int moduleNumber, static private boolean childWalkSym(DefaultPdbApplicator applicator, int streamNumber,
AbstractMsSymbolIterator iter) throws PdbException, CancelledException { MsSymbolIterator iter) throws PdbException, CancelledException {
if (!iter.hasNext()) { if (!iter.hasNext()) {
return false; return false;
} }
@ -459,18 +457,18 @@ public class PdbResearch {
} }
else if (applier instanceof ReferenceSymbolApplier) { else if (applier instanceof ReferenceSymbolApplier) {
ReferenceSymbolApplier refSymbolApplier = (ReferenceSymbolApplier) applier; ReferenceSymbolApplier refSymbolApplier = (ReferenceSymbolApplier) applier;
AbstractMsSymbolIterator refIter = MsSymbolIterator refIter =
refSymbolApplier.getInitializedReferencedSymbolGroupIterator(); refSymbolApplier.getInitializedReferencedSymbolGroupIterator();
if (refIter == null) { if (refIter == null) {
throw new PdbException("PDB: Referenced Symbol Error - not refIter"); throw new PdbException("PDB: Referenced Symbol Error - not refIter");
} }
// recursion // recursion
childWalkSym(applicator, refIter.getModuleNumber(), refIter); childWalkSym(applicator, refIter.getStreamNumber(), refIter);
} }
else if (applier instanceof DataSymbolApplier) { else if (applier instanceof DataSymbolApplier) {
DataSymbolApplier dataSymbolApplier = (DataSymbolApplier) applier; DataSymbolApplier dataSymbolApplier = (DataSymbolApplier) applier;
MsTypeApplier typeApplier = dataSymbolApplier.getTypeApplier(); MsTypeApplier typeApplier = dataSymbolApplier.getTypeApplier();
childWalkType(moduleNumber, typeApplier); childWalkType(streamNumber, typeApplier);
} }
else if (applier instanceof FunctionSymbolApplier) { else if (applier instanceof FunctionSymbolApplier) {
FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applier; FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applier;
@ -620,7 +618,7 @@ public class PdbResearch {
* reuse caused by Templates and/or Identical Code Folding. * reuse caused by Templates and/or Identical Code Folding.
*/ */
static void studyAggregateSymbols(DefaultPdbApplicator applicator, TaskMonitor monitor) static void studyAggregateSymbols(DefaultPdbApplicator applicator, TaskMonitor monitor)
throws CancelledException { throws CancelledException, PdbException {
Map<Address, List<Stuff>> mapByAddress = new HashMap<>(); Map<Address, List<Stuff>> mapByAddress = new HashMap<>();
processPublicSymbols(applicator, mapByAddress, monitor); processPublicSymbols(applicator, mapByAddress, monitor);
processGlobalSymbols(applicator, mapByAddress, monitor); processGlobalSymbols(applicator, mapByAddress, monitor);
@ -629,7 +627,8 @@ public class PdbResearch {
} }
private static void processPublicSymbols(DefaultPdbApplicator applicator, private static void processPublicSymbols(DefaultPdbApplicator applicator,
Map<Address, List<Stuff>> map, TaskMonitor monitor) throws CancelledException { Map<Address, List<Stuff>> map, TaskMonitor monitor)
throws CancelledException, PdbException {
AbstractPdb pdb = applicator.getPdb(); AbstractPdb pdb = applicator.getPdb();
PdbDebugInfo debugInfo = pdb.getDebugInfo(); PdbDebugInfo debugInfo = pdb.getDebugInfo();
@ -644,11 +643,10 @@ public class PdbResearch {
PublicSymbolInformation publicSymbolInformation = debugInfo.getPublicSymbolInformation(); PublicSymbolInformation publicSymbolInformation = debugInfo.getPublicSymbolInformation();
List<Long> offsets = publicSymbolInformation.getModifiedHashRecordSymbolOffsets(); List<Long> offsets = publicSymbolInformation.getModifiedHashRecordSymbolOffsets();
monitor.setMessage( monitor.setMessage("PDB: Applying " + offsets.size() + " public symbol components...");
"PDB: Applying " + offsets.size() + " public symbol components...");
monitor.initialize(offsets.size()); monitor.initialize(offsets.size());
AbstractMsSymbolIterator iter = symbolGroup.iterator(); MsSymbolIterator iter = symbolGroup.getSymbolIterator();
for (long offset : offsets) { for (long offset : offsets) {
monitor.checkCancelled(); monitor.checkCancelled();
iter.initGetByOffset(offset); iter.initGetByOffset(offset);
@ -664,7 +662,8 @@ public class PdbResearch {
} }
private static void processGlobalSymbols(DefaultPdbApplicator applicator, private static void processGlobalSymbols(DefaultPdbApplicator applicator,
Map<Address, List<Stuff>> map, TaskMonitor monitor) throws CancelledException { Map<Address, List<Stuff>> map, TaskMonitor monitor)
throws CancelledException, PdbException {
AbstractPdb pdb = applicator.getPdb(); AbstractPdb pdb = applicator.getPdb();
PdbDebugInfo debugInfo = pdb.getDebugInfo(); PdbDebugInfo debugInfo = pdb.getDebugInfo();
@ -682,7 +681,7 @@ public class PdbResearch {
monitor.setMessage("PDB: Applying global symbols..."); monitor.setMessage("PDB: Applying global symbols...");
monitor.initialize(offsets.size()); monitor.initialize(offsets.size());
AbstractMsSymbolIterator iter = symbolGroup.iterator(); MsSymbolIterator iter = symbolGroup.getSymbolIterator();
for (long offset : offsets) { for (long offset : offsets) {
monitor.checkCancelled(); monitor.checkCancelled();
iter.initGetByOffset(offset); iter.initGetByOffset(offset);
@ -698,7 +697,8 @@ public class PdbResearch {
} }
private static void processModuleSymbols(DefaultPdbApplicator applicator, private static void processModuleSymbols(DefaultPdbApplicator applicator,
Map<Address, List<Stuff>> map, TaskMonitor monitor) throws CancelledException { Map<Address, List<Stuff>> map, TaskMonitor monitor)
throws CancelledException, PdbException {
AbstractPdb pdb = applicator.getPdb(); AbstractPdb pdb = applicator.getPdb();
PdbDebugInfo debugInfo = pdb.getDebugInfo(); PdbDebugInfo debugInfo = pdb.getDebugInfo();
if (debugInfo == null) { if (debugInfo == null) {
@ -715,8 +715,7 @@ public class PdbResearch {
} }
totalCount += symbolGroup.size(); totalCount += symbolGroup.size();
} }
monitor.setMessage( monitor.setMessage("PDB: Applying " + totalCount + " module symbol components...");
"PDB: Applying " + totalCount + " module symbol components...");
monitor.initialize(totalCount); monitor.initialize(totalCount);
// Process symbols list for each module // Process symbols list for each module
@ -731,7 +730,7 @@ public class PdbResearch {
if (symbolGroup == null) { if (symbolGroup == null) {
continue; continue;
} }
AbstractMsSymbolIterator iter = symbolGroup.iterator(); MsSymbolIterator iter = symbolGroup.getSymbolIterator();
processSymbolGroup(applicator, map, moduleNumber, iter, monitor); processSymbolGroup(applicator, map, moduleNumber, iter, monitor);
// do not call monitor.incrementProgress(1) here, as it is updated inside of // do not call monitor.incrementProgress(1) here, as it is updated inside of
// processSymbolGroup. // processSymbolGroup.
@ -739,7 +738,7 @@ public class PdbResearch {
} }
private static void processSymbolGroup(DefaultPdbApplicator applicator, private static void processSymbolGroup(DefaultPdbApplicator applicator,
Map<Address, List<Stuff>> map, int moduleNumber, AbstractMsSymbolIterator iter, Map<Address, List<Stuff>> map, int moduleNumber, MsSymbolIterator iter,
TaskMonitor monitor) throws CancelledException { TaskMonitor monitor) throws CancelledException {
iter.initGet(); iter.initGet();
while (iter.hasNext()) { while (iter.hasNext()) {

View file

@ -20,7 +20,6 @@ import java.util.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.*; 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.AbstractMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractPublicMsSymbol; 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.address.Address;
import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.listing.Program; 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 // If we find some this way, then need to modify PdbVbtManager to also look
// through the loader symbol for them. // through the loader symbol for them.
private static Map<String, Address> findVirtualBaseTableSymbols(DefaultPdbApplicator applicator) private static Map<String, Address> findVirtualBaseTableSymbols(DefaultPdbApplicator applicator)
throws CancelledException { throws CancelledException, PdbException {
TaskMonitor monitor = applicator.getMonitor(); TaskMonitor monitor = applicator.getMonitor();
Map<String, Address> myAddressByMangledName = new HashMap<>(); Map<String, Address> myAddressByMangledName = new HashMap<>();
@ -71,7 +70,7 @@ public class PdbVbtManager extends VbtManager {
monitor.setMessage("PDB: Searching for virtual base table symbols..."); monitor.setMessage("PDB: Searching for virtual base table symbols...");
monitor.initialize(offsets.size()); monitor.initialize(offsets.size());
AbstractMsSymbolIterator iter = symbolGroup.iterator(); MsSymbolIterator iter = symbolGroup.getSymbolIterator();
for (long offset : offsets) { for (long offset : offsets) {
monitor.checkCancelled(); monitor.checkCancelled();
iter.initGetByOffset(offset); iter.initGetByOffset(offset);

View file

@ -15,10 +15,10 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; 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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.PeCoffGroupMsSymbol; 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.program.model.address.Address;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException; 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 applicator the {@link DefaultPdbApplicator} for which we are working.
* @param iter the Iterator containing the symbol sequence being processed * @param iter the Iterator containing the symbol sequence being processed
*/ */
public PeCoffGroupSymbolApplier(DefaultPdbApplicator applicator, public PeCoffGroupSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) {
AbstractMsSymbolIterator iter) {
super(applicator, iter); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
if (!(abstractSymbol instanceof PeCoffGroupMsSymbol)) { if (!(abstractSymbol instanceof PeCoffGroupMsSymbol)) {

View file

@ -15,10 +15,10 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; 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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.PeCoffSectionMsSymbol; 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.AssertException;
import ghidra.util.exception.CancelledException; 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 applicator the {@link DefaultPdbApplicator} for which we are working.
* @param iter the Iterator containing the symbol sequence being processed * @param iter the Iterator containing the symbol sequence being processed
*/ */
public PeCoffSectionSymbolApplier(DefaultPdbApplicator applicator, public PeCoffSectionSymbolApplier(DefaultPdbApplicator applicator, MsSymbolIterator iter) {
AbstractMsSymbolIterator iter) {
super(applicator, iter); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
if (!(abstractSymbol instanceof PeCoffSectionMsSymbol)) { if (!(abstractSymbol instanceof PeCoffSectionMsSymbol)) {

View file

@ -15,12 +15,12 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; 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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractPublicMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractPublicMsSymbol;
import ghidra.app.util.datatype.microsoft.GuidDataType; import ghidra.app.util.datatype.microsoft.GuidDataType;
import ghidra.app.util.datatype.microsoft.GuidUtil; 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.address.Address;
import ghidra.program.model.data.DataUtilities; import ghidra.program.model.data.DataUtilities;
import ghidra.program.model.data.DataUtilities.ClearDataMode; 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 applicator the {@link DefaultPdbApplicator} for which we are working.
* @param iter the Iterator containing the symbol sequence being processed * @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); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
if (!(abstractSymbol instanceof AbstractPublicMsSymbol)) { if (!(abstractSymbol instanceof AbstractPublicMsSymbol)) {

View file

@ -15,10 +15,10 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; 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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractReferenceMsSymbol; 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.AssertException;
import ghidra.util.exception.CancelledException; 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 applicator the {@link DefaultPdbApplicator} for which we are working.
* @param iter the Iterator containing the symbol sequence being processed * @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); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
if (!(abstractSymbol instanceof AbstractReferenceMsSymbol)) { if (!(abstractSymbol instanceof AbstractReferenceMsSymbol)) {
@ -52,19 +52,19 @@ public class ReferenceSymbolApplier extends MsSymbolApplier {
@Override @Override
void apply() throws CancelledException, PdbException { void apply() throws CancelledException, PdbException {
// Potential recursive call via applicator.procSym(). // Potential recursive call via applicator.procSym().
AbstractMsSymbolIterator refIter = getInitializedReferencedSymbolGroupIterator(); MsSymbolIterator refIter = getInitializedReferencedSymbolGroupIterator();
if (refIter == null) { if (refIter == null) {
throw new PdbException("PDB: Referenced Symbol Error - null refIter"); throw new PdbException("PDB: Referenced Symbol Error - null refIter");
} }
applicator.procSym(refIter); applicator.procSym(refIter);
} }
AbstractMsSymbolIterator getInitializedReferencedSymbolGroupIterator() { MsSymbolIterator getInitializedReferencedSymbolGroupIterator() throws PdbException {
SymbolGroup refSymbolGroup = getReferencedSymbolGroup(); SymbolGroup refSymbolGroup = getReferencedSymbolGroup();
if (refSymbolGroup == null) { if (refSymbolGroup == null) {
return null; return null;
} }
AbstractMsSymbolIterator refIter = refSymbolGroup.iterator(); MsSymbolIterator refIter = refSymbolGroup.getSymbolIterator();
refIter.initGetByOffset(getOffsetInReferencedSymbolGroup()); refIter.initGetByOffset(getOffsetInReferencedSymbolGroup());
return refIter; return refIter;
} }

View file

@ -17,10 +17,10 @@ package ghidra.app.util.pdb.pdbapplicator;
import java.util.Objects; 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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractRegisterRelativeAddressMsSymbol; 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.data.DataType;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
@ -40,7 +40,7 @@ public class RegisterRelativeSymbolApplier extends MsSymbolApplier {
* @param iter the Iterator containing the symbol sequence being processed * @param iter the Iterator containing the symbol sequence being processed
*/ */
public RegisterRelativeSymbolApplier(DefaultPdbApplicator applicator, public RegisterRelativeSymbolApplier(DefaultPdbApplicator applicator,
AbstractMsSymbolIterator iter) { MsSymbolIterator iter) {
super(applicator, iter); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
if (!(abstractSymbol instanceof AbstractRegisterRelativeAddressMsSymbol)) { if (!(abstractSymbol instanceof AbstractRegisterRelativeAddressMsSymbol)) {

View file

@ -19,9 +19,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import ghidra.app.cmd.comments.SetCommentCmd; 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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.SeparatedCodeFromCompilerSupportMsSymbol; 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.address.Address;
import ghidra.program.model.listing.CodeUnit; import ghidra.program.model.listing.CodeUnit;
import ghidra.util.Msg; import ghidra.util.Msg;
@ -46,7 +46,7 @@ public class SeparatedCodeSymbolApplier extends MsSymbolApplier {
private List<MsSymbolApplier> allAppliers = new ArrayList<>(); private List<MsSymbolApplier> allAppliers = new ArrayList<>();
private static AbstractMsSymbolIterator validateSymbol(AbstractMsSymbolIterator iter) { private static MsSymbolIterator validateSymbol(MsSymbolIterator iter) {
if (!(iter.peek() instanceof SeparatedCodeFromCompilerSupportMsSymbol)) { if (!(iter.peek() instanceof SeparatedCodeFromCompilerSupportMsSymbol)) {
throw new IllegalArgumentException("Not a SeparatedCodeFromCompilerSupportMsSymbol"); throw new IllegalArgumentException("Not a SeparatedCodeFromCompilerSupportMsSymbol");
} }
@ -60,7 +60,7 @@ public class SeparatedCodeSymbolApplier extends MsSymbolApplier {
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
*/ */
public SeparatedCodeSymbolApplier(DefaultPdbApplicator applicator, public SeparatedCodeSymbolApplier(DefaultPdbApplicator applicator,
AbstractMsSymbolIterator iter) throws CancelledException { MsSymbolIterator iter) throws CancelledException {
super(applicator, validateSymbol(iter)); super(applicator, validateSymbol(iter));
symbol = (SeparatedCodeFromCompilerSupportMsSymbol) iter.next(); symbol = (SeparatedCodeFromCompilerSupportMsSymbol) iter.next();
@ -111,8 +111,10 @@ public class SeparatedCodeSymbolApplier extends MsSymbolApplier {
private void setComments(boolean enabled) { private void setComments(boolean enabled) {
if (enabled) { if (enabled) {
String existingComment = applicator.getProgram().getListing().getComment( String existingComment = applicator.getProgram()
CodeUnit.PRE_COMMENT, specifiedAddress); .getListing()
.getComment(
CodeUnit.PRE_COMMENT, specifiedAddress);
String p = "*************************************************************\n"; String p = "*************************************************************\n";
String newComment = String newComment =
String.format(p + "* Separated code (from the compiler): %s - %s *\n" + p, String.format(p + "* Separated code (from the compiler): %s - %s *\n" + p,

View file

@ -15,8 +15,8 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; 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.bin.format.pdb2.pdbreader.symbol.*;
import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator;
import ghidra.util.exception.CancelledException; 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 // the AbstractMsSymbol (do one for AbstractMsType as well)? Symbols are different in that
// we are using SymbolGroup as a member instead of MsType. // 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(); AbstractMsSymbol symbol = iter.peek();
if (symbol == null) { if (symbol == null) {

View file

@ -20,7 +20,6 @@ import java.io.Writer;
import java.util.*; import java.util.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.*; 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.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
@ -157,152 +156,38 @@ public class SymbolGroup {
writer.write("\nEnd SymbolGroup---------------------------------------------\n"); 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<AbstractMsSymbol> {
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;
}
}
} }

View file

@ -15,10 +15,10 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; 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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.TrampolineMsSymbol; 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.address.Address;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
import ghidra.util.exception.AssertException; 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 applicator the {@link DefaultPdbApplicator} for which we are working.
* @param iter the Iterator containing the symbol sequence being processed * @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); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
if (!(abstractSymbol instanceof TrampolineMsSymbol)) { if (!(abstractSymbol instanceof TrampolineMsSymbol)) {

View file

@ -16,11 +16,9 @@
package ghidra.app.util.pdb.pdbapplicator; package ghidra.app.util.pdb.pdbapplicator;
import ghidra.app.util.SymbolPath; import ghidra.app.util.SymbolPath;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractUserDefinedTypeMsSymbol; 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.program.model.data.*;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException; 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 applicator the {@link DefaultPdbApplicator} for which we are working.
* @param iter the Iterator containing the symbol sequence being processed * @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); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
if (!(abstractSymbol instanceof AbstractUserDefinedTypeMsSymbol)) { if (!(abstractSymbol instanceof AbstractUserDefinedTypeMsSymbol)) {
@ -120,7 +118,7 @@ public class TypedefSymbolApplier extends MsSymbolApplier {
SymbolPath symbolPath = new SymbolPath(name); SymbolPath symbolPath = new SymbolPath(name);
CategoryPath categoryPath = CategoryPath categoryPath =
applicator.getTypedefsCategory(iter.getModuleNumber(), symbolPath); applicator.getTypedefsCategory(applicator.getCurrentModuleNumber(), symbolPath);
DataType typedef = new TypedefDataType(categoryPath.getParent(), categoryPath.getName(), DataType typedef = new TypedefDataType(categoryPath.getParent(), categoryPath.getName(),
dataType, applicator.getDataTypeManager()); dataType, applicator.getDataTypeManager());

View file

@ -15,10 +15,10 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; 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.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractWithMsSymbol; 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.program.model.address.Address;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException; 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 applicator the {@link DefaultPdbApplicator} for which we are working.
* @param iter the Iterator containing the symbol sequence being processed * @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); super(applicator, iter);
AbstractMsSymbol abstractSymbol = iter.next(); AbstractMsSymbol abstractSymbol = iter.next();
if (!(abstractSymbol instanceof AbstractWithMsSymbol)) { if (!(abstractSymbol instanceof AbstractWithMsSymbol)) {

View file

@ -16,6 +16,8 @@
package ghidra.app.util.bin.format.pdb2.pdbreader; package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException; 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.msf.StubMsf;
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
@ -29,6 +31,9 @@ public class DummyPdb700 extends Pdb700 {
private boolean debugInfoAvailable = true; private boolean debugInfoAvailable = true;
private Map<RecordNumber, AbstractMsType> dummyTypes = new HashMap<>();
private Map<RecordNumber, AbstractMsType> dummyItems = new HashMap<>();
//============================================================================================== //==============================================================================================
// API // API
//============================================================================================== //==============================================================================================
@ -42,8 +47,8 @@ public class DummyPdb700 extends Pdb700 {
* @throws IOException upon file IO seek/read issues * @throws IOException upon file IO seek/read issues
* @throws PdbException upon unknown value for configuration or error in processing components * @throws PdbException upon unknown value for configuration or error in processing components
*/ */
public DummyPdb700(int tpiIndexMin, int tpiIndexMaxExclusive, public DummyPdb700(int tpiIndexMin, int tpiIndexMaxExclusive, int ipiIndexMin,
int ipiIndexMin, int ipiIndexMaxExclusive) throws IOException, PdbException { int ipiIndexMaxExclusive) throws IOException, PdbException {
super(new StubMsf(), new PdbReaderOptions()); super(new StubMsf(), new PdbReaderOptions());
typeProgramInterface = typeProgramInterface =
new DummyTypeProgramInterface800(this, tpiIndexMin, tpiIndexMaxExclusive); new DummyTypeProgramInterface800(this, tpiIndexMin, tpiIndexMaxExclusive);
@ -76,7 +81,13 @@ public class DummyPdb700 extends Pdb700 {
* @return {@code true} if successful * @return {@code true} if successful
*/ */
public boolean setTypeRecord(int recordNumber, AbstractMsType type) { 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 * @return record number assigned
*/ */
public int addTypeRecord(AbstractMsType type) { 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 * @return {@code true} if successful
*/ */
public boolean setItemRecord(int recordNumber, AbstractMsType type) { 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 * @return record number assigned
*/ */
public int addItemRecord(AbstractMsType type) { 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 extends AbstractMsType> T getTypeRecord(RecordNumber recordNumber,
Class<T> 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);
} }
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 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(); String result = type.toString().trim();
assertEquals("DummyMsType[0:REGISTER: al, Type: DummyMsType, registerSymbolName][0:void]", assertEquals("DummyMsType[0:REGISTER: al, Type: DummyMsType, registerSymbolName][0:void]",
result); result);
} }
@Test @Test