GP-2367 - PDB U - cleanup: remove Abstract from some names, incorporate filename and monitor into MSF and make available to PDB and other classes, better employ monitor in reader, fix some javadoc

This commit is contained in:
ghizard
2022-09-09 16:23:09 -04:00
parent 6842712129
commit e7846664a8
67 changed files with 1583 additions and 1559 deletions
@@ -201,11 +201,10 @@ public class Pagedump extends DumpFile {
applicatorOptions.setProcessingControl(PdbApplicatorControl.DATA_TYPES_ONLY); applicatorOptions.setProcessingControl(PdbApplicatorControl.DATA_TYPES_ONLY);
try (AbstractPdb pdb = PdbParser.parse(pdbFile.getPath(), readerOptions, monitor)) { try (AbstractPdb pdb = PdbParser.parse(pdbFile.getPath(), readerOptions, monitor)) {
monitor.setMessage("PDB: Parsing " + pdbFile + "..."); monitor.setMessage("PDB: Parsing " + pdbFile + "...");
pdb.deserialize(monitor); pdb.deserialize();
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdbFile.getPath(), pdb); DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb);
applicator.applyTo(program, dtm, program.getImageBase(), applicator.applyTo(program, dtm, program.getImageBase(),
applicatorOptions, monitor, applicatorOptions, (MessageLog) null);
(MessageLog) null);
} }
catch (PdbException | IOException | CancelledException e) { catch (PdbException | IOException | CancelledException e) {
Msg.error(this, e.getMessage()); Msg.error(this, e.getMessage());
@@ -63,7 +63,7 @@ public class PdbDeveloperDumpScript extends GhidraScript {
monitor.setMessage(message); monitor.setMessage(message);
Msg.info(this, message); Msg.info(this, message);
try (AbstractPdb pdb = PdbParser.parse(pdbFileName, new PdbReaderOptions(), monitor)) { try (AbstractPdb pdb = PdbParser.parse(pdbFileName, new PdbReaderOptions(), monitor)) {
pdb.deserialize(monitor); pdb.deserialize();
FileWriter fileWriter = new FileWriter(dumpFile); FileWriter fileWriter = new FileWriter(dumpFile);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
outputHeaderMessage(bufferedWriter, pdbFileName); outputHeaderMessage(bufferedWriter, pdbFileName);
@@ -86,7 +86,7 @@ public class PdbDeveloperDumpSetScript extends GhidraScript {
println("Processing PDB Dump of: " + entry.input()); println("Processing PDB Dump of: " + entry.input());
try (AbstractPdb pdb = try (AbstractPdb pdb =
PdbParser.parse(entry.input(), new PdbReaderOptions(), monitor)) { PdbParser.parse(entry.input(), new PdbReaderOptions(), monitor)) {
pdb.deserialize(monitor); pdb.deserialize();
try (BufferedWriter bufferedWriter = try (BufferedWriter bufferedWriter =
new BufferedWriter(new FileWriter(new File(entry.output())))) { new BufferedWriter(new FileWriter(new File(entry.output())))) {
outputHeaderMessage(bufferedWriter, entry.input()); outputHeaderMessage(bufferedWriter, entry.input());
@@ -61,7 +61,7 @@ public class PdbFactory {
try { try {
AbstractPdb pdb = PdbParser.parse(filename, new PdbReaderOptions(), monitor); AbstractPdb pdb = PdbParser.parse(filename, new PdbReaderOptions(), monitor);
PdbIdentifiers identifiers = pdb.getIdentifiers(); PdbIdentifiers identifiers = pdb.getIdentifiers();
pdb.deserialize(monitor); pdb.deserialize();
PdbReaderMetrics metrics = pdb.getPdbReaderMetrics(); PdbReaderMetrics metrics = pdb.getPdbReaderMetrics();
pdbInfo = new PdbInfo(filename, identifiers, pdb, metrics); pdbInfo = new PdbInfo(filename, identifiers, pdb, metrics);
pdbInfoByFile.put(filename, pdbInfo); pdbInfoByFile.put(filename, pdbInfo);
@@ -41,7 +41,7 @@ public class PdbQuery {
*/ */
public static AbstractMsType getDataTypeRecord(GhidraScript script, AbstractPdb pdb, public static AbstractMsType getDataTypeRecord(GhidraScript script, AbstractPdb pdb,
int number) { int number) {
AbstractTypeProgramInterface tpi = pdb.getTypeProgramInterface(); TypeProgramInterface tpi = pdb.getTypeProgramInterface();
if (tpi == null) { if (tpi == null) {
println(script, "PDB does not contain a TPI... aborting search."); println(script, "PDB does not contain a TPI... aborting search.");
return null; return null;
@@ -75,7 +75,7 @@ public class PdbQuery {
*/ */
public static AbstractMsType getItemTypeRecord(GhidraScript script, AbstractPdb pdb, public static AbstractMsType getItemTypeRecord(GhidraScript script, AbstractPdb pdb,
int number) { int number) {
AbstractTypeProgramInterface ipi = pdb.getItemProgramInterface(); TypeProgramInterface ipi = pdb.getItemProgramInterface();
if (ipi == null) { if (ipi == null) {
println(script, "PDB does not contain an IPI... aborting search."); println(script, "PDB does not contain an IPI... aborting search.");
return null; return null;
@@ -102,7 +102,7 @@ public class PdbQuery {
/** /**
* Searches PDB data type records that contain the search string. Outputs results to the * Searches PDB data type records that contain the search string. Outputs results to the
* console. * console
* @param script the script for which we are working * @param script the script for which we are working
* @param pdb the PDB to search * @param pdb the PDB to search
* @param searchString the search string * @param searchString the search string
@@ -110,7 +110,7 @@ public class PdbQuery {
*/ */
public static void searchDataTypes(GhidraScript script, AbstractPdb pdb, String searchString) public static void searchDataTypes(GhidraScript script, AbstractPdb pdb, String searchString)
throws CancelledException { throws CancelledException {
AbstractTypeProgramInterface tpi = pdb.getTypeProgramInterface(); TypeProgramInterface tpi = pdb.getTypeProgramInterface();
if (tpi == null) { if (tpi == null) {
println(script, "PDB does not contain a TPI... aborting search."); println(script, "PDB does not contain a TPI... aborting search.");
} }
@@ -140,7 +140,7 @@ public class PdbQuery {
/** /**
* Searches PDB item records that contain the search string. Outputs results to the * Searches PDB item records that contain the search string. Outputs results to the
* console. * console
* @param script the script for which we are working * @param script the script for which we are working
* @param pdb the PDB to search * @param pdb the PDB to search
* @param searchString the search string * @param searchString the search string
@@ -148,7 +148,7 @@ public class PdbQuery {
*/ */
public static void searchItemTypes(GhidraScript script, AbstractPdb pdb, String searchString) public static void searchItemTypes(GhidraScript script, AbstractPdb pdb, String searchString)
throws CancelledException { throws CancelledException {
AbstractTypeProgramInterface ipi = pdb.getItemProgramInterface(); TypeProgramInterface ipi = pdb.getItemProgramInterface();
if (ipi == null) { if (ipi == null) {
println(script, "PDB does not contain an IPI... aborting search."); println(script, "PDB does not contain an IPI... aborting search.");
return; return;
@@ -179,7 +179,7 @@ public class PdbQuery {
/** /**
* Searches PDB symbol records that contain the search string. Outputs results to the * Searches PDB symbol records that contain the search string. Outputs results to the
* console. * console
* @param script the script for which we are working * @param script the script for which we are working
* @param pdb the PDB to search * @param pdb the PDB to search
* @param searchString the search string * @param searchString the search string
@@ -238,7 +238,7 @@ public class PdbQuery {
/** /**
* Method for outputting a message to the console (if script is not null); otherwise outputs * Method for outputting a message to the console (if script is not null); otherwise outputs
* the message to Msg.info(). * the message to Msg.info()
* @param script the script * @param script the script
* @param message the message to output to the console * @param message the message to output to the console
*/ */
@@ -180,10 +180,10 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
try (AbstractPdb pdb = PdbParser.parse(pdbFile.getPath(), pdbReaderOptions, monitor)) { try (AbstractPdb pdb = PdbParser.parse(pdbFile.getPath(), pdbReaderOptions, monitor)) {
monitor.setMessage("PDB: Parsing " + pdbFile + "..."); monitor.setMessage("PDB: Parsing " + pdbFile + "...");
pdb.deserialize(monitor); pdb.deserialize();
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdbFile.getPath(), pdb); DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb);
applicator.applyTo(program, program.getDataTypeManager(), program.getImageBase(), applicator.applyTo(program, program.getDataTypeManager(), program.getImageBase(),
pdbApplicatorOptions, monitor, log); pdbApplicatorOptions, log);
} }
catch (PdbException | IOException e) { catch (PdbException | IOException e) {
@@ -249,11 +249,11 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
* on the specified program. * on the specified program.
* <p> * <p>
* Normally the analyzer would locate the PDB file on its own, but if a * Normally the analyzer would locate the PDB file on its own, but if a
* headless script wishes to override the analyzer's behaivor, it can * headless script wishes to override the analyzer's behavior, it can
* use this method to specify a file. * use this method to specify a file.
* *
* @param program {@link Program} * @param program the program
* @param pdbFile the pdb file * @param pdbFile the PDB file
*/ */
public static void setPdbFileOption(Program program, File pdbFile) { public static void setPdbFileOption(Program program, File pdbFile) {
PdbAnalyzerCommon.setPdbFileOption(NAME, program, pdbFile); PdbAnalyzerCommon.setPdbFileOption(NAME, program, pdbFile);
@@ -21,7 +21,6 @@ import java.util.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* This class represents Global Symbol Information or Public Symbol Information component of a * This class represents Global Symbol Information or Public Symbol Information component of a
@@ -62,16 +61,16 @@ public abstract class AbstractSymbolInformation {
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param pdbIn {@link AbstractPdb} that owns the Abstract Symbol Information to process. * @param pdbIn {@link AbstractPdb} that owns the Abstract Symbol Information to process
*/ */
public AbstractSymbolInformation(AbstractPdb pdbIn) { public AbstractSymbolInformation(AbstractPdb pdbIn) {
pdb = pdbIn; pdb = pdbIn;
} }
/** /**
* Returns the list of symbols for this {@link AbstractSymbolInformation}. * Returns the list of symbols for this {@link AbstractSymbolInformation}
* @return the symbols. * @return the symbols
*/ */
public List<AbstractMsSymbol> getSymbols() { public List<AbstractMsSymbol> getSymbols() {
return symbols; return symbols;
@@ -79,7 +78,7 @@ public abstract class AbstractSymbolInformation {
/** /**
* Returns the Offsets of symbols within the symbol table; these are gotten from the * Returns the Offsets of symbols within the symbol table; these are gotten from the
* HashRecords and modified to point to the size field of the symbols in the symbol table. * HashRecords and modified to point to the size field of the symbols in the symbol table
* @return offsets * @return offsets
*/ */
public List<Long> getModifiedHashRecordSymbolOffsets() { public List<Long> getModifiedHashRecordSymbolOffsets() {
@@ -90,15 +89,14 @@ public abstract class AbstractSymbolInformation {
// Package-Protected Internals // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Deserialize the {@link AbstractSymbolInformation} from the appropriate stream in the Pdb. * Deserialize the {@link AbstractSymbolInformation} from the appropriate stream in the Pdb
* @param streamNumber the stream number containing the information to deserialize. * @param streamNumber the stream number containing the information to deserialize
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes
* inability to read required bytes. * @throws PdbException upon not enough data left to parse
* @throws PdbException Upon not enough data left to parse. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
void deserialize(int streamNumber, TaskMonitor monitor) void deserialize(int streamNumber)
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
if (pdb.hasMinimalDebugInfo()) { if (pdb.hasMinimalDebugInfo()) {
hashRecordsBitMapLength = 0x8000; hashRecordsBitMapLength = 0x8000;
@@ -113,11 +111,12 @@ public abstract class AbstractSymbolInformation {
} }
/** /**
* Debug method for dumping information from this {@link AbstractSymbolInformation}. * Debug method for dumping information from this {@link AbstractSymbolInformation}
* @param writer {@link Writer} to which to dump the information. * @param writer {@link Writer} to which to dump the information
* @throws IOException Upon IOException writing to the {@link Writer}. * @throws IOException upon IOException writing to the {@link Writer}
* @throws CancelledException upon user cancellation
*/ */
void dump(Writer writer) throws IOException { void dump(Writer writer) throws IOException, CancelledException {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("AbstractSymbolInformation-----------------------------------\n"); builder.append("AbstractSymbolInformation-----------------------------------\n");
dumpHashHeader(builder); dumpHashHeader(builder);
@@ -128,8 +127,8 @@ public abstract class AbstractSymbolInformation {
} }
/** /**
* Debug method for dumping basic information from this {@link AbstractSymbolInformation}. * Debug method for dumping basic information from this {@link AbstractSymbolInformation}
* @param builder {@link StringBuilder} to which to dump the information. * @param builder {@link StringBuilder} to which to dump the information
*/ */
protected void dumpHashBasics(StringBuilder builder) { protected void dumpHashBasics(StringBuilder builder) {
builder.append("HashBasics--------------------------------------------------\n"); builder.append("HashBasics--------------------------------------------------\n");
@@ -143,8 +142,8 @@ public abstract class AbstractSymbolInformation {
} }
/** /**
* Debug method for dumping information from this {@link AbstractSymbolInformation} header. * Debug method for dumping information from this {@link AbstractSymbolInformation} header
* @param builder {@link StringBuilder} to which to dump the information. * @param builder {@link StringBuilder} to which to dump the information
*/ */
protected void dumpHashHeader(StringBuilder builder) { protected void dumpHashHeader(StringBuilder builder) {
builder.append("HashHeader--------------------------------------------------\n"); builder.append("HashHeader--------------------------------------------------\n");
@@ -160,12 +159,11 @@ public abstract class AbstractSymbolInformation {
} }
/** /**
* Generates a list of symbols from the information that we have. * Generates a list of symbols from the information that we have
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws PdbException upon PDB corruption
* @throws PdbException Upon PDB corruption. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
protected void generateSymbolsList(TaskMonitor monitor) protected void generateSymbolsList()
throws PdbException, CancelledException { throws PdbException, CancelledException {
symbols = new ArrayList<>(); symbols = new ArrayList<>();
PdbDebugInfo debugInfo = pdb.getDebugInfo(); PdbDebugInfo debugInfo = pdb.getDebugInfo();
@@ -174,7 +172,7 @@ public abstract class AbstractSymbolInformation {
} }
Map<Long, AbstractMsSymbol> symbolsByOffset = debugInfo.getSymbolsByOffset(); Map<Long, AbstractMsSymbol> symbolsByOffset = debugInfo.getSymbolsByOffset();
for (SymbolHashRecord record : hashRecords) { for (SymbolHashRecord record : hashRecords) {
monitor.checkCanceled(); pdb.checkCanceled();
long offset = record.getOffset() - 2; // Modified offset long offset = record.getOffset() - 2; // Modified offset
AbstractMsSymbol symbol = symbolsByOffset.get(offset); AbstractMsSymbol symbol = symbolsByOffset.get(offset);
modifiedHashRecordSymbolOffsets.add(offset); modifiedHashRecordSymbolOffsets.add(offset);
@@ -186,13 +184,15 @@ public abstract class AbstractSymbolInformation {
} }
/** /**
* Debug method for dumping hash records from this {@link AbstractSymbolInformation}. * Debug method for dumping hash records from this {@link AbstractSymbolInformation}
* @param builder {@link StringBuilder} to which to dump the information. * @param builder {@link StringBuilder} to which to dump the information
* @throws CancelledException upon user cancellation
*/ */
protected void dumpHashRecords(StringBuilder builder) { protected void dumpHashRecords(StringBuilder builder) throws CancelledException {
builder.append("HashRecords-------------------------------------------------\n"); builder.append("HashRecords-------------------------------------------------\n");
builder.append("numHashRecords: " + hashRecords.size() + "\n"); builder.append("numHashRecords: " + hashRecords.size() + "\n");
for (SymbolHashRecord record : hashRecords) { for (SymbolHashRecord record : hashRecords) {
pdb.checkCanceled();
builder.append( builder.append(
String.format("0X%08X 0X%04X\n", record.getOffset(), record.getReferenceCount())); String.format("0X%08X 0X%04X\n", record.getOffset(), record.getReferenceCount()));
} }
@@ -200,13 +200,12 @@ public abstract class AbstractSymbolInformation {
} }
/** /**
* Deserializes the hash table for the symbols. * Deserializes the hash table for the symbols
* @param reader {@link PdbByteReader} containing the data buffer to process. * @param reader {@link PdbByteReader} containing the data buffer to process
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws PdbException upon not enough data left to parse
* @throws PdbException Upon not enough data left to parse. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
protected void deserializeHashTable(PdbByteReader reader, TaskMonitor monitor) protected void deserializeHashTable(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
deserializeHashHeader(reader); deserializeHashHeader(reader);
@@ -214,7 +213,7 @@ public abstract class AbstractSymbolInformation {
if (headerSignature == HEADER_SIGNATURE) { if (headerSignature == HEADER_SIGNATURE) {
switch (versionNumber) { switch (versionNumber) {
case GSI70: case GSI70:
deserializeGsi70HashTable(reader, monitor); deserializeGsi70HashTable(reader);
break; break;
default: default:
throw new PdbException("Unknown GSI Version Number"); throw new PdbException("Unknown GSI Version Number");
@@ -222,15 +221,15 @@ public abstract class AbstractSymbolInformation {
} }
else { else {
reader.reset(); // There was no header reader.reset(); // There was no header
deserializeGsiPre70HashTable(reader, monitor); deserializeGsiPre70HashTable(reader);
} }
} }
/** /**
* Deserialize the header of the Hash from the {@link PdbByteReader} provided. * Deserialize the header of the Hash from the {@link PdbByteReader} provided
* @param reader {@link PdbByteReader} containing the data buffer to process. * @param reader {@link PdbByteReader} containing the data buffer to process
* @throws PdbException Upon not enough data left to parse. * @throws PdbException upon not enough data left to parse
*/ */
private void deserializeHashHeader(PdbByteReader reader) throws PdbException { private void deserializeHashHeader(PdbByteReader reader) throws PdbException {
headerSignature = reader.parseInt(); headerSignature = reader.parseInt();
@@ -241,13 +240,12 @@ public abstract class AbstractSymbolInformation {
/** /**
* Deserialize the body of the {@link AbstractSymbolInformation} according to the GSI versions * Deserialize the body of the {@link AbstractSymbolInformation} according to the GSI versions
* prior to 7.00 specification. * prior to 7.00 specification
* @param reader {@link PdbByteReader} containing the data buffer to process. * @param reader {@link PdbByteReader} containing the data buffer to process
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws PdbException upon unexpected fields
* @throws PdbException Upon unexpected fields. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
private void deserializeGsiPre70HashTable(PdbByteReader reader, TaskMonitor monitor) private void deserializeGsiPre70HashTable(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
int numBucketsBytes = 4 * (numHashRecords + 1); int numBucketsBytes = 4 * (numHashRecords + 1);
@@ -264,7 +262,7 @@ public abstract class AbstractSymbolInformation {
hashBucketOffsets = new ArrayList<>(); hashBucketOffsets = new ArrayList<>();
while (bucketsReader.hasMore()) { while (bucketsReader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
hashBucketOffsets.add(bucketsReader.parseInt()); hashBucketOffsets.add(bucketsReader.parseInt());
} }
@@ -273,18 +271,17 @@ public abstract class AbstractSymbolInformation {
// take the offset and multiple by 2/3 to get the byte offset into the reader for the // 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. // actual record. Still need to deal with the collision logic after that.
deserializeHashRecords(hashRecordsReader, monitor); deserializeHashRecords(hashRecordsReader);
} }
/** /**
* Deserialize the body of the {@link AbstractSymbolInformation} according to the GSI 7.00 * Deserialize the body of the {@link AbstractSymbolInformation} according to the GSI 7.00
* specification. * specification
* @param reader {@link PdbByteReader} containing the data buffer to process. * @param reader {@link PdbByteReader} containing the data buffer to process
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws PdbException upon unexpected fields
* @throws PdbException Upon unexpected fields. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
private void deserializeGsi70HashTable(PdbByteReader reader, TaskMonitor monitor) private void deserializeGsi70HashTable(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
if (reader.numRemaining() != hashRecordsLength + bucketsLength) { if (reader.numRemaining() != hashRecordsLength + bucketsLength) {
@@ -297,7 +294,7 @@ public abstract class AbstractSymbolInformation {
PdbByteReader hashRecordsReader = reader.getSubPdbByteReader(hashRecordsLength); PdbByteReader hashRecordsReader = reader.getSubPdbByteReader(hashRecordsLength);
PdbByteReader bucketsReader = reader.getSubPdbByteReader(bucketsLength); PdbByteReader bucketsReader = reader.getSubPdbByteReader(bucketsLength);
deserializedCompressedHashBuckets(bucketsReader, monitor); deserializedCompressedHashBuckets(bucketsReader);
// int i = 0; // int i = 0;
// for (int x : hashBucketOffsets) { // for (int x : hashBucketOffsets) {
@@ -308,30 +305,29 @@ public abstract class AbstractSymbolInformation {
// take the offset and multiple by 2/3 to get the byte offset into the reader for the // 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. // actual record. Still need to deal with the collision logic after that.
deserializeHashRecords(hashRecordsReader, monitor); deserializeHashRecords(hashRecordsReader);
} }
/** /**
* Deserializes a compressed set of hash buckets from the {@link PdbByteReader} provided. The * Deserializes a compressed set of hash buckets from the {@link PdbByteReader} provided. The
* data comes as a bit-mapped representation of which indices should contain the data followed * data comes as a bit-mapped representation of which indices should contain the data followed
* by a flat set of hash buckets that will be set at those indices in the order provided. * by a flat set of hash buckets that will be set at those indices in the order provided
* @param reader {@link PdbByteReader} containing the data buffer to process. * @param reader {@link PdbByteReader} containing the data buffer to process
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws PdbException upon not enough data left to parse
* @throws PdbException Upon not enough data left to parse. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
private void deserializedCompressedHashBuckets(PdbByteReader reader, TaskMonitor monitor) private void deserializedCompressedHashBuckets(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
PdbByteReader bitEncoderReader = reader.getSubPdbByteReader(hashRecordsBitMapLength); PdbByteReader bitEncoderReader = reader.getSubPdbByteReader(hashRecordsBitMapLength);
// Throw away extra bytes between bit map and buckets. // Throw away extra bytes between bit map and buckets.
reader.getSubPdbByteReader(numExtraBytes); reader.getSubPdbByteReader(numExtraBytes);
while (bitEncoderReader.hasMore() && reader.hasMore()) { while (bitEncoderReader.hasMore() && reader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
long val = bitEncoderReader.parseUnsignedIntVal(); long val = bitEncoderReader.parseUnsignedIntVal();
//bitEncoded[index++] = val; //bitEncoded[index++] = val;
for (int bit = 0; bit < 32 && reader.hasMore(); bit++) { for (int bit = 0; bit < 32 && reader.hasMore(); bit++) {
monitor.checkCanceled(); pdb.checkCanceled();
if ((val & 0x01L) == 0x01L) { if ((val & 0x01L) == 0x01L) {
hashBucketOffsets.add(reader.parseInt()); hashBucketOffsets.add(reader.parseInt());
} }
@@ -348,7 +344,7 @@ public abstract class AbstractSymbolInformation {
throw new PdbException("Compressed GSI Hash Buckets corrupt"); throw new PdbException("Compressed GSI Hash Buckets corrupt");
} }
while (bitEncoderReader.hasMore()) { while (bitEncoderReader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
if (bitEncoderReader.parseUnsignedIntVal() != 0) { if (bitEncoderReader.parseUnsignedIntVal() != 0) {
throw new PdbException("Compressed GSI Hash Buckets corrupt"); throw new PdbException("Compressed GSI Hash Buckets corrupt");
} }
@@ -357,17 +353,16 @@ public abstract class AbstractSymbolInformation {
} }
/** /**
* * Deserializes the hash records
* @param reader {@link PdbByteReader} containing the data buffer to process. * @param reader {@link PdbByteReader} containing the data buffer to process
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws PdbException upon not enough data left to parse
* @throws PdbException Upon not enough data left to parse. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
private void deserializeHashRecords(PdbByteReader reader, TaskMonitor monitor) private void deserializeHashRecords(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
hashRecords = new TreeSet<>(); hashRecords = new TreeSet<>();
while (reader.hasMore()) { while (reader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
SymbolHashRecord record = new SymbolHashRecord(); SymbolHashRecord record = new SymbolHashRecord();
record.parse(reader); record.parse(reader);
hashRecords.add(record); hashRecords.add(record);
@@ -19,7 +19,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* C11Lines information. As best as we know, only one of C11Lines or C13Lines can be found after * C11Lines information. As best as we know, only one of C11Lines or C13Lines can be found after
@@ -48,12 +47,12 @@ public class C11Lines {
private List<List<List<Long>>> offsets; // unsigned int private List<List<List<Long>>> offsets; // unsigned int
private List<List<List<Integer>>> lineNumbers; // unsigned short private List<List<List<Integer>>> lineNumbers; // unsigned short
public static C11Lines parse(AbstractPdb pdb, PdbByteReader reader, TaskMonitor monitor) public static C11Lines parse(AbstractPdb pdb, PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
return new C11Lines(pdb, reader, monitor); return new C11Lines(pdb, reader);
} }
private C11Lines(AbstractPdb pdb, PdbByteReader reader, TaskMonitor monitor) private C11Lines(AbstractPdb pdb, PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
if (reader.numRemaining() < 4) { if (reader.numRemaining() < 4) {
return; return;
@@ -64,7 +63,7 @@ public class C11Lines {
startEnd = new ArrayList<>(); startEnd = new ArrayList<>();
seg = new ArrayList<>(); seg = new ArrayList<>();
for (int i = 0; i < cFile; i++) { for (int i = 0; i < cFile; i++) {
monitor.checkCanceled(); pdb.checkCanceled();
int val = reader.parseInt(); int val = reader.parseInt();
if (val < 0) { if (val < 0) {
throw new PdbException("beyond our max integer limitation"); throw new PdbException("beyond our max integer limitation");
@@ -72,13 +71,13 @@ public class C11Lines {
baseSrcFile.add(val); baseSrcFile.add(val);
} }
for (int i = 0; i < cSeg; i++) { for (int i = 0; i < cSeg; i++) {
monitor.checkCanceled(); pdb.checkCanceled();
StartEnd se = new StartEnd(); StartEnd se = new StartEnd();
se.parse(reader); se.parse(reader);
startEnd.add(se); startEnd.add(se);
} }
for (int i = 0; i < cSeg; i++) { for (int i = 0; i < cSeg; i++) {
monitor.checkCanceled(); pdb.checkCanceled();
seg.add(reader.parseUnsignedShortVal()); seg.add(reader.parseUnsignedShortVal());
} }
ccSegs = new ArrayList<>(); ccSegs = new ArrayList<>();
@@ -89,14 +88,14 @@ public class C11Lines {
offsets = new ArrayList<>(); offsets = new ArrayList<>();
lineNumbers = new ArrayList<>(); lineNumbers = new ArrayList<>();
for (int i = 0; i < cFile; i++) { for (int i = 0; i < cFile; i++) {
monitor.checkCanceled(); pdb.checkCanceled();
reader.setIndex(baseSrcFile.get(i)); reader.setIndex(baseSrcFile.get(i));
int ccSeg = reader.parseUnsignedShortVal(); int ccSeg = reader.parseUnsignedShortVal();
ccSegs.add(ccSeg); ccSegs.add(ccSeg);
reader.skip(2); // padding reader.skip(2); // padding
List<Integer> baseSrcLn = new ArrayList<>(); List<Integer> baseSrcLn = new ArrayList<>();
for (int j = 0; j < ccSeg; j++) { for (int j = 0; j < ccSeg; j++) {
monitor.checkCanceled(); pdb.checkCanceled();
baseSrcLn.add(reader.parseInt()); baseSrcLn.add(reader.parseInt());
} }
baseSrcLines.add(baseSrcLn); baseSrcLines.add(baseSrcLn);
@@ -113,20 +112,20 @@ public class C11Lines {
List<List<Long>> fileSegOffsets = new ArrayList<>(); // unsigned int List<List<Long>> fileSegOffsets = new ArrayList<>(); // unsigned int
List<List<Integer>> fileSegLineNums = new ArrayList<>(); // unsigned short List<List<Integer>> fileSegLineNums = new ArrayList<>(); // unsigned short
for (int j = 0; j < ccSeg; j++) { for (int j = 0; j < ccSeg; j++) {
monitor.checkCanceled(); pdb.checkCanceled();
reader.setIndex(baseSrcLn.get(j)); reader.setIndex(baseSrcLn.get(j));
int segNum = reader.parseUnsignedShortVal(); int segNum = reader.parseUnsignedShortVal();
segNums.add(segNum); segNums.add(segNum);
int cPair = reader.parseUnsignedShortVal(); int cPair = reader.parseUnsignedShortVal();
List<Long> segOffsets = new ArrayList<>(); // unsigned ints List<Long> segOffsets = new ArrayList<>(); // unsigned ints
for (int k = 0; k < cPair; k++) { for (int k = 0; k < cPair; k++) {
monitor.checkCanceled(); pdb.checkCanceled();
segOffsets.add(reader.parseUnsignedIntVal()); segOffsets.add(reader.parseUnsignedIntVal());
} }
fileSegOffsets.add(segOffsets); fileSegOffsets.add(segOffsets);
List<Integer> segLineNums = new ArrayList<>(); // unsigned shorts List<Integer> segLineNums = new ArrayList<>(); // unsigned shorts
for (int k = 0; k < cPair; k++) { for (int k = 0; k < cPair; k++) {
monitor.checkCanceled(); pdb.checkCanceled();
segLineNums.add(reader.parseUnsignedShortVal()); segLineNums.add(reader.parseUnsignedShortVal());
} }
fileSegLineNums.add(segLineNums); fileSegLineNums.add(segLineNums);
@@ -50,8 +50,8 @@ abstract class C13Section {
* @param reader reader to parse from * @param reader reader to parse from
* @param monitor {@link TaskMonitor} used for checking cancellation * @param monitor {@link TaskMonitor} used for checking cancellation
* @return the parsed data * @return the parsed data
* @throws PdbException Upon not enough data left to parse * @throws PdbException upon not enough data left to parse
* @throws CancelledException Upon user cancellation * @throws CancelledException upon user cancellation
*/ */
static C13Section parse(PdbByteReader reader, TaskMonitor monitor) static C13Section parse(PdbByteReader reader, TaskMonitor monitor)
throws CancelledException, PdbException { throws CancelledException, PdbException {
@@ -20,7 +20,6 @@ import java.io.Writer;
import java.util.*; import java.util.*;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* Debug Data structures for PDB files. There are a number of debug streams that can be processed. * Debug Data structures for PDB files. There are a number of debug streams that can be processed.
@@ -81,8 +80,8 @@ public class DebugData {
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param pdb {@link AbstractPdb} that owns this {@link DebugData}. * @param pdb {@link AbstractPdb} that owns this {@link DebugData}
*/ */
public DebugData(AbstractPdb pdb) { public DebugData(AbstractPdb pdb) {
Objects.requireNonNull(pdb, "pdb cannot be null"); Objects.requireNonNull(pdb, "pdb cannot be null");
@@ -91,7 +90,7 @@ public class DebugData {
/** /**
* Returns the Frame Pointer Omission data * Returns the Frame Pointer Omission data
* @return the framePointerOmissionData or null if does not exist. * @return the framePointerOmissionData or null if does not exist
*/ */
public List<FramePointerOmissionRecord> getFramePointerOmissionData() { public List<FramePointerOmissionRecord> getFramePointerOmissionData() {
return framePointerOmissionData; return framePointerOmissionData;
@@ -114,8 +113,8 @@ public class DebugData {
} }
/** /**
* Returns the {@link List}&lt;{@link ImageSectionHeader}&gt;. * Returns the {@link List}&lt;{@link ImageSectionHeader}&gt;
* @return the imageSectionHeaders or null if does not exist. * @return the imageSectionHeaders or null if does not exist
*/ */
public List<ImageSectionHeader> getImageSectionHeaders() { public List<ImageSectionHeader> getImageSectionHeaders() {
return imageSectionHeaders; return imageSectionHeaders;
@@ -123,9 +122,9 @@ public class DebugData {
/** /**
* Returns the {@link List}&lt;{@link ImageSectionHeader}&gt;. * Returns the {@link List}&lt;{@link ImageSectionHeader}&gt;.
* When this return a non-null list the OMAP_FROM_SRC should be * When this returns a non-null list the OMAP_FROM_SRC should be
* used for remapping global symbols. * used for remapping global symbols
* @return the imageSectionHeadersOrig or null if does not exist. * @return the imageSectionHeadersOrig or null if does not exist
*/ */
public List<ImageSectionHeader> getImageSectionHeadersOrig() { public List<ImageSectionHeader> getImageSectionHeadersOrig() {
return imageSectionHeadersOrig; return imageSectionHeadersOrig;
@@ -138,17 +137,16 @@ public class DebugData {
* Frame Pointer Omission debug data). A stream number of 0XFFFF says that there is no data * Frame Pointer Omission debug data). A stream number of 0XFFFF says that there is no data
* for that debug type; else the stream number represents the stream that should * for that debug type; else the stream number represents the stream that should
* be deserialized to retrieve the debug data of that type. The * be deserialized to retrieve the debug data of that type. The
* {@link #deserialize(TaskMonitor)} method deserializes each of these streams * {@link #deserialize()} method deserializes each of these streams
* that are valid to the corresponding debug data type. * that are valid to the corresponding debug data type
* @param reader {@link PdbByteReader} from which to parse the header. * @param reader {@link PdbByteReader} from which to parse the header
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws PdbException upon error in processing components
* @throws PdbException Upon error in processing components. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
public void deserializeHeader(PdbByteReader reader, TaskMonitor monitor) public void deserializeHeader(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
while (reader.hasMore()) { while (reader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
int debugStreamNumber = reader.parseUnsignedShortVal(); int debugStreamNumber = reader.parseUnsignedShortVal();
debugStreams.add(debugStreamNumber); debugStreams.add(debugStreamNumber);
} }
@@ -160,14 +158,13 @@ public class DebugData {
/** /**
* Deserialize each valid {@link DebugData} stream, based upon valid stream numbers found while * Deserialize each valid {@link DebugData} stream, based upon valid stream numbers found while
* parsing the {@link DebugData} header. * parsing the {@link DebugData} header
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws PdbException PdbException upon error in processing components
* @throws PdbException PdbException Upon error in processing components. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation. * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes
* inability to read required bytes.
*/ */
public void deserialize(TaskMonitor monitor) public void deserialize()
throws PdbException, CancelledException, IOException { throws PdbException, CancelledException, IOException {
if (debugStreams.isEmpty()) { if (debugStreams.isEmpty()) {
throw new PdbException( throw new PdbException(
@@ -180,7 +177,7 @@ public class DebugData {
} }
switch (dbg) { switch (dbg) {
case FRAME_POINTER_OMISSION: case FRAME_POINTER_OMISSION:
deserializeFramePointerOmissionData(streamNum, monitor); deserializeFramePointerOmissionData(streamNum);
break; break;
case EXCEPTION: case EXCEPTION:
// TODO: implement. // TODO: implement.
@@ -189,40 +186,40 @@ public class DebugData {
// TODO: implement. // TODO: implement.
break; break;
case OMAP_TO_SOURCE: case OMAP_TO_SOURCE:
// omapToSource = deserializeOMap(streamNum, monitor); // omapToSource = deserializeOMap(streamNum);
break; break;
case OMAP_FROM_SOURCE: case OMAP_FROM_SOURCE:
omapFromSource = deserializeOMap(streamNum, monitor); omapFromSource = deserializeOMap(streamNum);
break; break;
case SECTION_HEADER: case SECTION_HEADER:
imageSectionHeaders = deserializeSectionHeaders(streamNum, monitor); imageSectionHeaders = deserializeSectionHeaders(streamNum);
break; break;
case TOKEN_RID_MAP: case TOKEN_RID_MAP:
// TODO: implement. // TODO: implement.
break; break;
case X_DATA: case X_DATA:
deserializeXData(streamNum, monitor); deserializeXData(streamNum);
break; break;
case P_DATA: case P_DATA:
deserializePData(streamNum, monitor); deserializePData(streamNum);
break; break;
case NEW_FRAME_POINTER_OMISSION: case NEW_FRAME_POINTER_OMISSION:
// TODO: implement. // TODO: implement.
break; break;
case SECTION_HEADER_ORIG: case SECTION_HEADER_ORIG:
imageSectionHeadersOrig = deserializeSectionHeaders(streamNum, monitor); imageSectionHeadersOrig = deserializeSectionHeaders(streamNum);
break; break;
} }
} }
} }
private void deserializeFramePointerOmissionData(int streamNum, TaskMonitor monitor) private void deserializeFramePointerOmissionData(int streamNum)
throws PdbException, CancelledException, IOException { throws PdbException, CancelledException, IOException {
// TODO: check implementation for completeness. // TODO: check implementation for completeness.
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum, monitor); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
framePointerOmissionData = new ArrayList<>(); framePointerOmissionData = new ArrayList<>();
while (reader.hasMore()) { while (reader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
FramePointerOmissionRecord framePointerOmissionRecord = FramePointerOmissionRecord framePointerOmissionRecord =
new FramePointerOmissionRecord(); new FramePointerOmissionRecord();
framePointerOmissionRecord.parse(reader); framePointerOmissionRecord.parse(reader);
@@ -230,12 +227,12 @@ public class DebugData {
} }
} }
private SortedMap<Long, Long> deserializeOMap(int streamNum, TaskMonitor monitor) private SortedMap<Long, Long> deserializeOMap(int streamNum)
throws PdbException, CancelledException, IOException { throws PdbException, CancelledException, IOException {
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum, monitor); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
SortedMap<Long, Long> omap = new TreeMap<>(); SortedMap<Long, Long> omap = new TreeMap<>();
while (reader.hasMore()) { while (reader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
long v1 = reader.parseUnsignedIntVal(); long v1 = reader.parseUnsignedIntVal();
long v2 = reader.parseUnsignedIntVal(); long v2 = reader.parseUnsignedIntVal();
omap.put(v1, v2); omap.put(v1, v2);
@@ -243,12 +240,12 @@ public class DebugData {
return omap; return omap;
} }
private List<ImageSectionHeader> deserializeSectionHeaders(int streamNum, TaskMonitor monitor) private List<ImageSectionHeader> deserializeSectionHeaders(int streamNum)
throws PdbException, CancelledException, IOException { throws PdbException, CancelledException, IOException {
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum, monitor); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
List<ImageSectionHeader> sectionHeaders = new ArrayList<>(); List<ImageSectionHeader> sectionHeaders = new ArrayList<>();
while (reader.hasMore()) { while (reader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
ImageSectionHeader imageSectionHeader = new ImageSectionHeader(pdb); ImageSectionHeader imageSectionHeader = new ImageSectionHeader(pdb);
imageSectionHeader.parse(reader); imageSectionHeader.parse(reader);
sectionHeaders.add(imageSectionHeader); sectionHeaders.add(imageSectionHeader);
@@ -259,11 +256,11 @@ public class DebugData {
// TODO: This is incomplete. // TODO: This is incomplete.
/** /**
* See the {@link LinkerUnwindInfo} class that was built for and is pertinent to * See the {@link LinkerUnwindInfo} class that was built for and is pertinent to
* processing XData. * processing XData
*/ */
private void deserializeXData(int streamNum, TaskMonitor monitor) private void deserializeXData(int streamNum)
throws PdbException, CancelledException, IOException { throws PdbException, CancelledException, IOException {
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum, monitor); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
int streamLength = reader.getLimit(); int streamLength = reader.getLimit();
//System.out.println(reader.dump(0x20)); //System.out.println(reader.dump(0x20));
RvaVaDebugHeader header = new RvaVaDebugHeader(); RvaVaDebugHeader header = new RvaVaDebugHeader();
@@ -289,9 +286,9 @@ public class DebugData {
} }
// TODO: This is incomplete. // TODO: This is incomplete.
private void deserializePData(int streamNum, TaskMonitor monitor) private void deserializePData(int streamNum)
throws PdbException, CancelledException, IOException { throws PdbException, CancelledException, IOException {
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum, monitor); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
pData = new ArrayList<>(); pData = new ArrayList<>();
int streamLength = reader.getLimit(); int streamLength = reader.getLimit();
RvaVaDebugHeader header = new RvaVaDebugHeader(); RvaVaDebugHeader header = new RvaVaDebugHeader();
@@ -310,7 +307,7 @@ public class DebugData {
// TODO: current partial implementation does not work (throws exception) // TODO: current partial implementation does not work (throws exception)
// for ucrtbase.dll arm64. Need to look at this closer. // for ucrtbase.dll arm64. Need to look at this closer.
// while (reader.hasMore()) { // while (reader.hasMore()) {
// monitor.checkCanceled(); // pdb.checkCanceled();
// ImageFunctionEntry entry = new ImageFunctionEntry(); // ImageFunctionEntry entry = new ImageFunctionEntry();
// entry.deserialize(reader); // entry.deserialize(reader);
// pData.add(entry); // pData.add(entry);
@@ -340,17 +337,19 @@ public class DebugData {
} }
/** /**
* Dumps the {@link DebugData}. This package-protected method is for debugging only. * Dumps the {@link DebugData}. This package-protected method is for debugging only
* @param writer {@link Writer} to which to write the debug dump. * @param writer {@link Writer} to which to write the debug dump
* @throws IOException On issue writing to the {@link Writer}. * @throws IOException on issue writing to the {@link Writer}
* @throws CancelledException upon user cancellation
*/ */
void dump(Writer writer) throws IOException { void dump(Writer writer) throws IOException, CancelledException {
writer.write("DebugData---------------------------------------------------\n"); writer.write("DebugData---------------------------------------------------\n");
dumpDebugStreamList(writer); dumpDebugStreamList(writer);
writer.write("FramePointerOmissionData------------------------------------\n"); writer.write("FramePointerOmissionData------------------------------------\n");
if (framePointerOmissionData != null) { if (framePointerOmissionData != null) {
for (FramePointerOmissionRecord framePointerOmissionRecord : framePointerOmissionData) { for (FramePointerOmissionRecord framePointerOmissionRecord : framePointerOmissionData) {
pdb.checkCanceled();
framePointerOmissionRecord.dump(writer); framePointerOmissionRecord.dump(writer);
} }
} }
@@ -360,16 +359,18 @@ public class DebugData {
// if (omapToSource != null) { // if (omapToSource != null) {
// int num = 0; // int num = 0;
// for (Map.Entry<Long, Long> entry : omapToSource.entrySet()) { // for (Map.Entry<Long, Long> entry : omapToSource.entrySet()) {
// pdb.checkCanceled();
// writer.write(String.format("0X%08X: 0X%012X, 0X%012X\n", num++, entry.getKey(), // writer.write(String.format("0X%08X: 0X%012X, 0X%012X\n", num++, entry.getKey(),
// entry.getValue())); // entry.getValue()));
// } // }
// } // }
// writer.write("End OmapToSource--------------------------------------------\n"); // writer.write("End OmapToSource--------------------------------------------\n");
//
writer.write("OmapFromSource----------------------------------------------\n"); writer.write("OmapFromSource----------------------------------------------\n");
if (omapFromSource != null) { if (omapFromSource != null) {
int num = 0; int num = 0;
for (Map.Entry<Long, Long> entry : omapFromSource.entrySet()) { for (Map.Entry<Long, Long> entry : omapFromSource.entrySet()) {
pdb.checkCanceled();
writer.write(String.format("0X%08X: 0X%012X, 0X%012X\n", num++, entry.getKey(), writer.write(String.format("0X%08X: 0X%012X, 0X%012X\n", num++, entry.getKey(),
entry.getValue())); entry.getValue()));
} }
@@ -380,6 +381,7 @@ public class DebugData {
if (imageSectionHeaders != null) { if (imageSectionHeaders != null) {
int sectionNum = 0; int sectionNum = 0;
for (ImageSectionHeader imageSectionHeader : imageSectionHeaders) { for (ImageSectionHeader imageSectionHeader : imageSectionHeaders) {
pdb.checkCanceled();
imageSectionHeader.dump(writer, sectionNum++); imageSectionHeader.dump(writer, sectionNum++);
} }
} }
@@ -389,6 +391,7 @@ public class DebugData {
if (imageSectionHeadersOrig != null) { if (imageSectionHeadersOrig != null) {
int sectionNum = 0; int sectionNum = 0;
for (ImageSectionHeader imageSectionHeader : imageSectionHeadersOrig) { for (ImageSectionHeader imageSectionHeader : imageSectionHeadersOrig) {
pdb.checkCanceled();
imageSectionHeader.dump(writer, sectionNum++); imageSectionHeader.dump(writer, sectionNum++);
} }
} }
@@ -397,6 +400,7 @@ public class DebugData {
writer.write("PData-------------------------------------------------------\n"); writer.write("PData-------------------------------------------------------\n");
if (pData != null) { if (pData != null) {
for (ImageFunctionEntry entry : pData) { for (ImageFunctionEntry entry : pData) {
pdb.checkCanceled();
// TODO: need to output more if/when more PData is available (e.g., interpretation // TODO: need to output more if/when more PData is available (e.g., interpretation
// of XData. // of XData.
writer.append(entry.toString()); writer.append(entry.toString());
@@ -408,14 +412,16 @@ public class DebugData {
} }
/** /**
* Dumps the DebugStreamList. This package-protected method is for debugging only. * Dumps the DebugStreamList. This package-protected method is for debugging only
* @param writer {@link Writer} to which to write the debug dump. * @param writer {@link Writer} to which to write the debug dump
* @throws IOException On issue writing to the {@link Writer}. * @throws IOException on issue writing to the {@link Writer}
* @throws CancelledException upon user cancellation
*/ */
private void dumpDebugStreamList(Writer writer) throws IOException { private void dumpDebugStreamList(Writer writer) throws IOException, CancelledException {
writer.write("StreamList--------------------------------------------------\n"); writer.write("StreamList--------------------------------------------------\n");
int i = 0; int i = 0;
for (int strmNumber : debugStreams) { for (int strmNumber : debugStreams) {
pdb.checkCanceled();
writer.write(String.format("StrmNumber[%02d]: %04x\n", i++, strmNumber)); writer.write(String.format("StrmNumber[%02d]: %04x\n", i++, strmNumber));
} }
writer.write("End StreamList----------------------------------------------\n"); writer.write("End StreamList----------------------------------------------\n");
@@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
public class EmptyTPI extends AbstractTypeProgramInterface { public class EmptyTPI extends TypeProgramInterface {
EmptyTPI(AbstractPdb pdb) { EmptyTPI(AbstractPdb pdb) {
super(pdb, RecordCategory.TYPE, -1); super(pdb, RecordCategory.TYPE, -1);
@@ -22,7 +22,6 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* Iterator for Global Reference Offsets section of module stream. This iterator returns * Iterator for Global Reference Offsets section of module stream. This iterator returns
@@ -34,25 +33,21 @@ class GlobalReferenceIterator implements ParsingIterator<MsSymbolIterator> {
private AbstractPdb pdb; private AbstractPdb pdb;
private int symbolsStreamNumber; private int symbolsStreamNumber;
private TaskMonitor monitor;
private GlobalReferenceOffsetIterator offsetIterator = null; private GlobalReferenceOffsetIterator offsetIterator = null;
private MsSymbolIterator currentGlobalSymbolIterator = null; private MsSymbolIterator currentGlobalSymbolIterator = null;
/** /**
* An Iterator of Global Reference Symbol Iterators (iterator of iterators). * An Iterator of Global Reference Symbol Iterators (iterator of iterators)
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed * @param pdb {@link AbstractPdb} that owns the Symbols to be parsed
* @param reader PdbByteReader containing only Global Reference Offsets information and in * @param reader PdbByteReader containing only Global Reference Offsets information and in
* newly constructed state * newly constructed state
* @param monitor {@link TaskMonitor} used for checking user cancellation
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
* @throws PdbException Upon not enough data left to parse * @throws PdbException upon not enough data left to parse
*/ */
public GlobalReferenceIterator(AbstractPdb pdb, PdbByteReader reader, TaskMonitor monitor) public GlobalReferenceIterator(AbstractPdb pdb, PdbByteReader reader)
throws CancelledException, PdbException { throws CancelledException, PdbException {
this.pdb = pdb; this.pdb = pdb;
this.monitor = monitor;
PdbDebugInfo debugInfo = pdb.getDebugInfo(); PdbDebugInfo debugInfo = pdb.getDebugInfo();
if (debugInfo == null) { if (debugInfo == null) {
throw new PdbException( throw new PdbException(
@@ -102,7 +97,7 @@ class GlobalReferenceIterator implements ParsingIterator<MsSymbolIterator> {
Long offset = offsetIterator.next(); Long offset = offsetIterator.next();
PdbByteReader reader = PdbByteReader reader =
pdb.getReaderForStreamNumber(symbolsStreamNumber, offset.intValue(), pdb.getReaderForStreamNumber(symbolsStreamNumber, offset.intValue(),
MsfStream.MAX_STREAM_LENGTH, monitor); MsfStream.MAX_STREAM_LENGTH);
currentGlobalSymbolIterator = new MsSymbolIterator(pdb, reader); currentGlobalSymbolIterator = new MsSymbolIterator(pdb, reader);
} }
catch (IOException e) { catch (IOException e) {
@@ -34,7 +34,7 @@ class GlobalReferenceOffsetIterator implements ParsingIterator<Long> {
* @param reader PdbByteReader containing only Global Reference Offsets information and in * @param reader PdbByteReader containing only Global Reference Offsets information and in
* newly constructed state * newly constructed state
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
* @throws PdbException Upon not enough data left to parse * @throws PdbException upon not enough data left to parse
*/ */
public GlobalReferenceOffsetIterator(PdbByteReader reader) public GlobalReferenceOffsetIterator(PdbByteReader reader)
throws CancelledException, PdbException { throws CancelledException, PdbException {
@@ -80,7 +80,7 @@ class GlobalReferenceOffsetIterator implements ParsingIterator<Long> {
/** /**
* Reads and validates size field; leaves reader pointing at first record. * Reads and validates size field; leaves reader pointing at first record.
* @throws PdbException Upon not enough data left to parse * @throws PdbException upon not enough data left to parse
*/ */
private void processHeader() throws PdbException { private void processHeader() throws PdbException {
int sizeField = reader.parseInt(); int sizeField = reader.parseInt();
@@ -19,7 +19,6 @@ import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* This class represents Global Symbol Information component of a PDB file. This class is only * This class represents Global Symbol Information component of a PDB file. This class is only
@@ -41,32 +40,32 @@ public class GlobalSymbolInformation extends AbstractSymbolInformation {
} }
/** /**
* Deserialize the {@link GlobalSymbolInformation} from the appropriate stream in the Pdb. * Deserialize the {@link GlobalSymbolInformation} from the appropriate stream in the Pdb
* @param streamNumber the stream number containing the information to deserialize. * @param streamNumber the stream number containing the information to deserialize
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes
* inability to read required bytes. * @throws PdbException upon not enough data left to parse
* @throws PdbException Upon not enough data left to parse. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
@Override @Override
void deserialize(int streamNumber, TaskMonitor monitor) void deserialize(int streamNumber)
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
super.deserialize(streamNumber, monitor); super.deserialize(streamNumber);
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber);
deserializeHashTable(reader, monitor); deserializeHashTable(reader);
// Organize the information // Organize the information
generateSymbolsList(monitor); generateSymbolsList();
} }
/** /**
* Debug method for dumping information from this {@link GlobalSymbolInformation}. * Debug method for dumping information from this {@link GlobalSymbolInformation}
* @param writer {@link Writer} to which to dump the information. * @param writer {@link Writer} to which to dump the information
* @throws IOException Upon IOException writing to the {@link Writer}. * @throws IOException upon IOException writing to the {@link Writer}
* @throws CancelledException upon user cancellation
*/ */
@Override @Override
void dump(Writer writer) throws IOException { void dump(Writer writer) throws IOException, CancelledException {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("GlobalSymbolInformation-------------------------------------\n"); builder.append("GlobalSymbolInformation-------------------------------------\n");
dumpHashHeader(builder); dumpHashHeader(builder);
@@ -19,7 +19,7 @@ import org.apache.commons.lang3.StringUtils;
/** /**
* Parser, extending {@link TypeProgramInterfaceParser}, for detecting and returning the * Parser, extending {@link TypeProgramInterfaceParser}, for detecting and returning the
* appropriate {@link AbstractTypeProgramInterface} format to be used as the Item Program * appropriate {@link TypeProgramInterface} format to be used as the Item Program
* Interface for the filename given. * Interface for the filename given.
*/ */
public class ItemProgramInterfaceParser extends TypeProgramInterfaceParser { public class ItemProgramInterfaceParser extends TypeProgramInterfaceParser {
@@ -27,8 +27,8 @@ public class ItemProgramInterfaceParser extends TypeProgramInterfaceParser {
private static final int ITEM_PROGRAM_INTERFACE_STREAM_NUMBER = 4; private static final int ITEM_PROGRAM_INTERFACE_STREAM_NUMBER = 4;
/** /**
* Returns the standard stream number that contains the serialized Item Program Interface. * Returns the standard stream number that contains the serialized Item Program Interface
* @return The standard stream number that contains the Item Program Interface. * @return the standard stream number that contains the Item Program Interface
*/ */
@Override @Override
protected int getStreamNumber() { protected int getStreamNumber() {
@@ -38,8 +38,8 @@ public class ItemProgramInterfaceParser extends TypeProgramInterfaceParser {
/** /**
* Returns the appropriate {@link RecordCategory} needed while processing * Returns the appropriate {@link RecordCategory} needed while processing
* the Type Program Interface} (vs. Item Program Interface). * the Type Program Interface} (vs. Item Program Interface)
* @return {@link RecordCategory#ITEM}. * @return {@link RecordCategory#ITEM}
*/ */
@Override @Override
protected RecordCategory getCategory() { protected RecordCategory getCategory() {
@@ -48,10 +48,10 @@ public class ItemProgramInterfaceParser extends TypeProgramInterfaceParser {
} }
/** /**
* Returns true if there is not a name in the name table assigned to the stream number for * Returns {@code true} if there is not a name in the name table assigned to the stream number
* the IPI. * for the IPI
* @param nameTable the nametable that contains the stream/name map * @param nameTable the name table that contains the stream/name map
* @return {@code true} if no name associated with the IPI stream number. * @return {@code true} if no name associated with the IPI stream number
*/ */
public static boolean hackCheckNoNameForStream(NameTable nameTable) { public static boolean hackCheckNoNameForStream(NameTable nameTable) {
String name = nameTable.getNameFromStreamNumber(ITEM_PROGRAM_INTERFACE_STREAM_NUMBER); String name = nameTable.getNameFromStreamNumber(ITEM_PROGRAM_INTERFACE_STREAM_NUMBER);
@@ -22,16 +22,15 @@ import java.util.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream; import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* <B> Note that this class is new, in-progress creation, being designed as a better interface for * <B> Note that this class is new, in-progress creation, being designed as a better interface for
* getting information for any particular module (stream) in a more random-access manner.</B> * getting information for any particular module (stream) in a more random-access manner.</B>
* <P> * <P>
* This class represents Module Stream data of a PDB file. This is different from the * This class represents Module Stream data of a PDB file. This is different from the
* {@link AbstractModuleInformation} and children classes that are parsed from the DBI stream, * {@link ModuleInformation} and children classes that are parsed from the DBI stream,
* which describes (or is control information for) what is the stream from which this * which describes (or is control information for) what is the stream from which this
* {@link Module} is parsed. Note that we use the {@link AbstractModuleInformation} as one of * {@link Module} is parsed. Note that we use the {@link ModuleInformation} as one of
* the construction parameter to this class. * the construction parameter to this class.
* <P> * <P>
* This class is only suitable for reading; not for writing or modifying a PDB. * This class is only suitable for reading; not for writing or modifying a PDB.
@@ -42,8 +41,7 @@ import ghidra.util.task.TaskMonitor;
public class Module { public class Module {
private AbstractPdb pdb; private AbstractPdb pdb;
private AbstractModuleInformation moduleInformation; private ModuleInformation moduleInformation;
private TaskMonitor monitor;
private int streamNumber; private int streamNumber;
private MsfStream stream = null; private MsfStream stream = null;
@@ -61,17 +59,15 @@ public class Module {
private boolean doDumpGlobalRefererenceInfo = false; private boolean doDumpGlobalRefererenceInfo = false;
//============================================================================================== //==============================================================================================
public Module(AbstractPdb pdb, AbstractModuleInformation moduleInformation, public Module(AbstractPdb pdb, ModuleInformation moduleInformation) {
TaskMonitor monitor) {
Objects.requireNonNull(pdb, "pdb cannot be null"); Objects.requireNonNull(pdb, "pdb cannot be null");
Objects.requireNonNull(moduleInformation, "moduleInformation cannot be null"); Objects.requireNonNull(moduleInformation, "moduleInformation cannot be null");
this.pdb = pdb; this.pdb = pdb;
this.moduleInformation = moduleInformation; this.moduleInformation = moduleInformation;
this.monitor = monitor;
precalculateStreamLocations(); precalculateStreamLocations();
} }
public AbstractModuleInformation getModuleInformation() { public ModuleInformation getModuleInformation() {
return moduleInformation; return moduleInformation;
} }
@@ -115,10 +111,9 @@ public class Module {
} }
try { try {
PdbByteReader reader = PdbByteReader reader =
pdb.getReaderForStreamNumber(streamNumber, offsetLines, sizeLines, pdb.getReaderForStreamNumber(streamNumber, offsetLines, sizeLines);
monitor);
// This parser has not been tested with real data // This parser has not been tested with real data
C11Lines c11Lines = C11Lines.parse(pdb, reader, monitor); C11Lines c11Lines = C11Lines.parse(pdb, reader);
return c11Lines; return c11Lines;
} }
catch (IOException e) { catch (IOException e) {
@@ -193,7 +188,7 @@ public class Module {
* Returns a C13SectionIterator that iterators over all C13Sections of this module * Returns a C13SectionIterator that iterators over all C13Sections of this module
* @return the iterator * @return the iterator
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
* @throws PdbException Upon not enough data left to parse * @throws PdbException upon not enough data left to parse
*/ */
public C13SectionIterator<C13Section> getC13SectionIterator() public C13SectionIterator<C13Section> getC13SectionIterator()
throws CancelledException, PdbException { throws CancelledException, PdbException {
@@ -206,13 +201,13 @@ public class Module {
* @param clazz The class of the filter type * @param clazz The class of the filter type
* @return the iterator * @return the iterator
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
* @throws PdbException Upon not enough data left to parse * @throws PdbException upon not enough data left to parse
*/ */
public <T extends C13Section> C13SectionIterator<T> getC13SectionFilteredIterator( public <T extends C13Section> C13SectionIterator<T> getC13SectionFilteredIterator(
Class<T> clazz) throws CancelledException, PdbException { Class<T> clazz) throws CancelledException, PdbException {
PdbByteReader c13SectionReader = getC13LinesReader(); PdbByteReader c13SectionReader = getC13LinesReader();
C13SectionIterator<T> iterator = C13SectionIterator<T> iterator =
new C13SectionIterator<>(c13SectionReader, clazz, true, monitor); new C13SectionIterator<>(c13SectionReader, clazz, true, pdb.getMonitor());
return iterator; return iterator;
} }
@@ -225,7 +220,7 @@ public class Module {
* nested blocks until the closing END is found for the GPROC32 * nested blocks until the closing END is found for the GPROC32
* @return the iterator * @return the iterator
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
* @throws PdbException Upon not enough data left to parse * @throws PdbException upon not enough data left to parse
*/ */
public GlobalReferenceOffsetIterator getGlobalReferenceOffsetIterator() public GlobalReferenceOffsetIterator getGlobalReferenceOffsetIterator()
throws CancelledException, PdbException { throws CancelledException, PdbException {
@@ -245,13 +240,13 @@ public class Module {
* nested blocks until the closing END is found for the GPROC32 * nested blocks until the closing END is found for the GPROC32
* @return the iterator * @return the iterator
* @throws CancelledException upon user cancellation * @throws CancelledException upon user cancellation
* @throws PdbException Upon not enough data left to parse * @throws PdbException upon not enough data left to parse
*/ */
public GlobalReferenceIterator getGlobalReferenceIterator() public GlobalReferenceIterator getGlobalReferenceIterator()
throws CancelledException, PdbException { throws CancelledException, PdbException {
PdbByteReader globalRefsReader = getGlobalRefsReader(); PdbByteReader globalRefsReader = getGlobalRefsReader();
GlobalReferenceIterator iterator = GlobalReferenceIterator iterator =
new GlobalReferenceIterator(pdb, globalRefsReader, monitor); new GlobalReferenceIterator(pdb, globalRefsReader);
return iterator; return iterator;
} }
@@ -282,7 +277,7 @@ public class Module {
} }
try { try {
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber);
reader.skip(offset); reader.skip(offset);
try { try {
if (size == -1) { if (size == -1) {
@@ -312,11 +307,11 @@ public class Module {
// is loaded into the class (note that as of this writing, the PdbByteReader still contains // is loaded into the class (note that as of this writing, the PdbByteReader still contains
// full byte array of data, consuming memory at the time of use). // full byte array of data, consuming memory at the time of use).
/** /**
* Dumps this class to a Writer. * Dumps this class to a Writer
* @param writer {@link Writer} to which to dump the information * @param writer {@link Writer} to which to dump the information
* @throws PdbException Upon not enough data left to parse * @throws PdbException upon not enough data left to parse
* @throws CancelledException Upon user cancellation * @throws CancelledException upon user cancellation
* @throws IOException Upon IOException writing to the {@link Writer} * @throws IOException upon IOException writing to the {@link Writer}
*/ */
void dump(Writer writer) void dump(Writer writer)
throws CancelledException, PdbException, IOException { throws CancelledException, PdbException, IOException {
@@ -341,6 +336,7 @@ public class Module {
writer.write("Symbols-----------------------------------------------------\n"); writer.write("Symbols-----------------------------------------------------\n");
MsSymbolIterator symbolIterator = getSymbolIterator(); MsSymbolIterator symbolIterator = getSymbolIterator();
while (symbolIterator.hasNext()) { while (symbolIterator.hasNext()) {
pdb.checkCanceled();
AbstractMsSymbol symbol = symbolIterator.next(); AbstractMsSymbol symbol = symbolIterator.next();
writer.append(symbol.toString()); writer.append(symbol.toString());
} }
@@ -365,6 +361,7 @@ public class Module {
C13SectionIterator<C13Section> c13Iterator = C13SectionIterator<C13Section> c13Iterator =
getC13SectionFilteredIterator(C13Section.class); getC13SectionFilteredIterator(C13Section.class);
while (c13Iterator.hasNext()) { while (c13Iterator.hasNext()) {
pdb.checkCanceled();
C13Section c13Section = c13Iterator.next(); C13Section c13Section = c13Iterator.next();
c13Section.dump(writer); c13Section.dump(writer);
} }
@@ -375,6 +372,7 @@ public class Module {
// C13SectionIterator<DummyC13Symbols> c13SymbolsIterator = // C13SectionIterator<DummyC13Symbols> c13SymbolsIterator =
// getC13SectionFilteredIterator(DummyC13Symbols.class); // getC13SectionFilteredIterator(DummyC13Symbols.class);
// while (c13SymbolsIterator.hasNext()) { // while (c13SymbolsIterator.hasNext()) {
// pdb.checkCanceled();
// DummyC13Symbols dummyC13Symbols = c13SymbolsIterator.next(); // DummyC13Symbols dummyC13Symbols = c13SymbolsIterator.next();
// dummyC13Symbols.dump(writer); // dummyC13Symbols.dump(writer);
// } // }
@@ -382,6 +380,7 @@ public class Module {
// C13SectionIterator<C13Lines> c13LinesIterator = // C13SectionIterator<C13Lines> c13LinesIterator =
// getC13SectionFilteredIterator(C13Lines.class); // getC13SectionFilteredIterator(C13Lines.class);
// while (c13LinesIterator.hasNext()) { // while (c13LinesIterator.hasNext()) {
// pdb.checkCanceled();
// C13Lines myC13Lines = c13LinesIterator.next(); // C13Lines myC13Lines = c13LinesIterator.next();
// myC13Lines.dump(writer); // myC13Lines.dump(writer);
// } // }
@@ -395,6 +394,7 @@ public class Module {
GlobalReferenceOffsetIterator globalRefsOffsetIterator = GlobalReferenceOffsetIterator globalRefsOffsetIterator =
getGlobalReferenceOffsetIterator(); getGlobalReferenceOffsetIterator();
while (globalRefsOffsetIterator.hasNext()) { while (globalRefsOffsetIterator.hasNext()) {
pdb.checkCanceled();
Long val = globalRefsOffsetIterator.next(); Long val = globalRefsOffsetIterator.next();
writer.append(String.format("0x%08x\n", val)); writer.append(String.format("0x%08x\n", val));
tmp.add(val); tmp.add(val);
@@ -420,6 +420,7 @@ public class Module {
GlobalReferenceIterator globalReferenceIterator = GlobalReferenceIterator globalReferenceIterator =
getGlobalReferenceIterator(); getGlobalReferenceIterator();
while (globalReferenceIterator.hasNext()) { while (globalReferenceIterator.hasNext()) {
pdb.checkCanceled();
MsSymbolIterator symIter = globalReferenceIterator.next(); MsSymbolIterator symIter = globalReferenceIterator.next();
if (symIter.hasNext()) { if (symIter.hasNext()) {
AbstractMsSymbol sym = symIter.next(); AbstractMsSymbol sym = symIter.next();
@@ -24,13 +24,13 @@ import java.util.*;
* We have intended to implement according to the Microsoft PDB API (source); see the API for * We have intended to implement according to the Microsoft PDB API (source); see the API for
* truth. * truth.
*/ */
public abstract class AbstractModuleInformation { public abstract class ModuleInformation {
//============================================================================================== //==============================================================================================
// Internals // Internals
//============================================================================================== //==============================================================================================
protected long modulePointer; protected long modulePointer;
protected AbstractSectionContribution sectionContribution; protected SectionContribution sectionContribution;
protected boolean writtenSinceOpen; protected boolean writtenSinceOpen;
// TODO: consider what to do (gets parsed for 600 between 500 items. Want only in 600, // TODO: consider what to do (gets parsed for 600 between 500 items. Want only in 600,
// but would have to break up the deserialize and dumpInternal methods. Issue might be, // but would have to break up the deserialize and dumpInternal methods. Issue might be,
@@ -61,46 +61,46 @@ public abstract class AbstractModuleInformation {
//============================================================================================== //==============================================================================================
// API // API
//============================================================================================== //==============================================================================================
public AbstractModuleInformation(AbstractPdb pdb) { public ModuleInformation(AbstractPdb pdb) {
Objects.requireNonNull(pdb, "pdb cannot be null"); Objects.requireNonNull(pdb, "pdb cannot be null");
this.pdb = pdb; this.pdb = pdb;
} }
/** /**
* Returns the number of files contributing to the module. * Returns the number of files contributing to the module
* @return Number of files. * @return number of files
*/ */
public int getNumFilesContributing() { public int getNumFilesContributing() {
return numFilesContributing; return numFilesContributing;
} }
/** /**
* Returns list of offsets for the module. * Returns list of offsets for the module
* @return Offsets. * @return offsets
*/ */
public List<Integer> getOffsetsArray() { public List<Integer> getOffsetsArray() {
return offsetsArray; return offsetsArray;
} }
/** /**
* Returns list of file names for the module. * Returns list of file names for the module
* @return File names. * @return file names
*/ */
public List<String> getFilenamesArray() { public List<String> getFilenamesArray() {
return filenamesArray; return filenamesArray;
} }
/** /**
* Returns the stream number containing debug information. * Returns the stream number containing debug information
* @return Stream number. * @return stream number
*/ */
public int getStreamNumberDebugInformation() { public int getStreamNumberDebugInformation() {
return streamNumberDebugInformation; return streamNumberDebugInformation;
} }
/** /**
* Returns the size of the local symbols debug information. * Returns the size of the local symbols debug information
* @return Size of the local symbols debug information. * @return size of the local symbols debug information
*/ */
public int getSizeLocalSymbolsDebugInformation() { public int getSizeLocalSymbolsDebugInformation() {
return sizeLocalSymbolsDebugInformation; return sizeLocalSymbolsDebugInformation;
@@ -108,7 +108,7 @@ public abstract class AbstractModuleInformation {
/** /**
* Returns the size of the older-style line number information * Returns the size of the older-style line number information
* @return Size of the older-style line number information * @return size of the older-style line number information
*/ */
public int getSizeLineNumberDebugInformation() { public int getSizeLineNumberDebugInformation() {
return sizeLineNumberDebugInformation; return sizeLineNumberDebugInformation;
@@ -116,25 +116,25 @@ public abstract class AbstractModuleInformation {
/** /**
* Returns the size of the C13-style line number information * Returns the size of the C13-style line number information
* @return Size of the C13-style line number information * @return size of the C13-style line number information
*/ */
public int getSizeC13StyleLineNumberInformation() { public int getSizeC13StyleLineNumberInformation() {
return sizeC13StyleLineNumberInformation; return sizeC13StyleLineNumberInformation;
} }
/** /**
* Returns the name of the module. * Returns the name of the module
* @return Name of the module. * @return name of the module
*/ */
public String getModuleName() { public String getModuleName() {
return moduleName; return moduleName;
} }
/** /**
* Returns {@link AbstractSectionContribution} of the module. * Returns {@link SectionContribution} of the module
* @return {@link AbstractSectionContribution} of the module. * @return {@link SectionContribution} of the module
*/ */
public AbstractSectionContribution getSectionContribution() { public SectionContribution getSectionContribution() {
return sectionContribution; return sectionContribution;
} }
@@ -151,9 +151,9 @@ public abstract class AbstractModuleInformation {
// Internal Data Methods // Internal Data Methods
//============================================================================================== //==============================================================================================
/** /**
* Deserializes the module. * Deserializes the module
* @param reader {@link PdbByteReader} from which to deserialize the data. * @param reader {@link PdbByteReader} from which to deserialize the data
* @throws PdbException upon error parsing a string name. * @throws PdbException upon error parsing a string name
*/ */
protected void deserialize(PdbByteReader reader) throws PdbException { protected void deserialize(PdbByteReader reader) throws PdbException {
modulePointer = reader.parseUnsignedIntVal(); modulePointer = reader.parseUnsignedIntVal();
@@ -186,15 +186,15 @@ public abstract class AbstractModuleInformation {
//============================================================================================== //==============================================================================================
/** /**
* Deserializes the Additionals. Abstract method filled in by instances to parse additional * Deserializes the Additionals. Abstract method filled in by instances to parse additional
* data pertinent to themselves. * data pertinent to themselves
* @param reader {@link PdbByteReader} from which to deserialize the data. * @param reader {@link PdbByteReader} from which to deserialize the data
* @throws PdbException upon error parsing a string name. * @throws PdbException upon error parsing a string name
*/ */
protected abstract void parseAdditionals(PdbByteReader reader) throws PdbException; protected abstract void parseAdditionals(PdbByteReader reader) throws PdbException;
/** /**
* Dumps the Additionals. This method is for debugging only. * Dumps the Additionals. This method is for debugging only
* @return {@link String} of pretty output. * @return {@link String} of pretty output
*/ */
protected abstract String dumpAdditionals(); protected abstract String dumpAdditionals();
@@ -211,8 +211,8 @@ public abstract class AbstractModuleInformation {
} }
/** /**
* Dumps this module. This method is for debugging only. * Dumps this module. This method is for debugging only
* @return {@link String} of pretty output. * @return {@link String} of pretty output
*/ */
String dump() { String dump() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
@@ -16,9 +16,9 @@
package ghidra.app.util.bin.format.pdb2.pdbreader; package ghidra.app.util.bin.format.pdb2.pdbreader;
/** /**
* This class is the version of {@link AbstractModuleInformation} for Microsoft v5.00 PDB. * This class is the version of {@link ModuleInformation} for Microsoft v5.00 PDB.
*/ */
public class ModuleInformation500 extends AbstractModuleInformation { public class ModuleInformation500 extends ModuleInformation {
//============================================================================================== //==============================================================================================
// API // API
@@ -16,9 +16,9 @@
package ghidra.app.util.bin.format.pdb2.pdbreader; package ghidra.app.util.bin.format.pdb2.pdbreader;
/** /**
* This class is the version of {@link AbstractModuleInformation} for Microsoft v6.00 PDB. * This class is the version of {@link ModuleInformation} for Microsoft v6.00 PDB.
*/ */
public class ModuleInformation600 extends AbstractModuleInformation { public class ModuleInformation600 extends ModuleInformation {
//============================================================================================== //==============================================================================================
// API // API
@@ -19,7 +19,6 @@ import java.io.IOException;
import java.util.*; import java.util.*;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* This class represents Name Table component of a PDB file. This class is only * This class represents Name Table component of a PDB file. This class is only
@@ -54,8 +53,8 @@ public class NameTable {
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param pdb {@link AbstractPdb} that owns this Name Table. * @param pdb {@link AbstractPdb} that owns this Name Table
*/ */
public NameTable(AbstractPdb pdb) { public NameTable(AbstractPdb pdb) {
Objects.requireNonNull(pdb, "pdb cannot be null"); Objects.requireNonNull(pdb, "pdb cannot be null");
@@ -63,18 +62,18 @@ public class NameTable {
} }
/** /**
* Returns a name from the Name Table pertaining to the index argument. * Returns a name from the Name Table pertaining to the index argument
* @param index Index of the name to retrieve. * @param index index of the name to retrieve
* @return Name retrieved for the index. * @return name retrieved for the index
*/ */
public String getNameFromStreamNumber(int index) { public String getNameFromStreamNumber(int index) {
return namesByStreamNumber.get(index); return namesByStreamNumber.get(index);
} }
/** /**
* Returns an index of the name argument in the {@link NameTable}. * Returns an index of the name argument in the {@link NameTable}
* @param name Name to look up. * @param name name to look up
* @return Index of the name. * @return index of the name
*/ */
public int getStreamNumberFromName(String name) { public int getStreamNumberFromName(String name) {
Integer x = streamNumbersByName.getOrDefault(name, -1); Integer x = streamNumbersByName.getOrDefault(name, -1);
@@ -83,9 +82,9 @@ public class NameTable {
/** /**
* Returns a name from the Name Table pertaining to the byte-offset in the block of names for * Returns a name from the Name Table pertaining to the byte-offset in the block of names for
* the table. * the table
* @param offset Byte-offset of the name in the {@link NameTable} block. * @param offset byte-offset of the name in the {@link NameTable} block
* @return Name found at offset. * @return name found at offset
*/ */
public String getNameStringFromOffset(int offset) { public String getNameStringFromOffset(int offset) {
if (namesByOffset == null) { if (namesByOffset == null) {
@@ -96,9 +95,9 @@ public class NameTable {
/** /**
* IMPORTANT: This method is for testing only. It allows us to set a basic object. * IMPORTANT: This method is for testing only. It allows us to set a basic object.
* Note: not all values are initialized. Add a paired offset and {@link String} name. * Note: not all values are initialized. Add a paired offset and {@link String} name
* @param offset Offset part of pair. * @param offset offset part of pair
* @param name Name part of pair. * @param name name part of pair
*/ */
public void forTestingOnlyAddOffsetNamePair(int offset, String name) { public void forTestingOnlyAddOffsetNamePair(int offset, String name) {
if (namesByOffset == null) { if (namesByOffset == null) {
@@ -113,21 +112,20 @@ public class NameTable {
//============================================================================================== //==============================================================================================
// TODO: Regarding String conversions... We expect that US_ASCII could be a problem, but it // TODO: Regarding String conversions... We expect that US_ASCII could be a problem, but it
// is probably better than creating the String without any code set chosen at all. Do we // is probably better than creating the String without any code set chosen at all. Do we
// need to change all processing of Strings within the PDB so that we are only creating byte // need to change all processing of Strings within the PDB so that we are only creating byte
// arrays with some notional idea (1 byte, 2 byte, possibly utf-8, utf-16, wchar_t, or // arrays with some notional idea (1 byte, 2 byte, possibly utf-8, utf-16, wchar_t, or
// "unknown" and defer true interpretation/conversion to String until we know or until // "unknown" and defer true interpretation/conversion to String until we know or until
// Ghidra user can ad-hoc apply interpretations to those fields? Needs investigation, but // Ghidra user can ad-hoc apply interpretations to those fields? Needs investigation, but
// not critical at this time. // not critical at this time.
/** /**
* Deserializes the Directory. * Deserializes the Directory
* @param reader {@link PdbByteReader} from which to deserialize the data. * @param reader {@link PdbByteReader} from which to deserialize the data
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes
* inability to read required bytes. * @throws PdbException upon error parsing a string
* @throws PdbException upon error parsing a string. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
void deserializeDirectory(PdbByteReader reader, TaskMonitor monitor) void deserializeDirectory(PdbByteReader reader)
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
// Get the buffer of strings // Get the buffer of strings
@@ -152,10 +150,10 @@ public class NameTable {
streamNumbers = new int[numPairs]; streamNumbers = new int[numPairs];
// Read Present Set. Not really needed by us, as we use the java HashMap. // Read Present Set. Not really needed by us, as we use the java HashMap.
presentList.parse(reader, monitor); presentList.parse(reader, pdb.getMonitor());
// Read Deleted Set. Not really needed by us, as we use the java HashMap. // Read Deleted Set. Not really needed by us, as we use the java HashMap.
deletedList.parse(reader, monitor); deletedList.parse(reader, pdb.getMonitor());
// Read values of index into buffer and name index. Load the HashMaps. // Read values of index into buffer and name index. Load the HashMaps.
// Since we are using the java HashMap, we do not need to mimic the // Since we are using the java HashMap, we do not need to mimic the
@@ -163,7 +161,7 @@ public class NameTable {
// of domainSize) and do not need to store the domain and range items // of domainSize) and do not need to store the domain and range items
// in a list indexed by i. // in a list indexed by i.
for (int i = 0; i < numPairs; i++) { for (int i = 0; i < numPairs; i++) {
monitor.checkCanceled(); pdb.checkCanceled();
int bufOffset = reader.parseInt(); int bufOffset = reader.parseInt();
int streamNumber = reader.parseInt(); int streamNumber = reader.parseInt();
nameBufferReader.setIndex(bufOffset); nameBufferReader.setIndex(bufOffset);
@@ -174,7 +172,7 @@ public class NameTable {
namesByStreamNumber.put(streamNumber, name); namesByStreamNumber.put(streamNumber, name);
streamNumbersByName.put(name, streamNumber); streamNumbersByName.put(name, streamNumber);
} }
deserializeNameTableStreams(monitor); deserializeNameTableStreams();
} }
// TODO: Reduce code complexity once we know the details for the various cases. Probably // TODO: Reduce code complexity once we know the details for the various cases. Probably
@@ -182,19 +180,18 @@ public class NameTable {
// find here. // find here.
/** /**
* Deserializes Name Table Streams. An offset-to-string map is created for each stream; each * Deserializes Name Table Streams. An offset-to-string map is created for each stream; each
* map is placed into a stream-number-to-map map. * map is placed into a stream-number-to-map map
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes
* inability to read required bytes. * @throws PdbException upon error parsing a string
* @throws PdbException upon error parsing a string. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
void deserializeNameTableStreams(TaskMonitor monitor) void deserializeNameTableStreams()
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
for (int streamNumber : streamNumbers) { for (int streamNumber : streamNumbers) {
monitor.checkCanceled(); pdb.checkCanceled();
Map<Integer, String> stringsByOffset = new HashMap<>(); Map<Integer, String> stringsByOffset = new HashMap<>();
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber);
if (reader.getLimit() >= 12) { if (reader.getLimit() >= 12) {
long hdrMagic = reader.parseUnsignedIntVal(); long hdrMagic = reader.parseUnsignedIntVal();
int hdrVer = reader.parseInt(); int hdrVer = reader.parseInt();
@@ -205,7 +202,7 @@ public class NameTable {
int length = reader.parseInt(); int length = reader.parseInt();
PdbByteReader stringReader = reader.getSubPdbByteReader(length); PdbByteReader stringReader = reader.getSubPdbByteReader(length);
while (stringReader.hasMore()) { while (stringReader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
int offset = stringReader.getIndex(); int offset = stringReader.getIndex();
String string = stringReader.parseNullTerminatedUtf8String(); String string = stringReader.parseNullTerminatedUtf8String();
stringsByOffset.put(offset, string); stringsByOffset.put(offset, string);
@@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.AbstractMsf; import ghidra.app.util.bin.format.pdb2.pdbreader.msf.Msf;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@@ -31,20 +31,20 @@ public class Pdb200 extends AbstractPdb {
// Package-Protected Internals // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param msf {@link AbstractMsf} foundation for the PDB. * @param msf {@link Msf} foundation for the PDB
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB. * @param pdbOptions {@link PdbReaderOptions} used for processing the PDB
* @throws IOException Upon file IO seek/read issues. * @throws IOException upon file IO seek/read issues
* @throws PdbException Upon unknown value for configuration or error in processing components. * @throws PdbException upon unknown value for configuration or error in processing components
*/ */
Pdb200(AbstractMsf msf, PdbReaderOptions pdbOptions) throws IOException, PdbException { Pdb200(Msf msf, PdbReaderOptions pdbOptions) throws IOException, PdbException {
super(msf, pdbOptions); super(msf, pdbOptions);
} }
@Override @Override
void deserializeIdentifiersOnly(TaskMonitor monitor) void deserializeIdentifiersOnly(TaskMonitor monitor)
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
PdbByteReader reader = getDirectoryReader(monitor); PdbByteReader reader = getDirectoryReader();
deserializeVersionSignatureAge(reader); deserializeVersionSignatureAge(reader);
} }
@@ -52,9 +52,9 @@ public class Pdb200 extends AbstractPdb {
// Abstract Methods // Abstract Methods
//============================================================================================== //==============================================================================================
@Override @Override
void deserializeDirectory(TaskMonitor monitor) void deserializeDirectory()
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
PdbByteReader reader = getDirectoryReader(monitor); PdbByteReader reader = getDirectoryReader();
deserializeVersionSignatureAge(reader); deserializeVersionSignatureAge(reader);
} }
@@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.AbstractMsf; import ghidra.app.util.bin.format.pdb2.pdbreader.msf.Msf;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@@ -31,20 +31,20 @@ public class Pdb400 extends AbstractPdb {
// Package-Protected Internals // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param msf {@link AbstractMsf} foundation for the PDB. * @param msf {@link Msf} foundation for the PDB
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB. * @param pdbOptions {@link PdbReaderOptions} used for processing the PDB
* @throws IOException Upon file IO seek/read issues. * @throws IOException upon file IO seek/read issues
* @throws PdbException Upon unknown value for configuration or error in processing components. * @throws PdbException upon unknown value for configuration or error in processing components
*/ */
Pdb400(AbstractMsf msf, PdbReaderOptions pdbOptions) throws IOException, PdbException { Pdb400(Msf msf, PdbReaderOptions pdbOptions) throws IOException, PdbException {
super(msf, pdbOptions); super(msf, pdbOptions);
} }
@Override @Override
void deserializeIdentifiersOnly(TaskMonitor monitor) void deserializeIdentifiersOnly(TaskMonitor monitor)
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
PdbByteReader reader = getDirectoryReader(monitor); PdbByteReader reader = getDirectoryReader();
deserializeVersionSignatureAge(reader); deserializeVersionSignatureAge(reader);
} }
@@ -52,11 +52,11 @@ public class Pdb400 extends AbstractPdb {
// Abstract Methods // Abstract Methods
//============================================================================================== //==============================================================================================
@Override @Override
void deserializeDirectory(TaskMonitor monitor) void deserializeDirectory()
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
PdbByteReader reader = getDirectoryReader(monitor); PdbByteReader reader = getDirectoryReader();
deserializeVersionSignatureAge(reader); deserializeVersionSignatureAge(reader);
deserializeParameters(reader, monitor); deserializeParameters(reader);
} }
@Override @Override
@@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.AbstractMsf; import ghidra.app.util.bin.format.pdb2.pdbreader.msf.Msf;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@@ -31,20 +31,20 @@ public class Pdb700 extends AbstractPdb {
// Package-Protected Internals // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param msf {@link AbstractMsf} foundation for the PDB. * @param msf {@link Msf} foundation for the PDB
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB. * @param pdbOptions {@link PdbReaderOptions} used for processing the PDB
* @throws IOException Upon file IO seek/read issues. * @throws IOException upon file IO seek/read issues
* @throws PdbException Upon unknown value for configuration or error in processing components. * @throws PdbException upon unknown value for configuration or error in processing components
*/ */
Pdb700(AbstractMsf msf, PdbReaderOptions pdbOptions) throws IOException, PdbException { Pdb700(Msf msf, PdbReaderOptions pdbOptions) throws IOException, PdbException {
super(msf, pdbOptions); super(msf, pdbOptions);
} }
@Override @Override
void deserializeIdentifiersOnly(TaskMonitor monitor) void deserializeIdentifiersOnly(TaskMonitor monitor)
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
PdbByteReader reader = getDirectoryReader(monitor); PdbByteReader reader = getDirectoryReader();
deserializeVersionSignatureAge(reader); deserializeVersionSignatureAge(reader);
guid = reader.parseGUID(); guid = reader.parseGUID();
} }
@@ -53,12 +53,12 @@ public class Pdb700 extends AbstractPdb {
// Abstract Methods // Abstract Methods
//============================================================================================== //==============================================================================================
@Override @Override
void deserializeDirectory(TaskMonitor monitor) void deserializeDirectory()
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
PdbByteReader reader = getDirectoryReader(monitor); PdbByteReader reader = getDirectoryReader();
deserializeVersionSignatureAge(reader); deserializeVersionSignatureAge(reader);
guid = reader.parseGUID(); guid = reader.parseGUID();
deserializeParameters(reader, monitor); deserializeParameters(reader);
} }
@Override @Override
@@ -76,8 +76,8 @@ public class Pdb700 extends AbstractPdb {
// Internal Data Methods // Internal Data Methods
//============================================================================================== //==============================================================================================
/** /**
* Dumps the GUID. This method is for debugging only. * Dumps the GUID. This method is for debugging only
* @return {@link String} of pretty output. * @return {@link String} of pretty output
*/ */
protected String dumpGUID() { protected String dumpGUID() {
if (guid == null) { if (guid == null) {
@@ -19,7 +19,6 @@ import java.io.IOException;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* Parser for detecting the appropriate {@link PdbDebugInfo} format for the filename * Parser for detecting the appropriate {@link PdbDebugInfo} format for the filename
@@ -44,13 +43,13 @@ public class PdbDebugInfoParser {
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Parses information to determine the version of Database Interface to create. * Parses information to determine the version of debug info to create
* @param pdb {@link AbstractPdb} that owns this Database Interface. * @param pdb {@link AbstractPdb} that owns this debug info
* @return {@link PdbDebugInfo} of the appropriate Database Interface or null if * @return {@link PdbDebugInfo} of the appropriate debug info or null if the stream does not
* the stream does not have enough information to be parsed. * have enough information to be parsed
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* inability to read required bytes. * inability to read required bytes
* @throws PdbException Upon error in processing components. * @throws PdbException upon error in processing components
*/ */
public PdbDebugInfo parse(AbstractPdb pdb) throws IOException, PdbException { public PdbDebugInfo parse(AbstractPdb pdb) throws IOException, PdbException {
PdbDebugInfo debugInfo; PdbDebugInfo debugInfo;
@@ -58,7 +57,7 @@ public class PdbDebugInfoParser {
int streamNumber = getStreamNumber(); int streamNumber = getStreamNumber();
// Only reading 8-bytes - no need for monitor // Only reading 8-bytes - no need for monitor
PdbByteReader reader = PdbByteReader reader =
pdb.getReaderForStreamNumber(streamNumber, 0, 8, TaskMonitor.DUMMY); pdb.getReaderForStreamNumber(streamNumber, 0, 8);
if (reader.getLimit() == 0) { if (reader.getLimit() == 0) {
return null; return null;
} }
@@ -102,8 +101,8 @@ public class PdbDebugInfoParser {
// Internal Data Methods // Internal Data Methods
//============================================================================================== //==============================================================================================
/** /**
* Returns the standard stream number that contains the serialized Database Interface. * Returns the standard stream number that contains the serialized debug info
* @return Stream number that contains the Database Interface. * @return stream number that contains the debug info
*/ */
protected int getStreamNumber() { protected int getStreamNumber() {
return DEBUG_INFO_STREAM_NUMBER; return DEBUG_INFO_STREAM_NUMBER;
@@ -40,8 +40,8 @@ public class PdbLog {
* method gives control to the client to be able to turn on/off the messaging output without * method gives control to the client to be able to turn on/off the messaging output without
* having to do conditional checks at each point that one of the messaging methods is called. * having to do conditional checks at each point that one of the messaging methods is called.
* @param enable {@code true} to enable logging; {@code false} to disable logging. Initial * @param enable {@code true} to enable logging; {@code false} to disable logging. Initial
* state is {@code false}. * state is {@code false}
* @throws IOException upon problem creating a {@link FileWriter}. * @throws IOException upon problem creating a {@link FileWriter}
* @see #message(String) * @see #message(String)
* @see #message(String, Supplier...) * @see #message(String, Supplier...)
*/ */
@@ -53,11 +53,11 @@ public class PdbLog {
* Outputs a message to the PDB log if messaging has been enable, else ignored. This method * Outputs a message to the PDB log if messaging has been enable, else ignored. This method
* uses a format string and a variable arguments list of lambdas to allow for deferred * uses a format string and a variable arguments list of lambdas to allow for deferred
* processing of the message to output. Thus, when message output is disabled, the client * processing of the message to output. Thus, when message output is disabled, the client
* does not endure as much cost in supplying a message string that is not used. * does not endure as much cost in supplying a message string that is not used
* @param format a {@link String} format list as would be used to a printf() function, but * @param format a {@link String} format list as would be used to a printf() function, but
* which must only specify {@code %s} {@link String} outputs. * which must only specify {@code %s} {@link String} outputs.
* @param suppliers variable number of {@link Supplier}&lt;{@link String}&gt; arguments. The * @param suppliers variable number of {@link Supplier}&lt;{@link String}&gt; arguments. The
* number must match the number of {@code %s} outputs in the format string. * number must match the number of {@code %s} outputs in the format string
* @see #setEnabled(boolean) * @see #setEnabled(boolean)
*/ */
// We know this is @SafeVarags (or SuppressWarnings("unchecked")) on potential // We know this is @SafeVarags (or SuppressWarnings("unchecked")) on potential
@@ -89,9 +89,9 @@ public class PdbLog {
* Outputs a message to the PDB log if messaging has been enable, else ignored. This method * Outputs a message to the PDB log if messaging has been enable, else ignored. This method
* uses a {@link Supplier}&lt;{@link String}&gt; to allow for deferred processing of the message * uses a {@link Supplier}&lt;{@link String}&gt; to allow for deferred processing of the message
* to output. Thus, when message output is disabled, the client does not endure as much cost * to output. Thus, when message output is disabled, the client does not endure as much cost
* in supplying a message string that is not used. * in supplying a message string that is not used
* @param supplier a {@link Supplier}&lt;{@link String}&gt; that supplies a {@link String} * @param supplier a {@link Supplier}&lt;{@link String}&gt; that supplies a {@link String}
* message to be output. * message to be output
* @see #setEnabled(boolean) * @see #setEnabled(boolean)
*/ */
public static void message(Supplier<String> supplier) { public static void message(Supplier<String> supplier) {
@@ -111,8 +111,8 @@ public class PdbLog {
} }
/** /**
* Outputs a {@link String} message to the PDB log if messaging has been enable, else ignored. * Outputs a {@link String} message to the PDB log if messaging has been enable, else ignored
* @param message a {@link String} message to be output. * @param message a {@link String} message to be output
* @see #setEnabled(boolean) * @see #setEnabled(boolean)
*/ */
public static void message(String message) { public static void message(String message) {
@@ -145,17 +145,17 @@ public class PdbLog {
// might not have been read, depending on the order of how record sets are read. // might not have been read, depending on the order of how record sets are read.
// TODO: is using PdbLog here. Is that what we intend? // TODO: is using PdbLog here. Is that what we intend?
/** /**
* Logs fact of record index out of range (detection is performed by caller). * Logs fact of record index out of range (detection is performed by caller)
* @param tpi the TypeProgramInterface involved. * @param tpi the TypeProgramInterface involved
* @param recordNumber the record number to report. * @param recordNumber the record number to report
*/ */
public static void logBadTypeRecordIndex(AbstractTypeProgramInterface tpi, int recordNumber) { public static void logBadTypeRecordIndex(TypeProgramInterface tpi, int recordNumber) {
message("Bad requested type record " + recordNumber + ", min: " + tpi.getTypeIndexMin() + message("Bad requested type record " + recordNumber + ", min: " + tpi.getTypeIndexMin() +
", max: " + tpi.getTypeIndexMaxExclusive()); ", max: " + tpi.getTypeIndexMaxExclusive());
} }
/** /**
* Logs fact of record index out of range (detection is performed by caller). * Logs fact of record index out of range (detection is performed by caller)
* @param type {@link AbstractMsType} found * @param type {@link AbstractMsType} found
* @param itemRequiredClass class expected * @param itemRequiredClass class expected
*/ */
@@ -165,7 +165,7 @@ public class PdbLog {
} }
/** /**
* Cleans up the class by closing resources. * Cleans up the class by closing resources
*/ */
public static void dispose() { public static void dispose() {
try { try {
@@ -180,8 +180,8 @@ public class PdbLog {
} }
/** /**
* Returns the {@link Writer} for logging. * Returns the {@link Writer} for logging
* @return a {@link Writer} for for logging. * @return a {@link Writer} for for logging
*/ */
private static Writer getWriter() throws IOException { private static Writer getWriter() throws IOException {
return enabled ? getFileWriter() : getNullWriter(); return enabled ? getFileWriter() : getNullWriter();
@@ -189,8 +189,8 @@ public class PdbLog {
/** /**
* Returns the {@link FileWriter} for the log file. If the file is already open, it is * Returns the {@link FileWriter} for the log file. If the file is already open, it is
* returned. If not already open, it is opened and previous contents are deleted. * returned. If not already open, it is opened and previous contents are deleted
* @return a {@link FileWriter} for the log file. * @return a {@link FileWriter} for the log file
*/ */
private static Writer getFileWriter() throws IOException { private static Writer getFileWriter() throws IOException {
if (fileWriter == null) { if (fileWriter == null) {
@@ -210,8 +210,8 @@ public class PdbLog {
/** /**
* Returns a {@link NullWriter} for the log file when chosen instead of a FileWriter. If * Returns a {@link NullWriter} for the log file when chosen instead of a FileWriter. If
* one already exists, it is returned. Otherwise a new one is created. * one already exists, it is returned. Otherwise a new one is created
* @return a {@link NullWriter} for the log file. * @return a {@link NullWriter} for the log file
*/ */
private static Writer getNullWriter() { private static Writer getNullWriter() {
if (nullWriter == null) { if (nullWriter == null) {
@@ -21,7 +21,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* This class is the version of {@link PdbDebugInfo} for newer PDB files. * This class is the version of {@link PdbDebugInfo} for newer PDB files.
@@ -63,9 +62,9 @@ public class PdbNewDebugInfo extends PdbDebugInfo {
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param pdb {@link AbstractPdb} that owns this {@link PdbNewDebugInfo}. * @param pdb {@link AbstractPdb} that owns this {@link PdbNewDebugInfo}
* @param streamNumber The stream number that contains the {@link PdbNewDebugInfo} data. * @param streamNumber the stream number that contains the {@link PdbNewDebugInfo} data
*/ */
public PdbNewDebugInfo(AbstractPdb pdb, int streamNumber) { public PdbNewDebugInfo(AbstractPdb pdb, int streamNumber) {
super(pdb, streamNumber); super(pdb, streamNumber);
@@ -73,16 +72,16 @@ public class PdbNewDebugInfo extends PdbDebugInfo {
} }
/** /**
* Returns the {@link ImageFileMachine} machine type. * Returns the {@link ImageFileMachine} machine type
* @return the machine type. * @return the machine type
*/ */
public ImageFileMachine getMachineType() { public ImageFileMachine getMachineType() {
return machineType; return machineType;
} }
/** /**
* Returns the {@link DebugData} for this {@link PdbNewDebugInfo}. * Returns the {@link DebugData} for this {@link PdbNewDebugInfo}
* @return the {@link DebugData}. * @return the {@link DebugData}
*/ */
public DebugData getDebugData() { public DebugData getDebugData() {
return debugData; return debugData;
@@ -133,34 +132,34 @@ public class PdbNewDebugInfo extends PdbDebugInfo {
} }
@Override @Override
protected void deserializeInternalSubstreams(PdbByteReader reader, TaskMonitor monitor) protected void deserializeInternalSubstreams(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
processModuleInformation(reader, monitor, false); processModuleInformation(reader, false);
processSectionContributions(reader, monitor, false); processSectionContributions(reader, false);
processSegmentMap(reader, monitor, false); processSegmentMap(reader, false);
processFileInformation(reader, monitor, false); processFileInformation(reader, false);
processTypeServerMap(reader, false); processTypeServerMap(reader, false);
//Note that the next two are in reverse order from their length fields in the header. //Note that the next two are in reverse order from their length fields in the header.
processEditAndContinueInformation(reader, monitor, false); processEditAndContinueInformation(reader, false);
//processDebugHeader(reader, false); //processDebugHeader(reader, false);
debugData.deserializeHeader(reader, monitor); debugData.deserializeHeader(reader);
} }
@Override @Override
protected void deserializeAdditionalSubstreams(TaskMonitor monitor) protected void deserializeAdditionalSubstreams()
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
// TODO: evaluate. I don't think we need GlobalSymbolInformation (hash) or the // TODO: evaluate. I don't think we need GlobalSymbolInformation (hash) or the
// PublicSymbolInformation (hash), as they are both are search mechanisms. // PublicSymbolInformation (hash), as they are both are search mechanisms.
symbolRecords.deserialize(monitor); symbolRecords.deserialize();
globalSymbolInformation.deserialize(getGlobalSymbolsHashMaybeStreamNumber(), monitor); globalSymbolInformation.deserialize(getGlobalSymbolsHashMaybeStreamNumber());
publicSymbolInformation.deserialize(getPublicStaticSymbolsHashMaybeStreamNumber(), monitor); publicSymbolInformation.deserialize(getPublicStaticSymbolsHashMaybeStreamNumber());
//TODO: Process further information that might be found from ProcessTypeServerMap, //TODO: Process further information that might be found from ProcessTypeServerMap,
// and processEditAndContinueInformation. // and processEditAndContinueInformation.
debugData.deserialize(monitor); debugData.deserialize();
} }
@Override @Override
protected void processModuleInformation(PdbByteReader reader, TaskMonitor monitor, boolean skip) protected void processModuleInformation(PdbByteReader reader, boolean skip)
throws PdbException, CancelledException { throws PdbException, CancelledException {
if (lengthModuleInformationSubstream == 0) { if (lengthModuleInformationSubstream == 0) {
return; return;
@@ -172,8 +171,8 @@ public class PdbNewDebugInfo extends PdbDebugInfo {
PdbByteReader substreamReader = PdbByteReader substreamReader =
reader.getSubPdbByteReader(lengthModuleInformationSubstream); reader.getSubPdbByteReader(lengthModuleInformationSubstream);
while (substreamReader.hasMore()) { while (substreamReader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
AbstractModuleInformation moduleInformation = new ModuleInformation600(pdb); ModuleInformation moduleInformation = new ModuleInformation600(pdb);
moduleInformation.deserialize(substreamReader); moduleInformation.deserialize(substreamReader);
moduleInformationList.add(moduleInformation); moduleInformationList.add(moduleInformation);
} }
@@ -230,7 +229,7 @@ public class PdbNewDebugInfo extends PdbDebugInfo {
} }
@Override @Override
protected void dumpInternalSubstreams(Writer writer) throws IOException { protected void dumpInternalSubstreams(Writer writer) throws IOException, CancelledException {
writer.write("ModuleInformationList---------------------------------------\n"); writer.write("ModuleInformationList---------------------------------------\n");
dumpModuleInformation(writer); dumpModuleInformation(writer);
writer.write("\nEnd ModuleInformationList-----------------------------------\n"); writer.write("\nEnd ModuleInformationList-----------------------------------\n");
@@ -251,10 +250,10 @@ public class PdbNewDebugInfo extends PdbDebugInfo {
//============================================================================================== //==============================================================================================
//TODO: Find examples that exercise this. //TODO: Find examples that exercise this.
/** /**
* Deserializes/Processes the TypeServerMap. * Deserializes/processes the TypeServerMap
* @param reader {@link PdbByteReader} from which to deserialize the data. * @param reader {@link PdbByteReader} from which to deserialize the data
* @param skip Skip over the data in the {@link PdbByteReader}. * @param skip skip over the data in the {@link PdbByteReader}
* @throws PdbException Upon not enough data left to parse. * @throws PdbException upon not enough data left to parse
*/ */
@SuppressWarnings("unused") // substreamReader @SuppressWarnings("unused") // substreamReader
protected void processTypeServerMap(PdbByteReader reader, boolean skip) throws PdbException { protected void processTypeServerMap(PdbByteReader reader, boolean skip) throws PdbException {
@@ -270,16 +269,15 @@ public class PdbNewDebugInfo extends PdbDebugInfo {
} }
/** /**
* Deserializes/Processes the EditAndContinueInformation. * Deserializes/processes the EditAndContinueInformation
* @param reader {@link PdbByteReader} from which to deserialize the data. * @param reader {@link PdbByteReader} from which to deserialize the data
* @param monitor {@link TaskMonitor} used for checking cancellation. * @param skip skip over the data in the {@link PdbByteReader}
* @param skip Skip over the data in the {@link PdbByteReader}. * @throws PdbException upon error parsing a name or unexpected data
* @throws PdbException upon error parsing a name or unexpected data. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
@SuppressWarnings("unused") // hashVal @SuppressWarnings("unused") // hashVal
protected void processEditAndContinueInformation(PdbByteReader reader, TaskMonitor monitor, protected void processEditAndContinueInformation(PdbByteReader reader, boolean skip)
boolean skip) throws PdbException, CancelledException { throws PdbException, CancelledException {
if (lengthEditAndContinueSubstream == 0) { if (lengthEditAndContinueSubstream == 0) {
return; return;
} }
@@ -312,7 +310,7 @@ public class PdbNewDebugInfo extends PdbDebugInfo {
int count = tableSize; int count = tableSize;
int realEntryCount = 0; int realEntryCount = 0;
while (--count >= 0) { while (--count >= 0) {
monitor.checkCanceled(); pdb.checkCanceled();
int offset = substreamReader.parseInt(); int offset = substreamReader.parseInt();
bufferReader.setIndex(offset); bufferReader.setIndex(offset);
String name = bufferReader.parseNullTerminatedString( String name = bufferReader.parseNullTerminatedString(
@@ -336,8 +334,8 @@ public class PdbNewDebugInfo extends PdbDebugInfo {
/** /**
* Dumps the EditAndContinueNameList. This package-protected method is for debugging only. * Dumps the EditAndContinueNameList. This package-protected method is for debugging only.
* @param writer {@link Writer} to which to write the debug dump. * @param writer {@link Writer} to which to write the debug dump
* @throws IOException On issue writing to the {@link Writer}. * @throws IOException on issue writing to the {@link Writer}
*/ */
protected void dumpEditAndContinueNameList(Writer writer) throws IOException { protected void dumpEditAndContinueNameList(Writer writer) throws IOException {
for (String name : editAndContinueNameList) { for (String name : editAndContinueNameList) {
@@ -19,7 +19,6 @@ import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* This class is the version of {@link PdbDebugInfo} for older PDB files. * This class is the version of {@link PdbDebugInfo} for older PDB files.
@@ -34,9 +33,9 @@ public class PdbOldDebugInfo extends PdbDebugInfo {
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param pdb {@link AbstractPdb} that owns this {@link PdbOldDebugInfo}. * @param pdb {@link AbstractPdb} that owns this {@link PdbOldDebugInfo}
* @param streamNumber The number of the stream that contains the {@link PdbOldDebugInfo}. * @param streamNumber the number of the stream that contains the {@link PdbOldDebugInfo}
*/ */
public PdbOldDebugInfo(AbstractPdb pdb, int streamNumber) { public PdbOldDebugInfo(AbstractPdb pdb, int streamNumber) {
super(pdb, streamNumber); super(pdb, streamNumber);
@@ -62,28 +61,28 @@ public class PdbOldDebugInfo extends PdbDebugInfo {
} }
@Override @Override
protected void deserializeInternalSubstreams(PdbByteReader reader, TaskMonitor monitor) protected void deserializeInternalSubstreams(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
processModuleInformation(reader, monitor, false); processModuleInformation(reader, false);
processSectionContributions(reader, monitor, false); processSectionContributions(reader, false);
processSegmentMap(reader, monitor, false); processSegmentMap(reader, false);
processFileInformation(reader, monitor, false); processFileInformation(reader, false);
} }
@Override @Override
protected void deserializeAdditionalSubstreams(TaskMonitor monitor) protected void deserializeAdditionalSubstreams()
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
// TODO: evaluate. I don't think we need GlobalSymbolInformation (hash) or the // TODO: evaluate. I don't think we need GlobalSymbolInformation (hash) or the
// PublicSymbolInformation (hash), as they are both are search mechanisms. // PublicSymbolInformation (hash), as they are both are search mechanisms.
symbolRecords.deserialize(monitor); symbolRecords.deserialize();
globalSymbolInformation.deserialize(getGlobalSymbolsHashMaybeStreamNumber(), monitor); globalSymbolInformation.deserialize(getGlobalSymbolsHashMaybeStreamNumber());
publicSymbolInformation.deserialize(getPublicStaticSymbolsHashMaybeStreamNumber(), monitor); publicSymbolInformation.deserialize(getPublicStaticSymbolsHashMaybeStreamNumber());
//TODO: SectionContributions has information about code sections and refers to //TODO: SectionContributions has information about code sections and refers to
// debug streams for each. // debug streams for each.
} }
@Override @Override
protected void processModuleInformation(PdbByteReader reader, TaskMonitor monitor, boolean skip) protected void processModuleInformation(PdbByteReader reader, boolean skip)
throws PdbException, CancelledException { throws PdbException, CancelledException {
if (lengthModuleInformationSubstream == 0) { if (lengthModuleInformationSubstream == 0) {
return; return;
@@ -95,8 +94,8 @@ public class PdbOldDebugInfo extends PdbDebugInfo {
PdbByteReader substreamReader = PdbByteReader substreamReader =
reader.getSubPdbByteReader(lengthModuleInformationSubstream); reader.getSubPdbByteReader(lengthModuleInformationSubstream);
while (substreamReader.hasMore()) { while (substreamReader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
AbstractModuleInformation moduleInformation = new ModuleInformation500(pdb); ModuleInformation moduleInformation = new ModuleInformation500(pdb);
moduleInformation.deserialize(substreamReader); moduleInformation.deserialize(substreamReader);
moduleInformationList.add(moduleInformation); moduleInformationList.add(moduleInformation);
} }
@@ -129,7 +128,7 @@ public class PdbOldDebugInfo extends PdbDebugInfo {
} }
@Override @Override
protected void dumpInternalSubstreams(Writer writer) throws IOException { protected void dumpInternalSubstreams(Writer writer) throws IOException, CancelledException {
writer.write("ModuleInformationList---------------------------------------\n"); writer.write("ModuleInformationList---------------------------------------\n");
dumpModuleInformation(writer); dumpModuleInformation(writer);
writer.write("\nEnd ModuleInformationList-----------------------------------\n"); writer.write("\nEnd ModuleInformationList-----------------------------------\n");
@@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException; import java.io.IOException;
import java.util.Objects; import java.util.Objects;
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.AbstractMsf; import ghidra.app.util.bin.format.pdb2.pdbreader.msf.Msf;
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfParser; import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfParser;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@@ -43,16 +43,16 @@ public class PdbParser {
/** /**
* Static method to open a PDB file, determine its version, and return an {@link AbstractPdb} * Static method to open a PDB file, determine its version, and return an {@link AbstractPdb}
* appropriate for that version; it will not have been deserialized. The main method * appropriate for that version; it will not have been deserialized. The main method
* to deserialize it is {@link AbstractPdb#deserialize(TaskMonitor monitor)}; the method * to deserialize it is {@link AbstractPdb#deserialize()}; the method
* used to deserialize its main identifiers (signature, age, guid (if available)) is * used to deserialize its main identifiers (signature, age, guid (if available)) is
* {@link AbstractPdb#deserializeIdentifiersOnly(TaskMonitor monitor)}. * {@link AbstractPdb#deserializeIdentifiersOnly(TaskMonitor monitor)}
* @param filename {@link String} pathname of the PDB file to parse. * @param filename {@link String} pathname of the PDB file to parse
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB. * @param pdbOptions {@link PdbReaderOptions} used for processing the PDB
* @param monitor {@link TaskMonitor} used for checking cancellation. * @param monitor {@link TaskMonitor} used for checking cancellation
* @return {@link AbstractPdb} class object for the file. * @return {@link AbstractPdb} class object for the file
* @throws IOException on file I/O issues. * @throws IOException on file I/O issues
* @throws PdbException on parsing issues. * @throws PdbException on parsing issues
* @throws CancelledException Upon user cancellation. * @throws CancelledException upon user cancellation
*/ */
public static AbstractPdb parse(String filename, PdbReaderOptions pdbOptions, public static AbstractPdb parse(String filename, PdbReaderOptions pdbOptions,
TaskMonitor monitor) throws IOException, PdbException, CancelledException { TaskMonitor monitor) throws IOException, PdbException, CancelledException {
@@ -62,7 +62,7 @@ public class PdbParser {
// Do not do a try with resources here, as the msf must live within the PDB that is // Do not do a try with resources here, as the msf must live within the PDB that is
// created below. // created below.
AbstractMsf msf = MsfParser.parse(filename, pdbOptions, monitor); Msf msf = MsfParser.parse(filename, pdbOptions, monitor);
int versionNumber = AbstractPdb.deserializeVersionNumber(msf, monitor); int versionNumber = AbstractPdb.deserializeVersionNumber(msf, monitor);
@@ -20,7 +20,6 @@ import java.io.Writer;
import java.util.*; import java.util.*;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* This class represents Public Symbol Information component of a PDB file. This class is only * This class represents Public Symbol Information component of a PDB file. This class is only
@@ -56,56 +55,56 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param pdbIn {@link AbstractPdb} that owns the Public Symbol Information to process. * @param pdbIn {@link AbstractPdb} that owns the Public Symbol Information to process
*/ */
public PublicSymbolInformation(AbstractPdb pdbIn) { public PublicSymbolInformation(AbstractPdb pdbIn) {
super(pdbIn); super(pdbIn);
} }
/** /**
* Returns the number of thunks in the thunk table. * Returns the number of thunks in the thunk table
* @return the number of thunks. * @return the number of thunks
*/ */
public int getNumThunks() { public int getNumThunks() {
return numThunks; return numThunks;
} }
/** /**
* Returns the section within which the thunk table is located. * Returns the section within which the thunk table is located
* @return the section of the thunk table. * @return the section of the thunk table
*/ */
public int getThunkTableSection() { public int getThunkTableSection() {
return iSectionThunkTable; return iSectionThunkTable;
} }
/** /**
* Returns the offset of the thunk table within the section it is located. * Returns the offset of the thunk table within the section it is located
* @return the offset of the thunk table. * @return the offset of the thunk table
*/ */
public int getThunkTableOffset() { public int getThunkTableOffset() {
return offsetThunkTable; return offsetThunkTable;
} }
/** /**
* Returns the size of each thunk in the thunk table. * Returns the size of each thunk in the thunk table
* @return the size of a thunk. * @return the size of a thunk
*/ */
public int getThunkSize() { public int getThunkSize() {
return thunkSize; return thunkSize;
} }
/** /**
* Returns the overall length of the thunk table. * Returns the overall length of the thunk table
* @return the thunk table length. * @return the thunk table length
*/ */
public int getThunkTableLength() { public int getThunkTableLength() {
return thunkTableLength; return thunkTableLength;
} }
/** /**
* Returns the number of sections recorded for the program. * Returns the number of sections recorded for the program
* @return the number of sections. * @return the number of sections
*/ */
public int getNumSections() { public int getNumSections() {
return numSections; return numSections;
@@ -113,7 +112,7 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
/** /**
* Returns the Offsets of symbols within the symbol table gotten from the address map. These * Returns the Offsets of symbols within the symbol table gotten from the address map. These
* offsets to point to the size field of the symbols in the symbol table. * offsets to point to the size field of the symbols in the symbol table
* @return offsets * @return offsets
*/ */
public List<Long> getAddressMapSymbolOffsets() { public List<Long> getAddressMapSymbolOffsets() {
@@ -124,31 +123,30 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
// Package-Protected Internals // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Deserialize the {@link PublicSymbolInformation} from the appropriate stream in the Pdb. * Deserialize the {@link PublicSymbolInformation} from the appropriate stream in the Pdb
* @param streamNumber the stream number containing the information to deserialize. * @param streamNumber the stream number containing the information to deserialize
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes
* inability to read required bytes. * @throws PdbException upon not enough data left to parse
* @throws PdbException Upon not enough data left to parse. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
@Override @Override
void deserialize(int streamNumber, TaskMonitor monitor) void deserialize(int streamNumber)
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
super.deserialize(streamNumber, monitor); super.deserialize(streamNumber);
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber);
deserializePubHeader(reader); deserializePubHeader(reader);
PdbByteReader hashReader = reader.getSubPdbByteReader(symbolHashLength); PdbByteReader hashReader = reader.getSubPdbByteReader(symbolHashLength);
deserializeHashTable(hashReader, monitor); deserializeHashTable(hashReader);
PdbByteReader addressMapReader = reader.getSubPdbByteReader(addressMapLength); PdbByteReader addressMapReader = reader.getSubPdbByteReader(addressMapLength);
deserializeAddressMap(addressMapReader, monitor); deserializeAddressMap(addressMapReader);
PdbByteReader thunkMapReader = reader.getSubPdbByteReader(thunkMapLength); PdbByteReader thunkMapReader = reader.getSubPdbByteReader(thunkMapLength);
deserializeThunkMap(thunkMapReader, monitor); deserializeThunkMap(thunkMapReader);
/* /*
* See note in {@link #deserializePubHeader(PdbByteReader)} regarding spurious data * See note in {@link #deserializePubHeader(PdbByteReader)} regarding spurious data
@@ -161,19 +159,20 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
} }
numSections = sectionMapLength / 8; numSections = sectionMapLength / 8;
PdbByteReader sectionMapReader = reader.getSubPdbByteReader(sectionMapLength); PdbByteReader sectionMapReader = reader.getSubPdbByteReader(sectionMapLength);
deserializeSectionMap(sectionMapReader, monitor); deserializeSectionMap(sectionMapReader);
// Organize the information // Organize the information
generateSymbolsList(monitor); generateSymbolsList();
} }
/** /**
* Debug method for dumping information from this {@link PublicSymbolInformation}. * Debug method for dumping information from this {@link PublicSymbolInformation}
* @param writer {@link Writer} to which to dump the information. * @param writer {@link Writer} to which to dump the information
* @throws IOException Upon IOException writing to the {@link Writer}. * @throws IOException upon IOException writing to the {@link Writer}
* @throws CancelledException upon user cancellation
*/ */
@Override @Override
void dump(Writer writer) throws IOException { void dump(Writer writer) throws IOException, CancelledException {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("PublicSymbolInformation-------------------------------------\n"); builder.append("PublicSymbolInformation-------------------------------------\n");
dumpPubHeader(builder); dumpPubHeader(builder);
@@ -193,23 +192,22 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
// Private Internals // Private Internals
//============================================================================================== //==============================================================================================
/** /**
* Deserializes the Address Map for these public symbols. * Deserializes the Address Map for these public symbols
* @param reader {@link PdbByteReader} containing the data buffer to process. * @param reader {@link PdbByteReader} containing the data buffer to process
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws PdbException upon not enough data left to parse
* @throws PdbException Upon not enough data left to parse. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
private void deserializeAddressMap(PdbByteReader reader, TaskMonitor monitor) private void deserializeAddressMap(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
while (reader.hasMore()) { while (reader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
addressMapSymbolOffsets.add((long) reader.parseInt()); addressMapSymbolOffsets.add((long) reader.parseInt());
} }
} }
/** /**
* Debug method for dumping Address Map information from this {@link AbstractSymbolInformation}. * Debug method for dumping Address Map information from this {@link AbstractSymbolInformation}
* @param builder {@link StringBuilder} to which to dump the information. * @param builder {@link StringBuilder} to which to dump the information
*/ */
private void dumpAddressMap(StringBuilder builder) { private void dumpAddressMap(StringBuilder builder) {
builder.append("AddressMapSymbolOffsets-------------------------------------\n"); builder.append("AddressMapSymbolOffsets-------------------------------------\n");
@@ -222,17 +220,16 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
} }
/** /**
* Deserializes the Thunk Map for these public symbols. * Deserializes the Thunk Map for these public symbols
* @param reader {@link PdbByteReader} containing the data buffer to process. * @param reader {@link PdbByteReader} containing the data buffer to process
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws PdbException upon not enough data left to parse
* @throws PdbException Upon not enough data left to parse. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
private void deserializeThunkMap(PdbByteReader reader, TaskMonitor monitor) private void deserializeThunkMap(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
int count = 0; int count = 0;
while (reader.hasMore()) { while (reader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
int targetOffset = reader.parseInt(); int targetOffset = reader.parseInt();
int mapTableOffset = count * thunkSize + offsetThunkTable; int mapTableOffset = count * thunkSize + offsetThunkTable;
thunkTargetOffsetsByTableOffset.put(mapTableOffset, targetOffset); thunkTargetOffsetsByTableOffset.put(mapTableOffset, targetOffset);
@@ -240,8 +237,8 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
} }
/** /**
* Debug method for dumping Thunk Map information from this {@link AbstractSymbolInformation}. * Debug method for dumping Thunk Map information from this {@link AbstractSymbolInformation}
* @param builder {@link StringBuilder} to which to dump the information. * @param builder {@link StringBuilder} to which to dump the information
*/ */
private void dumpThunkMap(StringBuilder builder) { private void dumpThunkMap(StringBuilder builder) {
builder.append("ThunkMap----------------------------------------------------\n"); builder.append("ThunkMap----------------------------------------------------\n");
@@ -254,16 +251,15 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
} }
/** /**
* Deserializes the Section Map for these public symbols. * Deserializes the Section Map for these public symbols
* @param reader {@link PdbByteReader} containing the data buffer to process. * @param reader {@link PdbByteReader} containing the data buffer to process
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws PdbException upon not enough data left to parse
* @throws PdbException Upon not enough data left to parse. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
private void deserializeSectionMap(PdbByteReader reader, TaskMonitor monitor) private void deserializeSectionMap(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
while (reader.hasMore()) { while (reader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
int offset = reader.parseInt(); int offset = reader.parseInt();
int section = reader.parseUnsignedShortVal(); int section = reader.parseUnsignedShortVal();
reader.skip(2); // padding reader.skip(2); // padding
@@ -272,22 +268,24 @@ public class PublicSymbolInformation extends AbstractSymbolInformation {
} }
/** /**
* Debug method for dumping Section Map information from this {@link AbstractSymbolInformation}. * Debug method for dumping Section Map information from this {@link AbstractSymbolInformation}
* @param builder {@link StringBuilder} to which to dump the information. * @param builder {@link StringBuilder} to which to dump the information
* @throws CancelledException upon user cancellation
*/ */
private void dumpSectionMap(StringBuilder builder) { private void dumpSectionMap(StringBuilder builder) throws CancelledException {
builder.append("SectionMap--------------------------------------------------\n"); builder.append("SectionMap--------------------------------------------------\n");
builder.append( builder.append(
"numAbsoluteOffsetsBySectionNumber: " + absoluteOffsetsBySectionNumber.size() + "\n"); "numAbsoluteOffsetsBySectionNumber: " + absoluteOffsetsBySectionNumber.size() + "\n");
for (Map.Entry<Integer, Integer> entry : absoluteOffsetsBySectionNumber.entrySet()) { for (Map.Entry<Integer, Integer> entry : absoluteOffsetsBySectionNumber.entrySet()) {
pdb.checkCanceled();
builder.append(String.format("0X%08X 0X%08X\n", entry.getKey(), entry.getValue())); builder.append(String.format("0X%08X 0X%08X\n", entry.getKey(), entry.getValue()));
} }
builder.append("\nEnd SectionMap----------------------------------------------\n"); builder.append("\nEnd SectionMap----------------------------------------------\n");
} }
/** /**
* Debug method for dumping the {@link PublicSymbolInformation} header. * Debug method for dumping the {@link PublicSymbolInformation} header
* @param builder {@link StringBuilder} to which to dump the information. * @param builder {@link StringBuilder} to which to dump the information
*/ */
private void dumpPubHeader(StringBuilder builder) { private void dumpPubHeader(StringBuilder builder) {
builder.append("PublicSymbolInformationHeader-------------------------------\n"); builder.append("PublicSymbolInformationHeader-------------------------------\n");
@@ -22,7 +22,7 @@ package ghidra.app.util.bin.format.pdb2.pdbreader;
* We have intended to implement according to the Microsoft PDB API (source); see the API for * We have intended to implement according to the Microsoft PDB API (source); see the API for
* truth. * truth.
*/ */
public abstract class AbstractSectionContribution { public abstract class SectionContribution {
//============================================================================================== //==============================================================================================
// Internals // Internals
@@ -41,7 +41,7 @@ public abstract class AbstractSectionContribution {
//============================================================================================== //==============================================================================================
// API // API
//============================================================================================== //==============================================================================================
public AbstractSectionContribution() { public SectionContribution() {
} }
public int getSection() { public int getSection() {
@@ -69,15 +69,15 @@ public abstract class AbstractSectionContribution {
// Abstract Methods // Abstract Methods
//============================================================================================== //==============================================================================================
/** /**
* Deserializes the Section Contribution. * Deserializes the Section Contribution
* @param reader {@link PdbByteReader} from which to deserialize the data. * @param reader {@link PdbByteReader} from which to deserialize the data
* @throws PdbException Upon not enough data left to parse. * @throws PdbException upon not enough data left to parse
*/ */
abstract void deserialize(PdbByteReader reader) throws PdbException; abstract void deserialize(PdbByteReader reader) throws PdbException;
/** /**
* Dumps the SectionContribution. This method is for debugging only. * Dumps the SectionContribution. This method is for debugging only
* @return {@link String} of pretty output. * @return {@link String} of pretty output
*/ */
abstract String dumpInternals(); abstract String dumpInternals();
@@ -85,8 +85,8 @@ public abstract class AbstractSectionContribution {
// Package-Protected Internals // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Dumps the Section Contribution. This method is for debugging only. * Dumps the Section Contribution. This method is for debugging only
* @return {@link String} of pretty output. * @return {@link String} of pretty output
*/ */
String dump() { String dump() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
@@ -16,16 +16,15 @@
package ghidra.app.util.bin.format.pdb2.pdbreader; package ghidra.app.util.bin.format.pdb2.pdbreader;
/** /**
* This class is the version of {@link AbstractSectionContribution} for Microsoft v14.00 PDB. * This class is the version of {@link SectionContribution} for Microsoft v14.00 PDB.
*/ */
public class SectionContribution1400 extends AbstractSectionContribution { public class SectionContribution1400 extends SectionContribution {
//============================================================================================== //==============================================================================================
// Abstract Methods // Abstract Methods
//============================================================================================== //==============================================================================================
@Override @Override
void deserialize(PdbByteReader reader) throws PdbException { void deserialize(PdbByteReader reader) throws PdbException {
//System.out.println(reader.dump(0x200));
isect = reader.parseUnsignedShortVal(); isect = reader.parseUnsignedShortVal();
reader.parseBytes(2); // I think there is padding here. reader.parseBytes(2); // I think there is padding here.
offset = reader.parseInt(); offset = reader.parseInt();
@@ -16,16 +16,15 @@
package ghidra.app.util.bin.format.pdb2.pdbreader; package ghidra.app.util.bin.format.pdb2.pdbreader;
/** /**
* This class is the version of {@link AbstractSectionContribution} for Microsoft v2.00 PDB. * This class is the version of {@link SectionContribution} for Microsoft v2.00 PDB.
*/ */
public class SectionContribution200 extends AbstractSectionContribution { public class SectionContribution200 extends SectionContribution {
//============================================================================================== //==============================================================================================
// Abstract Methods // Abstract Methods
//============================================================================================== //==============================================================================================
@Override @Override
void deserialize(PdbByteReader reader) throws PdbException { void deserialize(PdbByteReader reader) throws PdbException {
//System.out.println(reader.dump());
isect = reader.parseUnsignedShortVal(); isect = reader.parseUnsignedShortVal();
offset = reader.parseInt(); offset = reader.parseInt();
length = reader.parseInt(); length = reader.parseInt();
@@ -16,16 +16,15 @@
package ghidra.app.util.bin.format.pdb2.pdbreader; package ghidra.app.util.bin.format.pdb2.pdbreader;
/** /**
* This class is the version of {@link AbstractSectionContribution} for Microsoft v4.00 PDB. * This class is the version of {@link SectionContribution} for Microsoft v4.00 PDB.
*/ */
public class SectionContribution400 extends AbstractSectionContribution { public class SectionContribution400 extends SectionContribution {
//============================================================================================== //==============================================================================================
// Abstract Methods // Abstract Methods
//============================================================================================== //==============================================================================================
@Override @Override
void deserialize(PdbByteReader reader) throws PdbException { void deserialize(PdbByteReader reader) throws PdbException {
//System.out.println(reader.dump(0x200));
isect = reader.parseUnsignedShortVal(); isect = reader.parseUnsignedShortVal();
reader.parseBytes(2); // I think there is padding here. reader.parseBytes(2); // I think there is padding here.
offset = reader.parseInt(); offset = reader.parseInt();
@@ -16,16 +16,15 @@
package ghidra.app.util.bin.format.pdb2.pdbreader; package ghidra.app.util.bin.format.pdb2.pdbreader;
/** /**
* This class is the version of {@link AbstractSectionContribution} for Microsoft v6.00 PDB. * This class is the version of {@link SectionContribution} for Microsoft v6.00 PDB.
*/ */
public class SectionContribution600 extends AbstractSectionContribution { public class SectionContribution600 extends SectionContribution {
//============================================================================================== //==============================================================================================
// Abstract Methods // Abstract Methods
//============================================================================================== //==============================================================================================
@Override @Override
void deserialize(PdbByteReader reader) throws PdbException { void deserialize(PdbByteReader reader) throws PdbException {
//System.out.println(reader.dump(0x200));
isect = reader.parseUnsignedShortVal(); isect = reader.parseUnsignedShortVal();
reader.parseBytes(2); // I think there is padding here. reader.parseBytes(2); // I think there is padding here.
offset = reader.parseInt(); offset = reader.parseInt();
@@ -21,7 +21,6 @@ import java.util.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* This class represents Symbol Records component of a PDB file. This class is only * This class represents Symbol Records component of a PDB file. This class is only
@@ -37,8 +36,8 @@ public class SymbolRecords {
private List<Map<Long, AbstractMsSymbol>> moduleSymbolsByOffset = new ArrayList<>(); private List<Map<Long, AbstractMsSymbol>> moduleSymbolsByOffset = new ArrayList<>();
/** /**
* Constructor. * Constructor
* @param pdb {@link AbstractPdb} to which the {@link SymbolRecords} belong. * @param pdb {@link AbstractPdb} to which the {@link SymbolRecords} belong
*/ */
public SymbolRecords(AbstractPdb pdb) { public SymbolRecords(AbstractPdb pdb) {
Objects.requireNonNull(pdb, "pdb cannot be null"); Objects.requireNonNull(pdb, "pdb cannot be null");
@@ -46,38 +45,37 @@ public class SymbolRecords {
} }
/** /**
* Returns the list of symbols. * Returns the list of symbols
* @return {@link Map}&lt;{@link Long},{@link AbstractMsSymbol}&gt; of buffer offsets to * @return {@link Map}&lt;{@link Long},{@link AbstractMsSymbol}&gt; of buffer offsets to
* symbols. * symbols
*/ */
protected Map<Long, AbstractMsSymbol> getSymbolsByOffset() { protected Map<Long, AbstractMsSymbol> getSymbolsByOffset() {
return symbolsByOffset; return symbolsByOffset;
} }
/** /**
* Returns the buffer-offset-to-symbol map for the module as specified by moduleNumber. * 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. * @param moduleNumber the number ID of the module for which to return the list
* @return {@link Map}&lt;{@link Long},{@link AbstractMsSymbol}&gt; of buffer offsets to * @return {@link Map}&lt;{@link Long},{@link AbstractMsSymbol}&gt; of buffer offsets to
* symbols for the specified module. * symbols for the specified module
*/ */
protected Map<Long, AbstractMsSymbol> getModuleSymbolsByOffset(int moduleNumber) { protected Map<Long, AbstractMsSymbol> getModuleSymbolsByOffset(int moduleNumber) {
return moduleSymbolsByOffset.get(moduleNumber); return moduleSymbolsByOffset.get(moduleNumber);
} }
/** /**
* Deserializes the {@link SymbolRecords} from the stream noted in the DBI header. * Deserializes the {@link SymbolRecords} from the stream noted in the DBI header
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or
* inability to read required bytes * inability to read required bytes
* @throws PdbException Upon not enough data left to parse * @throws PdbException upon not enough data left to parse
* @throws CancelledException Upon user cancellation * @throws CancelledException upon user cancellation
*/ */
void deserialize(TaskMonitor monitor) throws IOException, PdbException, CancelledException { void deserialize() throws IOException, PdbException, CancelledException {
processSymbols(monitor); processSymbols();
processModuleSymbols(monitor); processModuleSymbols();
} }
private void processSymbols(TaskMonitor monitor) private void processSymbols()
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
PdbDebugInfo debugInfo = pdb.getDebugInfo(); PdbDebugInfo debugInfo = pdb.getDebugInfo();
if (debugInfo == null) { if (debugInfo == null) {
@@ -87,14 +85,14 @@ public class SymbolRecords {
if (streamNumber <= 0) { if (streamNumber <= 0) {
return; return;
} }
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber);
symbolsByOffset = deserializeSymbolRecords(pdb, reader, monitor); symbolsByOffset = deserializeSymbolRecords(pdb, reader);
} }
// Could split this method up into separate methods: one for module symbols and the other for // 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 // Lines processing. Note: would be processing streams more than once; lines would need to
// skip over the symbols. // skip over the symbols.
private void processModuleSymbols(TaskMonitor monitor) private void processModuleSymbols()
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
// cvSignature: // cvSignature:
// >64K = C6 // >64K = C6
@@ -114,15 +112,15 @@ public class SymbolRecords {
return; return;
} }
for (AbstractModuleInformation module : debugInfo.moduleInformationList) { for (ModuleInformation module : debugInfo.moduleInformationList) {
monitor.checkCanceled(); pdb.checkCanceled();
int streamNumber = module.getStreamNumberDebugInformation(); int streamNumber = module.getStreamNumberDebugInformation();
if (streamNumber == 0xffff) { if (streamNumber == 0xffff) {
moduleSymbolsByOffset.add(new TreeMap<>()); moduleSymbolsByOffset.add(new TreeMap<>());
continue; continue;
} }
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber);
int sizeSymbolsSection = module.getSizeLocalSymbolsDebugInformation(); int sizeSymbolsSection = module.getSizeLocalSymbolsDebugInformation();
PdbByteReader symbolsReader = reader.getSubPdbByteReader(sizeSymbolsSection); PdbByteReader symbolsReader = reader.getSubPdbByteReader(sizeSymbolsSection);
@@ -152,7 +150,7 @@ public class SymbolRecords {
} }
Map<Long, AbstractMsSymbol> oneModuleSymbolsByOffset = Map<Long, AbstractMsSymbol> oneModuleSymbolsByOffset =
deserializeSymbolRecords(pdb, symbolsReader, monitor); deserializeSymbolRecords(pdb, symbolsReader);
moduleSymbolsByOffset.add(oneModuleSymbolsByOffset); moduleSymbolsByOffset.add(oneModuleSymbolsByOffset);
} }
} }
@@ -163,18 +161,17 @@ public class SymbolRecords {
* symbols * symbols
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed * @param pdb {@link AbstractPdb} that owns the Symbols to be parsed
* @param reader {@link PdbByteReader} containing the symbol records to deserialize * @param reader {@link PdbByteReader} containing the symbol records to deserialize
* @param monitor {@link TaskMonitor} used for checking cancellation
* @return map of buffer offsets to {@link AbstractMsSymbol symbols} * @return map of buffer offsets to {@link AbstractMsSymbol symbols}
* @throws PdbException Upon not enough data left to parse * @throws PdbException upon not enough data left to parse
* @throws CancelledException Upon user cancellation * @throws CancelledException upon user cancellation
*/ */
public static Map<Long, AbstractMsSymbol> deserializeSymbolRecords(AbstractPdb pdb, public static Map<Long, AbstractMsSymbol> deserializeSymbolRecords(AbstractPdb pdb,
PdbByteReader reader, TaskMonitor monitor) throws PdbException, CancelledException { PdbByteReader reader) throws PdbException, CancelledException {
Objects.requireNonNull(pdb, "pdb cannot be null"); Objects.requireNonNull(pdb, "pdb cannot be null");
//System.out.println(reader.dump(0x400)); //System.out.println(reader.dump(0x400));
Map<Long, AbstractMsSymbol> mySymbolsByOffset = new TreeMap<>(); Map<Long, AbstractMsSymbol> mySymbolsByOffset = new TreeMap<>();
while (reader.hasMore()) { while (reader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
// Including length in byte array for alignment purposes. // Including length in byte array for alignment purposes.
int offset = reader.getIndex(); int offset = reader.getIndex();
@@ -185,14 +182,16 @@ public class SymbolRecords {
} }
/** /**
* Debug method for dumping information from this Symbol Records instance. * Debug method for dumping information from this Symbol Records instance
* @param writer {@link Writer} to which to dump the information. * @param writer {@link Writer} to which to dump the information
* @throws IOException Upon IOException writing to the {@link Writer} * @throws IOException upon issue writing to the {@link Writer}
* @throws CancelledException upon user cancellation
*/ */
protected void dump(Writer writer) throws IOException { protected void dump(Writer writer) throws IOException, CancelledException {
writer.write("SymbolRecords-----------------------------------------------\n"); writer.write("SymbolRecords-----------------------------------------------\n");
dumpSymbolMap(symbolsByOffset, writer); dumpSymbolMap(symbolsByOffset, writer);
for (int i = 0; i < moduleSymbolsByOffset.size(); i++) { for (int i = 0; i < moduleSymbolsByOffset.size(); i++) {
pdb.checkCanceled();
Map<Long, AbstractMsSymbol> map = moduleSymbolsByOffset.get(i); Map<Long, AbstractMsSymbol> map = moduleSymbolsByOffset.get(i);
if (map != null) { if (map != null) {
writer.write("Module(" + i + ") List:\n"); writer.write("Module(" + i + ") List:\n");
@@ -204,14 +203,16 @@ public class SymbolRecords {
/** /**
* Debug method for dumping the symbols from a symbol map * Debug method for dumping the symbols from a symbol map
* @param mySymbolsByOffset the {@link Map}&lt;{@link Long},{@link AbstractMsSymbol}&gt; to dump. * @param mySymbolsByOffset the {@link Map}&lt;{@link Long},{@link AbstractMsSymbol}&gt; to dump
* @param writer {@link Writer} to which to dump the information. * @param writer {@link Writer} to which to dump the information
* @throws IOException Upon IOException writing to the {@link Writer} * @throws IOException upon issue writing to the {@link Writer}
* @throws CancelledException upon user cancellation
*/ */
protected void dumpSymbolMap(Map<Long, AbstractMsSymbol> mySymbolsByOffset, Writer writer) protected void dumpSymbolMap(Map<Long, AbstractMsSymbol> mySymbolsByOffset, Writer writer)
throws IOException { throws IOException, CancelledException {
writer.write("SymbolMap---------------------------------------------------"); writer.write("SymbolMap---------------------------------------------------");
for (Map.Entry<Long, AbstractMsSymbol> entry : mySymbolsByOffset.entrySet()) { for (Map.Entry<Long, AbstractMsSymbol> entry : mySymbolsByOffset.entrySet()) {
pdb.checkCanceled();
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("\n------------------------------------------------------------\n"); builder.append("\n------------------------------------------------------------\n");
builder.append(String.format("Offset: 0X%08X\n", entry.getKey())); builder.append(String.format("Offset: 0X%08X\n", entry.getKey()));
@@ -31,7 +31,7 @@ import ghidra.util.task.TaskMonitor;
* We have intended to implement according to the Microsoft PDB API (source); see the API for * We have intended to implement according to the Microsoft PDB API (source); see the API for
* truth. * truth.
*/ */
public abstract class AbstractTypeProgramInterface implements TPI { public abstract class TypeProgramInterface implements TPI {
public static final int STREAM_NUMBER_SIZE = 2; public static final int STREAM_NUMBER_SIZE = 2;
@@ -63,13 +63,12 @@ public abstract class AbstractTypeProgramInterface implements TPI {
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param pdb {@link AbstractPdb} that owns this {@link AbstractTypeProgramInterface}. * @param pdb {@link AbstractPdb} that owns this {@link TypeProgramInterface}
* @param recordCategory the RecordCategory of these records. * @param recordCategory the RecordCategory of these records
* @param streamNumber The stream number that contains the * @param streamNumber the stream number that contains the {@link TypeProgramInterface} data
* {@link AbstractTypeProgramInterface} data.
*/ */
public AbstractTypeProgramInterface(AbstractPdb pdb, RecordCategory recordCategory, public TypeProgramInterface(AbstractPdb pdb, RecordCategory recordCategory,
int streamNumber) { int streamNumber) {
Objects.requireNonNull(pdb, "pdb cannot be null"); Objects.requireNonNull(pdb, "pdb cannot be null");
this.pdb = pdb; this.pdb = pdb;
@@ -79,28 +78,28 @@ public abstract class AbstractTypeProgramInterface implements TPI {
} }
/** /**
* Returns the number of bytes needed to store a {@link AbstractTypeProgramInterface} * Returns the number of bytes needed to store a {@link TypeProgramInterface}
* version number. * version number
* @return The number of bytes read from the bytes array. * @return the number of bytes read from the bytes array
*/ */
static int getVersionNumberSize() { static int getVersionNumberSize() {
return VERSION_NUMBER_SIZE; return VERSION_NUMBER_SIZE;
} }
/** /**
* Deserializes Version Number of the {@link AbstractTypeProgramInterface} from the * Deserializes Version Number of the {@link TypeProgramInterface} from the
* {@link PdbByteReader}. * {@link PdbByteReader}
* @param reader {@link PdbByteReader} from which to deserialize. * @param reader {@link PdbByteReader} from which to deserialize
* @return Version number. * @return version number
* @throws PdbException Upon not enough data left to parse. * @throws PdbException upon not enough data left to parse
*/ */
static int deserializeVersionNumber(PdbByteReader reader) throws PdbException { static int deserializeVersionNumber(PdbByteReader reader) throws PdbException {
return reader.parseInt(); return reader.parseInt();
} }
/** /**
* Returns the TypeIndexMin. * Returns the TypeIndexMin
* @return The TypeIndexMin value from the header. * @return the TypeIndexMin value from the header
*/ */
@Override @Override
public int getTypeIndexMin() { public int getTypeIndexMin() {
@@ -108,8 +107,8 @@ public abstract class AbstractTypeProgramInterface implements TPI {
} }
/** /**
* Returns the TypeIndexMaxExclusive. * Returns the TypeIndexMaxExclusive
* @return TypeIndexMaxExclusive value from the header. * @return TypeIndexMaxExclusive value from the header
*/ */
@Override @Override
public int getTypeIndexMaxExclusive() { public int getTypeIndexMaxExclusive() {
@@ -118,9 +117,9 @@ public abstract class AbstractTypeProgramInterface implements TPI {
/** /**
* Retrieves the {@link AbstractMsType} record indicated by the recordNumber. The record must * Retrieves the {@link AbstractMsType} record indicated by the recordNumber. The record must
* already have been parsed and inserted into the list. * already have been parsed and inserted into the list
* @param recordNumber Record number to look up. * @param recordNumber Rrcord number to look up
* @return {@link AbstractMsType} pertaining to the record number. * @return {@link AbstractMsType} pertaining to the record number
*/ */
@Override @Override
public AbstractMsType getRecord(int recordNumber) { public AbstractMsType getRecord(int recordNumber) {
@@ -147,20 +146,19 @@ public abstract class AbstractTypeProgramInterface implements TPI {
// Package-Protected Internals // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Deserializes this {@link AbstractTypeProgramInterface}. * Deserializes this {@link TypeProgramInterface}
* @param monitor {@link TaskMonitor} used for checking cancellation. * @return version number of the {@link TypeProgramInterface}
* @return Version number of the {@link AbstractTypeProgramInterface}. * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes
* inability to read required bytes. * @throws PdbException upon not enough data left to parse
* @throws PdbException Upon not enough data left to parse. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
int deserialize(TaskMonitor monitor) throws IOException, PdbException, CancelledException { int deserialize() throws IOException, PdbException, CancelledException {
if (pdb.getMsf() == null) { if (pdb.getMsf() == null) {
// Should only be null dummy PDBs used for testing. // Should only be null dummy PDBs used for testing.
throw new PdbException("Unexpected null MSF."); throw new PdbException("Unexpected null MSF.");
} }
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber);
deserializeHeader(reader); deserializeHeader(reader);
@@ -169,15 +167,15 @@ public abstract class AbstractTypeProgramInterface implements TPI {
// we have this commented out. // we have this commented out.
//hash.deserializeHashStreams(monitor); //hash.deserializeHashStreams(monitor);
deserializeTypeRecords(reader, monitor); deserializeTypeRecords(reader);
return versionNumber; return versionNumber;
} }
/** /**
* Dumps this class. This package-protected method is for debugging only. * Dumps this class. This package-protected method is for debugging only
* @param writer {@link Writer} to which to write the debug dump. * @param writer {@link Writer} to which to write the debug dump
* @throws IOException On issue writing to the {@link Writer}. * @throws IOException on issue writing to the {@link Writer}
*/ */
void dump(Writer writer) throws IOException { void dump(Writer writer) throws IOException {
writer.write("TypeProgramInterfaceHeader----------------------------------\n"); writer.write("TypeProgramInterfaceHeader----------------------------------\n");
@@ -190,14 +188,16 @@ public abstract class AbstractTypeProgramInterface implements TPI {
/** /**
* IMPORTANT: This method is for testing only. It allows us to set a basic object. * IMPORTANT: This method is for testing only. It allows us to set a basic object.
* Note: not all values are initialized. This is a dummy constructor used to create a dummy * <p>
* {@link AbstractTypeProgramInterface}. * Note: not all values are initialized. This is a dummy constructor used to create a dummy
* Note: not all values of this class get initialized by this method. * {@link TypeProgramInterface}.
* @param pdb {@link AbstractPdb} that owns this this class. * <p>
* @param typeIndexMin The IndexMin to set/use. * Note: not all values of this class get initialized by this method.
* @param typeIndexMaxExclusive One greater than the MaxIndex to set/use. * @param pdb {@link AbstractPdb} that owns this this class
* @param typeIndexMin the IndexMin to set/use
* @param typeIndexMaxExclusive one greater than the MaxIndex to set/use
*/ */
AbstractTypeProgramInterface(AbstractPdb pdb, int typeIndexMin, int typeIndexMaxExclusive) { TypeProgramInterface(AbstractPdb pdb, int typeIndexMin, int typeIndexMaxExclusive) {
Objects.requireNonNull(pdb, "pdb cannot be null"); Objects.requireNonNull(pdb, "pdb cannot be null");
this.pdb = pdb; this.pdb = pdb;
this.typeIndexMin = typeIndexMin; this.typeIndexMin = typeIndexMin;
@@ -206,10 +206,10 @@ public abstract class AbstractTypeProgramInterface implements TPI {
/** /**
* IMPORTANT: This method is for testing only. It allows us to set a record for a particular * IMPORTANT: This method is for testing only. It allows us to set a record for a particular
* record number. * record number
* @param recordNumber Record number for the {@link AbstractMsType} to be inserted. * @param recordNumber record number for the {@link AbstractMsType} to be inserted
* @param type {@link AbstractMsType} to be inserted. * @param type {@link AbstractMsType} to be inserted
* @return True if successful. * @return {@code true} if successful
*/ */
boolean setRecord(int recordNumber, AbstractMsType type) { boolean setRecord(int recordNumber, AbstractMsType type) {
if (recordNumber < typeIndexMin) { if (recordNumber < typeIndexMin) {
@@ -224,9 +224,9 @@ public abstract class AbstractTypeProgramInterface implements TPI {
/** /**
* IMPORTANT: This method is for testing only. It allows us to add a record that gets its * IMPORTANT: This method is for testing only. It allows us to add a record that gets its
* record number automatically assigned. * record number automatically assigned
* @param type {@link AbstractMsType} to be inserted. * @param type {@link AbstractMsType} to be inserted
* @return Record number assigned. * @return record number assigned
*/ */
int addRecord(AbstractMsType type) { int addRecord(AbstractMsType type) {
int newRecordNum = typeList.size() + typeIndexMin; int newRecordNum = typeList.size() + typeIndexMin;
@@ -238,16 +238,16 @@ public abstract class AbstractTypeProgramInterface implements TPI {
// Abstract Methods // Abstract Methods
//============================================================================================== //==============================================================================================
/** /**
* Deserializes the Header of this class. * Deserializes the Header of this class
* @param reader {@link PdbByteReader} from which to deserialize the data. * @param reader {@link PdbByteReader} from which to deserialize the data
* @throws PdbException Upon not enough data left to parse. * @throws PdbException upon not enough data left to parse
*/ */
protected abstract void deserializeHeader(PdbByteReader reader) throws PdbException; protected abstract void deserializeHeader(PdbByteReader reader) throws PdbException;
/** /**
* Dumps the Header. This method is for debugging only. * Dumps the Header. This method is for debugging only
* @param writer {@link Writer} to which to dump the header. * @param writer {@link Writer} to which to dump the header
* @throws IOException On issue writing to the {@link Writer}. * @throws IOException on issue writing to the {@link Writer}
*/ */
protected abstract void dumpHeader(Writer writer) throws IOException; protected abstract void dumpHeader(Writer writer) throws IOException;
@@ -255,19 +255,18 @@ public abstract class AbstractTypeProgramInterface implements TPI {
// Internal Data Methods // Internal Data Methods
//============================================================================================== //==============================================================================================
/** /**
* Deserializes the Type Records of this class. * Deserializes the Type Records of this class
* @param reader {@link PdbByteReader} from which to deserialize the data. * @param reader {@link PdbByteReader} from which to deserialize the data
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws PdbException upon not enough data left to parse
* @throws PdbException Upon not enough data left to parse. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
protected void deserializeTypeRecords(PdbByteReader reader, TaskMonitor monitor) protected void deserializeTypeRecords(PdbByteReader reader)
throws PdbException, CancelledException { throws PdbException, CancelledException {
int recordLength; int recordLength;
int recordNumber = typeIndexMin; int recordNumber = typeIndexMin;
while (reader.hasMore()) { while (reader.hasMore()) {
monitor.checkCanceled(); pdb.checkCanceled();
recordLength = reader.parseUnsignedShortVal(); recordLength = reader.parseUnsignedShortVal();
PdbByteReader recordReader = reader.getSubPdbByteReader(recordLength); PdbByteReader recordReader = reader.getSubPdbByteReader(recordLength);
@@ -292,9 +291,9 @@ public abstract class AbstractTypeProgramInterface implements TPI {
//TODO: more to do for outputting individual records (might want a toString or dump method //TODO: more to do for outputting individual records (might want a toString or dump method
// on each). // on each).
/** /**
* Dumps the Type Records. This method is for debugging only. * Dumps the Type Records. This method is for debugging only
* @param writer {@link Writer} to which to dump the records. * @param writer {@link Writer} to which to dump the records
* @throws IOException On issue writing to the {@link Writer}. * @throws IOException on issue writing to the {@link Writer}
*/ */
protected void dumpTypeRecords(Writer writer) throws IOException { protected void dumpTypeRecords(Writer writer) throws IOException {
int recordNum = typeIndexMin; int recordNum = typeIndexMin;
@@ -338,9 +337,9 @@ public abstract class AbstractTypeProgramInterface implements TPI {
private List<TiOff> tiOffs = new ArrayList<>(); private List<TiOff> tiOffs = new ArrayList<>();
/** /**
* Deserializes the {@link TypeProgramInterfaceHash}. * Deserializes the {@link TypeProgramInterfaceHash}
* @param reader {@link PdbByteReader} from which to deserialize the data. * @param reader {@link PdbByteReader} from which to deserialize the data
* @throws PdbException Upon not enough data left to parse. * @throws PdbException upon not enough data left to parse
*/ */
protected void deserializeHeader800(PdbByteReader reader) throws PdbException { protected void deserializeHeader800(PdbByteReader reader) throws PdbException {
hashStreamNumber = reader.parseUnsignedShortVal(); hashStreamNumber = reader.parseUnsignedShortVal();
@@ -356,11 +355,11 @@ public abstract class AbstractTypeProgramInterface implements TPI {
} }
/** /**
* Deserializes the {@link TypeProgramInterfaceHash}. * Deserializes the {@link TypeProgramInterfaceHash}
* @param hashStreamNumberParam Stream number of the hash. * @param hashStreamNumberParam stream number of the hash
* @param typeIndexMinParam The IndexMin to set/use. * @param typeIndexMinParam the IndexMin to set/use
* @param typeIndexMaxExclusiveParam One greater than the MaxIndex to set/use. * @param typeIndexMaxExclusiveParam one greater than the MaxIndex to set/use
* @throws PdbException Upon not enough data left to parse. * @throws PdbException upon not enough data left to parse
*/ */
protected void initHeader200500(int hashStreamNumberParam, int typeIndexMinParam, protected void initHeader200500(int hashStreamNumberParam, int typeIndexMinParam,
int typeIndexMaxExclusiveParam) throws PdbException { int typeIndexMaxExclusiveParam) throws PdbException {
@@ -380,11 +379,11 @@ public abstract class AbstractTypeProgramInterface implements TPI {
// Suppress "unused" for hashBuffer, typeInfoOffsetPairsBuffer, hashAdjustmentBuffer // Suppress "unused" for hashBuffer, typeInfoOffsetPairsBuffer, hashAdjustmentBuffer
/** /**
* *UNDER CONSTRUCTION* Deserializes the Hash Streams... * *UNDER CONSTRUCTION* Deserializes the Hash Streams...
* @param monitor {@link TaskMonitor} used for checking cancellation. * @param monitor {@link TaskMonitor} used for checking cancellation
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* inability to read required bytes. * inability to read required bytes
* @throws PdbException Upon error in processing components. * @throws PdbException upon error in processing components
* @throws CancelledException Upon user cancellation. * @throws CancelledException upon user cancellation
*/ */
@SuppressWarnings("unused") // for method unused. @SuppressWarnings("unused") // for method unused.
protected void deserializeHashStreams(TaskMonitor monitor) protected void deserializeHashStreams(TaskMonitor monitor)
@@ -400,7 +399,7 @@ public abstract class AbstractTypeProgramInterface implements TPI {
if (hashStreamNumber == 0xffff) { if (hashStreamNumber == 0xffff) {
return; return;
} }
PdbByteReader reader = pdb.getReaderForStreamNumber(hashStreamNumber, monitor); PdbByteReader reader = pdb.getReaderForStreamNumber(hashStreamNumber);
//System.out.println(reader.dump()); //System.out.println(reader.dump());
reader.setIndex(offsetHashVals); reader.setIndex(offsetHashVals);
@@ -420,7 +419,7 @@ public abstract class AbstractTypeProgramInterface implements TPI {
return; return;
} }
PdbByteReader readerAuxiliary = PdbByteReader readerAuxiliary =
pdb.getReaderForStreamNumber(hashStreamNumberAuxiliary, monitor); pdb.getReaderForStreamNumber(hashStreamNumberAuxiliary);
//readerAuxiliary.dump(); //readerAuxiliary.dump();
} }
@@ -501,8 +500,8 @@ public abstract class AbstractTypeProgramInterface implements TPI {
} }
/** /**
* Dumps the this {@link TypeProgramInterfaceHash}. This method is for debugging only. * Dumps the this {@link TypeProgramInterfaceHash}. This method is for debugging only
* @return {@link String} of pretty output. * @return {@link String} of pretty output
*/ */
protected String dump() { protected String dump() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
@@ -543,9 +542,9 @@ public abstract class AbstractTypeProgramInterface implements TPI {
/** /**
* This method is only intended to be used to create a dummy key for performing * This method is only intended to be used to create a dummy key for performing
* a binary search. That is the reason that an {@code offset} parameter is not * a binary search. That is the reason that an {@code offset} parameter is not
* specified. The offset is set to zero. * specified. The offset is set to zero
* @param typeIndex The type index to fill into the key. * @param typeIndex the type index to fill into the key
*/ */
protected TiOff(int typeIndex) { protected TiOff(int typeIndex) {
this.typeIndex = typeIndex; this.typeIndex = typeIndex;
@@ -573,9 +572,9 @@ public abstract class AbstractTypeProgramInterface implements TPI {
private class KeyTiOff extends TiOff { private class KeyTiOff extends TiOff {
/** /**
* This method is only intended to be used to create a dummy key for performing * This method is only intended to be used to create a dummy key for performing
* a binary search. That is the reason that an {@code offset} parameter is not * a binary search. That is the reason that an {@code offset} parameter is not
* specified. The offset is set to zero. * specified. The offset is set to zero
* @param typeIndex The type index to fill into the key. * @param typeIndex the type index to fill into the key
*/ */
protected KeyTiOff(int typeIndex) { protected KeyTiOff(int typeIndex) {
super(typeIndex); super(typeIndex);
@@ -19,9 +19,9 @@ import java.io.IOException;
import java.io.Writer; import java.io.Writer;
/** /**
* This class is the version of {@link AbstractTypeProgramInterface} for Microsoft v2.00 PDB. * This class is the version of {@link TypeProgramInterface} for Microsoft v2.00 PDB.
*/ */
public class TypeProgramInterface200 extends AbstractTypeProgramInterface { public class TypeProgramInterface200 extends TypeProgramInterface {
//============================================================================================== //==============================================================================================
// Internals // Internals
@@ -32,10 +32,10 @@ public class TypeProgramInterface200 extends AbstractTypeProgramInterface {
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param pdb {@link AbstractPdb} that owns this {@link AbstractTypeProgramInterface}. * @param pdb {@link AbstractPdb} that owns this {@link TypeProgramInterface}
* @param recordCategory the RecordCategory of these records. * @param recordCategory the RecordCategory of these records
* @param streamNumber The stream number that contains the {@link AbstractTypeProgramInterface}. * @param streamNumber the stream number that contains the {@link TypeProgramInterface}
*/ */
public TypeProgramInterface200(AbstractPdb pdb, RecordCategory recordCategory, public TypeProgramInterface200(AbstractPdb pdb, RecordCategory recordCategory,
int streamNumber) { int streamNumber) {
@@ -79,12 +79,14 @@ public class TypeProgramInterface200 extends AbstractTypeProgramInterface {
//============================================================================================== //==============================================================================================
/** /**
* IMPORTANT: This method is for testing only. It allows us to set a basic object. * IMPORTANT: This method is for testing only. It allows us to set a basic object.
* Note: not all values are initialized. This is a dummy constructor used to create a dummy * <p>
* {@link AbstractTypeProgramInterface}. * Note: not all values are initialized. This is a dummy constructor used to create a dummy
* Note: not all values are initialized. * {@link TypeProgramInterface}.
* @param pdb {@link AbstractPdb} that owns this {@link AbstractTypeProgramInterface}. * <p>
* @param typeIndexMin The IndexMin to set/use. * Note: not all values are initialized.
* @param typeIndexMaxExclusive One greater than the MaxIndex to set/use. * @param pdb {@link AbstractPdb} that owns this {@link TypeProgramInterface}
* @param typeIndexMin the IndexMin to set/use
* @param typeIndexMaxExclusive one greater than the MaxIndex to set/use
*/ */
TypeProgramInterface200(AbstractPdb pdb, int typeIndexMin, int typeIndexMaxExclusive) { TypeProgramInterface200(AbstractPdb pdb, int typeIndexMin, int typeIndexMaxExclusive) {
super(pdb, typeIndexMin, typeIndexMaxExclusive); super(pdb, typeIndexMin, typeIndexMaxExclusive);
@@ -19,9 +19,9 @@ import java.io.IOException;
import java.io.Writer; import java.io.Writer;
/** /**
* This class is the version of {@link AbstractTypeProgramInterface} for Microsoft v5.00 PDB. * This class is the version of {@link TypeProgramInterface} for Microsoft v5.00 PDB.
*/ */
public class TypeProgramInterface500 extends AbstractTypeProgramInterface { public class TypeProgramInterface500 extends TypeProgramInterface {
//============================================================================================== //==============================================================================================
// Internals // Internals
@@ -32,10 +32,10 @@ public class TypeProgramInterface500 extends AbstractTypeProgramInterface {
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param pdb {@link AbstractPdb} that owns this {@link AbstractTypeProgramInterface}. * @param pdb {@link AbstractPdb} that owns this {@link TypeProgramInterface}
* @param recordCategory the RecordCategory of these records. * @param recordCategory the RecordCategory of these records
* @param streamNumber The stream number that contains the {@link AbstractTypeProgramInterface}. * @param streamNumber the stream number that contains the {@link TypeProgramInterface}
*/ */
public TypeProgramInterface500(AbstractPdb pdb, RecordCategory recordCategory, public TypeProgramInterface500(AbstractPdb pdb, RecordCategory recordCategory,
int streamNumber) { int streamNumber) {
@@ -77,12 +77,14 @@ public class TypeProgramInterface500 extends AbstractTypeProgramInterface {
//============================================================================================== //==============================================================================================
/** /**
* IMPORTANT: This method is for testing only. It allows us to set a basic object. * IMPORTANT: This method is for testing only. It allows us to set a basic object.
* Note: not all values are initialized. This is a dummy constructor used to create a dummy * <p>
* {@link AbstractTypeProgramInterface}. * Note: not all values are initialized. This is a dummy constructor used to create a dummy
* Note: not all values are initialized. * {@link TypeProgramInterface}.
* @param pdb {@link AbstractPdb} that owns this {@link AbstractTypeProgramInterface}. * <p>
* @param typeIndexMin The IndexMin to set/use. * Note: not all values are initialized.
* @param typeIndexMaxExclusive One greater than the MaxIndex to set/use. * @param pdb {@link AbstractPdb} that owns this {@link TypeProgramInterface}
* @param typeIndexMin the IndexMin to set/use
* @param typeIndexMaxExclusive one greater than the MaxIndex to set/use
*/ */
TypeProgramInterface500(AbstractPdb pdb, int typeIndexMin, int typeIndexMaxExclusive) { TypeProgramInterface500(AbstractPdb pdb, int typeIndexMin, int typeIndexMaxExclusive) {
super(pdb, typeIndexMin, typeIndexMaxExclusive); super(pdb, typeIndexMin, typeIndexMaxExclusive);
@@ -19,18 +19,18 @@ import java.io.IOException;
import java.io.Writer; import java.io.Writer;
/** /**
* This class is the version of {@link AbstractTypeProgramInterface} for Microsoft v8.00 PDB. * This class is the version of {@link TypeProgramInterface} for Microsoft v8.00 PDB.
*/ */
public class TypeProgramInterface800 extends AbstractTypeProgramInterface { public class TypeProgramInterface800 extends TypeProgramInterface {
//============================================================================================== //==============================================================================================
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param pdb {@link AbstractPdb} that owns this {@link AbstractTypeProgramInterface}. * @param pdb {@link AbstractPdb} that owns this {@link TypeProgramInterface}
* @param recordCategory the RecordCategory of these records. * @param recordCategory the RecordCategory of these records
* @param streamNumber The stream number that contains the {@link AbstractTypeProgramInterface}. * @param streamNumber the stream number that contains the {@link TypeProgramInterface}
*/ */
public TypeProgramInterface800(AbstractPdb pdb, RecordCategory recordCategory, public TypeProgramInterface800(AbstractPdb pdb, RecordCategory recordCategory,
int streamNumber) { int streamNumber) {
@@ -18,12 +18,11 @@ package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException; import java.io.IOException;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* Parser for detecting the appropriate {@link AbstractTypeProgramInterface} format for the * Parser for detecting the appropriate {@link TypeProgramInterface} format for the
* filename given. It then creates and returns the appropriate * filename given. It then creates and returns the appropriate
* {@link AbstractTypeProgramInterface} object. * {@link TypeProgramInterface} object.
*/ */
public class TypeProgramInterfaceParser { public class TypeProgramInterfaceParser {
@@ -44,30 +43,29 @@ public class TypeProgramInterfaceParser {
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Parses information to determine the version of {@link AbstractTypeProgramInterface} to * Parses information to determine the version of {@link TypeProgramInterface} to
* create. * create
* @param pdb {@link AbstractPdb} that owns this {@link AbstractTypeProgramInterface}. * @param pdb {@link AbstractPdb} that owns this {@link TypeProgramInterface}
* @param monitor {@link TaskMonitor} used for checking cancellation. * @return the appropriate {@link TypeProgramInterface} or null if the stream does
* @return the appropriate {@link AbstractTypeProgramInterface} or null if the stream does * not have enough information to be parsed
* not have enough information to be parsed. * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes
* inability to read required bytes. * @throws PdbException upon error in processing components
* @throws PdbException Upon error in processing components. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
public AbstractTypeProgramInterface parse(AbstractPdb pdb, TaskMonitor monitor) public TypeProgramInterface parse(AbstractPdb pdb)
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
AbstractTypeProgramInterface typeProgramInterface; TypeProgramInterface typeProgramInterface;
int versionNumberSize = AbstractTypeProgramInterface.getVersionNumberSize(); int versionNumberSize = TypeProgramInterface.getVersionNumberSize();
int streamNumber = getStreamNumber(); int streamNumber = getStreamNumber();
PdbByteReader reader = PdbByteReader reader =
pdb.getReaderForStreamNumber(streamNumber, 0, versionNumberSize, monitor); pdb.getReaderForStreamNumber(streamNumber, 0, versionNumberSize);
if (reader.getLimit() < versionNumberSize) { if (reader.getLimit() < versionNumberSize) {
return null; return null;
} }
int versionNumber = AbstractTypeProgramInterface.deserializeVersionNumber(reader); int versionNumber = TypeProgramInterface.deserializeVersionNumber(reader);
// TODO: we do not know where the line should be drawn for each of these // TODO: we do not know where the line should be drawn for each of these
// AbstractTypeProgramInterface instantiations. Had a TI50_ID that was not an 800 // AbstractTypeProgramInterface instantiations. Had a TI50_ID that was not an 800
@@ -102,8 +100,8 @@ public class TypeProgramInterfaceParser {
// Internal Data Methods // Internal Data Methods
//============================================================================================== //==============================================================================================
/** /**
* Returns the standard stream number that contains the serialized Type Program Interface. * Returns the standard stream number that contains the serialized Type Program Interface
* @return The standard stream number that contains the Type Program Interface. * @return the standard stream number that contains the Type Program Interface
*/ */
protected int getStreamNumber() { protected int getStreamNumber() {
return TYPE_PROGRAM_INTERFACE_STREAM_NUMBER; return TYPE_PROGRAM_INTERFACE_STREAM_NUMBER;
@@ -111,8 +109,8 @@ public class TypeProgramInterfaceParser {
/** /**
* Returns the appropriate {@link RecordCategory} needed while processing * Returns the appropriate {@link RecordCategory} needed while processing
* the Type Program Interface} (vs. Item Program Interface). * the Type Program Interface} (vs. Item Program Interface)
* @return {@link RecordCategory#TYPE}. * @return {@link RecordCategory#TYPE}
*/ */
protected RecordCategory getCategory() { protected RecordCategory getCategory() {
return RecordCategory.TYPE; return RecordCategory.TYPE;
@@ -17,6 +17,7 @@ package ghidra.app.util.bin.format.pdb2.pdbreader.msf;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.util.Objects;
import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.*;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
@@ -60,7 +61,7 @@ import ghidra.util.task.TaskMonitor;
* Number of Pages Number of pages 2 4 int * Number of Pages Number of pages 2 4 int
* currently used * currently used
* in the file * in the file
* Serialized Sequence of page * Serialized Sequence of page
* info about numbers * info about numbers
* directory * directory
* stream: * stream:
@@ -98,11 +99,11 @@ import ghidra.util.task.TaskMonitor;
* <P> * <P>
* @see MsfFileReader * @see MsfFileReader
* @see MsfStream * @see MsfStream
* @see AbstractMsfDirectoryStream * @see MsfDirectoryStream
* @see AbstractMsfFreePageMap * @see MsfFreePageMap
* @see AbstractMsfStreamTable * @see MsfStreamTable
*/ */
public abstract class AbstractMsf implements AutoCloseable { public abstract class Msf implements AutoCloseable {
private static final int HEADER_PAGE_NUMBER = 0; private static final int HEADER_PAGE_NUMBER = 0;
private static final int DIRECTORY_STREAM_NUMBER = 0; private static final int DIRECTORY_STREAM_NUMBER = 0;
@@ -113,9 +114,9 @@ public abstract class AbstractMsf implements AutoCloseable {
protected String filename; protected String filename;
protected MsfFileReader fileReader; protected MsfFileReader fileReader;
protected AbstractMsfFreePageMap freePageMap; protected MsfFreePageMap freePageMap;
protected AbstractMsfDirectoryStream directoryStream; protected MsfDirectoryStream directoryStream;
protected AbstractMsfStreamTable streamTable; protected MsfStreamTable streamTable;
protected int pageSize; protected int pageSize;
protected int log2PageSize; protected int log2PageSize;
@@ -125,23 +126,30 @@ public abstract class AbstractMsf implements AutoCloseable {
protected int currentFreePageMapFirstPageNumber; protected int currentFreePageMapFirstPageNumber;
protected int numPages = 1; // Set to 1 to allow initial read protected int numPages = 1; // Set to 1 to allow initial read
protected TaskMonitor monitor;
protected PdbReaderOptions pdbOptions; protected PdbReaderOptions pdbOptions;
//============================================================================================== //==============================================================================================
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Constructor for this class. * Constructor
* @param file The {@link RandomAccessFile} to process for this class. * @param file the {@link RandomAccessFile} to process for this class
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB. * @param filename name of {@code #file}
* @throws IOException Upon file IO seek/read issues. * @param monitor the TaskMonitor
* @throws PdbException Upon unknown value for configuration. * @param pdbOptions {@link PdbReaderOptions} used for processing the PDB
* @throws IOException upon file IO seek/read issues
* @throws PdbException upon unknown value for configuration
*/ */
public AbstractMsf(RandomAccessFile file, PdbReaderOptions pdbOptions) public Msf(RandomAccessFile file, String filename, TaskMonitor monitor,
PdbReaderOptions pdbOptions)
throws IOException, PdbException { throws IOException, PdbException {
Objects.requireNonNull(file, "file may not be null");
this.filename = Objects.requireNonNull(filename, "filename may not be null");
this.monitor = TaskMonitor.dummyIfNull(monitor);
this.pdbOptions = Objects.requireNonNull(pdbOptions, "PdbOptions may not be null");
// Do initial configuration with largest possible page size. ConfigureParameters will // Do initial configuration with largest possible page size. ConfigureParameters will
// be called again later with the proper pageSize set. // be called again later with the proper pageSize set.
this.pdbOptions = pdbOptions;
pageSize = 0x1000; pageSize = 0x1000;
configureParameters(); configureParameters();
// Create components. // Create components.
@@ -150,34 +158,58 @@ public abstract class AbstractMsf implements AutoCloseable {
} }
/** /**
* Returns the page size employed by this {@link AbstractMsf}. * Returns the filename
* @return Page size. * @return the filename
*/
public String getFilename() {
return filename;
}
/**
* Returns the TaskMonitor
* @return the monitor
*/
public TaskMonitor getMonitor() {
return monitor;
}
/**
* Check to see if this monitor has been canceled
* @throws CancelledException if monitor has been cancelled
*/
public void checkCanceled() throws CancelledException {
monitor.checkCanceled();
}
/**
* Returns the page size employed by this {@link Msf}
* @return page size
*/ */
public int getPageSize() { public int getPageSize() {
return pageSize; return pageSize;
} }
/** /**
* Returns the number of streams found in this {@link AbstractMsf}. * Returns the number of streams found in this {@link Msf}
* @return Number of streams. * @return number of streams
*/ */
public int getNumStreams() { public int getNumStreams() {
return streamTable.getNumStreams(); return streamTable.getNumStreams();
} }
/** /**
* Returns the {@link MsfStream} specified by {@link AbstractMsf}. * Returns the {@link MsfStream} specified by {@link Msf}
* @param streamNumber The number of the Stream to return. Must be less than the number * @param streamNumber the number of the Stream to return. Must be less than the number
* of streams returned by {@link #getNumStreams()}. * of streams returned by {@link #getNumStreams()}
* @return {@link MsfStream} or {@code null} if no stream for the streamNumber. * @return {@link MsfStream} or {@code null} if no stream for the streamNumber
*/ */
public MsfStream getStream(int streamNumber) { public MsfStream getStream(int streamNumber) {
return streamTable.getStream(streamNumber); return streamTable.getStream(streamNumber);
} }
/** /**
* Closes resources used by this {@link AbstractMsf}. * Closes resources used by this {@link Msf}
* @throws IOException Under circumstances found when closing a {@link RandomAccessFile}. * @throws IOException under circumstances found when closing a {@link RandomAccessFile}
*/ */
@Override @Override
public void close() throws IOException { public void close() throws IOException {
@@ -191,10 +223,10 @@ public abstract class AbstractMsf implements AutoCloseable {
//============================================================================================== //==============================================================================================
/** /**
* Returns the value of the floor (greatest integer less than or equal to) of the result * Returns the value of the floor (greatest integer less than or equal to) of the result
* upon dividing the dividend by a divisor which is the power-of-two of the log2Divisor. * upon dividing the dividend by a divisor which is the power-of-two of the log2Divisor
* @param dividend The dividend to the operator * @param dividend the dividend to the operator
* @param log2Divisor The log2 of the intended divisor value. * @param log2Divisor the log2 of the intended divisor value
* @return The floor of the division result. * @return the floor of the division result
*/ */
static final int floorDivisionWithLog2Divisor(int dividend, int log2Divisor) { static final int floorDivisionWithLog2Divisor(int dividend, int log2Divisor) {
return (dividend + (1 << log2Divisor) - 1) >> log2Divisor; return (dividend + (1 << log2Divisor) - 1) >> log2Divisor;
@@ -204,46 +236,45 @@ public abstract class AbstractMsf implements AutoCloseable {
// Abstract Methods // Abstract Methods
//============================================================================================== //==============================================================================================
/** /**
* Method that returns the identification byte[] required by this format. * Method that returns the identification byte[] required by this format
* @return The minimum required number. * @return the minimum required number
*/ */
protected abstract byte[] getIdentification(); protected abstract byte[] getIdentification();
/** /**
* Returns the offset (in bytes) of the PageSize within the header. * Returns the offset (in bytes) of the PageSize within the header
* @return The offset of the PageSize within the header. * @return the offset of the PageSize within the header
*/ */
protected abstract int getPageSizeOffset(); protected abstract int getPageSizeOffset();
/** /**
* Deserializes the Free Page Map page number from the {@link PdbByteReader}. * Deserializes the Free Page Map page number from the {@link PdbByteReader}
* @param reader {@link PdbByteReader} from which to read. * @param reader {@link PdbByteReader} from which to read
* @throws PdbException Upon not enough data left to parse. * @throws PdbException upon not enough data left to parse
*/ */
protected abstract void parseFreePageMapPageNumber(PdbByteReader reader) throws PdbException; protected abstract void parseFreePageMapPageNumber(PdbByteReader reader) throws PdbException;
/** /**
* Deserializes the value of the number of pages in the MSF. * Deserializes the value of the number of pages in the MSF
* @param reader {@link PdbByteReader} from which to read. * @param reader {@link PdbByteReader} from which to read
* @throws PdbException Upon not enough data left to parse. * @throws PdbException upon not enough data left to parse
*/ */
protected abstract void parseCurrentNumPages(PdbByteReader reader) throws PdbException; protected abstract void parseCurrentNumPages(PdbByteReader reader) throws PdbException;
/** /**
* Method to create the following components: StreamTable, FreePageMap, and DirectoryStream. * Method to create the following components: StreamTable, FreePageMap, and DirectoryStream.
* FreePageMap.
*/ */
abstract void create(); abstract void create();
/** /**
* Method to set parameters for the file based on version and page size. * Method to set parameters for the file based on version and page size
* @throws PdbException Upon unknown value for configuration. * @throws PdbException upon unknown value for configuration
*/ */
abstract void configureParameters() throws PdbException; abstract void configureParameters() throws PdbException;
/** /**
* Method to get the size of the page number (in bytes) when serialized to disc. * Method to get the size of the page number (in bytes) when serialized to disc
* @return The page size (in bytes). * @return the page size (in bytes)
*/ */
abstract protected int getPageNumberSize(); abstract protected int getPageNumberSize();
@@ -251,8 +282,8 @@ public abstract class AbstractMsf implements AutoCloseable {
// Class Internals // Class Internals
//============================================================================================== //==============================================================================================
/** /**
* Returns Log2 value of the page size employed by this MSF. * Returns Log2 value of the page size employed by this MSF
* @return The Log2 value of the page size employed by this MSF. * @return the Log2 value of the page size employed by this MSF
*/ */
protected int getLog2PageSize() { protected int getLog2PageSize() {
return log2PageSize; return log2PageSize;
@@ -260,33 +291,33 @@ public abstract class AbstractMsf implements AutoCloseable {
/** /**
* Returns the the mask used for masking off the upper bits of a value use to get the * Returns the the mask used for masking off the upper bits of a value use to get the
* mod-page-size of the value (pageSizes must be power of two for this to work). * mod-page-size of the value (pageSizes must be power of two for this to work)
* @return The mask. * @return the mask
*/ */
protected int getPageSizeModMask() { protected int getPageSizeModMask() {
return pageSizeModMask; return pageSizeModMask;
} }
/** /**
* Returns the number of pages found in sequence that compose the {@link AbstractMsfFreePageMap} * Returns the number of pages found in sequence that compose the {@link MsfFreePageMap}
* (for this {@link AbstractMsf}) when on disk. * (for this {@link Msf}) when on disk
* @return The number of sequential pages in the {@link AbstractMsfFreePageMap}. * @return the number of sequential pages in the {@link MsfFreePageMap}
*/ */
protected int getNumSequentialFreePageMapPages() { protected int getNumSequentialFreePageMapPages() {
return freePageMapNumSequentialPage; return freePageMapNumSequentialPage;
} }
/** /**
* Returns the page number containing the header of this MSF file. * Returns the page number containing the header of this MSF file
* @return The header page number. * @return the header page number
*/ */
protected int getHeaderPageNumber() { protected int getHeaderPageNumber() {
return HEADER_PAGE_NUMBER; return HEADER_PAGE_NUMBER;
} }
/** /**
* Returns the stream number containing the directory of this MSF file. * Returns the stream number containing the directory of this MSF file
* @return The directory stream number. * @return the directory stream number
*/ */
protected int getDirectoryStreamNumber() { protected int getDirectoryStreamNumber() {
return DIRECTORY_STREAM_NUMBER; return DIRECTORY_STREAM_NUMBER;
@@ -296,16 +327,16 @@ public abstract class AbstractMsf implements AutoCloseable {
// Internal Data Methods // Internal Data Methods
//============================================================================================== //==============================================================================================
/** /**
* Returns the number of pages contained in this MSF file. * Returns the number of pages contained in this MSF file
* @return The number of pages in this MSF. * @return the number of pages in this MSF
*/ */
protected int getNumPages() { protected int getNumPages() {
return numPages; return numPages;
} }
/** /**
* Returns the first page number of the current Free Page Map. * Returns the first page number of the current Free Page Map
* @return The first page number of the current Free Page Map. * @return the first page number of the current Free Page Map
*/ */
protected int getCurrentFreePageMapFirstPageNumber() { protected int getCurrentFreePageMapFirstPageNumber() {
return currentFreePageMapFirstPageNumber; return currentFreePageMapFirstPageNumber;
@@ -314,14 +345,13 @@ public abstract class AbstractMsf implements AutoCloseable {
/** /**
* Performs required initialization of this class, needed before trying to read any * Performs required initialization of this class, needed before trying to read any
* Streams. Initialization includes deserializing the remainder of the header as well * Streams. Initialization includes deserializing the remainder of the header as well
* as stream directory information. * as stream directory information
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes
* inability to read required bytes. * @throws PdbException upon unknown value for configuration
* @throws PdbException Upon unknown value for configuration. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
protected void deserialize(TaskMonitor monitor) protected void deserialize()
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
byte[] bytes = new byte[getPageSize()]; byte[] bytes = new byte[getPageSize()];
fileReader.read(getHeaderPageNumber(), 0, getPageSize(), bytes, 0); fileReader.read(getHeaderPageNumber(), 0, getPageSize(), bytes, 0);
@@ -333,13 +363,13 @@ public abstract class AbstractMsf implements AutoCloseable {
parseCurrentNumPages(reader); parseCurrentNumPages(reader);
configureParameters(); configureParameters();
directoryStream.deserializeStreamInfo(reader, monitor); directoryStream.deserializeStreamInfo(reader);
// Do not need FreePageMap for just reading files. // Do not need FreePageMap for just reading files.
freePageMap.deserialize(monitor); freePageMap.deserialize();
// For debug: freePageMap.dump(); // For debug: freePageMap.dump();
streamTable.deserialize(directoryStream, monitor); streamTable.deserialize(directoryStream);
} }
} }
@@ -20,11 +20,12 @@ import java.io.RandomAccessFile;
import java.util.Arrays; import java.util.Arrays;
import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.*;
import ghidra.util.task.TaskMonitor;
/** /**
* This class is the version of {@link AbstractMsf} for Microsoft v2.00 MSF. * This class is the version of {@link Msf} for Microsoft v2.00 MSF.
*/ */
public class Msf200 extends AbstractMsf { public class Msf200 extends Msf {
private static final int PAGE_NUMBER_SIZE = 2; private static final int PAGE_NUMBER_SIZE = 2;
private static final byte[] IDENTIFICATION = private static final byte[] IDENTIFICATION =
@@ -39,25 +40,28 @@ public class Msf200 extends AbstractMsf {
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param file The {@link RandomAccessFile} to process as a {@link Msf200}. * @param file the {@link RandomAccessFile} to process as a {@link Msf200}
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB. * @param filename name of {@code #file}
* @throws IOException Upon file IO seek/read issues. * @param monitor the TaskMonitor
* @throws PdbException Upon unknown value for configuration. * @param pdbOptions {@link PdbReaderOptions} used for processing the PDB
* @throws IOException upon file IO seek/read issues
* @throws PdbException upon unknown value for configuration
*/ */
public Msf200(RandomAccessFile file, PdbReaderOptions pdbOptions) public Msf200(RandomAccessFile file, String filename, TaskMonitor monitor,
PdbReaderOptions pdbOptions)
throws IOException, PdbException { throws IOException, PdbException {
super(file, pdbOptions); super(file, filename, monitor, pdbOptions);
} }
//============================================================================================== //==============================================================================================
// Package-Protected Internals // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Static method used to detect the header that belongs to this class. * Static method used to detect the header that belongs to this class
* @param file The {@link RandomAccessFile} to process as a {@link Msf200}. * @param file the {@link RandomAccessFile} to process as a {@link Msf200}
* @return True if the header for this class is positively identified. * @return {@code true} if the header for this class is positively identified
* @throws IOException Upon file IO seek/read issues. * @throws IOException upon file IO seek/read issues
*/ */
static boolean detected(RandomAccessFile file) throws IOException { static boolean detected(RandomAccessFile file) throws IOException {
byte[] bytes = new byte[IDENTIFICATION.length]; byte[] bytes = new byte[IDENTIFICATION.length];
@@ -20,11 +20,12 @@ import java.io.RandomAccessFile;
import java.util.Arrays; import java.util.Arrays;
import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.*;
import ghidra.util.task.TaskMonitor;
/** /**
* This class is the version of {@link AbstractMsf} for Microsoft v7.00 MSF. * This class is the version of {@link Msf} for Microsoft v7.00 MSF.
*/ */
public class Msf700 extends AbstractMsf { public class Msf700 extends Msf {
private static final int PAGE_NUMBER_SIZE = 4; private static final int PAGE_NUMBER_SIZE = 4;
private static final byte[] IDENTIFICATION = "Microsoft C/C++ MSF 7.00\r\n\u001aDS".getBytes(); private static final byte[] IDENTIFICATION = "Microsoft C/C++ MSF 7.00\r\n\u001aDS".getBytes();
@@ -38,15 +39,18 @@ public class Msf700 extends AbstractMsf {
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param file The {@link RandomAccessFile} to process as a {@link Msf700}. * @param file the {@link RandomAccessFile} to process as a {@link Msf700}
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB. * @param filename name of {@code #file}
* @throws IOException Upon file IO seek/read issues. * @param monitor the TaskMonitor
* @throws PdbException Upon unknown value for configuration. * @param pdbOptions {@link PdbReaderOptions} used for processing the PDB
* @throws IOException upon file IO seek/read issues
* @throws PdbException upon unknown value for configuration
*/ */
public Msf700(RandomAccessFile file, PdbReaderOptions pdbOptions) public Msf700(RandomAccessFile file, String filename, TaskMonitor monitor,
PdbReaderOptions pdbOptions)
throws IOException, PdbException { throws IOException, PdbException {
super(file, pdbOptions); super(file, filename, monitor, pdbOptions);
} }
//============================================================================================== //==============================================================================================
@@ -98,10 +102,10 @@ public class Msf700 extends AbstractMsf {
// Package-Protected Internals // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Static method used to detect the header that belongs to this class. * Static method used to detect the header that belongs to this class
* @param file The RandomAccessFile to process as a {@link Msf700}. * @param file the RandomAccessFile to process as a {@link Msf700}
* @return True if the header for this class is positively identified. * @return {@code true} if the header for this class is positively identified
* @throws IOException Upon file IO seek/read issues. * @throws IOException upon file IO seek/read issues
*/ */
static boolean detected(RandomAccessFile file) throws IOException { static boolean detected(RandomAccessFile file) throws IOException {
byte[] bytes = new byte[IDENTIFICATION.length]; byte[] bytes = new byte[IDENTIFICATION.length];
@@ -20,26 +20,26 @@ package ghidra.app.util.bin.format.pdb2.pdbreader.msf;
* in the older style MSF format, it was the same as a user (@link MsfStream}. Newer versions of * in the older style MSF format, it was the same as a user (@link MsfStream}. Newer versions of
* MSF needed a higher capacity stream * MSF needed a higher capacity stream
* Class extends {@link MsfStream} and represents a more complex Stream used as the Directory Stream * Class extends {@link MsfStream} and represents a more complex Stream used as the Directory Stream
* for the newer {@link AbstractMsf} (and PDB) format. In the older format, a regular * for the newer {@link Msf} (and PDB) format. In the older format, a regular
* Stream is used as the directory Stream. * Stream is used as the directory Stream.
* <P> * <P>
* Note: This extended Stream is not used as a user Stream--just as a higher-capacity directory * Note: This extended Stream is not used as a user Stream--just as a higher-capacity directory
* Stream. * Stream.
* <P> * <P>
* The format of how this {@link AbstractMsfDirectoryStream} is persisted to disk is described in * The format of how this {@link MsfDirectoryStream} is persisted to disk is described in
* the main {@link AbstractMsf} documentation. * the main {@link Msf} documentation.
*/ */
abstract class AbstractMsfDirectoryStream extends MsfStream { abstract class MsfDirectoryStream extends MsfStream {
//============================================================================================== //==============================================================================================
// Package-Protected Internals // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Constructor. Sets the byte length of the Stream to -1. This method is used when the * Constructor. Sets the byte length of the Stream to -1. This method is used when the
* Stream knows/reads its length. * Stream knows/reads its length
* @param msf The {@link AbstractMsf} to which the Stream belongs. * @param msf the {@link Msf} to which the Stream belongs
*/ */
AbstractMsfDirectoryStream(AbstractMsf msf) { MsfDirectoryStream(Msf msf) {
super(msf); super(msf);
} }
@@ -16,21 +16,21 @@
package ghidra.app.util.bin.format.pdb2.pdbreader.msf; package ghidra.app.util.bin.format.pdb2.pdbreader.msf;
/** /**
* This is the v200 of {@link AbstractMsfDirectoryStream}. It is essentially no different than * This is the v200 of {@link MsfDirectoryStream}. It is essentially no different than
* an {@link MsfStream}. * an {@link MsfStream}.
* @see AbstractMsfDirectoryStream * @see MsfDirectoryStream
*/ */
class MsfDirectoryStream200 extends AbstractMsfDirectoryStream { class MsfDirectoryStream200 extends MsfDirectoryStream {
//============================================================================================== //==============================================================================================
// Package-Protected Internals // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Constructor. Sets the byte length of the Stream to -1. This method is used when the * Constructor. Sets the byte length of the Stream to -1. This method is used when the
* Stream knows/reads its length. * Stream knows/reads its length
* @param msf The {@link AbstractMsf} to which the Stream belongs. * @param msf the {@link Msf} to which the Stream belongs
*/ */
MsfDirectoryStream200(AbstractMsf msf) { MsfDirectoryStream200(Msf msf) {
super(msf); super(msf);
} }
@@ -20,24 +20,23 @@ import java.io.IOException;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbByteReader; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbByteReader;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* This is the v700 of {@link AbstractMsfDirectoryStream}. It is essentially no different than * This is the v700 of {@link MsfDirectoryStream}. It is essentially no different than
* an {@link MsfStream}. * an {@link MsfStream}.
* @see AbstractMsfDirectoryStream * @see MsfDirectoryStream
*/ */
class MsfDirectoryStream700 extends AbstractMsfDirectoryStream { class MsfDirectoryStream700 extends MsfDirectoryStream {
//============================================================================================== //==============================================================================================
// Package-Protected Internals // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Constructor. Sets the byte length of the Stream to -1. This method is used when the * Constructor. Sets the byte length of the Stream to -1. This method is used when the
* Stream knows/reads its length. * Stream knows/reads its length
* @param msf The {@link AbstractMsf} to which the Stream belongs. * @param msf the {@link Msf} to which the Stream belongs
*/ */
MsfDirectoryStream700(AbstractMsf msf) { MsfDirectoryStream700(Msf msf) {
super(msf); super(msf);
} }
@@ -45,39 +44,38 @@ class MsfDirectoryStream700 extends AbstractMsfDirectoryStream {
* Deserializes Stream information from the bytes parameter starting at the index offset * Deserializes Stream information from the bytes parameter starting at the index offset
* and uses it to provide necessary information for the Stream to be usable. * and uses it to provide necessary information for the Stream to be usable.
* The information from the deserialization of the byte parameter then points to additional * The information from the deserialization of the byte parameter then points to additional
* {@link AbstractMsf} pages that need to be read as a subStream and deserialized to create * {@link Msf} pages that need to be read as a subStream and deserialized to create
* the {@link MsfDirectoryStream700}. * the {@link MsfDirectoryStream700}.
* <P> * <P>
* Generally, deserialization is part of the step of loading the Stream information from * Generally, deserialization is part of the step of loading the Stream information from
* persistent storage (disk). * persistent storage (disk).
* @param reader {@link PdbByteReader} from which to parse the information. * @param reader {@link PdbByteReader} from which to parse the information
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes
* inability to read required bytes. * @throws PdbException upon not enough data left to parse
* @throws PdbException Upon not enough data left to parse. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
@Override @Override
void deserializeStreamInfo(PdbByteReader reader, TaskMonitor monitor) void deserializeStreamInfo(PdbByteReader reader)
throws IOException, PdbException, CancelledException { throws IOException, PdbException, CancelledException {
// Parse the length of the overall (larger) stream. // Parse the length of the overall (larger) stream.
deserializeStreamLengthAndMapTableAddress(reader); deserializeStreamLengthAndMapTableAddress(reader);
// Calculate the length of the subStream which contains all of the page numbers necessary // Calculate the length of the subStream which contains all of the page numbers necessary
// for the overall (larger) stream and create a subStream with this calculated length. // for the overall (larger) stream and create a subStream with this calculated length.
int subStreamLength = int subStreamLength =
AbstractMsf.floorDivisionWithLog2Divisor(streamLength, msf.getLog2PageSize()) * Msf.floorDivisionWithLog2Divisor(streamLength, msf.getLog2PageSize()) *
msf.getPageNumberSize(); msf.getPageNumberSize();
MsfStream subStream = new MsfStream(msf, subStreamLength); MsfStream subStream = new MsfStream(msf, subStreamLength);
// Parse the page numbers of the subStream. // Parse the page numbers of the subStream.
subStream.deserializePageNumbers(reader, monitor); subStream.deserializePageNumbers(reader);
// Now read the whole subStream, creating a new byte array. // Now read the whole subStream, creating a new byte array.
byte[] bytes = subStream.read(0, subStreamLength, monitor); byte[] bytes = subStream.read(0, subStreamLength);
PdbByteReader pageNumberReader = new PdbByteReader(bytes); PdbByteReader pageNumberReader = new PdbByteReader(bytes);
// Next parse the page numbers for the overall (larger) stream from this new byte array // Next parse the page numbers for the overall (larger) stream from this new byte array
// that was read from the subStream. // that was read from the subStream.
deserializePageNumbers(pageNumberReader, monitor); deserializePageNumbers(pageNumberReader);
// The overall (larger) stream has now been set up with the overall stream length // The overall (larger) stream has now been set up with the overall stream length
// and its page numbers parsed. // and its page numbers parsed.
} }
@@ -20,7 +20,7 @@ import java.io.RandomAccessFile;
/** /**
* This class is responsible for reading pages from a {@link RandomAccessFile} for the * This class is responsible for reading pages from a {@link RandomAccessFile} for the
* {@link AbstractMsf} class and its underlying classes. * {@link Msf} class and its underlying classes.
*/ */
class MsfFileReader implements AutoCloseable { class MsfFileReader implements AutoCloseable {
@@ -28,14 +28,14 @@ class MsfFileReader implements AutoCloseable {
// Internals // Internals
//============================================================================================== //==============================================================================================
private RandomAccessFile file; private RandomAccessFile file;
private AbstractMsf msf; private Msf msf;
//============================================================================================== //==============================================================================================
// API // API
//============================================================================================== //==============================================================================================
/** /**
* Closes this class, including its underlying file resources. * Closes this class, including its underlying file resources
* @throws IOException Under circumstances found when closing a {@link RandomAccessFile}. * @throws IOException under circumstances found when closing a {@link RandomAccessFile}
*/ */
@Override @Override
public void close() throws IOException { public void close() throws IOException {
@@ -48,35 +48,35 @@ class MsfFileReader implements AutoCloseable {
// Package-Protected Internals // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param msf The {@link AbstractMsf} for which this class is to be associated. * @param msf the {@link Msf} for which this class is to be associated
* @param file {@link RandomAccessFile} underlying this class. * @param file {@link RandomAccessFile} underlying this class
*/ */
MsfFileReader(AbstractMsf msf, RandomAccessFile file) { MsfFileReader(Msf msf, RandomAccessFile file) {
this.msf = msf; this.msf = msf;
this.file = file; this.file = file;
} }
/** /**
* Reads a single page of bytes from the {@link AbstractMsf} and writes it into the bytes array. * Reads a single page of bytes from the {@link Msf} and writes it into the bytes array
* @param page The page number to read from the file. * @param page the page number to read from the file
* @param bytes The byte[] into which the data is to be written. * @param bytes the byte[] into which the data is to be written
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* inability to read required bytes. * inability to read required bytes
*/ */
void readPage(int page, byte[] bytes) throws IOException { void readPage(int page, byte[] bytes) throws IOException {
read(page, 0, msf.getPageSize(), bytes, 0); read(page, 0, msf.getPageSize(), bytes, 0);
} }
/** /**
* Reads bytes from the {@link AbstractMsf} into a byte[]. * Reads bytes from the {@link Msf} into a byte[]
* @param page The page number within which to start the read. * @param page the page number within which to start the read
* @param offset The byte offset within the page to start the read. * @param offset the byte offset within the page to start the read
* @param numToRead The total number of bytes to read. * @param numToRead the total number of bytes to read
* @param bytes The byte[] into which the data is to be written. * @param bytes the byte[] into which the data is to be written
* @param bytesOffset The starting offset within the bytes array in which to start writing. * @param bytesOffset the starting offset within the bytes array in which to start writing
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* inability to read required bytes. * inability to read required bytes
*/ */
void read(int page, int offset, int numToRead, byte[] bytes, int bytesOffset) void read(int page, int offset, int numToRead, byte[] bytes, int bytesOffset)
throws IOException { throws IOException {
@@ -95,7 +95,7 @@ class MsfFileReader implements AutoCloseable {
// Fail if file does not contain enough pages for the read--boundary case that assumes // Fail if file does not contain enough pages for the read--boundary case that assumes
// everything beyond the offset in the file belongs to this read. // everything beyond the offset in the file belongs to this read.
if (AbstractMsf.floorDivisionWithLog2Divisor(offset + numToRead, if (Msf.floorDivisionWithLog2Divisor(offset + numToRead,
msf.getLog2PageSize()) > msf.getNumPages()) { msf.getLog2PageSize()) > msf.getNumPages()) {
throw new IOException("Invalid MSF configuration"); throw new IOException("Invalid MSF configuration");
} }
@@ -20,14 +20,13 @@ import java.util.*;
import ghidra.util.LittleEndianDataConverter; import ghidra.util.LittleEndianDataConverter;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* This class is the Free Page Map for the Multi-Stream Format File (see Microsoft API). The * This class is the Free Page Map for the Multi-Stream Format File (see Microsoft API). The
* Free Page Map is a bit-encoding of whether a page within the {@link AbstractMsf} is * Free Page Map is a bit-encoding of whether a page within the {@link Msf} is
* currently used--for purposes of reusing available pages. * currently used--for purposes of reusing available pages.
* <P> * <P>
* This class was crafted to take the place of the formal Free Page Map in a complete * This class was crafted to take the place of the formal Free Page Map in a complete
* (read/write/modify) solution, but might not need to be used for a "reader" technology. * (read/write/modify) solution, but might not need to be used for a "reader" technology.
* <P> * <P>
* NOTE: This implementation is incomplete: we are not processing or accessing the bits yet. * NOTE: This implementation is incomplete: we are not processing or accessing the bits yet.
@@ -35,7 +34,7 @@ import ghidra.util.task.TaskMonitor;
* ENGINEERING PATH: Use java.util.BitSet for storage after processing. Could probably eliminate * ENGINEERING PATH: Use java.util.BitSet for storage after processing. Could probably eliminate
* the {@code List<Integer> map} storage. * the {@code List<Integer> map} storage.
*/ */
abstract class AbstractMsfFreePageMap { abstract class MsfFreePageMap {
//============================================================================================== //==============================================================================================
// Internals // Internals
@@ -44,22 +43,22 @@ abstract class AbstractMsfFreePageMap {
private List<Integer> map = new ArrayList<>(); private List<Integer> map = new ArrayList<>();
protected static final int MAP_FIELD_SIZE = Integer.BYTES; protected static final int MAP_FIELD_SIZE = Integer.BYTES;
protected AbstractMsf msf; protected Msf msf;
//============================================================================================== //==============================================================================================
// Package-Protected Internals // Package-Protected Internals
//============================================================================================== //==============================================================================================
/** /**
* Constructor. * Constructor
* @param msf The {@link AbstractMsf} to which this class belongs. * @param msf the {@link Msf} to which this class belongs
*/ */
AbstractMsfFreePageMap(AbstractMsf msf) { MsfFreePageMap(Msf msf) {
this.msf = msf; this.msf = msf;
} }
/** /**
* Debug method to dump some of the internals of this class. * Debug method to dump some of the internals of this class
* @return Data dumped in a pretty format. * @return data dumped in a pretty format
*/ */
String dump() { String dump() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
@@ -80,19 +79,18 @@ abstract class AbstractMsfFreePageMap {
// Abstract Methods // Abstract Methods
//============================================================================================== //==============================================================================================
/** /**
* Method used to deserialize this class from disk. * Method used to deserialize this class from disc
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws IOException on file seek or read, invalid parameters, bad file configuration, or
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or * inability to read required bytes
* inability to read required bytes. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
abstract void deserialize(TaskMonitor monitor) throws IOException, CancelledException; abstract void deserialize() throws IOException, CancelledException;
/** /**
* Method indicating whether the Free Page Map is a "Big" Free Page Map. Currently, we have * Method indicating whether the Free Page Map is a "Big" Free Page Map. Currently, we have
* at least two types extending this class. One is "Big" (the newer v7.00) and the other is * at least two types extending this class. One is "Big" (the newer v7.00) and the other is
* not. The {@link #dump()} method makes use of this method. * not. The {@link #dump()} method makes use of this method
* @return true if it is a "Big" version of this class. * @return {@code true} if it is a "Big" version of this class
*/ */
abstract boolean isBig(); abstract boolean isBig();
@@ -100,16 +98,15 @@ abstract class AbstractMsfFreePageMap {
// Internal Data Methods // Internal Data Methods
//============================================================================================== //==============================================================================================
/** /**
* Internal method for adding a records to the map from the {@code byte[]} argument. * Internal method for adding a records to the map from the {@code byte[]} argument
* @param bytes The {@code byte[]} containing the data. * @param bytes the {@code byte[]} containing the data
* @param monitor {@link TaskMonitor} used for checking cancellation. * @throws CancelledException upon user cancellation
* @throws CancelledException Upon user cancellation.
*/ */
protected void addMap(byte[] bytes, TaskMonitor monitor) throws CancelledException { protected void addMap(byte[] bytes) throws CancelledException {
// TODO: If we implement FreePageMap further, then consider passing in a PdbByteReader // TODO: If we implement FreePageMap further, then consider passing in a PdbByteReader
// and using the reader to parse the appropriate Integral types. // and using the reader to parse the appropriate Integral types.
for (int index = 0; index < bytes.length - MAP_FIELD_SIZE; index += MAP_FIELD_SIZE) { for (int index = 0; index < bytes.length - MAP_FIELD_SIZE; index += MAP_FIELD_SIZE) {
monitor.checkCanceled(); msf.checkCanceled();
byte[] selectedBytes = Arrays.copyOfRange(bytes, index, index + MAP_FIELD_SIZE); byte[] selectedBytes = Arrays.copyOfRange(bytes, index, index + MAP_FIELD_SIZE);
map.add(LittleEndianDataConverter.INSTANCE.getInt(selectedBytes)); map.add(LittleEndianDataConverter.INSTANCE.getInt(selectedBytes));
} }

Some files were not shown because too many files have changed in this diff Show More