GT-2895 global/public syms + more

This commit is contained in:
ghizard 2019-06-04 07:28:18 -04:00
parent 455d100a55
commit 26a36ab643
216 changed files with 1939 additions and 840 deletions

View file

@ -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,8 +1049,16 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl
public void initializeOptions() {
Options options = program.getOptions(Program.ANALYSIS_PROPERTIES);
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) {
byteTasks.optionsChanged(options);

View file

@ -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);
}
/**

View 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);
}
}

View file

@ -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.

View file

@ -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);
}
//==============================================================================================

View file

@ -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);
}
//==============================================================================================

View file

@ -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

View file

@ -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);
}
/**

View file

@ -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);

View file

@ -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.

View file

@ -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);

View file

@ -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);
}

View file

@ -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++;

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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);
//parser.deserializeSymbolRecords(reader);
//TODO: left off here 20180717
PdbByteReader addressMapReader = reader.getSubPdbByteReader(addressMapLength);
deserializeAddressMap(addressMapReader, monitor);
}
//==============================================================================================
//==============================================================================================
//==============================================================================================
// 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);
}
PdbByteReader thunkMapReader = reader.getSubPdbByteReader(thunkMapLength);
deserializeThunkMap(thunkMapReader, monitor);
/**
* 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.
* 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.
*/
void deserializeHeader(PdbByteReader reader) throws PdbException {
headerSignature = reader.parseUnsignedIntVal();
versionNumber = reader.parseUnsignedIntVal();
lengthHashRecords = reader.parseInt();
lengthBuckets = reader.parseInt();
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);
}
/**
* 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());
}
}

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;
}
}

View file

@ -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());
}
}

View file

@ -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());
}
}

View file

@ -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();

View file

@ -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();

View file

@ -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());
}
}

View file

@ -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());
}
}

View file

@ -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;

View file

@ -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();
}

View file

@ -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

View file

@ -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;

View file

@ -66,7 +66,7 @@ public abstract class AbstractDataHighLevelShaderLanguageSymbolInternals
@Override
protected void create() {
name = new StringUtf8Nt();
name = new StringUtf8Nt(pdb);
}
}

View file

@ -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);

View file

@ -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);
}

View file

@ -54,7 +54,7 @@ public class AttribLocOrParamReltoAMPMsSymbol
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
}

View file

@ -49,7 +49,7 @@ public class AttribLocOrParamReltoVFPMsSymbol
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
@Override

View file

@ -49,7 +49,7 @@ public class AttributedLocalOrParameterSIMRMsSymbol
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
@Override

View file

@ -48,7 +48,7 @@ public class AttributedLocalOrParameterSIRMsSymbol
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
@Override

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -46,7 +46,7 @@ public class Compile2MsSymbol extends AbstractCompile2MsSymbol {
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
@Override

View file

@ -46,7 +46,7 @@ public class Compile2StMsSymbol extends AbstractCompile2MsSymbol {
@Override
protected AbstractString create() {
return new StringUtf8St();
return new StringUtf8St(pdb);
}
@Override

View file

@ -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();

View file

@ -47,7 +47,7 @@ public class Constant16MsSymbol extends AbstractConstantMsSymbol {
@Override
protected void create() {
typeIndex = new TypeIndex16();
name = new StringUtf8St();
name = new StringUtf8St(pdb);
}
@Override

View file

@ -47,7 +47,7 @@ public class ConstantMsSymbol extends AbstractConstantMsSymbol {
@Override
protected void create() {
typeIndex = new TypeIndex32();
name = new StringUtf8Nt();
name = new StringUtf8Nt(pdb);
}
@Override

View file

@ -47,7 +47,7 @@ public class ConstantStMsSymbol extends AbstractConstantMsSymbol {
@Override
protected void create() {
typeIndex = new TypeIndex32();
name = new StringUtf8St();
name = new StringUtf8St(pdb);
}
@Override

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -47,7 +47,7 @@ public class GlobalManagedProcedureMsSymbol extends AbstractGlobalManagedProcedu
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
@Override

View file

@ -47,7 +47,7 @@ public class GlobalManagedProcedureStMsSymbol extends AbstractGlobalManagedProce
@Override
protected AbstractString create() {
return new StringUtf8St();
return new StringUtf8St(pdb);
}
@Override

View file

@ -47,7 +47,7 @@ public class GlobalProcedureIa64IdMsSymbol extends AbstractProcedureStartIa64MsS
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
@Override

View file

@ -47,7 +47,7 @@ public class GlobalProcedureStartIa64MsSymbol extends AbstractProcedureStartIa64
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
@Override

View file

@ -47,7 +47,7 @@ public class GlobalProcedureStartIa64StMsSymbol extends AbstractProcedureStartIa
@Override
protected AbstractString create() {
return new StringUtf8St();
return new StringUtf8St(pdb);
}
@Override

View file

@ -47,7 +47,7 @@ public class Label16MsSymbol extends AbstractLabelMsSymbol {
@Override
protected void create() {
offset = new Offset16();
name = new StringUtf8St();
name = new StringUtf8St(pdb);
}
@Override

View file

@ -47,7 +47,7 @@ public class Label32MsSymbol extends AbstractLabelMsSymbol {
@Override
protected void create() {
offset = new Offset32();
name = new StringUtf8Nt();
name = new StringUtf8Nt(pdb);
}
@Override

View file

@ -47,7 +47,7 @@ public class Label32StMsSymbol extends AbstractLabelMsSymbol {
@Override
protected void create() {
offset = new Offset32();
name = new StringUtf8St();
name = new StringUtf8St(pdb);
}
@Override

View file

@ -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();

View file

@ -47,7 +47,7 @@ public class LocalManagedProcedureMsSymbol extends AbstractLocalManagedProcedure
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
@Override

View file

@ -47,7 +47,7 @@ public class LocalManagedProcedureStMsSymbol extends AbstractLocalManagedProcedu
@Override
protected AbstractString create() {
return new StringUtf8St();
return new StringUtf8St(pdb);
}
@Override

View file

@ -46,7 +46,7 @@ public class LocalProcedureIa64IdMsSymbol extends AbstractProcedureStartIa64MsSy
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
@Override

View file

@ -47,7 +47,7 @@ public class LocalProcedureStartIa64MsSymbol extends AbstractProcedureStartIa64M
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
@Override

View file

@ -47,7 +47,7 @@ public class LocalProcedureStartIa64StMsSymbol extends AbstractProcedureStartIa6
@Override
protected AbstractString create() {
return new StringUtf8St();
return new StringUtf8St(pdb);
}
@Override

View file

@ -48,7 +48,7 @@ public class LocalSlotIndexFieldedLILMsSymbol extends AbstractLocalSlotIndexFiel
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
@Override

View file

@ -48,7 +48,7 @@ public class LocalSlotIndexFieldedLILStMsSymbol extends AbstractLocalSlotIndexFi
@Override
protected AbstractString create() {
return new StringUtf8St();
return new StringUtf8St(pdb);
}
@Override

View file

@ -54,7 +54,7 @@ public class ManLocOrParamReltoAMPMsSymbol
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
}

View file

@ -54,7 +54,7 @@ public class ManLocOrParamReltoAMPStMsSymbol
@Override
protected AbstractString create() {
return new StringUtf8St();
return new StringUtf8St(pdb);
}
}

View file

@ -49,7 +49,7 @@ public class ManLocOrParamReltoVFPMsSymbol
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
@Override

View file

@ -49,7 +49,7 @@ public class ManLocOrParamReltoVFPStMsSymbol
@Override
protected AbstractString create() {
return new StringUtf8St();
return new StringUtf8St(pdb);
}
@Override

View file

@ -47,7 +47,7 @@ public class ManagedConstantMsSymbol extends AbstractConstantMsSymbol {
@Override
protected void create() {
typeIndex = new TypeIndex32();
name = new StringUtf8Nt();
name = new StringUtf8Nt(pdb);
}
@Override

View file

@ -49,7 +49,7 @@ public class ManagedLocalOrParameterSIMR2MsSymbol
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
@Override

View file

@ -49,7 +49,7 @@ public class ManagedLocalOrParameterSIMR2StMsSymbol
@Override
protected AbstractString create() {
return new StringUtf8St();
return new StringUtf8St(pdb);
}
@Override

View file

@ -49,7 +49,7 @@ public class ManagedLocalOrParameterSIMRMsSymbol
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
@Override

View file

@ -49,7 +49,7 @@ public class ManagedLocalOrParameterSIMRStMsSymbol
@Override
protected AbstractString create() {
return new StringUtf8St();
return new StringUtf8St(pdb);
}
@Override

View file

@ -49,7 +49,7 @@ public class ManagedLocalOrParameterSIRMsSymbol
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
@Override

View file

@ -49,7 +49,7 @@ public class ManagedLocalOrParameterSIRStMsSymbol
@Override
protected AbstractString create() {
return new StringUtf8St();
return new StringUtf8St(pdb);
}
@Override

View file

@ -54,7 +54,7 @@ public class ManagedSymbolWithSlotIndexFieldMsSymbol
@Override
protected AbstractString create() {
return new StringUtf8Nt();
return new StringUtf8Nt(pdb);
}
}

View file

@ -54,7 +54,7 @@ public class ManagedSymbolWithSlotIndexFieldStMsSymbol
@Override
protected AbstractString create() {
return new StringUtf8St();
return new StringUtf8St(pdb);
}
}

View file

@ -48,7 +48,7 @@ public class ManyRegisterVariable16MsSymbol extends AbstractManyRegisterVariable
@Override
protected void create() {
typeIndex = new TypeIndex16();
name = new StringUtf8St();
name = new StringUtf8St(pdb);
}
@Override

View file

@ -48,7 +48,7 @@ public class ManyRegisterVariable2MsSymbol extends AbstractManyRegisterVariable2
@Override
protected void create() {
typeIndex = new TypeIndex32();
name = new StringUtf8Nt();
name = new StringUtf8Nt(pdb);
}
@Override

View file

@ -48,7 +48,7 @@ public class ManyRegisterVariable2StMsSymbol extends AbstractManyRegisterVariabl
@Override
protected void create() {
typeIndex = new TypeIndex32();
name = new StringUtf8St();
name = new StringUtf8St(pdb);
}
@Override

View file

@ -47,7 +47,7 @@ public class ManyRegisterVariableMsSymbol extends AbstractManyRegisterVariableMs
@Override
protected void create() {
typeIndex = new TypeIndex32();
name = new StringUtf8Nt();
name = new StringUtf8Nt(pdb);
}
@Override

View file

@ -48,7 +48,7 @@ public class ManyRegisterVariableStMsSymbol extends AbstractManyRegisterVariable
@Override
protected void create() {
typeIndex = new TypeIndex32();
name = new StringUtf8St();
name = new StringUtf8St(pdb);
}
@Override

View file

@ -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.

View file

@ -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();

View file

@ -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