From 4da04423bd50a524ef8ffc35dd07ce1d26cd2a50 Mon Sep 17 00:00:00 2001
From: ghizard <50744617+ghizard@users.noreply.github.com>
Date: Sun, 26 Nov 2023 12:40:10 -0500
Subject: [PATCH] GP-4025 - PDB - Use ByteProvider in place of RandomAccessFile
---
.../file/formats/dump/pagedump/Pagedump.java | 57 ++++++++-----------
.../PdbDeveloperApplyDummyScript.java | 2 +-
.../PdbDeveloperDumpScript.java | 2 +-
.../PdbDeveloperDumpSetScript.java | 4 +-
.../pdbquery/PdbFactory.java | 4 +-
.../core/analysis/PdbUniversalAnalyzer.java | 2 +-
.../bin/format/pdb2/pdbreader/PdbParser.java | 55 +++++++++++++++++-
.../pdb2/pdbreader/msf/AbstractMsf.java | 16 +++---
.../bin/format/pdb2/pdbreader/msf/Msf200.java | 18 +++---
.../bin/format/pdb2/pdbreader/msf/Msf700.java | 18 +++---
.../pdb2/pdbreader/msf/MsfFileReader.java | 27 ++++-----
.../format/pdb2/pdbreader/msf/MsfParser.java | 21 ++++---
.../PDB/src/main/java/pdb/LoadPdbTask.java | 7 +--
.../PDB/src/main/java/pdb/PdbUtils.java | 12 ++--
.../pdb2/pdbreader/msf/MsfReaderUnitTest.java | 21 +++++--
15 files changed, 152 insertions(+), 114 deletions(-)
diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/dump/pagedump/Pagedump.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/dump/pagedump/Pagedump.java
index 11c0ce34d1..5abd3308a9 100644
--- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/dump/pagedump/Pagedump.java
+++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/dump/pagedump/Pagedump.java
@@ -113,12 +113,10 @@ public class Pagedump extends DumpFile {
props.setString("Executable Format", PeLoader.PE_NAME);
initManagerList(addins);
- createBlocks =
- OptionUtils.getBooleanOptionValue(CREATE_MEMORY_BLOCKS_OPTION_NAME,
- options, CREATE_MEMORY_BLOCKS_OPTION_DEFAULT);
- String pdbLocation =
- OptionUtils.getOption(DEBUG_DATA_PATH_OPTION_NAME, options,
- DEBUG_DATA_PATH_OPTION_DEFAULT);
+ createBlocks = OptionUtils.getBooleanOptionValue(CREATE_MEMORY_BLOCKS_OPTION_NAME, options,
+ CREATE_MEMORY_BLOCKS_OPTION_DEFAULT);
+ String pdbLocation = OptionUtils.getOption(DEBUG_DATA_PATH_OPTION_NAME, options,
+ DEBUG_DATA_PATH_OPTION_DEFAULT);
if (!pdbLocation.equals("")) {
loadKernelPDB(pdbLocation, monitor);
}
@@ -152,8 +150,7 @@ public class Pagedump extends DumpFile {
data.add(new DumpData(hdrLen, dt));
data.add(new DumpData(full.getHeaderSize(), "Physical_Memory", 0));
offset = (int) full.getHeaderSize();
- addInteriorAddressObject("DumpHeader", hdrLen, hdrLen,
- offset - hdrLen);
+ addInteriorAddressObject("DumpHeader", hdrLen, hdrLen, offset - hdrLen);
if (createBlocks) {
mapPages(monitor);
}
@@ -164,20 +161,17 @@ public class Pagedump extends DumpFile {
break;
}
- addInteriorAddressObject("Unknown", offset, offset,
- reader.length() - offset);
+ addInteriorAddressObject("Unknown", offset, offset, reader.length() - offset);
break;
case DUMP_TYPE_TRIAGE:
triage = new TriageDump(reader, hdrLen);
dt = triage.toDataType();
data.add(new DumpData(hdrLen, dt));
- addInteriorAddressObject("DumpHeader", hdrLen, hdrLen,
- triage.getSizeOfDump());
+ addInteriorAddressObject("DumpHeader", hdrLen, hdrLen, triage.getSizeOfDump());
long next = hdrLen + triage.getSizeOfDump();
- addInteriorAddressObject("Unknown", next,
- next, reader.length() - next);
+ addInteriorAddressObject("Unknown", next, next, reader.length() - next);
buildKernelStructures();
break;
@@ -199,12 +193,12 @@ public class Pagedump extends DumpFile {
PdbReaderOptions readerOptions = new PdbReaderOptions();
PdbApplicatorOptions applicatorOptions = new PdbApplicatorOptions();
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 + "...");
pdb.deserialize();
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb);
- applicator.applyTo(program, dtm, program.getImageBase(),
- applicatorOptions, (MessageLog) null);
+ applicator.applyTo(program, dtm, program.getImageBase(), applicatorOptions,
+ (MessageLog) null);
}
catch (PdbException | IOException | CancelledException e) {
Msg.error(this, e.getMessage());
@@ -218,16 +212,16 @@ public class Pagedump extends DumpFile {
long runLength = run.getPageCount() * PAGE_SIZE;
boolean outOfBounds = runLength + total * PAGE_SIZE > reader.length();
long bound = (outOfBounds) ? (reader.length() - total * PAGE_SIZE) : runLength;
- ArrayDataType adt =
- new ArrayDataType(StructConverter.BYTE, (int) bound, 1);
+ ArrayDataType adt = new ArrayDataType(StructConverter.BYTE, (int) bound, 1);
data.add(new DumpData(total * PAGE_SIZE, adt));
// NB: Not sure if or where to place these
//addInteriorAddressObject(DumpFileLoader.LOCAL, total * PAGE_SIZE,
// run.getBasePage() * PAGE_SIZE, run.getPageCount() * PAGE_SIZE);
total += run.getPageCount();
- if (outOfBounds)
+ if (outOfBounds) {
break;
+ }
}
}
@@ -313,8 +307,7 @@ public class Pagedump extends DumpFile {
}
}
uds.add(new ArrayDataType(udt, (int) count, udt.getLength()),
- udt.getLength() * (int) count,
- "UnloadedDrivers", null);
+ udt.getLength() * (int) count, "UnloadedDrivers", null);
}
data.add(new DumpData(offset, uds));
}
@@ -325,8 +318,9 @@ public class Pagedump extends DumpFile {
while (offset < end) {
int len = reader.readInt(offset);
data.add(new DumpData(offset, StructConverter.DWORD, "", false, false));
- if (len == 0 || len == 0xFFFFFFFF)
+ if (len == 0 || len == 0xFFFFFFFF) {
break;
+ }
offset += 4;
DumpData dd = new DumpData(offset, new TerminatedUnicodeDataType(), "", false, false);
dd.setSize(len * 2 + 2);
@@ -348,8 +342,8 @@ public class Pagedump extends DumpFile {
DataType db = null;
for (int i = 0; i < triage.getDataBlocksCount(); i++) {
TriageDataBlock tdb = new TriageDataBlock(reader, reader.getPointerIndex());
- addInteriorAddressObject(DumpFileLoader.MEMORY, tdb.getOffset(),
- tdb.getAddress(), tdb.getSize());
+ addInteriorAddressObject(DumpFileLoader.MEMORY, tdb.getOffset(), tdb.getAddress(),
+ tdb.getSize());
VA2fileOffset.put(tdb.getAddress(), tdb.getOffset());
db = tdb.toDataType();
}
@@ -387,8 +381,7 @@ public class Pagedump extends DumpFile {
if (namePtr != 0) {
long fileOffset = virtualToRva(namePtr);
String name = reader.readUnicodeString(fileOffset);
- addExteriorAddressObject(name, 0, entry.getDllBase(),
- entry.getSizeOfImage());
+ addExteriorAddressObject(name, 0, entry.getDllBase(), entry.getSizeOfImage());
}
next = entry.getList_Flink();
if (entryKeys.contains(next)) {
@@ -464,10 +457,8 @@ public class Pagedump extends DumpFile {
@Override
public void analyze(TaskMonitor monitor) {
- boolean analyzeEmbeddedObjects =
- OptionUtils.getBooleanOptionValue(ANALYZE_EMBEDDED_OBJECTS_OPTION_NAME,
- options,
- ANALYZE_EMBEDDED_OBJECTS_OPTION_DEFAULT);
+ boolean analyzeEmbeddedObjects = OptionUtils.getBooleanOptionValue(
+ ANALYZE_EMBEDDED_OBJECTS_OPTION_NAME, options, ANALYZE_EMBEDDED_OBJECTS_OPTION_DEFAULT);
if (analyzeEmbeddedObjects) {
ModuleToPeHelper.queryModules(program, monitor);
}
@@ -566,7 +557,7 @@ public class Pagedump extends DumpFile {
private boolean isValid(int flags) {
return (flags & 0x1) > 0;
}
-
+
private void walkPages(int page, long va, int depth, boolean lp) throws IOException {
long fileOffset = fileOffset(page);
if (fileOffset < 0) {
@@ -615,7 +606,7 @@ public class Pagedump extends DumpFile {
* Get default Pagedump
loader options. Includes
* {@link #DEBUG_DATA_PATH_OPTION_NAME} plus default {@link DumpFile} options (see
* {@link DumpFile#getDefaultOptions(DumpFileReader)}).
- *
+ *
* @param reader dump file reader
* @return default collection of Pagedump loader options
*/
diff --git a/Ghidra/Features/PDB/developer_scripts/PdbDeveloperApplyDummyScript.java b/Ghidra/Features/PDB/developer_scripts/PdbDeveloperApplyDummyScript.java
index 2b024d9a10..c7f9e3e136 100644
--- a/Ghidra/Features/PDB/developer_scripts/PdbDeveloperApplyDummyScript.java
+++ b/Ghidra/Features/PDB/developer_scripts/PdbDeveloperApplyDummyScript.java
@@ -77,7 +77,7 @@ public class PdbDeveloperApplyDummyScript extends GhidraScript {
memory.createUninitializedBlock(pdbFileName, program.getImageBase(),
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 + "...");
pdb.deserialize();
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb);
diff --git a/Ghidra/Features/PDB/developer_scripts/PdbDeveloperDumpScript.java b/Ghidra/Features/PDB/developer_scripts/PdbDeveloperDumpScript.java
index 7788966362..871a7269d7 100644
--- a/Ghidra/Features/PDB/developer_scripts/PdbDeveloperDumpScript.java
+++ b/Ghidra/Features/PDB/developer_scripts/PdbDeveloperDumpScript.java
@@ -62,7 +62,7 @@ public class PdbDeveloperDumpScript extends GhidraScript {
String message = "Processing PDB Dump of: " + pdbFileName;
monitor.setMessage(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();
FileWriter fileWriter = new FileWriter(dumpFile);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
diff --git a/Ghidra/Features/PDB/developer_scripts/PdbDeveloperDumpSetScript.java b/Ghidra/Features/PDB/developer_scripts/PdbDeveloperDumpSetScript.java
index 20ab695836..cff8dfad11 100644
--- a/Ghidra/Features/PDB/developer_scripts/PdbDeveloperDumpSetScript.java
+++ b/Ghidra/Features/PDB/developer_scripts/PdbDeveloperDumpSetScript.java
@@ -84,8 +84,8 @@ public class PdbDeveloperDumpSetScript extends GhidraScript {
for (IOEntry entry : entries) {
monitor.checkCancelled();
println("Processing PDB Dump of: " + entry.input());
- try (AbstractPdb pdb =
- PdbParser.parse(entry.input(), new PdbReaderOptions(), monitor)) {
+ File pdbFile = new File(entry.input());
+ try (AbstractPdb pdb = PdbParser.parse(pdbFile, new PdbReaderOptions(), monitor)) {
pdb.deserialize();
try (BufferedWriter bufferedWriter =
new BufferedWriter(new FileWriter(new File(entry.output())))) {
diff --git a/Ghidra/Features/PDB/developer_scripts/pdbquery/PdbFactory.java b/Ghidra/Features/PDB/developer_scripts/pdbquery/PdbFactory.java
index ab8d6a694f..083ad02ef0 100644
--- a/Ghidra/Features/PDB/developer_scripts/pdbquery/PdbFactory.java
+++ b/Ghidra/Features/PDB/developer_scripts/pdbquery/PdbFactory.java
@@ -15,6 +15,7 @@
*/
package pdbquery;
+import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
@@ -59,7 +60,8 @@ public class PdbFactory {
println(script, "Opening PDB: " + filename);
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();
pdb.deserialize();
PdbReaderMetrics metrics = pdb.getPdbReaderMetrics();
diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java
index c255bdfc95..2c34efeb76 100644
--- a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java
+++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java
@@ -178,7 +178,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
PdbLog.message(DESCRIPTION);
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 + "...");
pdb.deserialize();
DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb);
diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbParser.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbParser.java
index ffbf026f26..1e1b8e4cf8 100644
--- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbParser.java
+++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbParser.java
@@ -15,11 +15,16 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
+import java.io.File;
import java.io.IOException;
+import java.nio.file.AccessMode;
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.MsfParser;
+import ghidra.formats.gfilesystem.FileSystemService;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@@ -54,15 +59,63 @@ public class PdbParser {
* @throws PdbException on parsing issues
* @throws CancelledException upon user cancellation
*/
+ @Deprecated
public static AbstractPdb parse(String filename, PdbReaderOptions pdbOptions,
TaskMonitor monitor) throws IOException, PdbException, CancelledException {
Objects.requireNonNull(filename, "filename cannot be null");
Objects.requireNonNull(pdbOptions, "pdbOptions 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
// created below.
- Msf msf = MsfParser.parse(filename, pdbOptions, monitor);
+ Msf msf = MsfParser.parse(byteProvider, pdbOptions, monitor);
int versionNumber = AbstractPdb.deserializeVersionNumber(msf, monitor);
diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/AbstractMsf.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/AbstractMsf.java
index a45c8994e0..ceb16291ca 100644
--- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/AbstractMsf.java
+++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/AbstractMsf.java
@@ -19,6 +19,7 @@ import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Objects;
+import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@@ -134,18 +135,16 @@ public abstract class AbstractMsf implements Msf {
//==============================================================================================
/**
* Constructor
- * @param file the {@link RandomAccessFile} to process for this class
- * @param filename name of {@code #file}
+ * @param byteProvider the ByteProvider providing bytes for the MSF
* @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, String filename, TaskMonitor monitor,
- PdbReaderOptions pdbOptions)
+ public AbstractMsf(ByteProvider byteProvider, 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");
+ Objects.requireNonNull(byteProvider, "ByteProvider may not be null");
+ this.filename = byteProvider.getAbsolutePath();
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
@@ -159,7 +158,7 @@ public abstract class AbstractMsf implements Msf {
pageSize = 0x1000;
configureParameters();
// Create components.
- fileReader = new MsfFileReader(this, file);
+ fileReader = new MsfFileReader(this, byteProvider);
create();
}
@@ -320,8 +319,7 @@ public abstract class AbstractMsf implements Msf {
* @throws CancelledException upon user cancellation
*/
@Override
- public void deserialize()
- throws IOException, PdbException, CancelledException {
+ public void deserialize() throws IOException, PdbException, CancelledException {
byte[] bytes = new byte[getPageSize()];
fileReader.read(getHeaderPageNumber(), 0, getPageSize(), bytes, 0);
diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/Msf200.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/Msf200.java
index 44cf3c2fc3..5322241c67 100644
--- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/Msf200.java
+++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/Msf200.java
@@ -16,9 +16,9 @@
package ghidra.app.util.bin.format.pdb2.pdbreader.msf;
import java.io.IOException;
-import java.io.RandomAccessFile;
import java.util.Arrays;
+import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
import ghidra.util.task.TaskMonitor;
@@ -41,17 +41,15 @@ public class Msf200 extends AbstractMsf {
//==============================================================================================
/**
* Constructor
- * @param file the {@link RandomAccessFile} to process as a {@link Msf200}
- * @param filename name of {@code #file}
+ * @param byteProvider the ByteProvider providing bytes for the MSF
* @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, String filename, TaskMonitor monitor,
- PdbReaderOptions pdbOptions)
+ public Msf200(ByteProvider byteProvider, TaskMonitor monitor, PdbReaderOptions pdbOptions)
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
- * @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
* @throws IOException upon file IO seek/read issues
*/
- static boolean detected(RandomAccessFile file) throws IOException {
- byte[] bytes = new byte[IDENTIFICATION.length];
- file.seek(0);
- file.read(bytes, 0, IDENTIFICATION.length);
+ static boolean detected(ByteProvider byteProvider) throws IOException {
+ byte[] bytes = byteProvider.readBytes(0, IDENTIFICATION.length);
return Arrays.equals(bytes, IDENTIFICATION);
}
diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/Msf700.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/Msf700.java
index 8d3e745651..76ef0b7d3e 100644
--- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/Msf700.java
+++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/Msf700.java
@@ -16,9 +16,9 @@
package ghidra.app.util.bin.format.pdb2.pdbreader.msf;
import java.io.IOException;
-import java.io.RandomAccessFile;
import java.util.Arrays;
+import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
import ghidra.util.task.TaskMonitor;
@@ -40,17 +40,15 @@ public class Msf700 extends AbstractMsf {
//==============================================================================================
/**
* Constructor
- * @param file the {@link RandomAccessFile} to process as a {@link Msf700}
- * @param filename name of {@code #file}
+ * @param byteProvider the ByteProvider providing bytes for the MSF
* @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, String filename, TaskMonitor monitor,
- PdbReaderOptions pdbOptions)
+ public Msf700(ByteProvider byteProvider, TaskMonitor monitor, PdbReaderOptions pdbOptions)
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
- * @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
* @throws IOException upon file IO seek/read issues
*/
- static boolean detected(RandomAccessFile file) throws IOException {
- byte[] bytes = new byte[IDENTIFICATION.length];
- file.seek(0);
- file.read(bytes, 0, IDENTIFICATION.length);
+ static boolean detected(ByteProvider byteProvider) throws IOException {
+ byte[] bytes = byteProvider.readBytes(0, IDENTIFICATION.length);
return Arrays.equals(bytes, IDENTIFICATION);
}
diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfFileReader.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfFileReader.java
index 372e4b434e..adade2441c 100644
--- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfFileReader.java
+++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfFileReader.java
@@ -18,6 +18,8 @@ package ghidra.app.util.bin.format.pdb2.pdbreader.msf;
import java.io.IOException;
import java.io.RandomAccessFile;
+import ghidra.app.util.bin.ByteProvider;
+
/**
* This class is responsible for reading pages from a {@link RandomAccessFile} for the
* {@link Msf} class and its underlying classes.
@@ -27,7 +29,7 @@ class MsfFileReader implements AutoCloseable {
//==============================================================================================
// Internals
//==============================================================================================
- private RandomAccessFile file;
+ private ByteProvider byteProvider;
private Msf msf;
//==============================================================================================
@@ -39,8 +41,8 @@ class MsfFileReader implements AutoCloseable {
*/
@Override
public void close() throws IOException {
- if (file != null) {
- file.close();
+ if (byteProvider != null) {
+ byteProvider.close();
}
}
@@ -50,11 +52,11 @@ class MsfFileReader implements AutoCloseable {
/**
* Constructor
* @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.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
// everything beyond the offset in the file belongs to this read.
- if (Msf.floorDivisionWithLog2Divisor(offset + numToRead,
- msf.getLog2PageSize()) > msf.getNumPages()) {
+ if (Msf.floorDivisionWithLog2Divisor(offset + numToRead, msf.getLog2PageSize()) > msf
+ .getNumPages()) {
throw new IOException("Invalid MSF configuration");
}
- int numBytesRead = 0;
- file.seek(fileOffset);
- numBytesRead = file.read(bytes, bytesOffset, numToRead);
-
- if (numBytesRead != numToRead) {
- throw new IOException("Could not read required bytes from MSF");
- }
+ System.arraycopy(byteProvider.readBytes(fileOffset, numToRead), 0, bytes, bytesOffset,
+ numToRead);
}
}
diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfParser.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfParser.java
index 0c71410093..dca4ebeede 100644
--- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfParser.java
+++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfParser.java
@@ -16,9 +16,9 @@
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.ByteProvider;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbReaderOptions;
import ghidra.util.exception.CancelledException;
@@ -33,7 +33,7 @@ public class MsfParser {
/**
* Detects, creates, and returns the appropriate {@link Msf} object found for
* 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 monitor {@link TaskMonitor} used for checking cancellation
* @return derived {@link Msf} object
@@ -41,24 +41,23 @@ public class MsfParser {
* @throws PdbException if an appropriate object cannot be created
* @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 {
- Objects.requireNonNull(filename, "filename cannot be null");
+ Objects.requireNonNull(byteProvider, "byteProvider cannot be null");
Objects.requireNonNull(pdbOptions, "pdbOptions cannot be null");
Objects.requireNonNull(monitor, "monitor cannot be null");
Msf msf;
- RandomAccessFile file = new RandomAccessFile(filename, "r");
- if (Msf200.detected(file)) {
- msf = new Msf200(file, filename, monitor, pdbOptions);
+ if (Msf200.detected(byteProvider)) {
+ msf = new Msf200(byteProvider, monitor, pdbOptions);
}
- else if (Msf700.detected(file)) {
- msf = new Msf700(file, filename, monitor, pdbOptions);
+ else if (Msf700.detected(byteProvider)) {
+ msf = new Msf700(byteProvider, monitor, pdbOptions);
}
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.
- file.close();
+ byteProvider.close();
throw new PdbException("MSF format not detected");
}
msf.deserialize();
diff --git a/Ghidra/Features/PDB/src/main/java/pdb/LoadPdbTask.java b/Ghidra/Features/PDB/src/main/java/pdb/LoadPdbTask.java
index 55855951e2..5ea66e8d4f 100644
--- a/Ghidra/Features/PDB/src/main/java/pdb/LoadPdbTask.java
+++ b/Ghidra/Features/PDB/src/main/java/pdb/LoadPdbTask.java
@@ -141,12 +141,11 @@ class LoadPdbTask extends Task {
pdbApplicatorOptions.setProcessingControl(control);
- try (AbstractPdb pdb = ghidra.app.util.bin.format.pdb2.pdbreader.PdbParser.parse(
- pdbFile.getAbsolutePath(), pdbReaderOptions, monitor)) {
+ try (AbstractPdb pdb = ghidra.app.util.bin.format.pdb2.pdbreader.PdbParser.parse(pdbFile,
+ pdbReaderOptions, monitor)) {
monitor.setMessage("PDB: Parsing " + pdbFile + "...");
pdb.deserialize();
- DefaultPdbApplicator applicator =
- new DefaultPdbApplicator(pdb);
+ DefaultPdbApplicator applicator = new DefaultPdbApplicator(pdb);
applicator.applyTo(program, program.getDataTypeManager(), program.getImageBase(),
pdbApplicatorOptions, log);
diff --git a/Ghidra/Features/PDB/src/main/java/pdb/PdbUtils.java b/Ghidra/Features/PDB/src/main/java/pdb/PdbUtils.java
index 0d6548dfd2..d7ae121cb8 100644
--- a/Ghidra/Features/PDB/src/main/java/pdb/PdbUtils.java
+++ b/Ghidra/Features/PDB/src/main/java/pdb/PdbUtils.java
@@ -15,9 +15,8 @@
*/
package pdb;
-import java.util.List;
-
import java.io.*;
+import java.util.List;
import org.apache.commons.io.FilenameUtils;
import org.xml.sax.SAXException;
@@ -36,7 +35,7 @@ public class PdbUtils {
* Attempts to extract {@link PdbIdentifiers} from the specified file, which
* can be either a pdb or pdb.xml file.
*
- * + * * @param file File to examine * @param monitor {@link TaskMonitor}to allow cancel and progress * @return new {@link PdbIdentifiers} instance with GUID/ID and age info, or null if @@ -46,8 +45,7 @@ public class PdbUtils { String extension = FilenameUtils.getExtension(file.getName()).toLowerCase(); switch (extension) { case "pdb": - try (AbstractPdb pdb = - PdbParser.parse(file.getPath(), new PdbReaderOptions(), monitor)) { + try (AbstractPdb pdb = PdbParser.parse(file, new PdbReaderOptions(), monitor)) { PdbIdentifiers identifiers = pdb.getIdentifiers(); return identifiers; } @@ -87,9 +85,9 @@ public class PdbUtils { /** * Extracts a singleton file from a cab file that only has 1 file - * + * * @param cabFile Compressed cab file that only has 1 file embedded in it - * @param destFile where to write the extracted file to + * @param destFile where to write the extracted file to * @param monitor {@link TaskMonitor} to allow canceling * @return original name of the file * @throws CancelledException if cancelled diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfReaderUnitTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfReaderUnitTest.java index 79fb1b4030..f51e00a909 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfReaderUnitTest.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfReaderUnitTest.java @@ -15,17 +15,20 @@ */ package ghidra.app.util.bin.format.pdb2.pdbreader.msf; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; import java.io.*; +import java.nio.file.AccessMode; import java.util.*; import org.junit.*; 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.PdbReaderOptions; +import ghidra.formats.gfilesystem.FileSystemService; import ghidra.util.Msg; import ghidra.util.exception.AssertException; import ghidra.util.task.TaskMonitor; @@ -109,8 +112,11 @@ public class MsfReaderUnitTest extends AbstractGenericTest { //============================================================================================== @Test public void testStreamFile200Header() { - try (Msf streamFile = - MsfParser.parse(testFileName200, new PdbReaderOptions(), TaskMonitor.DUMMY)) { + File file = new File(testFileName200); + 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(); StringBuilder builder = new StringBuilder(); builder.append("NumStreams: " + numStreams + "\n"); @@ -127,8 +133,11 @@ public class MsfReaderUnitTest extends AbstractGenericTest { @Test public void testStreamFile700Header() { - try (Msf streamFile = - MsfParser.parse(testFileName700, new PdbReaderOptions(), TaskMonitor.DUMMY)) { + File file = new File(testFileName700); + 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(); StringBuilder builder = new StringBuilder(); builder.append("NumStreams: " + numStreams + "\n");