mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GT-2895 global/public syms + more
This commit is contained in:
parent
455d100a55
commit
26a36ab643
216 changed files with 1939 additions and 840 deletions
|
@ -40,6 +40,7 @@ import ghidra.program.model.address.*;
|
|||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.util.*;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.bean.opteditor.OptionsVetoException;
|
||||
import ghidra.util.classfinder.ClassSearcher;
|
||||
import ghidra.util.datastruct.PriorityQueue;
|
||||
import ghidra.util.datastruct.WeakDataStructureFactory;
|
||||
|
@ -1048,7 +1049,15 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
|
|||
|
||||
public void initializeOptions() {
|
||||
Options options = program.getOptions(Program.ANALYSIS_PROPERTIES);
|
||||
initializeOptions(options);
|
||||
|
||||
try {
|
||||
initializeOptions(options);
|
||||
}
|
||||
catch (OptionsVetoException e) {
|
||||
// This will only happen if an Analyzer author makes a mistake
|
||||
Msg.showError(this, null, "Invalid Analysis Option",
|
||||
"Invalid Analysis option set during initialization", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void initializeOptions(Options options) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package ghidra.pdb;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
@ -41,13 +42,6 @@ import ghidra.util.LittleEndianDataConverter;
|
|||
* memory.
|
||||
*/
|
||||
public class PdbByteReader {
|
||||
// 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
|
||||
// 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.
|
||||
|
||||
//==============================================================================================
|
||||
// Internals
|
||||
|
@ -328,19 +322,19 @@ public class PdbByteReader {
|
|||
* string length is determined by the first byte of data (not returned)--there is not a null
|
||||
* terminator in the source bytes. This number of bytes is extracted and converted to a
|
||||
* String and returned.
|
||||
* @param charset the {@link Charset} to be used for parsing the {@link String}.
|
||||
* @return The String containing the bytes (excluding the byte containing the length).
|
||||
* @throws PdbException upon error parsing string.
|
||||
*/
|
||||
public String parseByteLengthPrefixedString() throws PdbException {
|
||||
public String parseByteLengthPrefixedString(Charset charset) throws PdbException {
|
||||
int length = parseUnsignedByteVal();
|
||||
if (length == 0) {
|
||||
return "";
|
||||
}
|
||||
int offset = index;
|
||||
index += length;
|
||||
// TODO: See note above regarding US_ASCII.
|
||||
try {
|
||||
return new String(bytes, offset, length, StandardCharsets.US_ASCII);
|
||||
return new String(bytes, offset, length, charset);
|
||||
}
|
||||
catch (IndexOutOfBoundsException e) {
|
||||
throw new PdbException("Error parsing String: " + e.toString());
|
||||
|
@ -373,10 +367,11 @@ public class PdbByteReader {
|
|||
/**
|
||||
* Parses a null-terminated string from the PdbByteReader and returns the {@link String} (minus
|
||||
* the terminating null character). If no null, then contract not fulfilled.
|
||||
* @param charset the {@link Charset} to be used for parsing the {@link String}.
|
||||
* @return The String parsed.
|
||||
* @throws PdbException upon error parsing string.
|
||||
*/
|
||||
public String parseNullTerminatedString() throws PdbException {
|
||||
public String parseNullTerminatedString(Charset charset) throws PdbException {
|
||||
int offset = index;
|
||||
int width = 1;
|
||||
int end = findNullTerminatorIndex(width);
|
||||
|
@ -384,8 +379,7 @@ public class PdbByteReader {
|
|||
if (end == offset) {
|
||||
return "";
|
||||
}
|
||||
// TODO: See note above regarding US_ASCII.
|
||||
return new String(bytes, offset, end - offset, StandardCharsets.US_ASCII);
|
||||
return new String(bytes, offset, end - offset, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -408,10 +402,11 @@ public class PdbByteReader {
|
|||
/**
|
||||
* Parses a null-terminated wchar_t string from the PdbByteReader and returns the String (minus
|
||||
* the terminating null character). If no null, then contract not fulfilled: returns "".
|
||||
* @param charset the {@link Charset} to be used for parsing the {@link String}.
|
||||
* @return The String parsed.
|
||||
* @throws PdbException upon error parsing string.
|
||||
*/
|
||||
public String parseNullTerminatedWcharString() throws PdbException {
|
||||
public String parseNullTerminatedWcharString(Charset charset) throws PdbException {
|
||||
int offset = index;
|
||||
int width = 2;
|
||||
int end = findNullTerminatorIndex(width);
|
||||
|
@ -419,7 +414,7 @@ public class PdbByteReader {
|
|||
if (end == offset) {
|
||||
return "";
|
||||
}
|
||||
return new String(bytes, offset, end - offset, StandardCharsets.UTF_16);
|
||||
return new String(bytes, offset, end - offset, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
157
Ghidra/Features/PDB/src/main/java/ghidra/pdb/PdbMessageLog.java
Normal file
157
Ghidra/Features/PDB/src/main/java/ghidra/pdb/PdbMessageLog.java
Normal file
|
@ -0,0 +1,157 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pdb;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import generic.io.NullWriter;
|
||||
import ghidra.framework.Application;
|
||||
|
||||
/**
|
||||
* A utility class providing logging PDB parsing and analyzing data and metrics for the purposes
|
||||
* of debugging and aiding in continued research and development of this package.
|
||||
*/
|
||||
public class PdbMessageLog {
|
||||
|
||||
private static File logFile;
|
||||
private static Writer nullWriter = new NullWriter();
|
||||
private static Writer fileWriter;
|
||||
private static Writer writer = nullWriter;
|
||||
private static boolean enabled;
|
||||
|
||||
/**
|
||||
* Enable or disable future messages to be output to the appropriate log resource. This
|
||||
* 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}.
|
||||
* @see #message(String)
|
||||
* @see #message(String, Supplier...)
|
||||
*/
|
||||
public static void setEnabled(boolean enable) throws IOException {
|
||||
if (fileWriter == null) {
|
||||
fileWriter = createFileWriter();
|
||||
}
|
||||
if (nullWriter == null) {
|
||||
// Doing this here, even though statically assigned above, just in case dispose() was
|
||||
// called prematurely.
|
||||
nullWriter = new NullWriter();
|
||||
}
|
||||
writer = enable ? fileWriter : nullWriter;
|
||||
enabled = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Note: User must supply appropriate new lines.
|
||||
* @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}<{@link String}> arguments. The
|
||||
* number must match the number of {@code %s} outputs in the format string.
|
||||
* @throws IOException upon problem with {@link Writer#append(CharSequence)} or
|
||||
* {@link Writer#flush()}.
|
||||
* @see #setEnabled(boolean)
|
||||
*/
|
||||
// We know this is @SafeVarags (or SuppressWarnings("unchecked")) on potential
|
||||
// "heap pollution" because we are only using the inputs as Objects.
|
||||
@SafeVarargs
|
||||
public static void message(String format, Supplier<String>... suppliers) throws IOException {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object[] varArgs = new Object[suppliers.length];
|
||||
for (int i = 0; i < suppliers.length; i++) {
|
||||
Supplier<String> supplier = suppliers[i];
|
||||
String var = supplier.get().toString();
|
||||
varArgs[i] = var;
|
||||
}
|
||||
writer.append(String.format(format, varArgs));
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a message to the PDB log if messaging has been enable, else ignored. This method
|
||||
* uses a {@link Supplier}<{@link String}> 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.
|
||||
* Note: User must supply appropriate new lines.
|
||||
* @param supplier a {@link Supplier}<{@link String}> that supplies a {@link String} message
|
||||
* to be output.
|
||||
* @throws IOException upon problem with {@link Writer#append(CharSequence)} or
|
||||
* {@link Writer#flush()}.
|
||||
* @see #setEnabled(boolean)
|
||||
*/
|
||||
public static void message(Supplier<String> supplier) throws IOException {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
writer.append(supplier.get());
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a {@link String} message to the PDB log if messaging has been enable, else ignored.
|
||||
* Note: User must supply appropriate new lines.
|
||||
* @param message a {@link String} message to be output.
|
||||
* @throws IOException upon problem with {@link Writer#append(CharSequence)} or
|
||||
* {@link Writer#flush()}.
|
||||
* @see #setEnabled(boolean)
|
||||
*/
|
||||
public static void message(String message) throws IOException {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
writer.append(message);
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the class by closing resources.
|
||||
* @throws IOException upon problem closing a {@link Writer}.
|
||||
*/
|
||||
public static void dispose() throws IOException {
|
||||
if (fileWriter != null) {
|
||||
fileWriter.close();
|
||||
fileWriter = null;
|
||||
}
|
||||
if (nullWriter != null) {
|
||||
nullWriter.close();
|
||||
nullWriter = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link FileWriter} for the log file to which we are planning to write, and
|
||||
* deletes existing contents of the log file.
|
||||
* @return a {@link FileWriter} for the log file.
|
||||
*/
|
||||
private static Writer createFileWriter() throws IOException {
|
||||
|
||||
logFile = new File(Application.getUserSettingsDirectory(), "pdb.analyzer.log");
|
||||
if (logFile.exists()) {
|
||||
logFile.delete();
|
||||
}
|
||||
return new FileWriter(logFile);
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ import java.io.RandomAccessFile;
|
|||
|
||||
import ghidra.pdb.PdbByteReader;
|
||||
import ghidra.pdb.PdbException;
|
||||
import ghidra.pdb.pdbreader.PdbReaderOptions;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
|
@ -126,18 +127,23 @@ public abstract class AbstractMsf implements AutoCloseable {
|
|||
protected int currentFreePageMapFirstPageNumber;
|
||||
protected int numPages = 1; // Set to 1 to allow initial read
|
||||
|
||||
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.
|
||||
*/
|
||||
public AbstractMsf(RandomAccessFile file) throws IOException, PdbException {
|
||||
public AbstractMsf(RandomAccessFile file, PdbReaderOptions pdbOptions)
|
||||
throws IOException, PdbException {
|
||||
// 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.
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Arrays;
|
|||
|
||||
import ghidra.pdb.PdbByteReader;
|
||||
import ghidra.pdb.PdbException;
|
||||
import ghidra.pdb.pdbreader.PdbReaderOptions;
|
||||
|
||||
/**
|
||||
* This class is the version of {@link AbstractMsf} for Microsoft v2.00 MSF.
|
||||
|
@ -42,11 +43,13 @@ public class Msf200 extends AbstractMsf {
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
public Msf200(RandomAccessFile file) throws IOException, PdbException {
|
||||
super(file);
|
||||
public Msf200(RandomAccessFile file, PdbReaderOptions pdbOptions)
|
||||
throws IOException, PdbException {
|
||||
super(file, pdbOptions);
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Arrays;
|
|||
|
||||
import ghidra.pdb.PdbByteReader;
|
||||
import ghidra.pdb.PdbException;
|
||||
import ghidra.pdb.pdbreader.PdbReaderOptions;
|
||||
|
||||
/**
|
||||
* This class is the version of {@link AbstractMsf} for Microsoft v7.00 MSF.
|
||||
|
@ -41,11 +42,13 @@ public class Msf700 extends AbstractMsf {
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
public Msf700(RandomAccessFile file) throws IOException, PdbException {
|
||||
super(file);
|
||||
public Msf700(RandomAccessFile file, PdbReaderOptions pdbOptions)
|
||||
throws IOException, PdbException {
|
||||
super(file, pdbOptions);
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
|
|
|
@ -18,7 +18,10 @@ package ghidra.pdb.msfreader;
|
|||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import ghidra.pdb.PdbException;
|
||||
import ghidra.pdb.pdbreader.PdbReaderOptions;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
|
@ -35,21 +38,26 @@ public class MsfParser {
|
|||
* Detects, creates, and returns the appropriate {@link AbstractMsf} object found for
|
||||
* the filename given.
|
||||
* @param filename Filename of the file to process.
|
||||
* @param pdbOptions {@link PdbReaderOptions} used for processing the PDB.
|
||||
* @param monitor {@link TaskMonitor} used for checking cancellation.
|
||||
* @return Derived {@link AbstractMsf} object.
|
||||
* @throws IOException For file I/O reasons
|
||||
* @throws PdbException If an appropriate object cannot be created.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
public static AbstractMsf parse(String filename, TaskMonitor monitor)
|
||||
public static AbstractMsf parse(String filename, PdbReaderOptions pdbOptions, TaskMonitor monitor)
|
||||
throws IOException, PdbException, CancelledException {
|
||||
Validate.notNull(filename, "filename cannot be null)");
|
||||
Validate.notNull(pdbOptions, "pdbOptions cannot be null)");
|
||||
Validate.notNull(monitor, "monitor cannot be null)");
|
||||
|
||||
AbstractMsf msf;
|
||||
RandomAccessFile file = new RandomAccessFile(filename, "r");
|
||||
if (Msf200.detected(file)) {
|
||||
msf = new Msf200(file);
|
||||
msf = new Msf200(file, pdbOptions);
|
||||
}
|
||||
else if (Msf700.detected(file)) {
|
||||
msf = new Msf700(file);
|
||||
msf = new Msf700(file, pdbOptions);
|
||||
}
|
||||
else {
|
||||
// Must close the file here. In cases where MSF is created, the MSF takes
|
||||
|
|
|
@ -17,8 +17,7 @@ package ghidra.pdb.pdbreader;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
|
@ -75,7 +74,8 @@ public abstract class AbstractDatabaseInterface {
|
|||
protected List<SegmentMapDescription> segmentMapList = new ArrayList<>();
|
||||
|
||||
protected SymbolRecords symbolRecords;
|
||||
// protected GlobalSymbolInformation globalSymbolInformation;
|
||||
protected GlobalSymbolInformation globalSymbolInformation;
|
||||
protected GlobalSymbolInformation publicSymbolInformation;
|
||||
|
||||
//==============================================================================================
|
||||
// API
|
||||
|
@ -89,7 +89,8 @@ public abstract class AbstractDatabaseInterface {
|
|||
Validate.notNull(pdb, "pdb cannot be null)");
|
||||
this.pdb = pdb;
|
||||
this.streamNumber = streamNumber;
|
||||
// globalSymbolInformation = new GlobalSymbolInformation(pdb);
|
||||
globalSymbolInformation = new GlobalSymbolInformation(pdb);
|
||||
publicSymbolInformation = new GlobalSymbolInformation(pdb);
|
||||
symbolRecords = new SymbolRecords(pdb);
|
||||
}
|
||||
|
||||
|
@ -174,20 +175,22 @@ public abstract class AbstractDatabaseInterface {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the list of regular {@link AbstractMsSymbol} symbols.
|
||||
* @return Regular {@link AbstractMsSymbol} symbols.
|
||||
* Returns the list of regular symbols.
|
||||
* @return {@link Map}<{@link Long},{@link AbstractMsSymbol}> of buffer offsets to
|
||||
* symbols.
|
||||
*/
|
||||
public List<AbstractMsSymbol> getSymbolsList() {
|
||||
return symbolRecords.getSymbolsList();
|
||||
public Map<Long, AbstractMsSymbol> getSymbolMap() {
|
||||
return symbolRecords.getSymbolMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of {@link AbstractMsSymbol} for the module specified.
|
||||
* 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 AbstractMsSymbol} symbols in the specified module.
|
||||
* @return {@link Map}<{@link Long},{@link AbstractMsSymbol}> of buffer offsets to
|
||||
* symbols for the specified module.
|
||||
*/
|
||||
public List<AbstractMsSymbol> getModuleSymbolLists(int moduleNumber) {
|
||||
return symbolRecords.getModuleSymbolLists(moduleNumber);
|
||||
public Map<Long, AbstractMsSymbol> getModuleSymbolMap(int moduleNumber) {
|
||||
return symbolRecords.getModuleSymbolMap(moduleNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,13 +217,22 @@ public abstract class AbstractDatabaseInterface {
|
|||
return symbolRecords;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Returns {@link GlobalSymbolInformation} component for this Database Interface.
|
||||
// * @return {@link GlobalSymbolInformation} component.
|
||||
// */
|
||||
// public GlobalSymbolInformation getGlobalSymbolInformation() {
|
||||
// return globalSymbolInformation;
|
||||
// }
|
||||
/**
|
||||
* Returns {@link GlobalSymbolInformation} component for this Database Interface.
|
||||
* @return {@link GlobalSymbolInformation} component.
|
||||
*/
|
||||
public GlobalSymbolInformation getGlobalSymbolInformation() {
|
||||
return globalSymbolInformation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Public Symbol Information (of type {@link GlobalSymbolInformation}) component for
|
||||
* this Database Interface.
|
||||
* @return Public Symbol Information component.
|
||||
*/
|
||||
public GlobalSymbolInformation getPublicSymbolInformation() {
|
||||
return publicSymbolInformation;
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
// Package-Protected Internals
|
||||
|
@ -283,11 +295,13 @@ public abstract class AbstractDatabaseInterface {
|
|||
/**
|
||||
* Deserializes/Processes the appropriate {@link AbstractModuleInformation} flavor.
|
||||
* @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 field.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
protected abstract void processModuleInformation(PdbByteReader reader, boolean skip)
|
||||
throws PdbException;
|
||||
protected abstract void processModuleInformation(PdbByteReader reader, TaskMonitor monitor,
|
||||
boolean skip) throws PdbException, CancelledException;
|
||||
|
||||
/**
|
||||
* Dumps the Header. This method is for debugging only.
|
||||
|
@ -309,11 +323,13 @@ public abstract class AbstractDatabaseInterface {
|
|||
/**
|
||||
* Deserializes/Processes the SectionContributions component.
|
||||
* @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 not enough data left to parse.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
protected void processSectionContributions(PdbByteReader reader, boolean skip)
|
||||
throws PdbException {
|
||||
protected void processSectionContributions(PdbByteReader reader, TaskMonitor monitor,
|
||||
boolean skip) throws PdbException, CancelledException {
|
||||
if (lengthSectionContributionSubstream == 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -328,6 +344,7 @@ public abstract class AbstractDatabaseInterface {
|
|||
if (version == SCV1400) {
|
||||
//long version2 = substreamReader.parseUnsignedIntVal();
|
||||
while (substreamReader.hasMore()) {
|
||||
monitor.checkCanceled();
|
||||
AbstractSectionContribution sectionContribution = new SectionContribution1400();
|
||||
sectionContribution.deserialize(substreamReader);
|
||||
sectionContributionList.add(sectionContribution);
|
||||
|
@ -336,6 +353,7 @@ public abstract class AbstractDatabaseInterface {
|
|||
else if (version == SCV600) {
|
||||
//long version2 = substreamReader.parseUnsignedIntVal();
|
||||
while (substreamReader.hasMore()) {
|
||||
monitor.checkCanceled();
|
||||
AbstractSectionContribution sectionContribution = new SectionContribution600();
|
||||
sectionContribution.deserialize(substreamReader);
|
||||
sectionContributionList.add(sectionContribution);
|
||||
|
@ -347,6 +365,7 @@ public abstract class AbstractDatabaseInterface {
|
|||
// be the override method for DatabaseInformationNew.
|
||||
else {
|
||||
while (substreamReader.hasMore()) {
|
||||
monitor.checkCanceled();
|
||||
AbstractSectionContribution sectionContribution = new SectionContribution400();
|
||||
sectionContribution.deserialize(substreamReader);
|
||||
sectionContributionList.add(sectionContribution);
|
||||
|
@ -354,17 +373,20 @@ public abstract class AbstractDatabaseInterface {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: unused value numSegLog?
|
||||
// Note: this is SegmentMap or SectionMap (API structs are segment; API code is Section)
|
||||
// Suppress "unused" for numSegLog
|
||||
/**
|
||||
* Deserializes/Processes the {@link SegmentMapDescription}.
|
||||
* @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 not enough data left to parse.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
// TODO: unused value numSegLog?
|
||||
// Note: this is SegmentMap or SectionMap (API structs are segment; API code is Section)
|
||||
// Suppress "unused" for numSegLog
|
||||
@SuppressWarnings("unused")
|
||||
protected void processSegmentMap(PdbByteReader reader, boolean skip) throws PdbException {
|
||||
protected void processSegmentMap(PdbByteReader reader, TaskMonitor monitor, boolean skip)
|
||||
throws PdbException, CancelledException {
|
||||
if (lengthSectionMap == 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -379,6 +401,7 @@ public abstract class AbstractDatabaseInterface {
|
|||
int numSegLog = substreamReader.parseUnsignedShortVal();
|
||||
// Process records
|
||||
while (substreamReader.hasMore()) {
|
||||
monitor.checkCanceled();
|
||||
SegmentMapDescription segment = new SegmentMapDescription();
|
||||
segment.deserialize(substreamReader);
|
||||
segmentMapList.add(segment);
|
||||
|
@ -391,11 +414,14 @@ public abstract class AbstractDatabaseInterface {
|
|||
/**
|
||||
* Deserializes/Processes the FileInformation.
|
||||
* @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 filename.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
@SuppressWarnings("unused") // pmod is not used below
|
||||
protected void processFileInformation(PdbByteReader reader, boolean skip) throws PdbException {
|
||||
protected void processFileInformation(PdbByteReader reader, TaskMonitor monitor, boolean skip)
|
||||
throws PdbException, CancelledException {
|
||||
if (lengthFileInformation == 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -412,6 +438,7 @@ public abstract class AbstractDatabaseInterface {
|
|||
int numRefs = substreamReader.parseUnsignedShortVal();
|
||||
int x = 0;
|
||||
for (int i = 0; i < numInformationModules; i++) {
|
||||
monitor.checkCanceled();
|
||||
int refIndex = substreamReader.parseUnsignedShortVal();
|
||||
AbstractModuleInformation module = moduleInformationList.get(i);
|
||||
int num = module.getNumFilesContributing();
|
||||
|
@ -421,11 +448,13 @@ public abstract class AbstractDatabaseInterface {
|
|||
x += num;
|
||||
}
|
||||
for (int i = 0; i < numInformationModules; i++) {
|
||||
monitor.checkCanceled();
|
||||
// TODO: Is there anything we can do with this?
|
||||
int pmod = substreamReader.parseUnsignedShortVal();
|
||||
}
|
||||
int count = 0;
|
||||
for (int i = 0; i < numInformationModules; i++) {
|
||||
monitor.checkCanceled();
|
||||
AbstractModuleInformation module = moduleInformationList.get(i);
|
||||
int num = module.getNumFilesContributing();
|
||||
for (int j = 0; j < num; j++) {
|
||||
|
@ -443,6 +472,7 @@ public abstract class AbstractDatabaseInterface {
|
|||
|
||||
//System.out.println(fileNameReader.dump());
|
||||
for (int i = 0; i < numInformationModules; i++) {
|
||||
monitor.checkCanceled();
|
||||
AbstractModuleInformation module = moduleInformationList.get(i);
|
||||
List<Integer> offsetsArray = module.getOffsetsArray();
|
||||
List<String> filenameArray = module.getFilenamesArray();
|
||||
|
@ -450,7 +480,8 @@ public abstract class AbstractDatabaseInterface {
|
|||
int offset = offsetsArray.get(j);
|
||||
//System.out.println(String.format("%04x", offset));
|
||||
fileNameReader.setIndex(offset);
|
||||
String filename = fileNameReader.parseNullTerminatedString();
|
||||
String filename = fileNameReader.parseNullTerminatedString(
|
||||
pdb.getPdbReaderOptions().getOneByteCharset());
|
||||
filenameArray.add(filename);
|
||||
//System.out.println(filename);
|
||||
}
|
||||
|
@ -483,8 +514,10 @@ public abstract class AbstractDatabaseInterface {
|
|||
*/
|
||||
protected void dumpAdditionalSubstreams(Writer writer) throws IOException {
|
||||
symbolRecords.dump(writer);
|
||||
// writer.write("\n");
|
||||
// globalSymbolInformation.dump(writer);
|
||||
writer.write("\n");
|
||||
globalSymbolInformation.dump(writer);
|
||||
writer.write("\n");
|
||||
publicSymbolInformation.dump(writer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -54,6 +54,8 @@ public abstract class AbstractPdb implements AutoCloseable {
|
|||
//==============================================================================================
|
||||
protected AbstractMsf msf;
|
||||
|
||||
protected PdbReaderOptions pdbOptions;
|
||||
|
||||
// Items below begin in Pdb200
|
||||
protected int versionNumber = 0;
|
||||
protected int signature = 0;
|
||||
|
@ -104,6 +106,14 @@ public abstract class AbstractPdb implements AutoCloseable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link PdbReaderOptions} for this PDB.
|
||||
* @return the {@link PdbReaderOptions} for this PDB.
|
||||
*/
|
||||
public PdbReaderOptions getPdbReaderOptions() {
|
||||
return pdbOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the main {@link PdbIdentifiers} found in the PDB Directory.
|
||||
* @return {@link PdbIdentifiers} of information.
|
||||
|
@ -565,11 +575,13 @@ public abstract class AbstractPdb implements AutoCloseable {
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
AbstractPdb(AbstractMsf msf) throws IOException, PdbException {
|
||||
AbstractPdb(AbstractMsf msf, PdbReaderOptions pdbOptions) throws IOException, PdbException {
|
||||
this.msf = msf;
|
||||
this.pdbOptions = pdbOptions;
|
||||
strings = new ArrayList<>();
|
||||
parameters = new ArrayList<>();
|
||||
nameTable = new NameTable(this);
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.pdb.pdbreader;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import ghidra.pdb.*;
|
||||
|
||||
/**
|
||||
|
@ -26,11 +28,22 @@ public abstract class AbstractString extends AbstractParsableItem {
|
|||
//==============================================================================================
|
||||
// Internals
|
||||
//==============================================================================================
|
||||
protected AbstractPdb pdb;
|
||||
protected String string = "";
|
||||
|
||||
//==============================================================================================
|
||||
// API
|
||||
//==============================================================================================
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param pdb {@link AbstractPdb} to which this type belongs.
|
||||
*/
|
||||
public AbstractString(AbstractPdb pdb) {
|
||||
Validate.notNull(pdb, "pdb cannot be null)");
|
||||
this.pdb = pdb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string value.
|
||||
* @return {@link String} value. Defaults to empty String if not parsed.
|
||||
|
|
|
@ -163,7 +163,7 @@ public abstract class AbstractTypeProgramInterface {
|
|||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
|
||||
|
||||
deserializeHeader(reader);
|
||||
deserializeTypeRecords(reader);
|
||||
deserializeTypeRecords(reader, monitor);
|
||||
|
||||
return versionNumber;
|
||||
}
|
||||
|
@ -252,14 +252,18 @@ public abstract class AbstractTypeProgramInterface {
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
protected void deserializeTypeRecords(PdbByteReader reader) throws PdbException {
|
||||
protected void deserializeTypeRecords(PdbByteReader reader, TaskMonitor monitor)
|
||||
throws PdbException, CancelledException {
|
||||
int recordLength;
|
||||
int recordNumber = typeIndexMin;
|
||||
TypeParser parser = pdb.getTypeParser();
|
||||
//System.out.println(reader.dump());
|
||||
while (reader.hasMore()) {
|
||||
monitor.checkCanceled();
|
||||
// // DO NOT REMOVE
|
||||
// int index = reader.getIndex();
|
||||
// //System.out.println("index: " + index);
|
||||
|
|
|
@ -59,10 +59,10 @@ class DatabaseInterface extends AbstractDatabaseInterface {
|
|||
@Override
|
||||
protected void deserializeInternalSubstreams(PdbByteReader reader, TaskMonitor monitor)
|
||||
throws PdbException, CancelledException {
|
||||
processModuleInformation(reader, false);
|
||||
processSectionContributions(reader, false);
|
||||
processSegmentMap(reader, false);
|
||||
processFileInformation(reader, false);
|
||||
processModuleInformation(reader, monitor, false);
|
||||
processSectionContributions(reader, monitor, false);
|
||||
processSegmentMap(reader, monitor, false);
|
||||
processFileInformation(reader, monitor, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -70,15 +70,18 @@ class DatabaseInterface extends AbstractDatabaseInterface {
|
|||
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.
|
||||
// globalSymbolInformation.deserialize(monitor);
|
||||
symbolRecords.deserialize(monitor);
|
||||
globalSymbolInformation.deserialize(
|
||||
pdb.databaseInterface.getGlobalSymbolsHashMaybeStreamNumber(), false, monitor);
|
||||
publicSymbolInformation.deserialize(
|
||||
pdb.databaseInterface.getPublicStaticSymbolsHashMaybeStreamNumber(), true, monitor);
|
||||
//TODO: SectionContributions has information about code sections and refers to
|
||||
// debug streams for each.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processModuleInformation(PdbByteReader reader, boolean skip)
|
||||
throws PdbException {
|
||||
protected void processModuleInformation(PdbByteReader reader, TaskMonitor monitor, boolean skip)
|
||||
throws PdbException, CancelledException {
|
||||
if (lengthModuleInformationSubstream == 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -89,7 +92,8 @@ class DatabaseInterface extends AbstractDatabaseInterface {
|
|||
PdbByteReader substreamReader =
|
||||
reader.getSubPdbByteReader(lengthModuleInformationSubstream);
|
||||
while (substreamReader.hasMore()) {
|
||||
AbstractModuleInformation moduleInformation = new ModuleInformation500();
|
||||
monitor.checkCanceled();
|
||||
AbstractModuleInformation moduleInformation = new ModuleInformation500(pdb);
|
||||
moduleInformation.deserialize(substreamReader);
|
||||
moduleInformationList.add(moduleInformation);
|
||||
}
|
||||
|
|
|
@ -127,13 +127,13 @@ public class DatabaseInterfaceNew extends AbstractDatabaseInterface {
|
|||
@Override
|
||||
protected void deserializeInternalSubstreams(PdbByteReader reader, TaskMonitor monitor)
|
||||
throws PdbException, CancelledException {
|
||||
processModuleInformation(reader, false);
|
||||
processSectionContributions(reader, false);
|
||||
processSegmentMap(reader, false);
|
||||
processFileInformation(reader, false);
|
||||
processModuleInformation(reader, monitor, false);
|
||||
processSectionContributions(reader, monitor, false);
|
||||
processSegmentMap(reader, monitor, false);
|
||||
processFileInformation(reader, monitor, false);
|
||||
processTypeServerMap(reader, false);
|
||||
//Note that the next two are in reverse order from their length fields in the header.
|
||||
processEditAndContinueInformation(reader, false);
|
||||
processEditAndContinueInformation(reader, monitor, false);
|
||||
//processDebugHeader(reader, false);
|
||||
debugData.deserializeHeader(reader, monitor);
|
||||
}
|
||||
|
@ -143,16 +143,19 @@ public class DatabaseInterfaceNew extends AbstractDatabaseInterface {
|
|||
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.
|
||||
// globalSymbolInformation.deserialize(monitor);
|
||||
symbolRecords.deserialize(monitor);
|
||||
globalSymbolInformation.deserialize(
|
||||
pdb.databaseInterface.getGlobalSymbolsHashMaybeStreamNumber(), false, monitor);
|
||||
publicSymbolInformation.deserialize(
|
||||
pdb.databaseInterface.getPublicStaticSymbolsHashMaybeStreamNumber(), true, monitor);
|
||||
//TODO: Process further information that might be found from ProcessTypeServerMap,
|
||||
// and processEditAndContinueInformation.
|
||||
debugData.deserialize(monitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processModuleInformation(PdbByteReader reader, boolean skip)
|
||||
throws PdbException {
|
||||
protected void processModuleInformation(PdbByteReader reader, TaskMonitor monitor, boolean skip)
|
||||
throws PdbException, CancelledException {
|
||||
if (lengthModuleInformationSubstream == 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -163,7 +166,8 @@ public class DatabaseInterfaceNew extends AbstractDatabaseInterface {
|
|||
PdbByteReader substreamReader =
|
||||
reader.getSubPdbByteReader(lengthModuleInformationSubstream);
|
||||
while (substreamReader.hasMore()) {
|
||||
AbstractModuleInformation moduleInformation = new ModuleInformation600();
|
||||
monitor.checkCanceled();
|
||||
AbstractModuleInformation moduleInformation = new ModuleInformation600(pdb);
|
||||
moduleInformation.deserialize(substreamReader);
|
||||
moduleInformationList.add(moduleInformation);
|
||||
}
|
||||
|
@ -263,12 +267,14 @@ public class DatabaseInterfaceNew extends AbstractDatabaseInterface {
|
|||
/**
|
||||
* 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.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
@SuppressWarnings("unused") // hashVal
|
||||
protected void processEditAndContinueInformation(PdbByteReader reader, boolean skip)
|
||||
throws PdbException {
|
||||
protected void processEditAndContinueInformation(PdbByteReader reader, TaskMonitor monitor,
|
||||
boolean skip) throws PdbException, CancelledException {
|
||||
if (lengthEditAndContinueSubstream == 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -301,9 +307,11 @@ public class DatabaseInterfaceNew extends AbstractDatabaseInterface {
|
|||
int count = tableSize;
|
||||
int realEntryCount = 0;
|
||||
while (--count >= 0) {
|
||||
monitor.checkCanceled();
|
||||
int offset = substreamReader.parseInt();
|
||||
bufferReader.setIndex(offset);
|
||||
String name = bufferReader.parseNullTerminatedString();
|
||||
String name = bufferReader.parseNullTerminatedString(
|
||||
pdb.getPdbReaderOptions().getOneByteCharset());
|
||||
//if (name != null) {
|
||||
if (name.length() != 0) {
|
||||
realEntryCount++;
|
||||
|
|
|
@ -17,8 +17,7 @@ package ghidra.pdb.pdbreader;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.pdb.PdbByteReader;
|
||||
import ghidra.pdb.PdbException;
|
||||
import ghidra.pdb.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
|
@ -38,6 +37,9 @@ public class DatabaseInterfaceParser {
|
|||
public static final int DBI70_ID = 19990903; // 0x01310977
|
||||
public static final int DBI110_ID = 20091201; // 0x01329141
|
||||
|
||||
//==============================================================================================
|
||||
private PdbByteReader debugReader;
|
||||
|
||||
//==============================================================================================
|
||||
// API
|
||||
//==============================================================================================
|
||||
|
@ -61,6 +63,11 @@ public class DatabaseInterfaceParser {
|
|||
if (reader.getLimit() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// In support of debug.
|
||||
debugReader = reader;
|
||||
PdbMessageLog.message(this::debug1);
|
||||
|
||||
int headerSignature = reader.parseInt();
|
||||
int versionNumber = reader.parseInt();
|
||||
|
||||
|
@ -84,6 +91,11 @@ public class DatabaseInterfaceParser {
|
|||
return databaseInterface;
|
||||
}
|
||||
|
||||
private String debug1() {
|
||||
return "DatabaseInterfaceParser data on stream " + getStreamNumber() + ":\n" +
|
||||
debugReader.dump() + "\n";
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
// Internal Data Methods
|
||||
//==============================================================================================
|
||||
|
@ -93,7 +105,6 @@ public class DatabaseInterfaceParser {
|
|||
*/
|
||||
protected int getStreamNumber() {
|
||||
return DATABASE_INTERFACE_STREAM_NUMBER;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -189,6 +189,7 @@ public class DebugData {
|
|||
// TODO: check implementation for completeness.
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum, monitor);
|
||||
while (reader.hasMore()) {
|
||||
monitor.checkCanceled();
|
||||
FramePointerOmissionRecord framePointerOmissionRecord =
|
||||
new FramePointerOmissionRecord();
|
||||
framePointerOmissionRecord.parse(reader);
|
||||
|
@ -200,7 +201,8 @@ public class DebugData {
|
|||
throws PdbException, CancelledException, IOException {
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum, monitor);
|
||||
while (reader.hasMore()) {
|
||||
ImageSectionHeader imageSectionHeader = new ImageSectionHeader();
|
||||
monitor.checkCanceled();
|
||||
ImageSectionHeader imageSectionHeader = new ImageSectionHeader(pdb);
|
||||
imageSectionHeader.parse(reader);
|
||||
imageSectionHeaders.add(imageSectionHeader);
|
||||
}
|
||||
|
@ -257,6 +259,7 @@ public class DebugData {
|
|||
reader.setIndex((int) headerLength);
|
||||
//System.out.println(reader.dump());
|
||||
while (reader.hasMore()) {
|
||||
monitor.checkCanceled();
|
||||
ImageFunctionEntry entry = new ImageFunctionEntry();
|
||||
entry.deserialize(reader);
|
||||
pData.add(entry);
|
||||
|
|
|
@ -17,9 +17,11 @@ package ghidra.pdb.pdbreader;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.pdb.PdbByteReader;
|
||||
import ghidra.pdb.PdbException;
|
||||
import ghidra.pdb.pdbreader.symbol.AbstractMsSymbol;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
|
@ -32,17 +34,43 @@ import ghidra.util.task.TaskMonitor;
|
|||
*/
|
||||
public class GlobalSymbolInformation {
|
||||
|
||||
public static final int HEADER_SIGNATURE = 0xffffffff;
|
||||
|
||||
public static final int GSI70 = 0xeffe0000 + 19990810; // 0xf12f091a = -248575718
|
||||
|
||||
//==============================================================================================
|
||||
// Internals
|
||||
//==============================================================================================
|
||||
protected AbstractPdb pdb;
|
||||
protected int lengthHashRecordsBitMap;
|
||||
protected int numHashRecords;
|
||||
protected int numExtraBytes;
|
||||
protected int hashRecordsBitMapLength;
|
||||
|
||||
private long headerSignature;
|
||||
private long versionNumber;
|
||||
private int lengthHashRecords;
|
||||
private int lengthBuckets;
|
||||
private int headerSignature;
|
||||
private int versionNumber;
|
||||
private int hashRecordsLength;
|
||||
private int bucketsLength;
|
||||
|
||||
//These belong to public symbols
|
||||
private int symbolHashLength;
|
||||
private int addressMapLength;
|
||||
private int numThunks; // unsigned int
|
||||
private int thunkSize;
|
||||
private int iSectionThunkTable; // unsigned short
|
||||
private int offsetThunkTable;
|
||||
private int numSections; // unsigned int
|
||||
private int thunkMapLength;
|
||||
private int thunkTableLength;
|
||||
private int sectionMapLength;
|
||||
|
||||
// These are read from "buckets."
|
||||
List<Integer> hashBucketOffsets = new ArrayList<>();
|
||||
Set<SymbolHashRecord> hashRecords = new TreeSet<>();
|
||||
List<Integer> symbolOffsets = new ArrayList<>();
|
||||
Map<Integer, Integer> mapTableOffsetToTargetOffset = new HashMap<>();
|
||||
Map<Integer, Integer> sectionNumToAbsoluteOffset = new HashMap<>();
|
||||
|
||||
List<AbstractMsSymbol> symbols = new ArrayList<>();
|
||||
|
||||
//==============================================================================================
|
||||
// API
|
||||
|
@ -55,137 +83,126 @@ public class GlobalSymbolInformation {
|
|||
pdb = pdbIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public int getThunkTableOffset() {
|
||||
return offsetThunkTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public int getThunkTableLength() {
|
||||
return thunkTableLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of sections recorded for the program.
|
||||
* @return the number of sections.
|
||||
*/
|
||||
public int getNumSections() {
|
||||
return numSections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of symbols for this {@link GlobalSymbolInformation}.
|
||||
* @return the symbols.
|
||||
*/
|
||||
public List<AbstractMsSymbol> getSymbols() {
|
||||
return symbols;
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
// Package-Protected Internals
|
||||
//==============================================================================================
|
||||
// NOTE 20190603: Plan is to refactor this class into two classes plus one abstract class:
|
||||
// Global and Public to be separated (see boolean pub below for now), but need to investigate
|
||||
// how individual modules might make use of this class or split class before making the final
|
||||
// decision... so in other words, this is still under investigation for this as of the time
|
||||
// of this submission for review, but need to move forward with what I currently have for now.
|
||||
/**
|
||||
* Deserialize the {@link GlobalSymbolInformation} from the appropriate stream in the Pdb.
|
||||
* @param streamNumber the stream number containing the information to deserialize.
|
||||
* @param pub {@code true} if Public symbol information vs. Global symbol 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.
|
||||
*/
|
||||
@SuppressWarnings("unused") // for buf1Reader and buf2Reader--still under investigation.
|
||||
void deserialize(TaskMonitor monitor) throws IOException, PdbException, CancelledException {
|
||||
void deserialize(int streamNumber, boolean pub, TaskMonitor monitor)
|
||||
throws IOException, PdbException, CancelledException {
|
||||
if (pdb.minimalDebugInfo) {
|
||||
//Maybe 0x200 for some and 0x201 for others? 0x200 works for cn3.pdb
|
||||
lengthHashRecordsBitMap = 0x200;
|
||||
numHashRecords = 0x1000;
|
||||
hashRecordsBitMapLength = 0x8000;
|
||||
numExtraBytes = 0; // I believe;
|
||||
numHashRecords = 0x3ffff;
|
||||
}
|
||||
else {
|
||||
lengthHashRecordsBitMap = 0x8000;
|
||||
numHashRecords = 0x3ffff; //0x40000?
|
||||
hashRecordsBitMapLength = 0x200;
|
||||
numExtraBytes = 4;
|
||||
numHashRecords = 0x1000;
|
||||
}
|
||||
int streamNumber = pdb.databaseInterface.getGlobalSymbolsHashMaybeStreamNumber();
|
||||
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
|
||||
//System.out.println(reader.dump());
|
||||
|
||||
deserializeHeader(reader);
|
||||
if (pub) {
|
||||
deserializePubHeader(reader);
|
||||
|
||||
PdbByteReader buf1Reader = reader.getSubPdbByteReader(lengthHashRecords);
|
||||
//System.out.println(buf1Reader.dump());
|
||||
PdbByteReader buf2Reader = reader.getSubPdbByteReader(lengthBuckets);
|
||||
// junkCheck(buf1, buf2); // TODO: this contains experiments if we want to do more.
|
||||
//System.out.println(buf2Reader.dump());
|
||||
if (reader.hasMore()) {
|
||||
assert false;
|
||||
PdbByteReader hashReader = reader.getSubPdbByteReader(symbolHashLength);
|
||||
deserializeHashTable(hashReader, monitor);
|
||||
|
||||
PdbByteReader addressMapReader = reader.getSubPdbByteReader(addressMapLength);
|
||||
deserializeAddressMap(addressMapReader, monitor);
|
||||
|
||||
PdbByteReader thunkMapReader = reader.getSubPdbByteReader(thunkMapLength);
|
||||
deserializeThunkMap(thunkMapReader, monitor);
|
||||
|
||||
/**
|
||||
* See note in {@link #deserializePubHeader(PdbByteReader)} regarding spurious data
|
||||
* for numSections. Because of this, we will assume the rest of the data in the
|
||||
* reader belongs to the section map and set the appropriate variable values here.
|
||||
*/
|
||||
sectionMapLength = reader.numRemaining();
|
||||
if (sectionMapLength % 8 != 0) {
|
||||
throw new PdbException("sectionMapLength size not multiple of 8");
|
||||
}
|
||||
numSections = sectionMapLength / 8;
|
||||
PdbByteReader sectionMapReader = reader.getSubPdbByteReader(sectionMapLength);
|
||||
deserializeSectionMap(sectionMapReader, monitor);
|
||||
}
|
||||
else {
|
||||
deserializeHashTable(reader, monitor);
|
||||
}
|
||||
|
||||
//parser.deserializeSymbolRecords(reader);
|
||||
//TODO: left off here 20180717
|
||||
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
//==============================================================================================
|
||||
//==============================================================================================
|
||||
// TODO: this contains some experiments for investigating hash reconstruction. Not sure
|
||||
// that we need the GlobalSymbolInformation hash table. The GlobalSymbolInformation is
|
||||
// supposed to be a "search" mechanism for searching based symbol names.
|
||||
// The PublicSymbolInformation is for searching (hash) based upon addresses. Don't need
|
||||
// it either, I think.
|
||||
@SuppressWarnings("unused")
|
||||
private void junkCheck(byte[] bytes1, byte[] bytes2) throws PdbException {
|
||||
System.out.println("length1: " + bytes1.length);
|
||||
System.out.println("length2: " + bytes2.length);
|
||||
|
||||
//Count bits.
|
||||
int count = 0;
|
||||
byte x;
|
||||
for (int i = 0; i < 0x200; i++) {
|
||||
x = bytes2[i];
|
||||
count += (x & 0x01);
|
||||
x >>= 1;
|
||||
count += (x & 0x01);
|
||||
x >>= 1;
|
||||
count += (x & 0x01);
|
||||
x >>= 1;
|
||||
count += (x & 0x01);
|
||||
x >>= 1;
|
||||
count += (x & 0x01);
|
||||
x >>= 1;
|
||||
count += (x & 0x01);
|
||||
x >>= 1;
|
||||
count += (x & 0x01);
|
||||
x >>= 1;
|
||||
count += (x & 0x01);
|
||||
}
|
||||
System.out.println("Bit count: " + count);
|
||||
|
||||
// Bits are used to expand the rest of bytes2. I can see from cn3.cpp, that
|
||||
// there are 1530 bits set and this is exactly how many records remain beyond
|
||||
// 0x200 offset. See gsi.cpp: ExpandBuckets as called by readHash(), which is the
|
||||
// high level mechanism for reconstructing the hash table.
|
||||
|
||||
//Check values.
|
||||
PdbByteReader reader = new PdbByteReader(bytes2);
|
||||
reader.parseBytes(0x200);
|
||||
int minx1 = Integer.MAX_VALUE;
|
||||
int maxx1 = Integer.MIN_VALUE;
|
||||
while (reader.hasMore()) {
|
||||
int x1 = reader.parseInt();
|
||||
minx1 = Math.min(minx1, x1);
|
||||
maxx1 = Math.max(maxx1, x1);
|
||||
}
|
||||
if (maxx1 > bytes1.length) {
|
||||
// Adjust (/12 then *8) offsets seen like x1 in loop above. These are then offsets
|
||||
// into the bytes1. Then a mechanisms like fixHashiIn() from gsi.cpp would need to
|
||||
// be done to create full hash table. Also the "hash" routine (see gsi and misc.h)
|
||||
// would need to be implemented to hash the "item" (as I'll call it) coming in...
|
||||
// see methods like gsi.cpp: getEnumSyms(), which utilizes the hash table and hash
|
||||
// alg. IMPORTANT: I do not know if we "have to have this." Can we get all we
|
||||
// need without this hash mechanism?
|
||||
}
|
||||
System.out.println("minx1: " + minx1);
|
||||
System.out.println("maxx1: " + maxx1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize the header of the {@link GlobalSymbolInformation} from the appropriate stream
|
||||
* in the PDB.
|
||||
* @param reader {@link PdbByteReader} containing the data buffer to process.
|
||||
* @throws PdbException Upon not enough data left to parse.
|
||||
*/
|
||||
void deserializeHeader(PdbByteReader reader) throws PdbException {
|
||||
headerSignature = reader.parseUnsignedIntVal();
|
||||
versionNumber = reader.parseUnsignedIntVal();
|
||||
lengthHashRecords = reader.parseInt();
|
||||
lengthBuckets = reader.parseInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*/
|
||||
protected void dump(Writer writer) throws IOException {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("GlobalSymbolInformation-------------------------------------\n");
|
||||
dumpHeader(builder);
|
||||
//builder.append(": " + );
|
||||
builder.append("\nEnd GlobalSymbolInformation---------------------------------\n");
|
||||
writer.write(builder.toString());
|
||||
// Organize the information
|
||||
generateSymbolsList(monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -193,17 +210,339 @@ public class GlobalSymbolInformation {
|
|||
* @param builder {@link StringBuilder} to which to dump the information.
|
||||
*/
|
||||
protected void dumpHeader(StringBuilder builder) {
|
||||
// System.out.println(String.format("GSI: %08x %08x %d %d", headerSignature, versionNumber,
|
||||
// lengthHashRecords, lengthBuckets));
|
||||
builder.append("GlobalSymbolInformationHeader-------------------------------\n");
|
||||
builder.append("headerSignature: ");
|
||||
builder.append(headerSignature);
|
||||
builder.append("\nversionNumber: ");
|
||||
builder.append(versionNumber);
|
||||
builder.append("\nlengthHashRecords: ");
|
||||
builder.append(lengthHashRecords);
|
||||
builder.append(hashRecordsLength);
|
||||
builder.append("\nlengthBuckets: ");
|
||||
builder.append(lengthBuckets);
|
||||
builder.append(bucketsLength);
|
||||
builder.append("\n End GlobalSymbolInformationHeader--------------------------\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug method for dumping hash records from this {@link GlobalSymbolInformation}.
|
||||
* @param builder {@link StringBuilder} to which to dump the information.
|
||||
*/
|
||||
void dumpHashRecords(StringBuilder builder) {
|
||||
builder.append("HashRecords-------------------------------------------------\n");
|
||||
builder.append("numHashRecords: " + hashRecords.size());
|
||||
for (SymbolHashRecord record : hashRecords) {
|
||||
builder.append(
|
||||
String.format("0X%08X 0X%04X", record.getOffset(), record.getReferenceCount()));
|
||||
}
|
||||
builder.append("\n End HashRecords--------------------------------------------\n");
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
// 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.
|
||||
*/
|
||||
private void deserializeAddressMap(PdbByteReader reader, TaskMonitor monitor)
|
||||
throws PdbException, CancelledException {
|
||||
while (reader.hasMore()) {
|
||||
monitor.checkCanceled();
|
||||
symbolOffsets.add(reader.parseInt());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
private void deserializeThunkMap(PdbByteReader reader, TaskMonitor monitor)
|
||||
throws PdbException, CancelledException {
|
||||
int count = 0;
|
||||
while (reader.hasMore()) {
|
||||
monitor.checkCanceled();
|
||||
int targetOffset = reader.parseInt();
|
||||
int mapTableOffset = count * thunkSize + offsetThunkTable;
|
||||
mapTableOffsetToTargetOffset.put(mapTableOffset, targetOffset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
private void deserializeSectionMap(PdbByteReader reader, TaskMonitor monitor)
|
||||
throws PdbException, CancelledException {
|
||||
while (reader.hasMore()) {
|
||||
monitor.checkCanceled();
|
||||
int offset = reader.parseInt();
|
||||
int section = reader.parseUnsignedShortVal();
|
||||
reader.skip(2); // padding
|
||||
sectionNumToAbsoluteOffset.put(section, offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
private void deserializeHashTable(PdbByteReader reader, TaskMonitor monitor)
|
||||
throws PdbException, CancelledException {
|
||||
|
||||
deserializeHashHeader(reader);
|
||||
|
||||
if (headerSignature == HEADER_SIGNATURE) {
|
||||
switch (versionNumber) {
|
||||
case GSI70:
|
||||
deserializeGsi70HashTable(reader, monitor);
|
||||
break;
|
||||
default:
|
||||
throw new PdbException("Unknown GSI Version Number");
|
||||
}
|
||||
}
|
||||
else {
|
||||
reader.reset(); // There was no header
|
||||
deserializeGsiPre70HashTable(reader, monitor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
versionNumber = reader.parseInt();
|
||||
hashRecordsLength = reader.parseInt();
|
||||
bucketsLength = reader.parseInt();
|
||||
}
|
||||
|
||||
// Issue: MSFT does not initialize PSGSIHDR with nSects(0) (our numSections), so spurious
|
||||
// data can be seen for this field. We cannot do sanity checks on the value. The only
|
||||
// effective thing we can do is to check if any data is left in the reader. Whatever amount
|
||||
// is left is what we will use.
|
||||
private void deserializePubHeader(PdbByteReader reader) throws PdbException {
|
||||
symbolHashLength = reader.parseInt();
|
||||
addressMapLength = reader.parseInt();
|
||||
long val = reader.parseUnsignedIntVal();
|
||||
if (val > Integer.MAX_VALUE) {
|
||||
throw new PdbException("Cannot support large unsigned integer num thunks");
|
||||
}
|
||||
numThunks = (int) val;
|
||||
thunkSize = reader.parseInt();
|
||||
iSectionThunkTable = reader.parseUnsignedShortVal();
|
||||
reader.skip(2); // padding
|
||||
offsetThunkTable = reader.parseInt();
|
||||
val = reader.parseUnsignedIntVal();
|
||||
// See note above regarding MSFT numSections issue
|
||||
//if (val > Integer.MAX_VALUE) {
|
||||
// throw new PdbException("Cannot support large unsigned integer num sections");
|
||||
//}
|
||||
numSections = (int) val;
|
||||
|
||||
// Calculated values.
|
||||
/**
|
||||
* We should calculate and store these as long values, but
|
||||
* {@link #PdbByteReader.getSubPdbByteReader(int)} does not support long, so we are
|
||||
* checking here and throwing exception if we cannot support it.
|
||||
*/
|
||||
val = 4 * numThunks;
|
||||
if (val > Integer.MAX_VALUE) {
|
||||
throw new PdbException("Cannot support large unsigned integer for thunk map length");
|
||||
}
|
||||
thunkMapLength = (int) val;
|
||||
val = thunkSize * numThunks;
|
||||
if (val > Integer.MAX_VALUE) {
|
||||
throw new PdbException("Cannot support large unsigned integer for thunk table length");
|
||||
}
|
||||
thunkTableLength = (int) val;
|
||||
// See note above regarding MSFT numSections issue
|
||||
//val = 8 * numSections;
|
||||
//if (val > Integer.MAX_VALUE) {
|
||||
// throw new PdbException("Cannot support long value for section map length");
|
||||
//}
|
||||
//sectionMapLength = (int) val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize the body of the {@link GlobalSymbolInformation} 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.
|
||||
*/
|
||||
private void deserializeGsiPre70HashTable(PdbByteReader reader, TaskMonitor monitor)
|
||||
throws PdbException, CancelledException {
|
||||
|
||||
int numBucketsBytes = 4 * (numHashRecords + 1);
|
||||
if (reader.numRemaining() < numBucketsBytes) {
|
||||
throw new PdbException("Not enough data for GSI");
|
||||
}
|
||||
int numRecordsBytes = (reader.numRemaining() - numBucketsBytes);
|
||||
|
||||
PdbByteReader hashRecordsReader = reader.getSubPdbByteReader(numRecordsBytes);
|
||||
PdbByteReader bucketsReader = reader.getSubPdbByteReader(numBucketsBytes);
|
||||
if (reader.hasMore()) {
|
||||
throw new PdbException("Unexpected extra information at and of GSI stream");
|
||||
}
|
||||
|
||||
hashBucketOffsets = new ArrayList<>();
|
||||
while (bucketsReader.hasMore()) {
|
||||
monitor.checkCanceled();
|
||||
hashBucketOffsets.add(bucketsReader.parseInt());
|
||||
}
|
||||
|
||||
// Note: each offset value is into an array of structures that are 12 bytes in length, but
|
||||
// whose on-disk size is 8 bytes. These are the structures in the hashRecordsReader. So
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize the body of the {@link GlobalSymbolInformation} 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.
|
||||
*/
|
||||
private void deserializeGsi70HashTable(PdbByteReader reader, TaskMonitor monitor)
|
||||
throws PdbException, CancelledException {
|
||||
|
||||
if (reader.numRemaining() != hashRecordsLength + bucketsLength) {
|
||||
throw new PdbException("Data count mismatch in GSI stream");
|
||||
}
|
||||
if (hashRecordsLength == 0 || bucketsLength == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
PdbByteReader hashRecordsReader = reader.getSubPdbByteReader(hashRecordsLength);
|
||||
PdbByteReader bucketsReader = reader.getSubPdbByteReader(bucketsLength);
|
||||
|
||||
deserializedCompressedHashBuckets(bucketsReader, monitor);
|
||||
|
||||
// int i = 0;
|
||||
// for (int x : hashBucketOffsets) {
|
||||
// System.out.println(String.format("0x%04x: 0x%08x", i++, x));
|
||||
// }
|
||||
// Note: each offset value is into an array of structures that are 12 bytes in length, but
|
||||
// whose on-disk size is 8 bytes. These are the structures in the hashRecordsReader. So
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 CancelledException Upon user cancellation.
|
||||
*/
|
||||
private void deserializedCompressedHashBuckets(PdbByteReader reader, TaskMonitor monitor)
|
||||
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();
|
||||
long val = bitEncoderReader.parseUnsignedIntVal();
|
||||
//bitEncoded[index++] = val;
|
||||
for (int bit = 0; bit < 32 && reader.hasMore(); bit++) {
|
||||
monitor.checkCanceled();
|
||||
if ((val & 0x01L) == 0x01L) {
|
||||
hashBucketOffsets.add(reader.parseInt());
|
||||
}
|
||||
else {
|
||||
hashBucketOffsets.add(-1);
|
||||
}
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
// Both readers should run out of data at the same time. We can have more bit encoder
|
||||
// data as long as there are not more bits set in the values. The following logic
|
||||
// checks this integrity.
|
||||
if (reader.hasMore()) {
|
||||
throw new PdbException("Compressed GSI Hash Buckets corrupt");
|
||||
}
|
||||
while (bitEncoderReader.hasMore()) {
|
||||
monitor.checkCanceled();
|
||||
if (bitEncoderReader.parseUnsignedIntVal() != 0) {
|
||||
throw new PdbException("Compressed GSI Hash Buckets corrupt");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
private void deserializeHashRecords(PdbByteReader reader, TaskMonitor monitor)
|
||||
throws PdbException, CancelledException {
|
||||
hashRecords = new TreeSet<>();
|
||||
while (reader.hasMore()) {
|
||||
monitor.checkCanceled();
|
||||
SymbolHashRecord record = new SymbolHashRecord();
|
||||
record.parse(reader);
|
||||
hashRecords.add(record);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a list of symbols from the information that we have.
|
||||
* @param monitor {@link TaskMonitor} used for checking cancellation.
|
||||
* @throws PdbException Upon not enough data left to parse.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
private void generateSymbolsList(TaskMonitor monitor) throws PdbException, CancelledException {
|
||||
symbols = new ArrayList<>();
|
||||
Map<Long, AbstractMsSymbol> map = pdb.getDatabaseInterface().getSymbolMap();
|
||||
for (SymbolHashRecord record : hashRecords) {
|
||||
monitor.checkCanceled();
|
||||
long offset = record.getOffset();
|
||||
AbstractMsSymbol symbol = map.get(offset);
|
||||
if (symbol == null) {
|
||||
throw new PdbException("PDB corrupted");
|
||||
}
|
||||
symbols.add(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*/
|
||||
void dump(Writer writer) throws IOException {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("GlobalSymbolInformation-------------------------------------\n");
|
||||
dumpHeader(builder);
|
||||
dumpHashRecords(builder);
|
||||
builder.append("\nEnd GlobalSymbolInformation---------------------------------\n");
|
||||
writer.write(builder.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ package ghidra.pdb.pdbreader;
|
|||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import ghidra.pdb.PdbByteReader;
|
||||
import ghidra.pdb.PdbException;
|
||||
|
||||
|
@ -29,6 +31,24 @@ import ghidra.pdb.PdbException;
|
|||
* confirm this.
|
||||
*/
|
||||
public class ImageSectionHeader {
|
||||
|
||||
//==============================================================================================
|
||||
// Internals
|
||||
//==============================================================================================
|
||||
private AbstractPdb pdb;
|
||||
|
||||
//==============================================================================================
|
||||
// API
|
||||
//==============================================================================================
|
||||
/**
|
||||
* Constructor.
|
||||
* @param pdb {@link AbstractPdb} to which this type belongs.
|
||||
*/
|
||||
public ImageSectionHeader(AbstractPdb pdb) {
|
||||
Validate.notNull(pdb, "pdb cannot be null)");
|
||||
this.pdb = pdb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ImageSectionHeader} name.
|
||||
* @return the name.
|
||||
|
@ -131,7 +151,7 @@ public class ImageSectionHeader {
|
|||
throw new PdbException("Not enough data for ImageSectionHeader");
|
||||
}
|
||||
PdbByteReader nameReader = reader.getSubPdbByteReader(8);
|
||||
name = nameReader.parseNullTerminatedString();
|
||||
name = nameReader.parseNullTerminatedString(pdb.getPdbReaderOptions().getOneByteCharset());
|
||||
unionPAVS = reader.parseUnsignedIntVal();
|
||||
virtualAddress = reader.parseUnsignedIntVal();
|
||||
rawDataSize = reader.parseUnsignedIntVal();
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.pdb.pdbreader;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import ghidra.pdb.PdbByteReader;
|
||||
import ghidra.pdb.PdbException;
|
||||
|
||||
|
@ -23,10 +25,17 @@ import ghidra.pdb.PdbException;
|
|||
*/
|
||||
public class ModuleInformation500 extends AbstractModuleInformation {
|
||||
|
||||
//==============================================================================================
|
||||
// Internals
|
||||
//==============================================================================================
|
||||
private AbstractPdb pdb;
|
||||
|
||||
//==============================================================================================
|
||||
// API
|
||||
//==============================================================================================
|
||||
public ModuleInformation500() {
|
||||
public ModuleInformation500(AbstractPdb pdb) {
|
||||
Validate.notNull(pdb, "pdb cannot be null)");
|
||||
this.pdb = pdb;
|
||||
sectionContribution = new SectionContribution400();
|
||||
}
|
||||
|
||||
|
@ -38,8 +47,10 @@ public class ModuleInformation500 extends AbstractModuleInformation {
|
|||
ecSymbolicInformationEnabled = false;
|
||||
nameIndexSourceFile = 0; // no value available.
|
||||
nameIndexCompilerPdbPath = 0; // no value available.
|
||||
moduleName = reader.parseNullTerminatedString();
|
||||
objectFileName = reader.parseNullTerminatedString();
|
||||
moduleName =
|
||||
reader.parseNullTerminatedString(pdb.getPdbReaderOptions().getOneByteCharset());
|
||||
objectFileName =
|
||||
reader.parseNullTerminatedString(pdb.getPdbReaderOptions().getOneByteCharset());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.pdb.pdbreader;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import ghidra.pdb.PdbByteReader;
|
||||
import ghidra.pdb.PdbException;
|
||||
|
||||
|
@ -23,10 +25,17 @@ import ghidra.pdb.PdbException;
|
|||
*/
|
||||
public class ModuleInformation600 extends AbstractModuleInformation {
|
||||
|
||||
//==============================================================================================
|
||||
// Internals
|
||||
//==============================================================================================
|
||||
private AbstractPdb pdb;
|
||||
|
||||
//==============================================================================================
|
||||
// API
|
||||
//==============================================================================================
|
||||
public ModuleInformation600() {
|
||||
public ModuleInformation600(AbstractPdb pdb) {
|
||||
Validate.notNull(pdb, "pdb cannot be null)");
|
||||
this.pdb = pdb;
|
||||
sectionContribution = new SectionContribution600();
|
||||
}
|
||||
|
||||
|
@ -39,8 +48,10 @@ public class ModuleInformation600 extends AbstractModuleInformation {
|
|||
spare >>= 1;
|
||||
nameIndexSourceFile = reader.parseUnsignedIntVal();
|
||||
nameIndexCompilerPdbPath = reader.parseUnsignedIntVal();
|
||||
moduleName = reader.parseNullTerminatedString();
|
||||
objectFileName = reader.parseNullTerminatedString();
|
||||
moduleName =
|
||||
reader.parseNullTerminatedString(pdb.getPdbReaderOptions().getOneByteCharset());
|
||||
objectFileName =
|
||||
reader.parseNullTerminatedString(pdb.getPdbReaderOptions().getOneByteCharset());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -172,7 +172,8 @@ public class NameTable {
|
|||
int bufOffset = reader.parseInt();
|
||||
int streamNumber = reader.parseInt();
|
||||
nameBufferReader.setIndex(bufOffset);
|
||||
String name = nameBufferReader.parseNullTerminatedString();
|
||||
String name = nameBufferReader.parseNullTerminatedString(
|
||||
pdb.getPdbReaderOptions().getOneByteCharset());
|
||||
streamNumbers[i] = streamNumber;
|
||||
names[i] = name;
|
||||
mapStreamNumberToName.put(streamNumber, name);
|
||||
|
@ -209,6 +210,7 @@ public class NameTable {
|
|||
int length = reader.parseInt();
|
||||
PdbByteReader stringReader = reader.getSubPdbByteReader(length);
|
||||
while (stringReader.hasMore()) {
|
||||
monitor.checkCanceled();
|
||||
int offset = stringReader.getIndex();
|
||||
String string = stringReader.parseNullTerminatedUtf8String();
|
||||
mapOffsetToString.put(offset, string);
|
||||
|
|
|
@ -35,11 +35,12 @@ public class Pdb200 extends AbstractPdb {
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
Pdb200(AbstractMsf msf) throws IOException, PdbException {
|
||||
super(msf);
|
||||
Pdb200(AbstractMsf msf, PdbReaderOptions pdbOptions) throws IOException, PdbException {
|
||||
super(msf, pdbOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -35,11 +35,12 @@ public class Pdb400 extends AbstractPdb {
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
Pdb400(AbstractMsf msf) throws IOException, PdbException {
|
||||
super(msf);
|
||||
Pdb400(AbstractMsf msf, PdbReaderOptions pdbOptions) throws IOException, PdbException {
|
||||
super(msf, pdbOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -35,11 +35,12 @@ public class Pdb700 extends AbstractPdb {
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
Pdb700(AbstractMsf msf) throws IOException, PdbException {
|
||||
super(msf);
|
||||
Pdb700(AbstractMsf msf, PdbReaderOptions pdbOptions) throws IOException, PdbException {
|
||||
super(msf, pdbOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,6 +17,8 @@ package ghidra.pdb.pdbreader;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import ghidra.pdb.PdbException;
|
||||
import ghidra.pdb.msfreader.AbstractMsf;
|
||||
import ghidra.pdb.msfreader.MsfParser;
|
||||
|
@ -50,38 +52,42 @@ public class PdbParser {
|
|||
* 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.
|
||||
*/
|
||||
public static AbstractPdb parse(String filename, TaskMonitor monitor)
|
||||
public static AbstractPdb parse(String filename, PdbReaderOptions pdbOptions, TaskMonitor monitor)
|
||||
throws IOException, PdbException, CancelledException {
|
||||
Validate.notNull(filename, "filename cannot be null)");
|
||||
Validate.notNull(pdbOptions, "pdbOptions cannot be null)");
|
||||
Validate.notNull(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.
|
||||
AbstractMsf msf = MsfParser.parse(filename, monitor);
|
||||
AbstractMsf msf = MsfParser.parse(filename, pdbOptions, monitor);
|
||||
|
||||
int versionNumber = AbstractPdb.deserializeVersionNumber(msf, monitor);
|
||||
|
||||
AbstractPdb pdb;
|
||||
switch (versionNumber) {
|
||||
case VC2_ID:
|
||||
pdb = new Pdb200(msf);
|
||||
pdb = new Pdb200(msf, pdbOptions);
|
||||
break;
|
||||
case VC4_ID:
|
||||
case VC41_ID:
|
||||
case VC50_ID:
|
||||
case VC98_ID:
|
||||
case VC70DEP_ID:
|
||||
pdb = new Pdb400(msf);
|
||||
pdb = new Pdb400(msf, pdbOptions);
|
||||
break;
|
||||
case VC70_ID:
|
||||
case VC80_ID:
|
||||
case VC110_ID:
|
||||
case VC140_ID:
|
||||
pdb = new Pdb700(msf);
|
||||
pdb = new Pdb700(msf, pdbOptions);
|
||||
break;
|
||||
default:
|
||||
// Must close the MSF here. In cases where PDB is created, the PDB takes
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pdb.pdbreader;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.program.model.data.CharsetInfo;
|
||||
|
||||
/**
|
||||
* Options used while reading a PDB ({@link AbstractPdb}) that control various aspects. These
|
||||
* can be optional values used during our development of this PdbReader. Currently included are
|
||||
* a field to control debug logging and {@link Charset} values used for String interpretation.
|
||||
*/
|
||||
public class PdbReaderOptions extends Exception {
|
||||
|
||||
private static final String DEFAULT_ONE_BYTE_CHARSET_NAME = CharsetInfo.UTF8;
|
||||
private static final String DEFAULT_TWO_BYTE_CHARSET_NAME = CharsetInfo.UTF16;
|
||||
|
||||
private static List<String> oneByteCharsetNames =
|
||||
CharsetInfo.getInstance().getCharsetNamesWithCharSize(1);
|
||||
private static List<String> twoByteCharsetNames =
|
||||
CharsetInfo.getInstance().getCharsetNamesWithCharSize(2);
|
||||
|
||||
private String oneByteCharsetName;
|
||||
private String twoByteCharsetName;
|
||||
|
||||
private Charset oneByteCharset;
|
||||
private Charset twoByteCharset;
|
||||
|
||||
private boolean debug;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public PdbReaderOptions() {
|
||||
oneByteCharsetName = DEFAULT_ONE_BYTE_CHARSET_NAME;
|
||||
twoByteCharsetName = DEFAULT_TWO_BYTE_CHARSET_NAME;
|
||||
setOneByteCharsetForName(oneByteCharsetName);
|
||||
setWideCharCharsetForName(twoByteCharsetName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of Charsets that encode one byte characters.
|
||||
* @return Charsets that encode one byte characters.
|
||||
*/
|
||||
public static List<String> getOneByteCharsetNames() {
|
||||
return oneByteCharsetNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of Charsets that encode two byte characters.
|
||||
* @return Charsets that encode two byte characters.
|
||||
*/
|
||||
public static List<String> getTwoByteCharsetNames() {
|
||||
return twoByteCharsetNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the one-byte Charset to use for PDB processing.
|
||||
* @param name Name of the Charset to use.
|
||||
* @return {@code true} if was able to set the Charset.
|
||||
*/
|
||||
public boolean setOneByteCharsetForName(String name) {
|
||||
if (!oneByteCharsetNames.contains(name)) {
|
||||
return false;
|
||||
}
|
||||
oneByteCharset = Charset.forName(name);
|
||||
oneByteCharsetName = name;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Wchar Charset to use for PDB processing.
|
||||
* @param name Name of the Charset to use.
|
||||
* @return {@code true} if was able to set the Charset.
|
||||
*/
|
||||
public boolean setWideCharCharsetForName(String name) {
|
||||
if (!twoByteCharsetNames.contains(name)) {
|
||||
return false;
|
||||
}
|
||||
twoByteCharset = Charset.forName(name);
|
||||
twoByteCharsetName = name;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the one-byte Charset in use for PDB processing.
|
||||
* @return the name of the Charset.
|
||||
*/
|
||||
public String getOneByteCharsetName() {
|
||||
return oneByteCharsetName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the two-byte Charset in use for PDB processing.
|
||||
* @return the name of the Charset.
|
||||
*/
|
||||
public String getTwoByteCharsetName() {
|
||||
return twoByteCharsetName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the one-byte Charset in use for PDB processing.
|
||||
* @return the Charset.
|
||||
*/
|
||||
public Charset getOneByteCharset() {
|
||||
return oneByteCharset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the two-byte Charset in use for PDB processing.
|
||||
* @return the Charset.
|
||||
*/
|
||||
public Charset getTwoByteCharset() {
|
||||
return twoByteCharset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable developmental debug.
|
||||
* @param debug {@code true} to turn debug on; default is {@code false}.
|
||||
*/
|
||||
public void setEnabled(boolean debug) {
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if debug is "on."
|
||||
* @return {@code true} if debug is "on."
|
||||
*/
|
||||
public boolean doDebug() {
|
||||
return debug;
|
||||
}
|
||||
|
||||
}
|
|
@ -23,12 +23,17 @@ import ghidra.pdb.PdbException;
|
|||
*/
|
||||
public class StringNt extends AbstractString {
|
||||
|
||||
//==============================================================================================
|
||||
// Abstract Methods
|
||||
//==============================================================================================
|
||||
/**
|
||||
* Constructor.
|
||||
* @param pdb {@link AbstractPdb} to which this type belongs.
|
||||
*/
|
||||
public StringNt(AbstractPdb pdb) {
|
||||
super(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doParse(PdbByteReader reader) throws PdbException {
|
||||
return reader.parseNullTerminatedString();
|
||||
return reader.parseNullTerminatedString(pdb.getPdbReaderOptions().getOneByteCharset());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,12 +24,17 @@ import ghidra.pdb.PdbException;
|
|||
*/
|
||||
public class StringSt extends AbstractString {
|
||||
|
||||
//==============================================================================================
|
||||
// Abstract Methods
|
||||
//==============================================================================================
|
||||
/**
|
||||
* Constructor.
|
||||
* @param pdb {@link AbstractPdb} to which this type belongs.
|
||||
*/
|
||||
public StringSt(AbstractPdb pdb) {
|
||||
super(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doParse(PdbByteReader reader) throws PdbException {
|
||||
return reader.parseByteLengthPrefixedString();
|
||||
return reader.parseByteLengthPrefixedString(pdb.getPdbReaderOptions().getOneByteCharset());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,9 +23,14 @@ import ghidra.pdb.PdbException;
|
|||
*/
|
||||
public class StringUtf8Nt extends AbstractString {
|
||||
|
||||
//==============================================================================================
|
||||
// Abstract Methods
|
||||
//==============================================================================================
|
||||
/**
|
||||
* Constructor.
|
||||
* @param pdb {@link AbstractPdb} to which this type belongs.
|
||||
*/
|
||||
public StringUtf8Nt(AbstractPdb pdb) {
|
||||
super(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doParse(PdbByteReader reader) throws PdbException {
|
||||
return reader.parseNullTerminatedUtf8String();
|
||||
|
|
|
@ -24,9 +24,14 @@ import ghidra.pdb.PdbException;
|
|||
*/
|
||||
public class StringUtf8St extends AbstractString {
|
||||
|
||||
//==============================================================================================
|
||||
// Abstract Methods
|
||||
//==============================================================================================
|
||||
/**
|
||||
* Constructor.
|
||||
* @param pdb {@link AbstractPdb} to which this type belongs.
|
||||
*/
|
||||
public StringUtf8St(AbstractPdb pdb) {
|
||||
super(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doParse(PdbByteReader reader) throws PdbException {
|
||||
return reader.parseByteLengthPrefixedUtf8String();
|
||||
|
|
|
@ -24,12 +24,17 @@ import ghidra.pdb.PdbException;
|
|||
*/
|
||||
public class StringWcharNt extends AbstractString {
|
||||
|
||||
//==============================================================================================
|
||||
// Abstract Methods
|
||||
//==============================================================================================
|
||||
/**
|
||||
* Constructor.
|
||||
* @param pdb {@link AbstractPdb} to which this type belongs.
|
||||
*/
|
||||
public StringWcharNt(AbstractPdb pdb) {
|
||||
super(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doParse(PdbByteReader reader) throws PdbException {
|
||||
return reader.parseNullTerminatedWcharString();
|
||||
return reader.parseNullTerminatedWcharString(pdb.getPdbReaderOptions().getTwoByteCharset());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.pdb.pdbreader;
|
||||
|
||||
import ghidra.pdb.PdbByteReader;
|
||||
import ghidra.pdb.PdbException;
|
||||
|
||||
/**
|
||||
* This class represents a Symbol Hash Record used by Global Symbol Information and Public
|
||||
* Symbol Information.
|
||||
*/
|
||||
public class SymbolHashRecord implements Comparable<SymbolHashRecord> {
|
||||
|
||||
private long offsetVal;
|
||||
private int referenceCount;
|
||||
|
||||
/**
|
||||
* @param reader {@link PdbByteReader} from which to deserialize the data.
|
||||
* @throws PdbException Upon not enough data left to parse.
|
||||
*/
|
||||
public void parse(PdbByteReader reader) throws PdbException {
|
||||
// MSFT does a bunch of pointer gyrations for this "+ 1"
|
||||
offsetVal = reader.parseUnsignedIntVal() + 1;
|
||||
referenceCount = reader.parseInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset component of the MSFT symbol hash record.
|
||||
* @return offset component of the hash record.
|
||||
*/
|
||||
public long getOffset() {
|
||||
return offsetVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reference count component of the MSFT symbol hash record.
|
||||
* @return reference count component of the hash record.
|
||||
*/
|
||||
public long getReferenceCount() {
|
||||
return referenceCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(SymbolHashRecord o) {
|
||||
return (int) ((offsetVal != o.getOffset()) ? offsetVal - o.getOffset()
|
||||
: referenceCount - o.getReferenceCount());
|
||||
}
|
||||
|
||||
}
|
|
@ -15,13 +15,13 @@
|
|||
*/
|
||||
package ghidra.pdb.pdbreader;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import ghidra.pdb.*;
|
||||
import ghidra.pdb.pdbreader.symbol.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
/**
|
||||
* Parser for detecting the parsing the appropriate Symbol structures ({@link AbstractMsSymbol}) in
|
||||
|
@ -266,8 +266,14 @@ public class SymbolParser {
|
|||
public String getNewSymbolTypesLog() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
DelimiterState ds = new DelimiterState("New Symbol IDs Seen: ", ",");
|
||||
for (Integer val : newSymbolTypesSeen) {
|
||||
builder.append(ds.out(true, String.format("0x04X, ", val)));
|
||||
/**
|
||||
* We are creating the sorted set now, as we are willing to incur the cost of a sorted
|
||||
* set now, but do not want to incur too much debug cost for adding to the
|
||||
* {@link newSymbolTypesSeen} when not doing debug.
|
||||
*/
|
||||
Set<Integer> sortedSet = new TreeSet<>(newSymbolTypesSeen);
|
||||
for (Integer val : sortedSet) {
|
||||
builder.append(ds.out(true, String.format("0X%04X", val)));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
@ -277,8 +283,9 @@ public class SymbolParser {
|
|||
* @param reader {@link PdbByteReader} from which to deserialize the symbol record.
|
||||
* @return {@link AbstractMsSymbol} that was parsed.
|
||||
* @throws PdbException upon error parsing a field.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
public AbstractMsSymbol parse(PdbByteReader reader) throws PdbException {
|
||||
public AbstractMsSymbol parse(PdbByteReader reader) throws PdbException, CancelledException {
|
||||
int symbolTypeId = reader.parseUnsignedShortVal();
|
||||
AbstractMsSymbol symbol;
|
||||
try {
|
||||
|
@ -295,9 +302,10 @@ public class SymbolParser {
|
|||
* @param reader {@link PdbByteReader} from which to deserialize the symbol record.
|
||||
* @return {@link AbstractMsSymbol} that was parsed.
|
||||
* @throws PdbException upon error parsing a field.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
private AbstractMsSymbol parseRecord(int symbolTypeId, PdbByteReader reader)
|
||||
throws PdbException {
|
||||
throws PdbException, CancelledException {
|
||||
// //System.out.println(reader.dump(0x200));
|
||||
// // DO NOT REMOVE
|
||||
// // The following code is for developmental investigations;
|
||||
|
|
|
@ -17,8 +17,7 @@ package ghidra.pdb.pdbreader;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
|
@ -41,8 +40,8 @@ public class SymbolRecords {
|
|||
// Internals
|
||||
//==============================================================================================
|
||||
private AbstractPdb pdb;
|
||||
private List<AbstractMsSymbol> symbolList;
|
||||
private List<List<AbstractMsSymbol>> moduleSymbolLists = new ArrayList<>();
|
||||
private Map<Long, AbstractMsSymbol> symbolMap;
|
||||
private List<Map<Long, AbstractMsSymbol>> moduleSymbols = new ArrayList<>();
|
||||
private int comprehensiveSymbolCount = 0;
|
||||
private List<AbstractMsSymbol> comprehensiveSymbolList = new ArrayList<>();
|
||||
|
||||
|
@ -85,20 +84,22 @@ public class SymbolRecords {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the list of regular symbols.
|
||||
* @return Regular {@link AbstractMsSymbol} symbols.
|
||||
* Returns the list of symbols.
|
||||
* @return {@link Map}<{@link Long},{@link AbstractMsSymbol}> of buffer offsets to
|
||||
* symbols.
|
||||
*/
|
||||
protected List<AbstractMsSymbol> getSymbolsList() {
|
||||
return symbolList;
|
||||
protected Map<Long, AbstractMsSymbol> getSymbolMap() {
|
||||
return symbolMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the symbol list for the module as specified by moduleNumber.
|
||||
* Returns the buffer-offset-to-symbol map for the module as specified by moduleNumber.
|
||||
* @param moduleNumber The number ID of the module for which to return the list.
|
||||
* @return {@link AbstractMsSymbol} Symbols in the specified module.
|
||||
* @return {@link Map}<{@link Long},{@link AbstractMsSymbol}> of buffer offsets to
|
||||
* symbols for the specified module.
|
||||
*/
|
||||
protected List<AbstractMsSymbol> getModuleSymbolLists(int moduleNumber) {
|
||||
return moduleSymbolLists.get(moduleNumber);
|
||||
protected Map<Long, AbstractMsSymbol> getModuleSymbolMap(int moduleNumber) {
|
||||
return moduleSymbols.get(moduleNumber);
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
|
@ -118,7 +119,7 @@ public class SymbolRecords {
|
|||
|
||||
streamNumber = pdb.databaseInterface.getSymbolRecordsStreamNumber();
|
||||
reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
|
||||
symbolList = deserializeSymbolRecords(reader);
|
||||
symbolMap = deserializeSymbolRecords(reader, monitor);
|
||||
|
||||
for (AbstractModuleInformation module : pdb.databaseInterface.moduleInformationList) {
|
||||
streamNumber = module.getStreamNumberDebugInformation();
|
||||
|
@ -129,57 +130,77 @@ public class SymbolRecords {
|
|||
int sizeDebug = module.getSizeLocalSymbolsDebugInformation();
|
||||
sizeDebug -= x; //TODO: seems right, but need to evaluate this
|
||||
PdbByteReader debugReader = reader.getSubPdbByteReader(sizeDebug);
|
||||
List<AbstractMsSymbol> moduleList = deserializeSymbolRecords(debugReader);
|
||||
Map<Long, AbstractMsSymbol> moduleSymbolsMap =
|
||||
deserializeSymbolRecords(debugReader, monitor);
|
||||
moduleSymbols.add(moduleSymbolsMap);
|
||||
// PdbByteReader rest = reader.getSubPdbByteReader(reader.numRemaining());
|
||||
// System.out.println(rest.dump());
|
||||
|
||||
// System.out.println(reader.dump(4));
|
||||
// System.out.println("stream: " + streamNumber + ", current index: " +
|
||||
// reader.getIndex() + ", index limit: " + reader.getLimit());
|
||||
// System.out.println(reader.dump(0x100));
|
||||
// TODO: figure out the rest of the bytes in the stream (index of reader)
|
||||
moduleSymbolLists.add(moduleList);
|
||||
}
|
||||
else {
|
||||
moduleSymbolLists.add(null);
|
||||
moduleSymbols.add(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the {@link AbstractMsSymbol} symbols from the {@link PdbByteReader}.
|
||||
* Deserializes the {@link AbstractMsSymbol} symbols from the {@link PdbByteReader} and
|
||||
* returns a {@link Map}<{@link Long},{@link AbstractMsSymbol}> of buffer offsets to
|
||||
* symbols.
|
||||
* @param reader {@link PdbByteReader} containing the symbol records to deserialize.
|
||||
* @return {@link AbstractMsSymbol} symbols.
|
||||
* @param monitor {@link TaskMonitor} used for checking cancellation.
|
||||
// * @return {@link AbstractMsSymbol} symbols.
|
||||
* @return map of buffer offsets to {@link AbstractMsSymbol} symbols.
|
||||
* @throws PdbException Upon not enough data left to parse.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
public List<AbstractMsSymbol> deserializeSymbolRecords(PdbByteReader reader)
|
||||
throws PdbException {
|
||||
int recordNumber = 0;
|
||||
public Map<Long, AbstractMsSymbol> deserializeSymbolRecords(PdbByteReader reader,
|
||||
TaskMonitor monitor) throws PdbException, CancelledException {
|
||||
//System.out.println(reader.dump(0x400));
|
||||
SymbolParser parser = pdb.getSymbolParser();
|
||||
List<AbstractMsSymbol> mySymbolList = new ArrayList<>();
|
||||
Map<Long, AbstractMsSymbol> mySymbolMap = new TreeMap<>();
|
||||
while (reader.hasMore()) {
|
||||
// //System.out.println("Symbol Record: " + recordNumber);
|
||||
monitor.checkCanceled();
|
||||
|
||||
// //System.out.println("Buffer Offset: " + offset);
|
||||
// // DO NOT REMOVE
|
||||
// // The following code is for developmental investigations;
|
||||
// // set break point on "int a = 1;" instead of a
|
||||
// // conditional break point.
|
||||
// if (recordNumber == 839) {
|
||||
// if (offset == -1) {
|
||||
// int a = 1;
|
||||
// a = a + 1;
|
||||
// //System.out.println(reader.dump(0x200));
|
||||
// }
|
||||
// Including length in byte array for alignment purposes.
|
||||
int recordLength = reader.parseUnsignedShortVal();
|
||||
int offset = reader.getIndex();
|
||||
|
||||
// System.out.println(String.format("SROffset: 0x%08x; compSymbCount: %d\n",
|
||||
// reader.getIndex(), comprehensiveSymbolCount));
|
||||
|
||||
if (offset == 0xb5a || offset == 0x160ae || offset == 0x3008a || offset == 0x161b6 ||
|
||||
(offset > 28350 && offset < 28400)) { // val I'm tracking: 0x161b5 (+1)
|
||||
int a = 1;
|
||||
a = a + 1;
|
||||
}
|
||||
|
||||
PdbByteReader recordReader = reader.getSubPdbByteReader(recordLength);
|
||||
pdb.pushDependencyStack(
|
||||
new CategoryIndex(CategoryIndex.Category.SYMBOL, comprehensiveSymbolCount));
|
||||
AbstractMsSymbol symbol = parser.parse(recordReader);
|
||||
pdb.popDependencyStack();
|
||||
mySymbolList.add(symbol);
|
||||
recordNumber++;
|
||||
mySymbolMap.put((long) offset, symbol);
|
||||
comprehensiveSymbolList.add(symbol);
|
||||
comprehensiveSymbolCount++;
|
||||
}
|
||||
return mySymbolList;
|
||||
return mySymbolMap;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -189,12 +210,12 @@ public class SymbolRecords {
|
|||
*/
|
||||
protected void dump(Writer writer) throws IOException {
|
||||
writer.write("SymbolRecords-----------------------------------------------\n");
|
||||
writer.write(dumpSymbolList(symbolList));
|
||||
for (int i = 0; i < moduleSymbolLists.size(); i++) {
|
||||
List<AbstractMsSymbol> list = moduleSymbolLists.get(i);
|
||||
if (list != null) {
|
||||
writer.write(dumpSymbolMap(symbolMap));
|
||||
for (int i = 0; i < moduleSymbols.size(); i++) {
|
||||
Map<Long, AbstractMsSymbol> map = moduleSymbols.get(i);
|
||||
if (map != null) {
|
||||
writer.write("Module(" + i + ") List:\n");
|
||||
writer.write(dumpSymbolList(list));
|
||||
writer.write(dumpSymbolMap(map));
|
||||
}
|
||||
}
|
||||
writer.write("\nEnd SymbolRecords-------------------------------------------\n");
|
||||
|
@ -204,18 +225,20 @@ public class SymbolRecords {
|
|||
// Internal Data Methods
|
||||
//==============================================================================================
|
||||
/**
|
||||
* Debug method for dumping the symbols from a symbol list
|
||||
* @param list The symbol list to dump.
|
||||
* Debug method for dumping the symbols from a symbol map
|
||||
* @param map the {@link Map}<{@link Long},{@link AbstractMsSymbol}> to dump.
|
||||
* @return {@link String} of pretty output of symbols dumped.
|
||||
*/
|
||||
protected String dumpSymbolList(List<AbstractMsSymbol> list) {
|
||||
protected String dumpSymbolMap(Map<Long, AbstractMsSymbol> map) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("SymbolList--------------------------------------------------");
|
||||
for (AbstractMsSymbol symbol : list) {
|
||||
builder.append("SymbolMap---------------------------------------------------");
|
||||
for (Long offset : map.keySet()) {
|
||||
AbstractMsSymbol symbol = map.get(offset);
|
||||
builder.append("\n------------------------------------------------------------\n");
|
||||
builder.append(String.format("Offset: 0X%08X\n", offset));
|
||||
builder.append(symbol);
|
||||
}
|
||||
builder.append("\nEnd SymbolList----------------------------------------------\n");
|
||||
builder.append("\nEnd SymbolMap-----------------------------------------------\n");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
*/
|
||||
package ghidra.pdb.pdbreader;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import ghidra.pdb.*;
|
||||
import ghidra.pdb.pdbreader.type.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
/**
|
||||
* Parser for detecting the parsing the appropriate Data\Item structures ({@link AbstractMsType})
|
||||
|
@ -204,8 +204,14 @@ public class TypeParser {
|
|||
public String getNewDataTypesLog() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
DelimiterState ds = new DelimiterState("New Symbol IDs Seen: ", ",");
|
||||
for (Integer val : newDataTypesSeen) {
|
||||
builder.append(ds.out(true, String.format("0x04X, ", val)));
|
||||
/**
|
||||
* We are creating the sorted set now, as we are willing to incur the cost of a sorted
|
||||
* set now, but do not want to incur too much debug cost for adding to the
|
||||
* {@link newDataTypesSeen} when not doing debug.
|
||||
*/
|
||||
Set<Integer> sortedSet = new TreeSet<>(newDataTypesSeen);
|
||||
for (Integer val : sortedSet) {
|
||||
builder.append(ds.out(true, String.format("0X%04X", val)));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
@ -215,8 +221,9 @@ public class TypeParser {
|
|||
* @param reader {@link PdbByteReader} from which to deserialize the data.
|
||||
* @return {@link AbstractMsType} parsed.
|
||||
* @throws PdbException upon error parsing a field.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
public AbstractMsType parse(PdbByteReader reader) throws PdbException {
|
||||
public AbstractMsType parse(PdbByteReader reader) throws PdbException, CancelledException {
|
||||
int dataTypeId = reader.parseUnsignedShortVal();
|
||||
AbstractMsType type;
|
||||
try {
|
||||
|
@ -233,8 +240,10 @@ public class TypeParser {
|
|||
* @param reader {@link PdbByteReader} from which to deserialize the data.
|
||||
* @return {@link AbstractMsType} parsed.
|
||||
* @throws PdbException upon error parsing a field.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
private AbstractMsType parseRecord(int dataTypeId, PdbByteReader reader) throws PdbException {
|
||||
private AbstractMsType parseRecord(int dataTypeId, PdbByteReader reader)
|
||||
throws PdbException, CancelledException {
|
||||
//Debugging and research investigation
|
||||
//System.out.println(reader.dump());
|
||||
// Leaving commented-out code here for continued research/development
|
||||
|
|
|
@ -71,7 +71,7 @@ public abstract class AbstractCompile2MsSymbol extends AbstractMsSymbol {
|
|||
//TODO: This might be a set of null-terminated strings... look at real data.
|
||||
compilerVersionString.parse(reader);
|
||||
while (reader.hasMore()) {
|
||||
AbstractString string = new StringUtf8Nt();
|
||||
AbstractString string = new StringUtf8Nt(pdb);
|
||||
string.parse(reader);
|
||||
if (string.get().isEmpty()) {
|
||||
break;
|
||||
|
|
|
@ -66,7 +66,7 @@ public abstract class AbstractDataHighLevelShaderLanguageSymbolInternals
|
|||
|
||||
@Override
|
||||
protected void create() {
|
||||
name = new StringUtf8Nt();
|
||||
name = new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public abstract class AbstractLocalSymbolInOptimizedCodeMsSymbol extends Abstrac
|
|||
public AbstractLocalSymbolInOptimizedCodeMsSymbol(AbstractPdb pdb, PdbByteReader reader)
|
||||
throws PdbException {
|
||||
super(pdb, reader);
|
||||
name = new StringUtf8Nt(); // Might need a create() method if the 2005 version needs St ver.
|
||||
name = new StringUtf8Nt(pdb); // Might need a create() method if the 2005 version needs St ver.
|
||||
typeIndex = reader.parseInt();
|
||||
localVariableFlags = new LocalVariableFlags(reader);
|
||||
name.parse(reader);
|
||||
|
|
|
@ -48,7 +48,7 @@ public class AnnotationMsSymbol extends AbstractMsSymbol {
|
|||
segment = reader.parseUnsignedShortVal();
|
||||
int count = reader.parseUnsignedShortVal();
|
||||
for (int i = 0; i < count; i++) {
|
||||
AbstractString string = new StringUtf8Nt();
|
||||
AbstractString string = new StringUtf8Nt(pdb);
|
||||
string.parse(reader);
|
||||
annotationStringList.add(string);
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ public class AttribLocOrParamReltoAMPMsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ public class AttribLocOrParamReltoVFPMsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,7 +49,7 @@ public class AttributedLocalOrParameterSIMRMsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -48,7 +48,7 @@ public class AttributedLocalOrParameterSIRMsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,7 +49,7 @@ public class BasePointerRelative16MsSymbol extends AbstractBasePointerRelativeMs
|
|||
protected void create() {
|
||||
offset = new Offset16();
|
||||
typeIndex = new TypeIndex16();
|
||||
name = new StringUtf8St();
|
||||
name = new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,7 +49,7 @@ public class BasePointerRelative3216MsSymbol extends AbstractBasePointerRelative
|
|||
protected void create() {
|
||||
offset = new Offset32();
|
||||
typeIndex = new TypeIndex16();
|
||||
name = new StringUtf8St();
|
||||
name = new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -50,7 +50,7 @@ public class BasePointerRelative32MsSymbol extends AbstractBasePointerRelativeMs
|
|||
protected void create() {
|
||||
offset = new Offset32();
|
||||
typeIndex = new TypeIndex32();
|
||||
name = new StringUtf8Nt();
|
||||
name = new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,7 +49,7 @@ public class BasePointerRelative32StMsSymbol extends AbstractBasePointerRelative
|
|||
protected void create() {
|
||||
offset = new Offset32();
|
||||
typeIndex = new TypeIndex32();
|
||||
name = new StringUtf8St();
|
||||
name = new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -48,7 +48,7 @@ public class Block16MsSymbol extends AbstractBlockMsSymbol {
|
|||
protected void create() {
|
||||
length = new Offset16();
|
||||
offset = new Offset16();
|
||||
name = new StringUtf8St();
|
||||
name = new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -48,7 +48,7 @@ public class Block32MsSymbol extends AbstractBlockMsSymbol {
|
|||
protected void create() {
|
||||
length = new Offset32();
|
||||
offset = new Offset32();
|
||||
name = new StringUtf8Nt();
|
||||
name = new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -48,7 +48,7 @@ public class Block32StMsSymbol extends AbstractBlockMsSymbol {
|
|||
protected void create() {
|
||||
length = new Offset32();
|
||||
offset = new Offset32();
|
||||
name = new StringUtf8St();
|
||||
name = new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -46,7 +46,7 @@ public class Compile2MsSymbol extends AbstractCompile2MsSymbol {
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -46,7 +46,7 @@ public class Compile2StMsSymbol extends AbstractCompile2MsSymbol {
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8St();
|
||||
return new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -62,7 +62,7 @@ public class Compile3MsSymbol extends AbstractMsSymbol {
|
|||
*/
|
||||
public Compile3MsSymbol(AbstractPdb pdb, PdbByteReader reader) throws PdbException {
|
||||
super(pdb, reader);
|
||||
compilerVersionString = new StringUtf8Nt();
|
||||
compilerVersionString = new StringUtf8Nt(pdb);
|
||||
processFlags(reader.parseUnsignedIntVal());
|
||||
processor = Processor.fromValue(reader.parseUnsignedShortVal());
|
||||
frontEndMajorVersionNumber = reader.parseUnsignedShortVal();
|
||||
|
|
|
@ -47,7 +47,7 @@ public class Constant16MsSymbol extends AbstractConstantMsSymbol {
|
|||
@Override
|
||||
protected void create() {
|
||||
typeIndex = new TypeIndex16();
|
||||
name = new StringUtf8St();
|
||||
name = new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,7 +47,7 @@ public class ConstantMsSymbol extends AbstractConstantMsSymbol {
|
|||
@Override
|
||||
protected void create() {
|
||||
typeIndex = new TypeIndex32();
|
||||
name = new StringUtf8Nt();
|
||||
name = new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,7 +47,7 @@ public class ConstantStMsSymbol extends AbstractConstantMsSymbol {
|
|||
@Override
|
||||
protected void create() {
|
||||
typeIndex = new TypeIndex32();
|
||||
name = new StringUtf8St();
|
||||
name = new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -41,7 +41,7 @@ public class DataSymbolInternals16 extends AbstractDataSymbolInternals {
|
|||
protected void create() {
|
||||
typeIndex = new TypeIndex16();
|
||||
offset = new Offset16();
|
||||
name = new StringUtf8St();
|
||||
name = new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -41,7 +41,7 @@ public class DataSymbolInternals32 extends AbstractDataSymbolInternals {
|
|||
protected void create() {
|
||||
typeIndex = new TypeIndex32();
|
||||
offset = new Offset32();
|
||||
name = new StringUtf8Nt();
|
||||
name = new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -41,7 +41,7 @@ public class DataSymbolInternals3216 extends AbstractDataSymbolInternals {
|
|||
protected void create() {
|
||||
typeIndex = new TypeIndex16();
|
||||
offset = new Offset32();
|
||||
name = new StringUtf8St();
|
||||
name = new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -41,7 +41,7 @@ public class DataSymbolInternals32St extends AbstractDataSymbolInternals {
|
|||
protected void create() {
|
||||
typeIndex = new TypeIndex32();
|
||||
offset = new Offset32();
|
||||
name = new StringUtf8St();
|
||||
name = new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,6 +20,8 @@ import java.util.*;
|
|||
import ghidra.pdb.PdbByteReader;
|
||||
import ghidra.pdb.PdbException;
|
||||
import ghidra.pdb.pdbreader.AbstractPdb;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* This class represents the Discarded By Link symbol.
|
||||
|
@ -76,8 +78,10 @@ public class DiscardedByLinkMsSymbol extends AbstractMsSymbol {
|
|||
* @param pdb {@link AbstractPdb} to which this symbol belongs.
|
||||
* @param reader {@link PdbByteReader} from which this symbol is deserialized.
|
||||
* @throws PdbException Upon not enough data left to parse.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
public DiscardedByLinkMsSymbol(AbstractPdb pdb, PdbByteReader reader) throws PdbException {
|
||||
public DiscardedByLinkMsSymbol(AbstractPdb pdb, PdbByteReader reader)
|
||||
throws PdbException, CancelledException {
|
||||
super(pdb, reader);
|
||||
long fields = reader.parseUnsignedIntVal();
|
||||
discardedVal = (int) (fields & 0xff);
|
||||
|
@ -92,7 +96,8 @@ public class DiscardedByLinkMsSymbol extends AbstractMsSymbol {
|
|||
PdbByteReader dataReader = new PdbByteReader(data);
|
||||
// SymbolParser parser = new SymbolParser(pdb);
|
||||
// symbolList = parser.deserializeSymbolRecords(dataReader);
|
||||
symbolList = pdb.getSymbolRecords().deserializeSymbolRecords(dataReader);
|
||||
symbolList = new ArrayList<>(pdb.getSymbolRecords().deserializeSymbolRecords(dataReader,
|
||||
TaskMonitor.DUMMY).values());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -54,7 +54,7 @@ public class EnvironmentBlockMsSymbol extends AbstractMsSymbol {
|
|||
super(pdb, reader);
|
||||
flags = reader.parseUnsignedByteVal();
|
||||
while (reader.hasMore()) {
|
||||
AbstractString string = new StringUtf8Nt();
|
||||
AbstractString string = new StringUtf8Nt(pdb);
|
||||
string.parse(reader);
|
||||
if (string.get().isEmpty()) {
|
||||
break;
|
||||
|
|
|
@ -46,7 +46,7 @@ public class ExportMsSymbol extends AbstractMsSymbol {
|
|||
*/
|
||||
public ExportMsSymbol(AbstractPdb pdb, PdbByteReader reader) throws PdbException {
|
||||
super(pdb, reader);
|
||||
name = new StringUtf8Nt();
|
||||
name = new StringUtf8Nt(pdb);
|
||||
ordinal = reader.parseUnsignedShortVal();
|
||||
int flags = reader.parseUnsignedShortVal();
|
||||
processFlags(flags);
|
||||
|
|
|
@ -42,7 +42,7 @@ public class FileStaticMsSymbol extends AbstractMsSymbol {
|
|||
*/
|
||||
public FileStaticMsSymbol(AbstractPdb pdb, PdbByteReader reader) throws PdbException {
|
||||
super(pdb, reader);
|
||||
name = new StringUtf8Nt();
|
||||
name = new StringUtf8Nt(pdb);
|
||||
typeIndex = reader.parseInt();
|
||||
moduleFilenameStringTableIndex = reader.parseInt();
|
||||
localVariableFlags = new LocalVariableFlags(reader);
|
||||
|
|
|
@ -47,7 +47,7 @@ public class GlobalManagedProcedureMsSymbol extends AbstractGlobalManagedProcedu
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,7 +47,7 @@ public class GlobalManagedProcedureStMsSymbol extends AbstractGlobalManagedProce
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8St();
|
||||
return new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,7 +47,7 @@ public class GlobalProcedureIa64IdMsSymbol extends AbstractProcedureStartIa64MsS
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,7 +47,7 @@ public class GlobalProcedureStartIa64MsSymbol extends AbstractProcedureStartIa64
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,7 +47,7 @@ public class GlobalProcedureStartIa64StMsSymbol extends AbstractProcedureStartIa
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8St();
|
||||
return new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,7 +47,7 @@ public class Label16MsSymbol extends AbstractLabelMsSymbol {
|
|||
@Override
|
||||
protected void create() {
|
||||
offset = new Offset16();
|
||||
name = new StringUtf8St();
|
||||
name = new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,7 +47,7 @@ public class Label32MsSymbol extends AbstractLabelMsSymbol {
|
|||
@Override
|
||||
protected void create() {
|
||||
offset = new Offset32();
|
||||
name = new StringUtf8Nt();
|
||||
name = new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,7 +47,7 @@ public class Label32StMsSymbol extends AbstractLabelMsSymbol {
|
|||
@Override
|
||||
protected void create() {
|
||||
offset = new Offset32();
|
||||
name = new StringUtf8St();
|
||||
name = new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -44,7 +44,7 @@ public class LocalDeferredProcedureCallGroupSharedMsSymbol extends AbstractMsSym
|
|||
public LocalDeferredProcedureCallGroupSharedMsSymbol(AbstractPdb pdb, PdbByteReader reader)
|
||||
throws PdbException {
|
||||
super(pdb, reader);
|
||||
name = new StringUtf8Nt();
|
||||
name = new StringUtf8Nt(pdb);
|
||||
typeIndex = reader.parseInt();
|
||||
flags = new LocalVariableFlags(reader);
|
||||
dataSlot = reader.parseUnsignedShortVal();
|
||||
|
|
|
@ -47,7 +47,7 @@ public class LocalManagedProcedureMsSymbol extends AbstractLocalManagedProcedure
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,7 +47,7 @@ public class LocalManagedProcedureStMsSymbol extends AbstractLocalManagedProcedu
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8St();
|
||||
return new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -46,7 +46,7 @@ public class LocalProcedureIa64IdMsSymbol extends AbstractProcedureStartIa64MsSy
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,7 +47,7 @@ public class LocalProcedureStartIa64MsSymbol extends AbstractProcedureStartIa64M
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,7 +47,7 @@ public class LocalProcedureStartIa64StMsSymbol extends AbstractProcedureStartIa6
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8St();
|
||||
return new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -48,7 +48,7 @@ public class LocalSlotIndexFieldedLILMsSymbol extends AbstractLocalSlotIndexFiel
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -48,7 +48,7 @@ public class LocalSlotIndexFieldedLILStMsSymbol extends AbstractLocalSlotIndexFi
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8St();
|
||||
return new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -54,7 +54,7 @@ public class ManLocOrParamReltoAMPMsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ public class ManLocOrParamReltoAMPStMsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8St();
|
||||
return new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ public class ManLocOrParamReltoVFPMsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,7 +49,7 @@ public class ManLocOrParamReltoVFPStMsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8St();
|
||||
return new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,7 +47,7 @@ public class ManagedConstantMsSymbol extends AbstractConstantMsSymbol {
|
|||
@Override
|
||||
protected void create() {
|
||||
typeIndex = new TypeIndex32();
|
||||
name = new StringUtf8Nt();
|
||||
name = new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,7 +49,7 @@ public class ManagedLocalOrParameterSIMR2MsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,7 +49,7 @@ public class ManagedLocalOrParameterSIMR2StMsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8St();
|
||||
return new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,7 +49,7 @@ public class ManagedLocalOrParameterSIMRMsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,7 +49,7 @@ public class ManagedLocalOrParameterSIMRStMsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8St();
|
||||
return new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,7 +49,7 @@ public class ManagedLocalOrParameterSIRMsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,7 +49,7 @@ public class ManagedLocalOrParameterSIRStMsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8St();
|
||||
return new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -54,7 +54,7 @@ public class ManagedSymbolWithSlotIndexFieldMsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ public class ManagedSymbolWithSlotIndexFieldStMsSymbol
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8St();
|
||||
return new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ public class ManyRegisterVariable16MsSymbol extends AbstractManyRegisterVariable
|
|||
@Override
|
||||
protected void create() {
|
||||
typeIndex = new TypeIndex16();
|
||||
name = new StringUtf8St();
|
||||
name = new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -48,7 +48,7 @@ public class ManyRegisterVariable2MsSymbol extends AbstractManyRegisterVariable2
|
|||
@Override
|
||||
protected void create() {
|
||||
typeIndex = new TypeIndex32();
|
||||
name = new StringUtf8Nt();
|
||||
name = new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -48,7 +48,7 @@ public class ManyRegisterVariable2StMsSymbol extends AbstractManyRegisterVariabl
|
|||
@Override
|
||||
protected void create() {
|
||||
typeIndex = new TypeIndex32();
|
||||
name = new StringUtf8St();
|
||||
name = new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,7 +47,7 @@ public class ManyRegisterVariableMsSymbol extends AbstractManyRegisterVariableMs
|
|||
@Override
|
||||
protected void create() {
|
||||
typeIndex = new TypeIndex32();
|
||||
name = new StringUtf8Nt();
|
||||
name = new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -48,7 +48,7 @@ public class ManyRegisterVariableStMsSymbol extends AbstractManyRegisterVariable
|
|||
@Override
|
||||
protected void create() {
|
||||
typeIndex = new TypeIndex32();
|
||||
name = new StringUtf8St();
|
||||
name = new StringUtf8St(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -29,8 +29,8 @@ public class MapToMiniPdbMsSymbol extends AbstractMsSymbol {
|
|||
|
||||
public static final int PDB_ID = 0x1161;
|
||||
|
||||
private AbstractString fromName = new StringWcharNt();
|
||||
private AbstractString toName = new StringWcharNt();
|
||||
private AbstractString fromName = new StringWcharNt(pdb);
|
||||
private AbstractString toName = new StringWcharNt(pdb);
|
||||
|
||||
/**
|
||||
* Constructor for this symbol.
|
||||
|
|
|
@ -47,7 +47,7 @@ public class MiniPdbReferenceMsSymbol extends AbstractMsSymbol {
|
|||
*/
|
||||
public MiniPdbReferenceMsSymbol(AbstractPdb pdb, PdbByteReader reader) throws PdbException {
|
||||
super(pdb, reader);
|
||||
name = new StringUtf8Nt();
|
||||
name = new StringUtf8Nt(pdb);
|
||||
long val = reader.parseUnsignedIntVal();
|
||||
moduleIndex = reader.parseUnsignedShortVal();
|
||||
int flags = reader.parseUnsignedShortVal();
|
||||
|
|
|
@ -46,7 +46,7 @@ public class ObjectNameMsSymbol extends AbstractObjectNameMsSymbol {
|
|||
|
||||
@Override
|
||||
protected AbstractString create() {
|
||||
return new StringUtf8Nt();
|
||||
return new StringUtf8Nt(pdb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue