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