Merge remote-tracking branch 'origin/GP-2367_ghizard_PDB_U_cleanup_refactor_rename_itfc_changes--SQUASHED'

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

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