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

This commit is contained in:
ghizard
2022-09-09 16:23:09 -04:00
parent 6842712129
commit e7846664a8
67 changed files with 1583 additions and 1559 deletions
@@ -201,11 +201,10 @@ public class Pagedump extends DumpFile {
applicatorOptions.setProcessingControl(PdbApplicatorControl.DATA_TYPES_ONLY);
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