mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GP-4025 - PDB - Use ByteProvider in place of RandomAccessFile
This commit is contained in:
parent
c225fac124
commit
4da04423bd
15 changed files with 152 additions and 114 deletions
|
@ -113,12 +113,10 @@ public class Pagedump extends DumpFile {
|
||||||
props.setString("Executable Format", PeLoader.PE_NAME);
|
props.setString("Executable Format", PeLoader.PE_NAME);
|
||||||
initManagerList(addins);
|
initManagerList(addins);
|
||||||
|
|
||||||
createBlocks =
|
createBlocks = OptionUtils.getBooleanOptionValue(CREATE_MEMORY_BLOCKS_OPTION_NAME, options,
|
||||||
OptionUtils.getBooleanOptionValue(CREATE_MEMORY_BLOCKS_OPTION_NAME,
|
CREATE_MEMORY_BLOCKS_OPTION_DEFAULT);
|
||||||
options, CREATE_MEMORY_BLOCKS_OPTION_DEFAULT);
|
String pdbLocation = OptionUtils.getOption(DEBUG_DATA_PATH_OPTION_NAME, options,
|
||||||
String pdbLocation =
|
DEBUG_DATA_PATH_OPTION_DEFAULT);
|
||||||
OptionUtils.getOption(DEBUG_DATA_PATH_OPTION_NAME, options,
|
|
||||||
DEBUG_DATA_PATH_OPTION_DEFAULT);
|
|
||||||
if (!pdbLocation.equals("")) {
|
if (!pdbLocation.equals("")) {
|
||||||
loadKernelPDB(pdbLocation, monitor);
|
loadKernelPDB(pdbLocation, monitor);
|
||||||
}
|
}
|
||||||
|
@ -152,8 +150,7 @@ public class Pagedump extends DumpFile {
|
||||||
data.add(new DumpData(hdrLen, dt));
|
data.add(new DumpData(hdrLen, dt));
|
||||||
data.add(new DumpData(full.getHeaderSize(), "Physical_Memory", 0));
|
data.add(new DumpData(full.getHeaderSize(), "Physical_Memory", 0));
|
||||||
offset = (int) full.getHeaderSize();
|
offset = (int) full.getHeaderSize();
|
||||||
addInteriorAddressObject("DumpHeader", hdrLen, hdrLen,
|
addInteriorAddressObject("DumpHeader", hdrLen, hdrLen, offset - hdrLen);
|
||||||
offset - hdrLen);
|
|
||||||
if (createBlocks) {
|
if (createBlocks) {
|
||||||
mapPages(monitor);
|
mapPages(monitor);
|
||||||
}
|
}
|
||||||
|
@ -164,20 +161,17 @@ public class Pagedump extends DumpFile {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
addInteriorAddressObject("Unknown", offset, offset,
|
addInteriorAddressObject("Unknown", offset, offset, reader.length() - offset);
|
||||||
reader.length() - offset);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DUMP_TYPE_TRIAGE:
|
case DUMP_TYPE_TRIAGE:
|
||||||
triage = new TriageDump(reader, hdrLen);
|
triage = new TriageDump(reader, hdrLen);
|
||||||
dt = triage.toDataType();
|
dt = triage.toDataType();
|
||||||
data.add(new DumpData(hdrLen, dt));
|
data.add(new DumpData(hdrLen, dt));
|
||||||
addInteriorAddressObject("DumpHeader", hdrLen, hdrLen,
|
addInteriorAddressObject("DumpHeader", hdrLen, hdrLen, triage.getSizeOfDump());
|
||||||
triage.getSizeOfDump());
|
|
||||||
|
|
||||||
long next = hdrLen + triage.getSizeOfDump();
|
long next = hdrLen + triage.getSizeOfDump();
|
||||||
addInteriorAddressObject("Unknown", next,
|
addInteriorAddressObject("Unknown", next, next, reader.length() - next);
|
||||||
next, reader.length() - next);
|
|
||||||
|
|
||||||
buildKernelStructures();
|
buildKernelStructures();
|
||||||
break;
|
break;
|
||||||
|
@ -199,12 +193,12 @@ public class Pagedump extends DumpFile {
|
||||||
PdbReaderOptions readerOptions = new PdbReaderOptions();
|
PdbReaderOptions readerOptions = new PdbReaderOptions();
|
||||||
PdbApplicatorOptions applicatorOptions = new PdbApplicatorOptions();
|
PdbApplicatorOptions applicatorOptions = new PdbApplicatorOptions();
|
||||||
applicatorOptions.setProcessingControl(PdbApplicatorControl.DATA_TYPES_ONLY);
|
applicatorOptions.setProcessingControl(PdbApplicatorControl.DATA_TYPES_ONLY);
|
||||||
try (AbstractPdb pdb = PdbParser.parse(pdbFile.getPath(), readerOptions, monitor)) {
|
try (AbstractPdb pdb = PdbParser.parse(pdbFile, readerOptions, monitor)) {
|
||||||
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
|
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
|
||||||
pdb.deserialize();
|
pdb.deserialize();
|
||||||
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb);
|
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb);
|
||||||
applicator.applyTo(program, dtm, program.getImageBase(),
|
applicator.applyTo(program, dtm, program.getImageBase(), applicatorOptions,
|
||||||
applicatorOptions, (MessageLog) null);
|
(MessageLog) null);
|
||||||
}
|
}
|
||||||
catch (PdbException | IOException | CancelledException e) {
|
catch (PdbException | IOException | CancelledException e) {
|
||||||
Msg.error(this, e.getMessage());
|
Msg.error(this, e.getMessage());
|
||||||
|
@ -218,16 +212,16 @@ public class Pagedump extends DumpFile {
|
||||||
long runLength = run.getPageCount() * PAGE_SIZE;
|
long runLength = run.getPageCount() * PAGE_SIZE;
|
||||||
boolean outOfBounds = runLength + total * PAGE_SIZE > reader.length();
|
boolean outOfBounds = runLength + total * PAGE_SIZE > reader.length();
|
||||||
long bound = (outOfBounds) ? (reader.length() - total * PAGE_SIZE) : runLength;
|
long bound = (outOfBounds) ? (reader.length() - total * PAGE_SIZE) : runLength;
|
||||||
ArrayDataType adt =
|
ArrayDataType adt = new ArrayDataType(StructConverter.BYTE, (int) bound, 1);
|
||||||
new ArrayDataType(StructConverter.BYTE, (int) bound, 1);
|
|
||||||
data.add(new DumpData(total * PAGE_SIZE, adt));
|
data.add(new DumpData(total * PAGE_SIZE, adt));
|
||||||
|
|
||||||
// NB: Not sure if or where to place these
|
// NB: Not sure if or where to place these
|
||||||
//addInteriorAddressObject(DumpFileLoader.LOCAL, total * PAGE_SIZE,
|
//addInteriorAddressObject(DumpFileLoader.LOCAL, total * PAGE_SIZE,
|
||||||
// run.getBasePage() * PAGE_SIZE, run.getPageCount() * PAGE_SIZE);
|
// run.getBasePage() * PAGE_SIZE, run.getPageCount() * PAGE_SIZE);
|
||||||
total += run.getPageCount();
|
total += run.getPageCount();
|
||||||
if (outOfBounds)
|
if (outOfBounds) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,8 +307,7 @@ public class Pagedump extends DumpFile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uds.add(new ArrayDataType(udt, (int) count, udt.getLength()),
|
uds.add(new ArrayDataType(udt, (int) count, udt.getLength()),
|
||||||
udt.getLength() * (int) count,
|
udt.getLength() * (int) count, "UnloadedDrivers", null);
|
||||||
"UnloadedDrivers", null);
|
|
||||||
}
|
}
|
||||||
data.add(new DumpData(offset, uds));
|
data.add(new DumpData(offset, uds));
|
||||||
}
|
}
|
||||||
|
@ -325,8 +318,9 @@ public class Pagedump extends DumpFile {
|
||||||
while (offset < end) {
|
while (offset < end) {
|
||||||
int len = reader.readInt(offset);
|
int len = reader.readInt(offset);
|
||||||
data.add(new DumpData(offset, StructConverter.DWORD, "", false, false));
|
data.add(new DumpData(offset, StructConverter.DWORD, "", false, false));
|
||||||
if (len == 0 || len == 0xFFFFFFFF)
|
if (len == 0 || len == 0xFFFFFFFF) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
offset += 4;
|
offset += 4;
|
||||||
DumpData dd = new DumpData(offset, new TerminatedUnicodeDataType(), "", false, false);
|
DumpData dd = new DumpData(offset, new TerminatedUnicodeDataType(), "", false, false);
|
||||||
dd.setSize(len * 2 + 2);
|
dd.setSize(len * 2 + 2);
|
||||||
|
@ -348,8 +342,8 @@ public class Pagedump extends DumpFile {
|
||||||
DataType db = null;
|
DataType db = null;
|
||||||
for (int i = 0; i < triage.getDataBlocksCount(); i++) {
|
for (int i = 0; i < triage.getDataBlocksCount(); i++) {
|
||||||
TriageDataBlock tdb = new TriageDataBlock(reader, reader.getPointerIndex());
|
TriageDataBlock tdb = new TriageDataBlock(reader, reader.getPointerIndex());
|
||||||
addInteriorAddressObject(DumpFileLoader.MEMORY, tdb.getOffset(),
|
addInteriorAddressObject(DumpFileLoader.MEMORY, tdb.getOffset(), tdb.getAddress(),
|
||||||
tdb.getAddress(), tdb.getSize());
|
tdb.getSize());
|
||||||
VA2fileOffset.put(tdb.getAddress(), tdb.getOffset());
|
VA2fileOffset.put(tdb.getAddress(), tdb.getOffset());
|
||||||
db = tdb.toDataType();
|
db = tdb.toDataType();
|
||||||
}
|
}
|
||||||
|
@ -387,8 +381,7 @@ public class Pagedump extends DumpFile {
|
||||||
if (namePtr != 0) {
|
if (namePtr != 0) {
|
||||||
long fileOffset = virtualToRva(namePtr);
|
long fileOffset = virtualToRva(namePtr);
|
||||||
String name = reader.readUnicodeString(fileOffset);
|
String name = reader.readUnicodeString(fileOffset);
|
||||||
addExteriorAddressObject(name, 0, entry.getDllBase(),
|
addExteriorAddressObject(name, 0, entry.getDllBase(), entry.getSizeOfImage());
|
||||||
entry.getSizeOfImage());
|
|
||||||
}
|
}
|
||||||
next = entry.getList_Flink();
|
next = entry.getList_Flink();
|
||||||
if (entryKeys.contains(next)) {
|
if (entryKeys.contains(next)) {
|
||||||
|
@ -464,10 +457,8 @@ public class Pagedump extends DumpFile {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void analyze(TaskMonitor monitor) {
|
public void analyze(TaskMonitor monitor) {
|
||||||
boolean analyzeEmbeddedObjects =
|
boolean analyzeEmbeddedObjects = OptionUtils.getBooleanOptionValue(
|
||||||
OptionUtils.getBooleanOptionValue(ANALYZE_EMBEDDED_OBJECTS_OPTION_NAME,
|
ANALYZE_EMBEDDED_OBJECTS_OPTION_NAME, options, ANALYZE_EMBEDDED_OBJECTS_OPTION_DEFAULT);
|
||||||
options,
|
|
||||||
ANALYZE_EMBEDDED_OBJECTS_OPTION_DEFAULT);
|
|
||||||
if (analyzeEmbeddedObjects) {
|
if (analyzeEmbeddedObjects) {
|
||||||
ModuleToPeHelper.queryModules(program, monitor);
|
ModuleToPeHelper.queryModules(program, monitor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ public class PdbDeveloperApplyDummyScript extends GhidraScript {
|
||||||
memory.createUninitializedBlock(pdbFileName, program.getImageBase(),
|
memory.createUninitializedBlock(pdbFileName, program.getImageBase(),
|
||||||
Memory.MAX_BLOCK_SIZE / 16, false);
|
Memory.MAX_BLOCK_SIZE / 16, false);
|
||||||
|
|
||||||
try (AbstractPdb pdb = PdbParser.parse(pdbFile.getPath(), pdbReaderOptions, monitor)) {
|
try (AbstractPdb pdb = PdbParser.parse(pdbFile, pdbReaderOptions, monitor)) {
|
||||||
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
|
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
|
||||||
pdb.deserialize();
|
pdb.deserialize();
|
||||||
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb);
|
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb);
|
||||||
|
|
|
@ -62,7 +62,7 @@ public class PdbDeveloperDumpScript extends GhidraScript {
|
||||||
String message = "Processing PDB Dump of: " + pdbFileName;
|
String message = "Processing PDB Dump of: " + pdbFileName;
|
||||||
monitor.setMessage(message);
|
monitor.setMessage(message);
|
||||||
Msg.info(this, message);
|
Msg.info(this, message);
|
||||||
try (AbstractPdb pdb = PdbParser.parse(pdbFileName, new PdbReaderOptions(), monitor)) {
|
try (AbstractPdb pdb = PdbParser.parse(pdbFile, new PdbReaderOptions(), monitor)) {
|
||||||
pdb.deserialize();
|
pdb.deserialize();
|
||||||
FileWriter fileWriter = new FileWriter(dumpFile);
|
FileWriter fileWriter = new FileWriter(dumpFile);
|
||||||
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
|
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
|
||||||
|
|
|
@ -84,8 +84,8 @@ public class PdbDeveloperDumpSetScript extends GhidraScript {
|
||||||
for (IOEntry entry : entries) {
|
for (IOEntry entry : entries) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
println("Processing PDB Dump of: " + entry.input());
|
println("Processing PDB Dump of: " + entry.input());
|
||||||
try (AbstractPdb pdb =
|
File pdbFile = new File(entry.input());
|
||||||
PdbParser.parse(entry.input(), new PdbReaderOptions(), monitor)) {
|
try (AbstractPdb pdb = PdbParser.parse(pdbFile, new PdbReaderOptions(), monitor)) {
|
||||||
pdb.deserialize();
|
pdb.deserialize();
|
||||||
try (BufferedWriter bufferedWriter =
|
try (BufferedWriter bufferedWriter =
|
||||||
new BufferedWriter(new FileWriter(new File(entry.output())))) {
|
new BufferedWriter(new FileWriter(new File(entry.output())))) {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package pdbquery;
|
package pdbquery;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
@ -59,7 +60,8 @@ public class PdbFactory {
|
||||||
println(script, "Opening PDB: " + filename);
|
println(script, "Opening PDB: " + filename);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
AbstractPdb pdb = PdbParser.parse(filename, new PdbReaderOptions(), monitor);
|
File pdbFile = new File(filename);
|
||||||
|
AbstractPdb pdb = PdbParser.parse(pdbFile, new PdbReaderOptions(), monitor);
|
||||||
PdbIdentifiers identifiers = pdb.getIdentifiers();
|
PdbIdentifiers identifiers = pdb.getIdentifiers();
|
||||||
pdb.deserialize();
|
pdb.deserialize();
|
||||||
PdbReaderMetrics metrics = pdb.getPdbReaderMetrics();
|
PdbReaderMetrics metrics = pdb.getPdbReaderMetrics();
|
||||||
|
|
|
@ -178,7 +178,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||||
PdbLog.message(DESCRIPTION);
|
PdbLog.message(DESCRIPTION);
|
||||||
PdbLog.message("PDB Filename: " + pdbFile + "\n");
|
PdbLog.message("PDB Filename: " + pdbFile + "\n");
|
||||||
|
|
||||||
try (AbstractPdb pdb = PdbParser.parse(pdbFile.getPath(), pdbReaderOptions, monitor)) {
|
try (AbstractPdb pdb = PdbParser.parse(pdbFile, pdbReaderOptions, monitor)) {
|
||||||
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
|
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
|
||||||
pdb.deserialize();
|
pdb.deserialize();
|
||||||
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb);
|
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb);
|
||||||
|
|
|
@ -15,11 +15,16 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.bin.format.pdb2.pdbreader;
|
package ghidra.app.util.bin.format.pdb2.pdbreader;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.AccessMode;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
|
import ghidra.app.util.bin.FileByteProvider;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.Msf;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.Msf;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfParser;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfParser;
|
||||||
|
import ghidra.formats.gfilesystem.FileSystemService;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
@ -54,15 +59,63 @@ public class PdbParser {
|
||||||
* @throws PdbException on parsing issues
|
* @throws PdbException on parsing issues
|
||||||
* @throws CancelledException upon user cancellation
|
* @throws CancelledException upon user cancellation
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static AbstractPdb parse(String filename, PdbReaderOptions pdbOptions,
|
public static AbstractPdb parse(String filename, PdbReaderOptions pdbOptions,
|
||||||
TaskMonitor monitor) throws IOException, PdbException, CancelledException {
|
TaskMonitor monitor) throws IOException, PdbException, CancelledException {
|
||||||
Objects.requireNonNull(filename, "filename cannot be null");
|
Objects.requireNonNull(filename, "filename cannot be null");
|
||||||
Objects.requireNonNull(pdbOptions, "pdbOptions cannot be null");
|
Objects.requireNonNull(pdbOptions, "pdbOptions cannot be null");
|
||||||
Objects.requireNonNull(monitor, "monitor cannot be null");
|
Objects.requireNonNull(monitor, "monitor cannot be null");
|
||||||
|
File file = new File(filename);
|
||||||
|
return parse(file, pdbOptions, monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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()}; the method
|
||||||
|
* used to deserialize its main identifiers (signature, age, guid (if available)) is
|
||||||
|
* {@link AbstractPdb#deserializeIdentifiersOnly(TaskMonitor monitor)}
|
||||||
|
* @param file 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(File file, PdbReaderOptions pdbOptions, TaskMonitor monitor)
|
||||||
|
throws IOException, PdbException, CancelledException {
|
||||||
|
Objects.requireNonNull(file, "file cannot be null");
|
||||||
|
Objects.requireNonNull(pdbOptions, "pdbOptions cannot be null");
|
||||||
|
Objects.requireNonNull(monitor, "monitor cannot be null");
|
||||||
|
ByteProvider byteProvider = new FileByteProvider(file,
|
||||||
|
FileSystemService.getInstance().getLocalFSRL(file), AccessMode.READ);
|
||||||
|
return parse(byteProvider, pdbOptions, monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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()}; the method
|
||||||
|
* used to deserialize its main identifiers (signature, age, guid (if available)) is
|
||||||
|
* {@link AbstractPdb#deserializeIdentifiersOnly(TaskMonitor monitor)}
|
||||||
|
* @param byteProvider the ByteProvider providing bytes for the PDB
|
||||||
|
* @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(ByteProvider byteProvider, PdbReaderOptions pdbOptions,
|
||||||
|
TaskMonitor monitor) throws IOException, PdbException, CancelledException {
|
||||||
|
Objects.requireNonNull(byteProvider, "byteProvider cannot be null");
|
||||||
|
Objects.requireNonNull(pdbOptions, "pdbOptions cannot be null");
|
||||||
|
Objects.requireNonNull(monitor, "monitor cannot be null");
|
||||||
|
|
||||||
// Do not do a try with resources here, as the msf must live within the PDB that is
|
// Do not do a try with resources here, as the msf must live within the PDB that is
|
||||||
// created below.
|
// created below.
|
||||||
Msf msf = MsfParser.parse(filename, pdbOptions, monitor);
|
Msf msf = MsfParser.parse(byteProvider, pdbOptions, monitor);
|
||||||
|
|
||||||
int versionNumber = AbstractPdb.deserializeVersionNumber(msf, monitor);
|
int versionNumber = AbstractPdb.deserializeVersionNumber(msf, monitor);
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
@ -134,18 +135,16 @@ public abstract class AbstractMsf implements Msf {
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param file the {@link RandomAccessFile} to process for this class
|
* @param byteProvider the ByteProvider providing bytes for the MSF
|
||||||
* @param filename name of {@code #file}
|
|
||||||
* @param monitor the TaskMonitor
|
* @param monitor the TaskMonitor
|
||||||
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB
|
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB
|
||||||
* @throws IOException upon file IO seek/read issues
|
* @throws IOException upon file IO seek/read issues
|
||||||
* @throws PdbException upon unknown value for configuration
|
* @throws PdbException upon unknown value for configuration
|
||||||
*/
|
*/
|
||||||
public AbstractMsf(RandomAccessFile file, String filename, TaskMonitor monitor,
|
public AbstractMsf(ByteProvider byteProvider, TaskMonitor monitor, PdbReaderOptions pdbOptions)
|
||||||
PdbReaderOptions pdbOptions)
|
|
||||||
throws IOException, PdbException {
|
throws IOException, PdbException {
|
||||||
Objects.requireNonNull(file, "file may not be null");
|
Objects.requireNonNull(byteProvider, "ByteProvider may not be null");
|
||||||
this.filename = Objects.requireNonNull(filename, "filename may not be null");
|
this.filename = byteProvider.getAbsolutePath();
|
||||||
this.monitor = TaskMonitor.dummyIfNull(monitor);
|
this.monitor = TaskMonitor.dummyIfNull(monitor);
|
||||||
this.pdbOptions = Objects.requireNonNull(pdbOptions, "PdbOptions may not be null");
|
this.pdbOptions = Objects.requireNonNull(pdbOptions, "PdbOptions may not be null");
|
||||||
// Do initial configuration with largest possible page size. ConfigureParameters will
|
// Do initial configuration with largest possible page size. ConfigureParameters will
|
||||||
|
@ -159,7 +158,7 @@ public abstract class AbstractMsf implements Msf {
|
||||||
pageSize = 0x1000;
|
pageSize = 0x1000;
|
||||||
configureParameters();
|
configureParameters();
|
||||||
// Create components.
|
// Create components.
|
||||||
fileReader = new MsfFileReader(this, file);
|
fileReader = new MsfFileReader(this, byteProvider);
|
||||||
create();
|
create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,8 +319,7 @@ public abstract class AbstractMsf implements Msf {
|
||||||
* @throws CancelledException upon user cancellation
|
* @throws CancelledException upon user cancellation
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void deserialize()
|
public void deserialize() throws IOException, PdbException, CancelledException {
|
||||||
throws IOException, PdbException, CancelledException {
|
|
||||||
byte[] bytes = new byte[getPageSize()];
|
byte[] bytes = new byte[getPageSize()];
|
||||||
fileReader.read(getHeaderPageNumber(), 0, getPageSize(), bytes, 0);
|
fileReader.read(getHeaderPageNumber(), 0, getPageSize(), bytes, 0);
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
package ghidra.app.util.bin.format.pdb2.pdbreader.msf;
|
package ghidra.app.util.bin.format.pdb2.pdbreader.msf;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
@ -41,17 +41,15 @@ public class Msf200 extends AbstractMsf {
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param file the {@link RandomAccessFile} to process as a {@link Msf200}
|
* @param byteProvider the ByteProvider providing bytes for the MSF
|
||||||
* @param filename name of {@code #file}
|
|
||||||
* @param monitor the TaskMonitor
|
* @param monitor the TaskMonitor
|
||||||
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB
|
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB
|
||||||
* @throws IOException upon file IO seek/read issues
|
* @throws IOException upon file IO seek/read issues
|
||||||
* @throws PdbException upon unknown value for configuration
|
* @throws PdbException upon unknown value for configuration
|
||||||
*/
|
*/
|
||||||
public Msf200(RandomAccessFile file, String filename, TaskMonitor monitor,
|
public Msf200(ByteProvider byteProvider, TaskMonitor monitor, PdbReaderOptions pdbOptions)
|
||||||
PdbReaderOptions pdbOptions)
|
|
||||||
throws IOException, PdbException {
|
throws IOException, PdbException {
|
||||||
super(file, filename, monitor, pdbOptions);
|
super(byteProvider, monitor, pdbOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
@ -59,14 +57,12 @@ public class Msf200 extends AbstractMsf {
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
/**
|
/**
|
||||||
* Static method used to detect the header that belongs to this class
|
* Static method used to detect the header that belongs to this class
|
||||||
* @param file the {@link RandomAccessFile} to process as a {@link Msf200}
|
* @param byteProvider the ByteProvider to process as a {@link Msf200}
|
||||||
* @return {@code true} if the header for this class is positively identified
|
* @return {@code true} if the header for this class is positively identified
|
||||||
* @throws IOException upon file IO seek/read issues
|
* @throws IOException upon file IO seek/read issues
|
||||||
*/
|
*/
|
||||||
static boolean detected(RandomAccessFile file) throws IOException {
|
static boolean detected(ByteProvider byteProvider) throws IOException {
|
||||||
byte[] bytes = new byte[IDENTIFICATION.length];
|
byte[] bytes = byteProvider.readBytes(0, IDENTIFICATION.length);
|
||||||
file.seek(0);
|
|
||||||
file.read(bytes, 0, IDENTIFICATION.length);
|
|
||||||
return Arrays.equals(bytes, IDENTIFICATION);
|
return Arrays.equals(bytes, IDENTIFICATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
package ghidra.app.util.bin.format.pdb2.pdbreader.msf;
|
package ghidra.app.util.bin.format.pdb2.pdbreader.msf;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
@ -40,17 +40,15 @@ public class Msf700 extends AbstractMsf {
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param file the {@link RandomAccessFile} to process as a {@link Msf700}
|
* @param byteProvider the ByteProvider providing bytes for the MSF
|
||||||
* @param filename name of {@code #file}
|
|
||||||
* @param monitor the TaskMonitor
|
* @param monitor the TaskMonitor
|
||||||
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB
|
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB
|
||||||
* @throws IOException upon file IO seek/read issues
|
* @throws IOException upon file IO seek/read issues
|
||||||
* @throws PdbException upon unknown value for configuration
|
* @throws PdbException upon unknown value for configuration
|
||||||
*/
|
*/
|
||||||
public Msf700(RandomAccessFile file, String filename, TaskMonitor monitor,
|
public Msf700(ByteProvider byteProvider, TaskMonitor monitor, PdbReaderOptions pdbOptions)
|
||||||
PdbReaderOptions pdbOptions)
|
|
||||||
throws IOException, PdbException {
|
throws IOException, PdbException {
|
||||||
super(file, filename, monitor, pdbOptions);
|
super(byteProvider, monitor, pdbOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
@ -107,14 +105,12 @@ public class Msf700 extends AbstractMsf {
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
/**
|
/**
|
||||||
* Static method used to detect the header that belongs to this class
|
* Static method used to detect the header that belongs to this class
|
||||||
* @param file the RandomAccessFile to process as a {@link Msf700}
|
* @param byteProvider the ByteProvider to process as a {@link Msf700}
|
||||||
* @return {@code true} if the header for this class is positively identified
|
* @return {@code true} if the header for this class is positively identified
|
||||||
* @throws IOException upon file IO seek/read issues
|
* @throws IOException upon file IO seek/read issues
|
||||||
*/
|
*/
|
||||||
static boolean detected(RandomAccessFile file) throws IOException {
|
static boolean detected(ByteProvider byteProvider) throws IOException {
|
||||||
byte[] bytes = new byte[IDENTIFICATION.length];
|
byte[] bytes = byteProvider.readBytes(0, IDENTIFICATION.length);
|
||||||
file.seek(0);
|
|
||||||
file.read(bytes, 0, IDENTIFICATION.length);
|
|
||||||
return Arrays.equals(bytes, IDENTIFICATION);
|
return Arrays.equals(bytes, IDENTIFICATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ package ghidra.app.util.bin.format.pdb2.pdbreader.msf;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is responsible for reading pages from a {@link RandomAccessFile} for the
|
* This class is responsible for reading pages from a {@link RandomAccessFile} for the
|
||||||
* {@link Msf} class and its underlying classes.
|
* {@link Msf} class and its underlying classes.
|
||||||
|
@ -27,7 +29,7 @@ class MsfFileReader implements AutoCloseable {
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
// Internals
|
// Internals
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
private RandomAccessFile file;
|
private ByteProvider byteProvider;
|
||||||
private Msf msf;
|
private Msf msf;
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
@ -39,8 +41,8 @@ class MsfFileReader implements AutoCloseable {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (file != null) {
|
if (byteProvider != null) {
|
||||||
file.close();
|
byteProvider.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,11 +52,11 @@ class MsfFileReader implements AutoCloseable {
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param msf the {@link Msf} for which this class is to be associated
|
* @param msf the {@link Msf} for which this class is to be associated
|
||||||
* @param file {@link RandomAccessFile} underlying this class
|
* @param byteProvider the ByteProvider providing bytes for the MSF
|
||||||
*/
|
*/
|
||||||
MsfFileReader(Msf msf, RandomAccessFile file) {
|
MsfFileReader(Msf msf, ByteProvider byteProvider) {
|
||||||
this.msf = msf;
|
this.msf = msf;
|
||||||
this.file = file;
|
this.byteProvider = byteProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -95,18 +97,13 @@ class MsfFileReader implements AutoCloseable {
|
||||||
|
|
||||||
// Fail if file does not contain enough pages for the read--boundary case that assumes
|
// Fail if file does not contain enough pages for the read--boundary case that assumes
|
||||||
// everything beyond the offset in the file belongs to this read.
|
// everything beyond the offset in the file belongs to this read.
|
||||||
if (Msf.floorDivisionWithLog2Divisor(offset + numToRead,
|
if (Msf.floorDivisionWithLog2Divisor(offset + numToRead, msf.getLog2PageSize()) > msf
|
||||||
msf.getLog2PageSize()) > msf.getNumPages()) {
|
.getNumPages()) {
|
||||||
throw new IOException("Invalid MSF configuration");
|
throw new IOException("Invalid MSF configuration");
|
||||||
}
|
}
|
||||||
|
|
||||||
int numBytesRead = 0;
|
System.arraycopy(byteProvider.readBytes(fileOffset, numToRead), 0, bytes, bytesOffset,
|
||||||
file.seek(fileOffset);
|
numToRead);
|
||||||
numBytesRead = file.read(bytes, bytesOffset, numToRead);
|
|
||||||
|
|
||||||
if (numBytesRead != numToRead) {
|
|
||||||
throw new IOException("Could not read required bytes from MSF");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
package ghidra.app.util.bin.format.pdb2.pdbreader.msf;
|
package ghidra.app.util.bin.format.pdb2.pdbreader.msf;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbReaderOptions;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbReaderOptions;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
@ -33,7 +33,7 @@ public class MsfParser {
|
||||||
/**
|
/**
|
||||||
* Detects, creates, and returns the appropriate {@link Msf} object found for
|
* Detects, creates, and returns the appropriate {@link Msf} object found for
|
||||||
* the filename given
|
* the filename given
|
||||||
* @param filename name of the file to process
|
* @param byteProvider the ByteProvider providing bytes for the MSF
|
||||||
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB
|
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB
|
||||||
* @param monitor {@link TaskMonitor} used for checking cancellation
|
* @param monitor {@link TaskMonitor} used for checking cancellation
|
||||||
* @return derived {@link Msf} object
|
* @return derived {@link Msf} object
|
||||||
|
@ -41,24 +41,23 @@ public class MsfParser {
|
||||||
* @throws PdbException if an appropriate object cannot be created
|
* @throws PdbException if an appropriate object cannot be created
|
||||||
* @throws CancelledException upon user cancellation
|
* @throws CancelledException upon user cancellation
|
||||||
*/
|
*/
|
||||||
public static Msf parse(String filename, PdbReaderOptions pdbOptions,
|
public static Msf parse(ByteProvider byteProvider, PdbReaderOptions pdbOptions,
|
||||||
TaskMonitor monitor) throws IOException, PdbException, CancelledException {
|
TaskMonitor monitor) throws IOException, PdbException, CancelledException {
|
||||||
Objects.requireNonNull(filename, "filename cannot be null");
|
Objects.requireNonNull(byteProvider, "byteProvider cannot be null");
|
||||||
Objects.requireNonNull(pdbOptions, "pdbOptions cannot be null");
|
Objects.requireNonNull(pdbOptions, "pdbOptions cannot be null");
|
||||||
Objects.requireNonNull(monitor, "monitor cannot be null");
|
Objects.requireNonNull(monitor, "monitor cannot be null");
|
||||||
|
|
||||||
Msf msf;
|
Msf msf;
|
||||||
RandomAccessFile file = new RandomAccessFile(filename, "r");
|
if (Msf200.detected(byteProvider)) {
|
||||||
if (Msf200.detected(file)) {
|
msf = new Msf200(byteProvider, monitor, pdbOptions);
|
||||||
msf = new Msf200(file, filename, monitor, pdbOptions);
|
|
||||||
}
|
}
|
||||||
else if (Msf700.detected(file)) {
|
else if (Msf700.detected(byteProvider)) {
|
||||||
msf = new Msf700(file, filename, monitor, pdbOptions);
|
msf = new Msf700(byteProvider, monitor, pdbOptions);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Must close the file here. In cases where MSF is created, the MSF takes
|
// Must close the ByteProvider here. In cases where MSF is created, the MSF takes
|
||||||
// responsibility for closing the file.
|
// responsibility for closing the file.
|
||||||
file.close();
|
byteProvider.close();
|
||||||
throw new PdbException("MSF format not detected");
|
throw new PdbException("MSF format not detected");
|
||||||
}
|
}
|
||||||
msf.deserialize();
|
msf.deserialize();
|
||||||
|
|
|
@ -141,12 +141,11 @@ class LoadPdbTask extends Task {
|
||||||
|
|
||||||
pdbApplicatorOptions.setProcessingControl(control);
|
pdbApplicatorOptions.setProcessingControl(control);
|
||||||
|
|
||||||
try (AbstractPdb pdb = ghidra.app.util.bin.format.pdb2.pdbreader.PdbParser.parse(
|
try (AbstractPdb pdb = ghidra.app.util.bin.format.pdb2.pdbreader.PdbParser.parse(pdbFile,
|
||||||
pdbFile.getAbsolutePath(), pdbReaderOptions, monitor)) {
|
pdbReaderOptions, monitor)) {
|
||||||
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
|
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
|
||||||
pdb.deserialize();
|
pdb.deserialize();
|
||||||
DefaultPdbApplicator applicator =
|
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb);
|
||||||
new DefaultPdbApplicator(pdb);
|
|
||||||
applicator.applyTo(program, program.getDataTypeManager(), program.getImageBase(),
|
applicator.applyTo(program, program.getDataTypeManager(), program.getImageBase(),
|
||||||
pdbApplicatorOptions, log);
|
pdbApplicatorOptions, log);
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package pdb;
|
package pdb;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
@ -46,8 +45,7 @@ public class PdbUtils {
|
||||||
String extension = FilenameUtils.getExtension(file.getName()).toLowerCase();
|
String extension = FilenameUtils.getExtension(file.getName()).toLowerCase();
|
||||||
switch (extension) {
|
switch (extension) {
|
||||||
case "pdb":
|
case "pdb":
|
||||||
try (AbstractPdb pdb =
|
try (AbstractPdb pdb = PdbParser.parse(file, new PdbReaderOptions(), monitor)) {
|
||||||
PdbParser.parse(file.getPath(), new PdbReaderOptions(), monitor)) {
|
|
||||||
PdbIdentifiers identifiers = pdb.getIdentifiers();
|
PdbIdentifiers identifiers = pdb.getIdentifiers();
|
||||||
return identifiers;
|
return identifiers;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,17 +15,20 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.bin.format.pdb2.pdbreader.msf;
|
package ghidra.app.util.bin.format.pdb2.pdbreader.msf;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.nio.file.AccessMode;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
import generic.test.AbstractGenericTest;
|
import generic.test.AbstractGenericTest;
|
||||||
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
|
import ghidra.app.util.bin.FileByteProvider;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbByteWriter;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbByteWriter;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbReaderOptions;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbReaderOptions;
|
||||||
|
import ghidra.formats.gfilesystem.FileSystemService;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
@ -109,8 +112,11 @@ public class MsfReaderUnitTest extends AbstractGenericTest {
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
@Test
|
@Test
|
||||||
public void testStreamFile200Header() {
|
public void testStreamFile200Header() {
|
||||||
try (Msf streamFile =
|
File file = new File(testFileName200);
|
||||||
MsfParser.parse(testFileName200, new PdbReaderOptions(), TaskMonitor.DUMMY)) {
|
try (ByteProvider byteProvider = new FileByteProvider(file,
|
||||||
|
FileSystemService.getInstance().getLocalFSRL(file), AccessMode.READ);
|
||||||
|
Msf streamFile =
|
||||||
|
MsfParser.parse(byteProvider, new PdbReaderOptions(), TaskMonitor.DUMMY)) {
|
||||||
int numStreams = streamFile.getNumStreams();
|
int numStreams = streamFile.getNumStreams();
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
builder.append("NumStreams: " + numStreams + "\n");
|
builder.append("NumStreams: " + numStreams + "\n");
|
||||||
|
@ -127,8 +133,11 @@ public class MsfReaderUnitTest extends AbstractGenericTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStreamFile700Header() {
|
public void testStreamFile700Header() {
|
||||||
try (Msf streamFile =
|
File file = new File(testFileName700);
|
||||||
MsfParser.parse(testFileName700, new PdbReaderOptions(), TaskMonitor.DUMMY)) {
|
try (ByteProvider byteProvider = new FileByteProvider(file,
|
||||||
|
FileSystemService.getInstance().getLocalFSRL(file), AccessMode.READ);
|
||||||
|
Msf streamFile =
|
||||||
|
MsfParser.parse(byteProvider, new PdbReaderOptions(), TaskMonitor.DUMMY)) {
|
||||||
int numStreams = streamFile.getNumStreams();
|
int numStreams = streamFile.getNumStreams();
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
builder.append("NumStreams: " + numStreams + "\n");
|
builder.append("NumStreams: " + numStreams + "\n");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue