Merge remote-tracking branch 'origin/GP-1776_ghizard_PDB_Part1_Add_C13_sections_modules_iterators_20220824--SQUASHED'

This commit is contained in:
Ryan Kurtz 2022-08-31 12:29:37 -04:00
commit af7476b21f
40 changed files with 4084 additions and 87 deletions

View File

@ -0,0 +1,291 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* C13Lines information. As best as we know, only one of C11Lines or C13Lines (We are actually
* creating a C13Debug class at a higher level, and making C13Lines be the specific C13Debug
* information for "type" 0xf2 (and maybe 0xf4) can be found after the symbol information in
* module debug streams.
*/
public class AbstractC13Lines extends C13Section {
private long offCon; // uint32
private int segCon; // uint16
private int flags; // uint16
private long lenCon; // uint32
private List<FileRecord> fileRecords = new ArrayList<>();
protected AbstractC13Lines(PdbByteReader reader, boolean ignore, TaskMonitor monitor)
throws PdbException, CancelledException {
super(ignore);
if (reader.numRemaining() < 12) {
throw new PdbException("Not enough data for header");
}
offCon = reader.parseUnsignedIntVal();
segCon = reader.parseUnsignedShortVal();
flags = reader.parseUnsignedShortVal();
lenCon = reader.parseUnsignedIntVal();
boolean hasColumn = ((flags & 0X0001) != 0);
while (reader.hasMore()) {
monitor.checkCanceled();
FileRecord fileRecord = FileRecord.parse(reader, hasColumn, monitor);
if (fileRecord == null) {
break;
}
fileRecords.add(fileRecord);
}
}
long getOffCon() {
return offCon;
}
int getSegCon() {
return segCon;
}
int getFlags() {
return flags;
}
long getLenCon() {
return lenCon;
}
@Override
public String toString() {
return String.format(
"%s: offCon = %ld, segCon = %d, flags = 0x%04x, lenCon = %d; num records = %d",
getClass().getSimpleName(), offCon, segCon, flags, lenCon, fileRecords.size());
}
/**
* Dumps this class to a Writer
* @param writer {@link Writer} to which to dump the information
* @throws IOException Upon IOException writing to the {@link Writer}
*/
@Override
void dump(Writer writer) throws IOException {
writer.write("C13Lines----------------------------------------------------\n");
dumpInternal(writer);
writer.write("End C13Lines------------------------------------------------\n");
}
protected void dumpInternal(Writer writer) throws IOException {
writer.write(String.format("offCon: 0x%08x segCon: %d flags: 0x%08x lenCon: 0x%08x\n",
offCon, segCon, flags, lenCon));
for (FileRecord record : fileRecords) {
record.dump(writer, offCon);
}
}
static class FileRecord {
private long fileId; // uint32
private long nLines; // uint32
private long lenFileBlock; // uint32
private List<LineRecord> lineRecords = new ArrayList<>();
static FileRecord parse(PdbByteReader reader, boolean hasColumn, TaskMonitor monitor)
throws PdbException {
return new FileRecord(reader, hasColumn, monitor);
}
private FileRecord(PdbByteReader reader, boolean hasColumn, TaskMonitor monitor)
throws PdbException {
if (reader.numRemaining() < 12) {
throw new PdbException("Not enough data for FileRecord header");
}
fileId = reader.parseUnsignedIntVal();
nLines = reader.parseUnsignedIntVal();
lenFileBlock = reader.parseUnsignedIntVal();
long lenMinusHeader = lenFileBlock - 12; // 12 is size of header
Long x = nLines;
int nLinesI = x.intValue();
int sizeLines = nLinesI * 8;
int sizeColumns = nLinesI * (hasColumn ? 4 : 0);
int sizeRequired = sizeLines + sizeColumns;
// was test ">" but both are suspect... not all records might have the columns
if (lenMinusHeader != sizeRequired) {
throw new PdbException("Corrupt FileRecord");
}
if (reader.numRemaining() < sizeRequired) {
throw new PdbException("Not enough data for FileRecord records");
}
PdbByteReader lineReader = reader.getSubPdbByteReader(sizeLines);
PdbByteReader columnReader =
(hasColumn ? reader.getSubPdbByteReader(sizeColumns) : null);
for (int i = 0; i < nLines; i++) {
LineRecord lineRecord = LineRecord.parse(lineReader, columnReader);
lineRecords.add(lineRecord);
}
}
long getFileId() {
return fileId;
}
long getNLines() {
return nLines;
}
long getLenFileBlock() {
return lenFileBlock;
}
List<LineRecord> getLineRecords() {
return lineRecords;
}
void dump(Writer writer, long offCon) throws IOException {
writer.write(String.format("fileId: %06x, nLines: %d, lenFileBlock: %d\n",
getFileId(), getNLines(), getLenFileBlock()));
for (int i = 0; i < getNLines(); i++) {
List<LineRecord> records = getLineRecords();
records.get(i).dump(writer, offCon);
writer.write("\n");
}
}
}
static class LineRecord {
private long offset; // uint32
private long bitVals; // uint32
private ColumnRecord columnRecord = null;
long getOffset() {
return offset;
}
long getBitVals() {
return bitVals;
}
long getLineNumStart() {
return bitVals & 0xffffffL;
}
long getDeltaLineEnd() {
return (bitVals >> 24) & 0x7fL;
}
ColumnRecord getColumnRecord() {
return columnRecord;
}
/**
* Returns true if the line number is that of an statement
* @return true if for an statement
*/
boolean isStatement() {
return (bitVals & 0x80000000L) != 0L;
}
/**
* Returns true if the line number is that of an expression
* @return true if for an expression
*/
boolean isExpression() {
return !isStatement();
}
static LineRecord parse(PdbByteReader lineReader, PdbByteReader columnReader)
throws PdbException {
return new LineRecord(lineReader, columnReader);
}
private LineRecord(PdbByteReader lineReader, PdbByteReader columnReader)
throws PdbException {
offset = lineReader.parseUnsignedIntVal();
bitVals = lineReader.parseUnsignedIntVal();
if (columnReader != null) { // means hasColumn is true
columnRecord = ColumnRecord.parse(columnReader);
}
}
private boolean isSpecialLine() {
long start = getLineNumStart();
return (start == 0xfeefeeL || start == 0xf00f00L);
}
void dump(Writer writer, long offCon) throws IOException {
String lineStart = (isSpecialLine() ? String.format("%06x", getLineNumStart())
: String.format("%d", getLineNumStart()));
if (columnRecord != null) {
if (columnRecord.getOffsetColumnEnd() != 0L) {
writer.write(String.format("%5d:%5d-%5d-%5d 0x%08x %s", getLineNumStart(),
columnRecord.getOffsetColumnStart(), getLineNumStart() + getDeltaLineEnd(),
columnRecord.getOffsetColumnEnd(), getOffset() + offCon,
(isStatement() ? "Statement" : "Expression")));
}
else {
writer.write(String.format("%s-%5d 0x%08x %s", lineStart,
columnRecord.getOffsetColumnStart(), getOffset() + offCon,
(isStatement() ? "Statement" : "Expression")));
}
}
else {
writer.write(String.format("%s 0x%08x %s", lineStart, getOffset() + offCon,
(isStatement() ? "Statement" : "Expression")));
}
}
}
static class ColumnRecord {
private int offsetColumnStart; // unsigned short
private int offsetColumnEnd; // unsigned short
int getOffsetColumnStart() {
return offsetColumnStart;
}
int getOffsetColumnEnd() {
return offsetColumnEnd;
}
static ColumnRecord parse(PdbByteReader reader) throws PdbException {
return new ColumnRecord(reader);
}
private ColumnRecord(PdbByteReader reader) throws PdbException {
offsetColumnStart = reader.parseUnsignedShortVal();
offsetColumnEnd = reader.parseUnsignedShortVal();
}
@Override
public String toString() {
return String.format("Start: 0x%04x, End: 0x%04x", getOffsetColumnStart(),
getOffsetColumnEnd());
}
}
}

View File

@ -54,12 +54,16 @@ public abstract class AbstractModuleInformation {
protected long nameIndexCompilerPdbPath; // unsigned 32-bit
//==============================================================================================
protected AbstractPdb pdb;
private Map<Integer, String> filenameByOffset = new HashMap<>();
//==============================================================================================
// API
//==============================================================================================
public AbstractModuleInformation() {
public AbstractModuleInformation(AbstractPdb pdb) {
Objects.requireNonNull(pdb, "pdb cannot be null");
this.pdb = pdb;
}
/**
@ -96,12 +100,28 @@ public abstract class AbstractModuleInformation {
/**
* Returns the size of the local symbols debug information.
* @return Size of the local symbosl debug information.
* @return Size of the local symbols debug information.
*/
public int getSizeLocalSymbolsDebugInformation() {
return sizeLocalSymbolsDebugInformation;
}
/**
* Returns the size of the older-style line number information
* @return Size of the older-style line number information
*/
public int getSizeLineNumberDebugInformation() {
return sizeLineNumberDebugInformation;
}
/**
* Returns the size of the C13-style line number information
* @return Size of the C13-style line number information
*/
public int getSizeC13StyleLineNumberInformation() {
return sizeC13StyleLineNumberInformation;
}
/**
* Returns the name of the module.
* @return Name of the module.

View File

@ -547,7 +547,7 @@ public abstract class AbstractPdb implements AutoCloseable {
PdbByteReader getReaderForStreamNumber(int streamNumber, int streamOffset, int numToRead,
TaskMonitor monitor) throws IOException, CancelledException {
MsfStream stream = msf.getStream(streamNumber);
numToRead = Math.min(numToRead, stream.getLength());
numToRead = Math.min(numToRead, stream.getLength() - streamOffset);
byte[] bytes = stream.read(streamOffset, numToRead, monitor);
PdbByteReader reader = new PdbByteReader(bytes);
return reader;
@ -697,8 +697,10 @@ public abstract class AbstractPdb implements AutoCloseable {
* debugging only.
* @param writer {@link Writer}.
* @throws IOException On issue writing to the {@link Writer}.
* @throws CancelledException Upon user cancellation
* @throws PdbException Upon not enough data left to parse
*/
public void dumpSubStreams(Writer writer) throws IOException {
public void dumpSubStreams(Writer writer) throws IOException, CancelledException, PdbException {
writer.write("SubStreams--------------------------------------------------\n");
if (typeProgramInterface != null) {
writer.write("TypeProgramInterface----------------------------------------\n");

View File

@ -60,6 +60,11 @@ public abstract class AbstractSectionContribution {
return imod;
}
@Override
public String toString() {
return dump();
}
//==============================================================================================
// Abstract Methods
//==============================================================================================

View File

@ -0,0 +1,52 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
import ghidra.util.task.TaskMonitor;
/**
* Abstract class for C13 Sections which do not yet have a good implementation.
* Class exists to output the fact (in a dump) that data of this type has been encountered.
*/
abstract class AbstractUnimplementedC13Section extends C13Section {
private PdbByteReader myReader = null;
protected AbstractUnimplementedC13Section(PdbByteReader reader, boolean ignore,
TaskMonitor monitor) {
super(ignore);
myReader = reader;
}
@Override
public String toString() {
return getClass().getSimpleName();
}
@Override
void dump(Writer writer) throws IOException {
String n = getClass().getSimpleName();
int len = n.length();
writer.write(n + dashes.substring(len));
writer.write("***NOT IMPLEMENTED*** Bytes follow...\n");
writer.write(myReader.dump());
writer.write("\n");
writer.write("End " + n + dashes.substring(len + 4));
}
}

View File

@ -22,15 +22,13 @@ import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* C11Lines information. As best as we know, only one of C11Lines or C13Lines (not implemented
* yet) can be found after the symbol information in module debug streams.
* C11Lines information. As best as we know, only one of C11Lines or C13Lines can be found after
* the symbol information in module debug streams.
* <P>
* Note: we have not tested or put this to use yet.
*/
public class C11Lines {
private AbstractPdb pdb;
private int cFile; // unsigned short
private int cSeg; // unsigned short
// array of (Windows C) unsigned long values (which is 32-bit int); we are limiting to java int.
@ -50,11 +48,12 @@ public class C11Lines {
private List<List<List<Long>>> offsets; // unsigned int
private List<List<List<Integer>>> lineNumbers; // unsigned short
public C11Lines(AbstractPdb pdb) {
this.pdb = pdb;
public static C11Lines parse(AbstractPdb pdb, PdbByteReader reader, TaskMonitor monitor)
throws PdbException, CancelledException {
return new C11Lines(pdb, reader, monitor);
}
public void parse(PdbByteReader reader, TaskMonitor monitor)
private C11Lines(AbstractPdb pdb, PdbByteReader reader, TaskMonitor monitor)
throws PdbException, CancelledException {
if (reader.numRemaining() < 4) {
return;

View File

@ -0,0 +1,35 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import ghidra.util.task.TaskMonitor;
/**
* Class for C13Type COFF_SYMBOL_RVA.
* <p>
* This temporary class implementation currently extends {@link AbstractUnimplementedC13Section},
* but this should be changed to {@link C13Section} when the format is understood and the
* implementation is made concrete.
*/
class C13CoffSymbolRva extends AbstractUnimplementedC13Section {
static C13CoffSymbolRva parse(PdbByteReader reader, boolean ignore, TaskMonitor monitor) {
return new C13CoffSymbolRva(reader, ignore, monitor);
}
protected C13CoffSymbolRva(PdbByteReader reader, boolean ignore, TaskMonitor monitor) {
super(reader, ignore, monitor);
}
}

View File

@ -0,0 +1,114 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* PDB C13 Cross-Scope Exports information.
*/
public class C13CrossScopeExports extends C13Section {
private List<CrossScopeExport> crossScopeExports = new ArrayList<>();
/**
* Parse and return a {@link C13CrossScopeExports}.
* @param reader {@link PdbByteReader} containing the symbol records to deserialize
* @param ignore flag indicating whether the record should be ignored
* @param monitor {@link TaskMonitor} used for checking cancellation
* @return the parsed data
* @throws PdbException Upon not enough data left to parse
* @throws CancelledException Upon user cancellation
*/
static C13CrossScopeExports parse(PdbByteReader reader, boolean ignore, TaskMonitor monitor)
throws PdbException, CancelledException {
return new C13CrossScopeExports(reader, ignore, monitor);
}
protected C13CrossScopeExports(PdbByteReader reader, boolean ignore, TaskMonitor monitor)
throws CancelledException, PdbException {
super(ignore);
while (reader.numRemaining() >= CrossScopeExport.getBaseRecordSize()) {
monitor.checkCanceled();
CrossScopeExport crossExport = new CrossScopeExport(reader);
crossScopeExports.add(crossExport);
}
if (reader.hasMore()) {
Msg.debug(C13CrossScopeExports.class,
String.format("Num Extra C13CrossScopeExports bytes: %d", reader.numRemaining()));
}
}
List<CrossScopeExport> getCrossScopeExports() {
return crossScopeExports;
}
@Override
public String toString() {
return String.format("%s: num cross-scope exports = %d", getClass().getSimpleName(),
crossScopeExports.size());
}
/**
* Dumps this class to a Writer
* @param writer {@link Writer} to which to dump the information
* @throws IOException Upon IOException writing to the {@link Writer}
*/
@Override
void dump(Writer writer) throws IOException {
writer.write("C13CrossScopeExports----------------------------------------\n");
for (CrossScopeExport crossScopeExport : crossScopeExports) {
writer.write(crossScopeExport.toString());
writer.write('\n');
}
writer.write("End C13CrossScopeExports------------------------------------\n");
}
static class CrossScopeExport {
private long localId; // unsigned 32-bit
private long globalId; // unsigned 32-bit
private static int getBaseRecordSize() {
return 8;
}
CrossScopeExport(PdbByteReader reader) throws PdbException {
localId = reader.parseUnsignedIntVal();
globalId = reader.parseUnsignedIntVal();
}
long getLocalId() {
return localId;
}
long getGlobalId() {
return globalId;
}
@Override
public String toString() {
return String.format("0x%08x, 0x%08x", localId, globalId);
}
}
}

View File

@ -0,0 +1,128 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* PDB C13 Cross-Scope Imports information.... also known as Cross-Scope References.
*/
public class C13CrossScopeImports extends C13Section {
private List<CrossScopeImport> crossScopeImports = new ArrayList<>();
/**
* Parse and return a {@link C13CrossScopeImports}.
* @param reader {@link PdbByteReader} containing the symbol records to deserialize
* @param ignore flag indicating whether the record should be ignored
* @param monitor {@link TaskMonitor} used for checking cancellation
* @return the parsed data
* @throws PdbException Upon not enough data left to parse
* @throws CancelledException Upon user cancellation
*/
static C13CrossScopeImports parse(PdbByteReader reader, boolean ignore, TaskMonitor monitor)
throws PdbException, CancelledException {
return new C13CrossScopeImports(reader, ignore, monitor);
}
protected C13CrossScopeImports(PdbByteReader reader, boolean ignore, TaskMonitor monitor)
throws CancelledException, PdbException {
super(ignore);
while (reader.numRemaining() >= CrossScopeImport.getBaseRecordSize()) {
monitor.checkCanceled();
CrossScopeImport crossImport = new CrossScopeImport(reader);
crossScopeImports.add(crossImport);
}
if (reader.hasMore()) {
Msg.debug(C13CrossScopeExports.class,
String.format("Num Extra C13CrossScopeExports bytes: %d", reader.numRemaining()));
}
}
List<CrossScopeImport> getCrossScopeImports() {
return crossScopeImports;
}
@Override
public String toString() {
return String.format("%s: num cross-scope imports = %d", getClass().getSimpleName(),
crossScopeImports.size());
}
/**
* Dumps this class to a Writer
* @param writer {@link Writer} to which to dump the information
* @throws IOException Upon IOException writing to the {@link Writer}
*/
@Override
void dump(Writer writer) throws IOException {
writer.write("C13CrossScopeImports----------------------------------------\n");
for (CrossScopeImport crossScopeImport : crossScopeImports) {
writer.write(crossScopeImport.toString());
writer.write('\n');
}
writer.write("End C13CrossScopeImports------------------------------------\n");
}
static class CrossScopeImport {
private int offsetObjectFilePath; // the module file; signed 32-bit
private long numCrossReferences; // unsigned 32-bit
private List<Long> referenceIds; // Array of unsigned 32-bit values
private static int getBaseRecordSize() {
return 8;
}
CrossScopeImport(PdbByteReader reader) throws PdbException {
offsetObjectFilePath = reader.parseInt();
numCrossReferences = reader.parseUnsignedIntVal();
referenceIds = new ArrayList<>();
for (long i = 0; i < numCrossReferences; i++) {
referenceIds.add(reader.parseUnsignedIntVal());
}
}
long getOffsetObjectFilePath() {
return offsetObjectFilePath;
}
long getNumCrossReferences() {
return numCrossReferences;
}
List<Long> getReferenceIds() {
return referenceIds;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(String.format("0x%08x, %5d", offsetObjectFilePath, numCrossReferences));
for (Long id : referenceIds) {
builder.append(String.format(" 0x%08x", id));
}
return builder.toString();
}
}
}

View File

@ -0,0 +1,161 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
import ghidra.util.Msg;
import ghidra.util.NumericUtilities;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* PDB C13 Module File Checksums.
*/
public class C13FileChecksums extends C13Section {
private List<FileChecksum> fileChecksums = new ArrayList<>();
/**
* Parse and return a {@link C13FileChecksums}.
* @param reader {@link PdbByteReader} containing the symbol records to deserialize
* @param ignore flag indicating whether the record should be ignored
* @param monitor {@link TaskMonitor} used for checking cancellation
* @return the parsed data
* @throws PdbException Upon not enough data left to parse
* @throws CancelledException Upon user cancellation
*/
static C13FileChecksums parse(PdbByteReader reader, boolean ignore, TaskMonitor monitor)
throws PdbException, CancelledException {
return new C13FileChecksums(reader, ignore, monitor);
}
protected C13FileChecksums(PdbByteReader reader, boolean ignore, TaskMonitor monitor)
throws CancelledException, PdbException {
super(ignore);
while (reader.numRemaining() >= FileChecksum.getBaseRecordSize()) {
monitor.checkCanceled();
FileChecksum fileChecksum = new FileChecksum(reader);
fileChecksums.add(fileChecksum);
}
if (reader.hasMore()) {
Msg.debug(C13FileChecksums.class,
String.format("Num Extra C13FileChecksums bytes: %d", reader.numRemaining()));
}
}
public List<FileChecksum> getFileChecksums() {
return fileChecksums;
}
@Override
public String toString() {
return String.format(
"%s: num checksums = %d", getClass().getSimpleName(), fileChecksums.size());
}
/**
* Dumps this class to a Writer
* @param writer {@link Writer} to which to dump the information
* @throws IOException Upon IOException writing to the {@link Writer}
*/
@Override
void dump(Writer writer) throws IOException {
writer.write("C13FileChecksums--------------------------------------------\n");
for (FileChecksum checksum : fileChecksums) {
writer.write(checksum.toString());
writer.write('\n');
}
writer.write("End C13FileChecksums----------------------------------------\n");
}
static class FileChecksum {
private long offsetFilename; // unsigned 32-bit
private int length;
private int checksumTypeValue;
private byte[] bytes;
private static int getBaseRecordSize() {
return 6;
}
FileChecksum(PdbByteReader reader) throws PdbException {
offsetFilename = reader.parseUnsignedIntVal();
length = reader.parseUnsignedByteVal();
checksumTypeValue = reader.parseUnsignedByteVal();
bytes = reader.parseBytes(length);
reader.align4();
}
long getOffsetFilename() {
return offsetFilename;
}
long getLength() {
return length;
}
long getChecksumTypeValue() {
return checksumTypeValue;
}
byte[] getChecsumBytes() {
return bytes;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(String.format("0x%08x, 0x%02x %s(%02x): ", offsetFilename, length,
ChecksumType.fromValue(checksumTypeValue), checksumTypeValue));
builder.append(NumericUtilities.convertBytesToString(bytes));
return builder.toString();
}
}
private static enum ChecksumType {
UnknownChecksumType(-0x01),
NoneChecksumType(0x00),
Md5ChecksumType(0x01),
Sha1ChecksumType(0x02),
Sha256ChecksumType(0x03);
private static final Map<Integer, ChecksumType> BY_VALUE = new HashMap<>();
static {
for (ChecksumType val : values()) {
BY_VALUE.put(val.value, val);
}
}
private final int value;
public static ChecksumType fromValue(int val) {
ChecksumType t = BY_VALUE.getOrDefault(val, UnknownChecksumType);
if (t == UnknownChecksumType && val != UnknownChecksumType.value) {
Msg.warn(null,
String.format("PDB: C13FileChecksum - Unknown checksum type %08x", val));
}
return t;
}
private ChecksumType(int value) {
this.value = value;
}
}
}

View File

@ -0,0 +1,35 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import ghidra.util.task.TaskMonitor;
/**
* Class for C13Type FRAMEDATA.
* <p>
* This temporary class implementation currently extends {@link AbstractUnimplementedC13Section},
* but this should be changed to {@link C13Section} when the format is understood and the
* implementation is made concrete.
*/
class C13FrameData extends AbstractUnimplementedC13Section {
static C13FrameData parse(PdbByteReader reader, boolean ignore, TaskMonitor monitor) {
return new C13FrameData(reader, ignore, monitor);
}
protected C13FrameData(PdbByteReader reader, boolean ignore, TaskMonitor monitor) {
super(reader, ignore, monitor);
}
}

View File

@ -0,0 +1,35 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import ghidra.util.task.TaskMonitor;
/**
* Class for C13Type FUNC_MDTOKEN_MAP.
* <p>
* This temporary class implementation currently extends {@link AbstractUnimplementedC13Section},
* but this should be changed to {@link C13Section} when the format is understood and the
* implementation is made concrete.
*/
class C13FuncMdTokenMap extends AbstractUnimplementedC13Section {
static C13FuncMdTokenMap parse(PdbByteReader reader, boolean ignore, TaskMonitor monitor) {
return new C13FuncMdTokenMap(reader, ignore, monitor);
}
protected C13FuncMdTokenMap(PdbByteReader reader, boolean ignore, TaskMonitor monitor) {
super(reader, ignore, monitor);
}
}

View File

@ -0,0 +1,61 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* C13IlLines information. This is C13 IL Lines, where "IL" meaning is uncertain... could mean
* Incremental Link. MSFT defers parsing to C13Lines, so it is the same format, which we have
* given to a common parent, {@link AbstractC13Lines}.
*/
public class C13IlLines extends AbstractC13Lines {
/**
* Parse and return a {@link C13IlLines}.
* @param reader {@link PdbByteReader} containing the symbol records to deserialize
* @param ignore flag indicating whether the record should be ignored
* @param monitor {@link TaskMonitor} used for checking cancellation
* @return the parsed data
* @throws PdbException Upon not enough data left to parse
* @throws CancelledException Upon user cancellation
*/
static C13IlLines parse(PdbByteReader reader, boolean ignore, TaskMonitor monitor)
throws PdbException, CancelledException {
return new C13IlLines(reader, ignore, monitor);
}
protected C13IlLines(PdbByteReader reader, boolean ignore, TaskMonitor monitor)
throws PdbException, CancelledException {
super(reader, ignore, monitor);
}
/**
* Dumps this class to a Writer
* @param writer {@link Writer} to which to dump the information
* @throws IOException Upon IOException writing to the {@link Writer}
*/
@Override
void dump(Writer writer) throws IOException {
writer.write("C13IlLines--------------------------------------------------\n");
dumpInternal(writer);
writer.write("End C13IlLines----------------------------------------------\n");
}
}

View File

@ -0,0 +1,188 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* PDB C13InlineeLines information.
*/
public class C13InlineeLines extends C13Section {
// These are actually DWORDs, but we are ignoring the unsigned nature and using int.
private static final int InlineeSourceLineSignature = 0x0;
private static final int ExtendedInlineeSourceLineSignature = 0x1;
private int signature; //actually a DWORD (unsigned int)
private List<InlineeSourceLine> inlineeLines = new ArrayList<>();
/**
* Parse and return a {@link C13InlineeLines}.
* @param reader {@link PdbByteReader} containing the symbol records to deserialize
* @param ignore flag indicating whether the record should be ignored
* @param monitor {@link TaskMonitor} used for checking cancellation
* @return the parsed data
* @throws PdbException Upon not enough data left to parse
* @throws CancelledException Upon user cancellation
*/
static C13InlineeLines parse(PdbByteReader reader, boolean ignore, TaskMonitor monitor)
throws PdbException, CancelledException {
return new C13InlineeLines(reader, ignore, monitor);
}
private static List<InlineeSourceLine> parseInlineeLines(PdbByteReader reader,
TaskMonitor monitor) throws CancelledException, PdbException {
List<InlineeSourceLine> lines = new ArrayList<>();
while (reader.numRemaining() >= InlineeSourceLine.getBaseRecordSize()) {
monitor.checkCanceled();
InlineeSourceLine line = new InlineeSourceLine(reader);
lines.add(line);
}
return lines;
}
private static List<InlineeSourceLine> parseExtendedInlineeLines(PdbByteReader reader,
TaskMonitor monitor) throws CancelledException, PdbException {
List<InlineeSourceLine> lines = new ArrayList<>();
while (reader.numRemaining() >= ExtendedInlineeSourceLine.getBaseRecordSize()) {
monitor.checkCanceled();
ExtendedInlineeSourceLine line = new ExtendedInlineeSourceLine(reader, monitor);
lines.add(line);
}
return lines;
}
protected C13InlineeLines(PdbByteReader reader, boolean ignore, TaskMonitor monitor)
throws PdbException, CancelledException {
super(ignore);
signature = reader.parseInt(); //actually a DWORD (unsigned int)
switch (signature) {
case InlineeSourceLineSignature:
inlineeLines = parseInlineeLines(reader, monitor);
break;
case ExtendedInlineeSourceLineSignature:
inlineeLines = parseExtendedInlineeLines(reader, monitor);
break;
default:
inlineeLines = new ArrayList<>();
break;
}
if (reader.hasMore()) {
Msg.debug(C13InlineeLines.class,
String.format("Extra inlinee bytes remain for signature: 0x%03x", signature));
}
}
List<InlineeSourceLine> getInlineeLines() {
return inlineeLines;
}
@Override
public String toString() {
return String.format(
"%s: num inlinee lines = %d", getClass().getSimpleName(), inlineeLines.size());
}
/**
* Dumps this class to a Writer
* @param writer {@link Writer} to which to dump the information
* @throws IOException Upon IOException writing to the {@link Writer}
*/
@Override
void dump(Writer writer) throws IOException {
writer.write("C13InlineeLines---------------------------------------------\n");
writer.write(String.format("Signature: 0x%03x\n", signature));
for (InlineeSourceLine line : inlineeLines) {
writer.write(line.toString());
writer.write('\n');
}
writer.write("End C13InlineeLines-----------------------------------------\n");
}
static class InlineeSourceLine {
protected long inlinee; // unsigned 32-bit
protected int fileId;
protected int sourceLineNum;
private static int getBaseRecordSize() {
return 12;
}
InlineeSourceLine(PdbByteReader reader) throws PdbException {
inlinee = reader.parseUnsignedIntVal();
fileId = reader.parseInt();
sourceLineNum = reader.parseInt();
}
long getInlinee() {
return inlinee;
}
long getFileId() {
return fileId;
}
long getSourceLineNum() {
return sourceLineNum;
}
@Override
public String toString() {
return String.format("0x%09x, 0x%06x, %d", inlinee, fileId, sourceLineNum);
}
}
static class ExtendedInlineeSourceLine extends InlineeSourceLine {
private static int getBaseRecordSize() {
return 16;
}
private List<Integer> extraFileIds = new ArrayList<>(); // array of longs
ExtendedInlineeSourceLine(PdbByteReader reader, TaskMonitor monitor)
throws PdbException, CancelledException {
super(reader);
long numExtraFiles = reader.parseUnsignedIntVal(); // unsigned int
for (long i = 0; i < numExtraFiles; i++) {
monitor.checkCanceled();
extraFileIds.add(reader.parseInt());
}
}
int getNumExtraFileIds() {
return extraFileIds.size();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(String.format("0x%09x, 0x%06x, %d", inlinee, fileId, sourceLineNum));
for (Integer id : extraFileIds) {
builder.append(String.format(" 0x%06x", id));
}
return builder.toString();
}
}
}

View File

@ -0,0 +1,63 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* C13Lines information. As best as we know, only one of C11Lines or C13Lines (We have actually
* created a C13Section class at a higher level, and making C13Lines be the specific lines
* information for "type" 0xf2 (and maybe 0xf4) can be found after the symbol information in
* module debug streams.
*/
public class C13Lines extends AbstractC13Lines {
/**
* Parse and return a {@link C13Lines}.
* @param reader {@link PdbByteReader} containing the symbol records to deserialize
* @param ignore flag indicating whether the record should be ignored
* @param monitor {@link TaskMonitor} used for checking cancellation
* @return the parsed data
* @throws PdbException Upon not enough data left to parse
* @throws CancelledException Upon user cancellation
*/
static C13Lines parse(PdbByteReader reader, boolean ignore, TaskMonitor monitor)
throws PdbException, CancelledException {
return new C13Lines(reader, ignore, monitor);
}
protected C13Lines(PdbByteReader reader, boolean ignore, TaskMonitor monitor)
throws PdbException, CancelledException {
super(reader, ignore, monitor);
}
/**
* Dumps this class to a Writer
* @param writer {@link Writer} to which to dump the information
* @throws IOException Upon IOException writing to the {@link Writer}
*/
@Override
void dump(Writer writer) throws IOException {
writer.write("C13Lines----------------------------------------------------\n");
dumpInternal(writer);
writer.write("End C13Lines------------------------------------------------\n");
}
}

View File

@ -0,0 +1,37 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import ghidra.util.task.TaskMonitor;
/**
* Class for C13Type MERGED_ASSEMBLY_INPUT.
* <p>
* This temporary class implementation currently extends {@link AbstractUnimplementedC13Section},
* but this should be changed to {@link C13Section} when the format is understood and the
* implementation is made concrete.
*/
class C13MergedAssemblyInput extends AbstractUnimplementedC13Section {
static C13MergedAssemblyInput parse(PdbByteReader reader, boolean ignore,
TaskMonitor monitor) {
return new C13MergedAssemblyInput(reader, ignore, monitor);
}
protected C13MergedAssemblyInput(PdbByteReader reader, boolean ignore,
TaskMonitor monitor) {
super(reader, ignore, monitor);
}
}

View File

@ -0,0 +1,95 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* Abstract class for C13 section types.
*/
abstract class C13Section {
protected static final String dashes =
"------------------------------------------------------------\n";
private boolean ignore;
protected C13Section(boolean ignore) {
this.ignore = ignore;
}
boolean ignore() {
return ignore;
}
void dump(Writer writer) throws IOException {
String n = getClass().getSimpleName();
int len = n.length();
writer.write(n + dashes.substring(len));
writer.write("End " + n + dashes.substring(len + 4));
}
/**
* Parse and return a {@link C13Section} of a specific type pointed to by a section record.
* @param reader reader to parse from
* @param monitor {@link TaskMonitor} used for checking cancellation
* @return the parsed data
* @throws PdbException Upon not enough data left to parse
* @throws CancelledException Upon user cancellation
*/
static C13Section parse(PdbByteReader reader, TaskMonitor monitor)
throws CancelledException, PdbException {
int typeVal = reader.parseInt();
boolean ignore = C13Type.ignore(typeVal);
C13Type type = C13Type.fromValue(typeVal);
int length = reader.parseInt();
PdbByteReader recordReader = reader.getSubPdbByteReader(length);
switch (type) {
case SYMBOLS:
return C13Symbols.parse(recordReader, ignore, monitor);
case LINES:
return C13Lines.parse(recordReader, ignore, monitor);
case STRING_TABLE:
return C13StringTable.parse(recordReader, ignore, monitor);
case FILE_CHECKSUMS:
return C13FileChecksums.parse(recordReader, ignore, monitor);
case FRAMEDATA:
return C13FrameData.parse(recordReader, ignore, monitor);
case INLINEE_LINES:
return C13InlineeLines.parse(recordReader, ignore, monitor);
case CROSS_SCOPE_IMPORTS:
return C13CrossScopeImports.parse(recordReader, ignore, monitor);
case CROSS_SCOPE_EXPORTS:
return C13CrossScopeExports.parse(recordReader, ignore, monitor);
case IL_LINES:
return C13IlLines.parse(recordReader, ignore, monitor);
case FUNC_MDTOKEN_MAP:
return C13FuncMdTokenMap.parse(recordReader, ignore, monitor);
case TYPE_MDTOKEN_MAP:
return C13TypeMdTokenMap.parse(recordReader, ignore, monitor);
case MERGED_ASSEMBLY_INPUT:
return C13MergedAssemblyInput.parse(recordReader, ignore, monitor);
case COFF_SYMBOL_RVA: // Relative Virtual Address
return C13CoffSymbolRva.parse(recordReader, ignore, monitor);
default:
return UnknownC13Section.parse(recordReader, ignore, monitor);
}
}
}

View File

@ -0,0 +1,122 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.util.NoSuchElementException;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* Iterator for {@link C13Section} data being read from C13 section of module stream.
* @param <T> the iterator type
*/
class C13SectionIterator<T extends C13Section> implements ParsingIterator<T> {
private PdbByteReader reader;
private Class<T> clazz;
private boolean processIgnore;
private TaskMonitor monitor;
private C13Type requestedType;
private C13Type detectedType; // section type detected
private T currentSection = null;
/**
* An Iterator of C13 Section types
* @param reader PdbByteReader containing only C13 Section information and in newly
* constructed state
* @param clazz the class of the iterator type
* @param processIgnore processes records marked as ignore
* @param monitor {@link TaskMonitor} used for checking user cancellation
* @throws CancelledException upon user cancellation
*/
public C13SectionIterator(PdbByteReader reader, Class<T> clazz, boolean processIgnore,
TaskMonitor monitor) throws CancelledException {
this.reader = reader;
this.clazz = clazz;
this.requestedType = C13Type.fromClassValue(clazz);
this.processIgnore = processIgnore;
this.monitor = monitor;
}
@Override
public boolean hasNext() throws CancelledException {
if (currentSection == null) {
find();
}
return (currentSection != null);
}
@Override
public T next() throws CancelledException, NoSuchElementException {
if (hasNext()) {
T returnSection = currentSection;
currentSection = null;
return returnSection;
}
throw new NoSuchElementException("next() called with no more elements");
}
@Override
public T peek() throws CancelledException, NoSuchElementException {
if (hasNext()) {
return currentSection;
}
throw new NoSuchElementException("peek() called with no more elements");
}
private void find() throws CancelledException {
try {
currentSection = findAndParse();
}
catch (PdbException e) {
Msg.error(this, "Problem seen in find()", e);
currentSection = null;
}
}
/**
* Finds and parses the next C13 Section type requested
* @return the found and parsed element. Can be null if not found
* @throws CancelledException upon user cancellation
* @throws PdbException upon problem parsing data
*/
public T findAndParse() throws CancelledException, PdbException {
while (reader.hasMore()) {
monitor.checkCanceled();
int index = reader.getIndex();
int typeVal = reader.parseInt();
boolean ignore = C13Type.ignore(typeVal);
detectedType = C13Type.fromValue(typeVal);
int len = reader.parseInt();
if ((!ignore || processIgnore) &&
(requestedType == C13Type.ALL || detectedType == requestedType)) {
reader.setIndex(index);
C13Section parsedSection = C13Section.parse(reader, monitor);
return (parsedSection.getClass().equals(clazz) ||
C13Section.class.equals(clazz))
? clazz.cast(parsedSection)
: null;
}
reader.skip(len);
}
return null;
}
}

View File

@ -0,0 +1,35 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import ghidra.util.task.TaskMonitor;
/**
* Class for C13Type STRING_TABLE.
* <p>
* This temporary class implementation currently extends {@link AbstractUnimplementedC13Section},
* but this should be changed to {@link C13Section} when the format is understood and the
* implementation is made concrete.
*/
class C13StringTable extends AbstractUnimplementedC13Section {
static C13StringTable parse(PdbByteReader reader, boolean ignore, TaskMonitor monitor) {
return new C13StringTable(reader, ignore, monitor);
}
protected C13StringTable(PdbByteReader reader, boolean ignore, TaskMonitor monitor) {
super(reader, ignore, monitor);
}
}

View File

@ -0,0 +1,35 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import ghidra.util.task.TaskMonitor;
/**
* Class for C13Type SYMBOLS.
* <p>
* This temporary class implementation currently extends {@link AbstractUnimplementedC13Section},
* but this should be changed to {@link C13Section} when the format is understood and the
* implementation is made concrete.
*/
class C13Symbols extends AbstractUnimplementedC13Section {
static C13Symbols parse(PdbByteReader reader, boolean ignore, TaskMonitor monitor) {
return new C13Symbols(reader, ignore, monitor);
}
protected C13Symbols(PdbByteReader reader, boolean ignore, TaskMonitor monitor) {
super(reader, ignore, monitor);
}
}

View File

@ -0,0 +1,128 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.util.HashMap;
import java.util.Map;
import ghidra.util.Msg;
/**
* Enum storing the type value of C13 Section along with the class of the section implementation.
* The value is what will be parsed prior to the rest of record that will be parsed according to
* its type. The class information is available to ensure proper casting to the type specified.
* <p>
* Note that we have created two additional enumerates: one for values that don't match in the
* {@link #fromValue(int)} method and can typically be used default switch cases. The other
* is used to "select" ALL standard C13 Section types when used appropriately. Of course, there
* is a chance that the enumerate values we have chosen for these could cause an unforeseen
* problem, but we tried to choose values that will not be problematic.
* <p>
* Note that lookups by value mask off an "ignore" bit, and since we are an enum, we cannot store
* the fact of ignore or not unless we double the number of enumerates.
* However, we have incorporated a utility method testing the "ignore" value on the parsed value
* prior to doing the lookup of with the {@link #fromValue(int)} method.
*/
enum C13Type {
UNKNOWN(0x80000000, UnknownC13Section.class), // We created; fix/eliminate if causes problems
ALL(0x00000000, C13Section.class), // We created; fix if causes problems
SYMBOLS(0xf1, C13Symbols.class),
LINES(0xf2, C13Lines.class),
STRING_TABLE(0xf3, C13StringTable.class),
FILE_CHECKSUMS(0xf4, C13FileChecksums.class),
FRAMEDATA(0xf5, C13FrameData.class),
INLINEE_LINES(0xf6, C13InlineeLines.class),
CROSS_SCOPE_IMPORTS(0xf7, C13CrossScopeImports.class),
CROSS_SCOPE_EXPORTS(0xf8, C13CrossScopeExports.class),
IL_LINES(0xf9, C13IlLines.class),
FUNC_MDTOKEN_MAP(0xfa, C13FuncMdTokenMap.class),
TYPE_MDTOKEN_MAP(0xfb, C13TypeMdTokenMap.class),
MERGED_ASSEMBLY_INPUT(0xfc, C13MergedAssemblyInput.class),
COFF_SYMBOL_RVA(0xfd, C13CoffSymbolRva.class);
private static final int IGNORE_BIT = 0x80000000;
private static final int IGNORE_BIT_MASK = ~IGNORE_BIT;
private static final Map<Integer, C13Type> BY_VALUE = new HashMap<>();
private static final Map<Class<? extends C13Section>, C13Type> BY_CLASS_VALUE = new HashMap<>();
static {
for (C13Type val : values()) {
BY_VALUE.put(val.value, val);
BY_CLASS_VALUE.put(val.classValue, val);
}
}
private final int value;
private final Class<? extends C13Section> classValue;
/**
* Returns the C13Type corresponding to the parse value for the C13 Section type.
* @param val the parse value
* @return the C13Type
*/
public static C13Type fromValue(int val) {
C13Type t = BY_VALUE.getOrDefault(maskIgnore(val), UNKNOWN);
if (t == UNKNOWN) {
Msg.debug(C13Type.class, String.format("C13Debug - Unknown section type %08x", val));
}
return t;
}
/**
* Returns the C13Type which has the (parse) value that is used to identify a section of the
* type specified by the {@code classVal} parameter
* @param classVal the implementation class we are need
* @return the C13Type for this type
*/
public static C13Type fromClassValue(Class<? extends C13Section> classVal) {
C13Type t = BY_CLASS_VALUE.getOrDefault(classVal, UNKNOWN);
if (t == UNKNOWN) {
Msg.debug(C13Type.class,
String.format("C13Debug - Unknown classValue %s", classVal.getSimpleName()));
}
return t;
}
public static boolean ignore(int val) {
return ((val & IGNORE_BIT) != 0);
}
public static int maskIgnore(int val) {
return val & IGNORE_BIT_MASK;
}
private C13Type(int value, Class<? extends C13Section> classValue) {
this.value = value;
this.classValue = classValue;
}
/**
* Returns the value of the enum
* @return the value
*/
public int getValue() {
return value;
}
/**
* Returns the Class that is associated with the enum
* @return the Class
*/
public Class<? extends C13Section> getSectionClass() {
return classValue;
}
}

View File

@ -0,0 +1,35 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import ghidra.util.task.TaskMonitor;
/**
* Class for C13Type TYPE_MDTOKEN_MAP.
* <p>
* This temporary class implementation currently extends {@link AbstractUnimplementedC13Section},
* but this should be changed to {@link C13Section} when the format is understood and the
* implementation is made concrete.
*/
class C13TypeMdTokenMap extends AbstractUnimplementedC13Section {
static C13TypeMdTokenMap parse(PdbByteReader reader, boolean ignore, TaskMonitor monitor) {
return new C13TypeMdTokenMap(reader, ignore, monitor);
}
protected C13TypeMdTokenMap(PdbByteReader reader, boolean ignore, TaskMonitor monitor) {
super(reader, ignore, monitor);
}
}

View File

@ -0,0 +1,114 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.util.NoSuchElementException;
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* Iterator for Global Reference Offsets section of module stream. This iterator returns
* an {@link AbstractMsSymbol} iterator from the global symbols section that has been initialized
* with the offset specified in this modules global reference offset section.
*/
class GlobalReferenceIterator implements ParsingIterator<MsSymbolIterator> {
private AbstractPdb pdb;
private int symbolsStreamNumber;
private TaskMonitor monitor;
private GlobalReferenceOffsetIterator offsetIterator = null;
private MsSymbolIterator currentGlobalSymbolIterator = null;
/**
* An Iterator of Global Reference Symbol Iterators (iterator of iterators).
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed
* @param reader PdbByteReader containing only Global Reference Offsets information and in
* newly constructed state
* @param monitor {@link TaskMonitor} used for checking user cancellation
* @throws CancelledException upon user cancellation
* @throws PdbException Upon not enough data left to parse
*/
public GlobalReferenceIterator(AbstractPdb pdb, PdbByteReader reader, TaskMonitor monitor)
throws CancelledException, PdbException {
this.pdb = pdb;
this.monitor = monitor;
PdbDebugInfo debugInfo = pdb.getDebugInfo();
if (debugInfo == null) {
throw new PdbException(
"Cannot create " + getClass() + " because PDB Debug Info is null");
}
symbolsStreamNumber = debugInfo.getSymbolRecordsStreamNumber();
if (symbolsStreamNumber == 0xffff) {
throw new PdbException(
"Cannot create " + getClass() + " because there is no symbol stream");
}
offsetIterator = new GlobalReferenceOffsetIterator(reader);
}
@Override
public boolean hasNext() throws CancelledException {
if (currentGlobalSymbolIterator == null) {
find();
}
return (currentGlobalSymbolIterator != null);
}
@Override
public MsSymbolIterator next() throws CancelledException, NoSuchElementException {
if (hasNext()) {
MsSymbolIterator returnGlobalSymbolIterator = currentGlobalSymbolIterator;
currentGlobalSymbolIterator = null;
return returnGlobalSymbolIterator;
}
throw new NoSuchElementException("next() called with no more elements");
}
@Override
public MsSymbolIterator peek() throws CancelledException, NoSuchElementException {
if (hasNext()) {
return currentGlobalSymbolIterator;
}
throw new NoSuchElementException("peek() called with no more elements");
}
private void find() throws CancelledException {
if (!offsetIterator.hasNext()) {
currentGlobalSymbolIterator = null;
return;
}
try {
Long offset = offsetIterator.next();
PdbByteReader reader =
pdb.getReaderForStreamNumber(symbolsStreamNumber, offset.intValue(),
MsfStream.MAX_STREAM_LENGTH, monitor);
currentGlobalSymbolIterator = new MsSymbolIterator(pdb, reader);
}
catch (IOException e) {
Msg.error(this, "Problem seen in find()", e);
currentGlobalSymbolIterator = null;
}
}
}

View File

@ -0,0 +1,94 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.util.NoSuchElementException;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
/**
* Iterator for Global Reference Offsets section of module stream.
*/
class GlobalReferenceOffsetIterator implements ParsingIterator<Long> {
private PdbByteReader reader;
private Long currentGlobalReferenceOffset = null;
/**
* An Iterator of Global Reference Offsets
* @param reader PdbByteReader containing only Global Reference Offsets information and in
* newly constructed state
* @throws CancelledException upon user cancellation
* @throws PdbException Upon not enough data left to parse
*/
public GlobalReferenceOffsetIterator(PdbByteReader reader)
throws CancelledException, PdbException {
this.reader = reader;
processHeader();
}
@Override
public boolean hasNext() {
if (currentGlobalReferenceOffset == null) {
find();
}
return (currentGlobalReferenceOffset != null);
}
@Override
public Long next() throws NoSuchElementException {
if (hasNext()) {
Long returnGlobalReferenceOffset = currentGlobalReferenceOffset;
currentGlobalReferenceOffset = null;
return returnGlobalReferenceOffset;
}
throw new NoSuchElementException("next() called with no more elements");
}
@Override
public Long peek() throws NoSuchElementException {
if (hasNext()) {
return currentGlobalReferenceOffset;
}
throw new NoSuchElementException("peek() called with no more elements");
}
private void find() {
try {
currentGlobalReferenceOffset = reader.parseUnsignedIntVal();
}
catch (PdbException e) {
Msg.error(this, "Problem seen in find()", e);
currentGlobalReferenceOffset = null;
}
}
/**
* Reads and validates size field; leaves reader pointing at first record.
* @throws PdbException Upon not enough data left to parse
*/
private void processHeader() throws PdbException {
int sizeField = reader.parseInt();
if (sizeField + 4 != reader.getLimit()) {
throw new PdbException(
String.format("Error in module global refs size field: %d != %d", sizeField,
reader.getLimit()));
}
}
}

View File

@ -0,0 +1,435 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.msf.MsfStream;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* <B> Note that this class is new, in-progress creation, being designed as a better interface for
* getting information for any particular module (stream) in a more random-access manner.</B>
* <P>
* This class represents Module Stream data of a PDB file. This is different from the
* {@link AbstractModuleInformation} and children classes that are parsed from the DBI stream,
* which describes (or is control information for) what is the stream from which this
* {@link Module} is parsed. Note that we use the {@link AbstractModuleInformation} as one of
* the construction parameter to this class.
* <P>
* This class is only suitable for reading; not for writing or modifying a PDB.
* <P>
* We have intended to implement according to the Microsoft PDB API (source); see the API for
* truth.
*/
public class Module {
private AbstractPdb pdb;
private AbstractModuleInformation moduleInformation;
private TaskMonitor monitor;
private int streamNumber;
private MsfStream stream = null;
private int offsetSymbols;
private int offsetLines;
private int offsetC13Lines;
private int offsetGlobalRefs;
private int sizeSymbols;
private int sizeLines;
private int sizeC13Lines;
private int sizeGlobalRefs;
private boolean doDumpGlobalRefererenceInfo = false;
//==============================================================================================
public Module(AbstractPdb pdb, AbstractModuleInformation moduleInformation,
TaskMonitor monitor) {
Objects.requireNonNull(pdb, "pdb cannot be null");
Objects.requireNonNull(moduleInformation, "moduleInformation cannot be null");
this.pdb = pdb;
this.moduleInformation = moduleInformation;
this.monitor = monitor;
precalculateStreamLocations();
}
public AbstractModuleInformation getModuleInformation() {
return moduleInformation;
}
private void precalculateStreamLocations() {
streamNumber = moduleInformation.getStreamNumberDebugInformation();
if (streamNumber == 0xffff) {
return;
}
stream = pdb.getMsf().getStream(streamNumber);
if (stream == null) {
return;
}
int length = stream.getLength();
sizeSymbols = moduleInformation.getSizeLocalSymbolsDebugInformation();
sizeLines = moduleInformation.getSizeLineNumberDebugInformation();
sizeC13Lines = moduleInformation.getSizeC13StyleLineNumberInformation();
offsetSymbols = 0;
offsetLines = sizeSymbols;
offsetC13Lines = offsetLines + sizeLines;
offsetGlobalRefs = offsetC13Lines + sizeC13Lines;
// Note that sizeGlobalRefs includes the size field found within the stream and the field
// should have a value that is 4 less than this size here. Note that if additional
// data is added to this stream by MSFT after these global at a future date, then this
// calculation will not be correct.
sizeGlobalRefs = length - offsetGlobalRefs;
}
//==============================================================================================
/**
* Return the C11 Lines for this Module
* @return the C11 Lines
* @throws CancelledException upon user cancellation
* @throws PdbException upon issue reading this Module's stream
*/
public C11Lines getLineInformation()
throws CancelledException, PdbException {
if (sizeLines == 0) {
return null;
}
try {
PdbByteReader reader =
pdb.getReaderForStreamNumber(streamNumber, offsetLines, sizeLines,
monitor);
// This parser has not been tested with real data
C11Lines c11Lines = C11Lines.parse(pdb, reader, monitor);
return c11Lines;
}
catch (IOException e) {
return null;
}
}
//==============================================================================================
/**
* Returns an MsSymbolIterator for the symbols of this module
* @return the iterator
* @throws CancelledException upon user cancellation
* @throws PdbException upon invalid cvSignature
*/
public MsSymbolIterator getSymbolIterator() throws CancelledException, PdbException {
PdbByteReader symbolsReader = getSymbolsReader();
parseSignature(symbolsReader);
MsSymbolIterator iterator = new MsSymbolIterator(pdb, symbolsReader);
return iterator;
}
private void parseSignature(PdbByteReader symbolsReader) throws PdbException {
if (symbolsReader == PdbByteReader.DUMMY) {
return; // DUMMY is empty.
}
// cvSignature:
// >64K = C6
// 1 = C7
// 2 = C11 (vc5.x)
// 3 = ??? (not specified, and not marked as reserved)
// 4 = C13 (vc7.x)
// 5-64K = RESERVED
//
// Both cvdump (1660 and 1668) and mod.cpp (575) seem to indicate that the first module
// might have the cvSignature of C7 or C11 (when C7/C11), but modules thereafter will not
// or may not have the value. C13 would always have the C13 signature.
// NOTE: the following logic was originally intended for when processing multiple modules,
// back-to-back. It won't work here, as the getSig value is not retained. Thing is, we
// have no real data to test the questionable requirement (what we think was in MSFT
// design) at this time.
boolean getSig = true;
int cvSignature = 0;
if (getSig) {
cvSignature = symbolsReader.parseInt();
}
switch (cvSignature) {
case 1:
case 2:
// We have no 1,2 examples to test this logic for cvSignature. Confirming
// or rejecting this logic is important for simplifying/refactoring this
// method or writing new methods to allow for extraction of information from
// individual modules. The current implementation has cross-module logic
// (setting state in the processing of the first and using this state in the
// processing of follow-on modules).
getSig = false;
break;
case 4:
break;
default:
if (cvSignature < 0x10000) {
throw new PdbException(
"PDB Error: Invalid module CV signature in stream " + streamNumber);
}
break;
}
}
//==============================================================================================
/**
* Returns a C13SectionIterator that iterators over all C13Sections of this module
* @return the iterator
* @throws CancelledException upon user cancellation
* @throws PdbException Upon not enough data left to parse
*/
public C13SectionIterator<C13Section> getC13SectionIterator()
throws CancelledException, PdbException {
C13SectionIterator<C13Section> iterator = getC13SectionFilteredIterator(C13Section.class);
return iterator;
}
/**
* Returns a C13SectionIterator that iterators over all filtered C13Sections of this module
* @param clazz The class of the filter type
* @return the iterator
* @throws CancelledException upon user cancellation
* @throws PdbException Upon not enough data left to parse
*/
public <T extends C13Section> C13SectionIterator<T> getC13SectionFilteredIterator(
Class<T> clazz) throws CancelledException, PdbException {
PdbByteReader c13SectionReader = getC13LinesReader();
C13SectionIterator<T> iterator =
new C13SectionIterator<>(c13SectionReader, clazz, true, monitor);
return iterator;
}
//==============================================================================================
/**
* Returns a GlobalReferenceOffsetIterator, but note that there is no determined end for
* iteration other than running out of data... it is very unlikely that it should be iterated
* until it is out of data. Context should probably be used. For instance, if the global
* symbol that is first in this iterator is a GPROC32, then it should probably be iterated over
* nested blocks until the closing END is found for the GPROC32
* @return the iterator
* @throws CancelledException upon user cancellation
* @throws PdbException Upon not enough data left to parse
*/
public GlobalReferenceOffsetIterator getGlobalReferenceOffsetIterator()
throws CancelledException, PdbException {
PdbByteReader globalRefsReader = getGlobalRefsReader();
GlobalReferenceOffsetIterator iterator =
new GlobalReferenceOffsetIterator(globalRefsReader);
return iterator;
}
//==============================================================================================
/**
* Returns a GlobalReferenceIterator. Iterations of the GlobalReferenceIterator returns
* new MsSymbolIterators, but note that there is no determined end for each MsSymbolIterator
* other than running out of data... it is very unlikely that it should be iterated until
* it is out of data. Context should probably be used. For instance, if the global symbol
* that is first in this iterator is a GPROC32, then it should probably be iterated over
* nested blocks until the closing END is found for the GPROC32
* @return the iterator
* @throws CancelledException upon user cancellation
* @throws PdbException Upon not enough data left to parse
*/
public GlobalReferenceIterator getGlobalReferenceIterator()
throws CancelledException, PdbException {
PdbByteReader globalRefsReader = getGlobalRefsReader();
GlobalReferenceIterator iterator =
new GlobalReferenceIterator(pdb, globalRefsReader, monitor);
return iterator;
}
//==============================================================================================
private PdbByteReader getSymbolsReader() throws CancelledException {
return getReader(offsetSymbols, sizeSymbols, "Symbols");
}
// Not yet used, but intended for when we change C11 Lines to the iterator model.
@SuppressWarnings("unused")
private PdbByteReader getLinesReader() throws CancelledException {
return getReader(offsetLines, sizeLines, "Lines");
}
private PdbByteReader getC13LinesReader() throws CancelledException {
return getReader(offsetC13Lines, sizeC13Lines,
"C13Lines");
}
private PdbByteReader getGlobalRefsReader() throws CancelledException {
return getReader(offsetGlobalRefs, sizeGlobalRefs, "GlobalRefs");
}
private PdbByteReader getReader(int offset, int size, String sectionName)
throws CancelledException {
if (streamNumber == 0xffff) {
return PdbByteReader.DUMMY;
}
try {
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
reader.skip(offset);
try {
if (size == -1) {
size = reader.parseInt();
}
if (size == 0) {
return PdbByteReader.DUMMY;
}
return reader.getSubPdbByteReader(size);
}
catch (PdbException e) {
PdbLog.message("Exception retrieving PdbByteReader for stream " + streamNumber +
" sectionName: " + e.getMessage());
return PdbByteReader.DUMMY;
}
}
catch (IOException e) {
PdbLog.message("Exception sub-reader from reader for stream " + streamNumber +
" sectionName: " + e.getMessage());
return PdbByteReader.DUMMY;
}
}
//==============================================================================================
// Note that we are slowly changing the model to an iterator model so that not everything
// is loaded into the class (note that as of this writing, the PdbByteReader still contains
// full byte array of data, consuming memory at the time of use).
/**
* Dumps this class to a Writer.
* @param writer {@link Writer} to which to dump the information
* @throws PdbException Upon not enough data left to parse
* @throws CancelledException Upon user cancellation
* @throws IOException Upon IOException writing to the {@link Writer}
*/
void dump(Writer writer)
throws CancelledException, PdbException, IOException {
writer.write("Module------------------------------------------------------\n");
dumpSymbols(writer);
dumpC11Lines(writer);
dumpC13Sections(writer);
// These can add tons of output, so have a flag to control whether they are output.
if (doDumpGlobalRefererenceInfo) {
dumpGlobalReferenceOffsets(writer);
dumpGlobalReferences(writer);
}
writer.write("End Module--------------------------------------------------\n");
}
private void dumpSymbols(Writer writer)
throws IOException, CancelledException, PdbException {
writer.write("Symbols-----------------------------------------------------\n");
MsSymbolIterator symbolIterator = getSymbolIterator();
while (symbolIterator.hasNext()) {
AbstractMsSymbol symbol = symbolIterator.next();
writer.append(symbol.toString());
}
writer.write("End Symbols-------------------------------------------------\n");
}
private void dumpC11Lines(Writer writer)
throws IOException, CancelledException, PdbException {
// Need to confirm C11 parsing and then convert it to an Iterator model; would be very
// helpful to find some real data
writer.write("C11Lines----------------------------------------------------\n");
C11Lines c11lines = getLineInformation();
if (c11lines != null) {
writer.write(c11lines.dump());
}
writer.write("End C11Lines------------------------------------------------\n");
}
private void dumpC13Sections(Writer writer)
throws IOException, CancelledException, PdbException {
writer.write("C13Sections-------------------------------------------------\n");
C13SectionIterator<C13Section> c13Iterator =
getC13SectionFilteredIterator(C13Section.class);
while (c13Iterator.hasNext()) {
C13Section c13Section = c13Iterator.next();
c13Section.dump(writer);
}
writer.write("End C13Sections---------------------------------------------\n");
// These are here as examples of what we might output in the future... the C13 types
// in a type-by-type basis, including Dummy types.
// C13SectionIterator<DummyC13Symbols> c13SymbolsIterator =
// getC13SectionFilteredIterator(DummyC13Symbols.class);
// while (c13SymbolsIterator.hasNext()) {
// DummyC13Symbols dummyC13Symbols = c13SymbolsIterator.next();
// dummyC13Symbols.dump(writer);
// }
//
// C13SectionIterator<C13Lines> c13LinesIterator =
// getC13SectionFilteredIterator(C13Lines.class);
// while (c13LinesIterator.hasNext()) {
// C13Lines myC13Lines = c13LinesIterator.next();
// myC13Lines.dump(writer);
// }
}
// Need to confirm the global ref offsets and symbols by "study."
private void dumpGlobalReferenceOffsets(Writer writer)
throws IOException, CancelledException, PdbException {
writer.write("GlobalReferenceSymbolOffsets--------------------------------\n");
List<Long> tmp = new ArrayList<>();
GlobalReferenceOffsetIterator globalRefsOffsetIterator =
getGlobalReferenceOffsetIterator();
while (globalRefsOffsetIterator.hasNext()) {
Long val = globalRefsOffsetIterator.next();
writer.append(String.format("0x%08x\n", val));
tmp.add(val);
}
int cnt = 0;
GlobalReferenceOffsetIterator globalReferenceOffsetIterator =
getGlobalReferenceOffsetIterator();
while (globalReferenceOffsetIterator.hasNext()) {
long val = globalReferenceOffsetIterator.next();
long val2 = tmp.get(cnt++);
if (val != val2) {
int a = 1;
a = a + 1;
}
}
writer.write("End GlobalReferenceSymbolOffsets----------------------------\n");
}
// Need to confirm the global ref offsets and symbols by "study."
private void dumpGlobalReferences(Writer writer)
throws IOException, CancelledException, PdbException {
writer.write("GlobalReferenceSymbols--------------------------------------\n");
GlobalReferenceIterator globalReferenceIterator =
getGlobalReferenceIterator();
while (globalReferenceIterator.hasNext()) {
MsSymbolIterator symIter = globalReferenceIterator.next();
if (symIter.hasNext()) {
AbstractMsSymbol sym = symIter.next();
writer.append(String.format("%s\n", sym.toString()));
}
else {
writer.append("No sym in MsSymIterator returned by GlobalReferensIterator\n");
}
}
writer.write("End GlobalReferenceSymbols----------------------------------\n");
}
}

View File

@ -15,24 +15,16 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.util.Objects;
/**
* This class is the version of {@link AbstractModuleInformation} for Microsoft v5.00 PDB.
*/
public class ModuleInformation500 extends AbstractModuleInformation {
//==============================================================================================
// Internals
//==============================================================================================
private AbstractPdb pdb;
//==============================================================================================
// API
//==============================================================================================
public ModuleInformation500(AbstractPdb pdb) {
Objects.requireNonNull(pdb, "pdb cannot be null");
this.pdb = pdb;
super(pdb);
sectionContribution = new SectionContribution400();
}

View File

@ -15,24 +15,16 @@
*/
package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.util.Objects;
/**
* This class is the version of {@link AbstractModuleInformation} for Microsoft v6.00 PDB.
*/
public class ModuleInformation600 extends AbstractModuleInformation {
//==============================================================================================
// Internals
//==============================================================================================
private AbstractPdb pdb;
//==============================================================================================
// API
//==============================================================================================
public ModuleInformation600(AbstractPdb pdb) {
Objects.requireNonNull(pdb, "pdb cannot be null");
this.pdb = pdb;
super(pdb);
sectionContribution = new SectionContribution600();
}

View File

@ -0,0 +1,85 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.util.NoSuchElementException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
/**
* Iterator for {@link AbstractMsSymbol AbstractMsSymbols} being read from a stream.
*/
class MsSymbolIterator implements ParsingIterator<AbstractMsSymbol> {
private AbstractPdb pdb;
private PdbByteReader reader;
private AbstractMsSymbol currentSymbol = null;
/**
* Constructor.
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed
* @param reader for the stream section containing the symbol information
* @throws CancelledException upon user cancellation
*/
public MsSymbolIterator(AbstractPdb pdb, PdbByteReader reader) throws CancelledException {
this.pdb = pdb;
this.reader = reader;
}
@Override
public boolean hasNext() throws CancelledException {
if (currentSymbol == null) {
find();
}
return (currentSymbol != null);
}
@Override
public AbstractMsSymbol next() throws CancelledException, NoSuchElementException {
if (hasNext()) {
AbstractMsSymbol returnSymbol = currentSymbol;
currentSymbol = null;
return returnSymbol;
}
throw new NoSuchElementException("next() called with no more elements");
}
@Override
public AbstractMsSymbol peek() throws CancelledException, NoSuchElementException {
if (hasNext()) {
return currentSymbol;
}
throw new NoSuchElementException("peek() called with no more elements");
}
private void find() throws CancelledException {
if (!reader.hasMore()) {
currentSymbol = null;
return;
}
try {
currentSymbol = SymbolParser.parseLengthAndSymbol(pdb, reader);
}
catch (PdbException e) {
Msg.error(this, "Problem seen in find()", e);
currentSymbol = null;
}
}
}

View File

@ -0,0 +1,59 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import java.util.NoSuchElementException;
import ghidra.util.exception.CancelledException;
/**
* Parsing Iterator, which allows CancelledException.
* <p>
* Has {@link #hasNext()} and {@link #next()}.
* <p>
* Also has {@link #peek()}, which performs the same operation as {@link #next()} without advancing
* the iterator.
* <p>
* Does not have {@code remove()} and {@code forEachRemaining()} that are in {@code Iterator}.
* <p>
*@param <E> the iterator type
*/
interface ParsingIterator<E> {
/**
* Returns {@code true} if more elements exist
* @return {@code true} if more elements exist
* @throws CancelledException upon user cancellation
*/
boolean hasNext() throws CancelledException;
/**
* Returns the next element in the iteration.
* @return the next element in the iteration
* @throws CancelledException upon user cancellation
* @throws NoSuchElementException if the iteration has no more elements
*/
E next() throws CancelledException, NoSuchElementException;
/**
* Returns the next element in the iteration without advancing the iterator.
* @return the next element in the iteration
* @throws CancelledException upon user cancellation
* @throws NoSuchElementException if the iteration has no more elements
*/
E peek() throws CancelledException, NoSuchElementException;
}

View File

@ -39,10 +39,12 @@ import ghidra.util.LittleEndianDataConverter;
*
* <P>Other utility methods exist for setting/getting the {@code index} or for moving the
* {@code index} along to align or pad-out according to how a C/C++ structure would be padded in
* memory.
* memory.
*/
public class PdbByteReader {
public static final PdbByteReader DUMMY = new PdbByteReader(new byte[] {});
//==============================================================================================
// Internals
//==============================================================================================

View File

@ -73,6 +73,12 @@ public abstract class PdbDebugInfo {
protected GlobalSymbolInformation globalSymbolInformation;
protected PublicSymbolInformation publicSymbolInformation;
//==============================================================================================
// NEW STUFF FROM REFACTOR/REWORK (can be duplicative with other stuff)... might be turned off
// during development.
private boolean doNewStuff = false;
private List<Module> modules = new ArrayList<>();
//==============================================================================================
// API
//==============================================================================================
@ -100,7 +106,7 @@ public abstract class PdbDebugInfo {
/**
* Deserializes the {@link PdbDebugInfo}-based instance.
* The pdb is updated with dbiAge and targetProcessor during deserialization
* The PDB is updated with dbiAge and targetProcessor during deserialization
* of new DBI header.
* @param headerOnly if true only the DBI header fields will be parsed
* @param monitor {@link TaskMonitor} used for checking cancellation.
@ -122,6 +128,12 @@ public abstract class PdbDebugInfo {
deserializeHeader(reader);
deserializeInternalSubstreams(reader, monitor);
deserializeAdditionalSubstreams(monitor);
// BELOW: NEW STUFF FROM REFACTOR/REWORK (can be duplicative with other stuff)
if (doNewStuff) {
parseModules(monitor);
compareSymbols(monitor); //temporary to ensure same results with previous work.
}
// ABOVE: NEW STUFF FROM REFACTOR/REWORK (can be duplicative with other stuff)
}
return versionNumber;
}
@ -518,8 +530,10 @@ public abstract class PdbDebugInfo {
* instance.
* @param writer {@link Writer} to which to dump the information.
* @throws IOException Upon IOException writing to the {@link Writer}.
* @throws CancelledException Upon user cancellation
* @throws PdbException Upon not enough data left to parse
*/
protected void dump(Writer writer) throws IOException {
protected void dump(Writer writer) throws IOException, CancelledException, PdbException {
writer.write("DebugInfoHeader---------------------------------------------\n");
dumpHeader(writer);
writer.write("\nEnd DebugInfoHeader-----------------------------------------\n");
@ -536,13 +550,22 @@ public abstract class PdbDebugInfo {
* {@link PdbDebugInfo}-based instance.
* @param writer {@link Writer} to which to dump the information.
* @throws IOException Upon IOException writing to the {@link Writer}.
* @throws CancelledException Upon user cancellation
* @throws PdbException Upon not enough data left to parse
*/
protected void dumpAdditionalSubstreams(Writer writer) throws IOException {
protected void dumpAdditionalSubstreams(Writer writer)
throws IOException, CancelledException, PdbException {
symbolRecords.dump(writer);
writer.write("\n");
globalSymbolInformation.dump(writer);
writer.write("\n");
publicSymbolInformation.dump(writer);
if (doNewStuff) {
dumpSymbols(writer);
for (Module module : modules) {
module.dump(writer);
}
}
}
/**
@ -586,4 +609,139 @@ public abstract class PdbDebugInfo {
}
}
//==============================================================================================
// NEW STUFF FROM REFACTOR/REWORK (can be duplicative with other stuff)... might be turned off
// during development.
private void parseModules(TaskMonitor monitor) throws CancelledException {
for (AbstractModuleInformation moduleInformation : moduleInformationList) {
monitor.checkCanceled();
Module module = new Module(pdb, moduleInformation, monitor);
modules.add(module);
}
}
private int numModules() {
return modules.size();
}
/**
* Return the Module based upon the module number.
* @param moduleNum the module number
* @return the module
*/
public Module getModule(int moduleNum) {
return modules.get(moduleNum);
}
// NOTE: Designs are not done regarding possibly iterators for iterating only globals or publics
/**
* Returns the symbol iterator for general (public and global symbols.
* @param monitor monitor for the job
* @return an iterator over all symbols of the module
* @throws CancelledException Upon user cancellation
* @throws IOException upon issue reading the stream
*/
public MsSymbolIterator getSymbolIterator(TaskMonitor monitor)
throws CancelledException, IOException {
if (streamNumberSymbolRecords == 0xffff) {
return null;
}
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumberSymbolRecords, monitor);
MsSymbolIterator iterator = new MsSymbolIterator(pdb, reader);
return iterator;
}
/**
* Returns the symbol iterator symbols of the specified module.
* @param moduleNum the module number
* @return an iterator over all symbols of the module
* @throws CancelledException Upon user cancellation
* @throws PdbException Upon not enough data left to parse
*/
MsSymbolIterator getSymbolIterator(int moduleNum) throws CancelledException, PdbException {
Module module = modules.get(moduleNum);
return module.getSymbolIterator();
}
private void dumpSymbols(Writer writer) throws CancelledException, IOException {
// TODO: in GP-2367 (rename/refactor) ticket... put in appropriate monitor
MsSymbolIterator iterator = getSymbolIterator(TaskMonitor.DUMMY);
List<AbstractMsSymbol> symbols = new ArrayList<>();
while (iterator.hasNext()) {
symbols.add(iterator.next());
}
}
// This method is temporary. It only exists for ensuring results as we transition processing
// mechanisms.
private void compareSymbols(TaskMonitor monitor)
throws CancelledException, PdbException, IOException {
PdbDebugInfo debugInfo = pdb.getDebugInfo();
if (debugInfo == null) {
return;
}
// Compare general symbols
MsSymbolIterator iterator = getSymbolIterator(monitor);
List<AbstractMsSymbol> symbols = new ArrayList<>();
while (iterator.hasNext()) {
symbols.add(iterator.next());
}
if (symbols.size() != symbolRecords.getSymbolsByOffset().size()) {
// Set break-point on next line. Multiple lines here to eliminate Eclipse warning.
int a = 1;
a = a + 1;
}
int cnt = 0;
for (Map.Entry<Long, AbstractMsSymbol> entry : symbolRecords.getSymbolsByOffset()
.entrySet()) {
AbstractMsSymbol msym = entry.getValue();
AbstractMsSymbol lsym = symbols.get(cnt);
String mstr = msym.toString();
String lstr = lsym.toString();
if (!mstr.equals(lstr)) {
// Set break-point on next line. Multiple lines here to eliminate Eclipse warning.
int b = 1;
b = b + 1;
}
cnt++;
}
// Compare module symbols
for (int modnum = 0; modnum < numModules(); modnum++) {
Module module = modules.get(modnum);
MsSymbolIterator moduleSymbolsIterator = module.getSymbolIterator();
cnt = 0;
Map<Long, AbstractMsSymbol> map = symbolRecords.getModuleSymbolsByOffset(modnum);
List<Long> keys = new ArrayList<>();
for (Map.Entry<Long, AbstractMsSymbol> entry : map.entrySet()) {
Long key = entry.getKey();
keys.add(key);
}
Collections.sort(keys);
for (Long key : keys) {
AbstractMsSymbol msym = map.get(key);
if (!moduleSymbolsIterator.hasNext()) {
// Set break-point on next line. Multiple lines here to eliminate Eclipse warning.
int c = 1;
c = c + 1;
break;
}
AbstractMsSymbol lsym = moduleSymbolsIterator.next();
String mstr = msym.toString();
String lstr = lsym.toString();
if (!mstr.equals(lstr)) {
// Set break-point on next line. Multiple lines here to eliminate Eclipse warning.
int b = 1;
b = b + 1;
}
cnt++;
}
if (moduleSymbolsIterator.hasNext()) {
// Set break-point on next line. Multiple lines here to eliminate Eclipse warning.
int d = 1;
d = d + 1;
}
}
}
}

View File

@ -4,9 +4,9 @@
* 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.

View File

@ -121,6 +121,11 @@ public class SegmentMapDescription {
segLength = substreamReader.parseUnsignedIntVal();
}
@Override
public String toString() {
return dump();
}
/**
* Dumps the {@link SegmentMapDescription}. This method is for debugging only.
* @return {@link String} of pretty output.

View File

@ -35,6 +35,23 @@ public class SymbolParser {
private SymbolParser() {
}
/**
* Deserializes the record length and {@link AbstractMsSymbol} from the {@link PdbByteReader}
* and returns the symbol.
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed.
* @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 static AbstractMsSymbol parseLengthAndSymbol(AbstractPdb pdb, PdbByteReader reader)
throws PdbException, CancelledException {
int recordLength = reader.parseUnsignedShortVal();
PdbByteReader recordReader = reader.getSubPdbByteReader(recordLength);
recordReader.markAlign(2);
return parse(pdb, recordReader);
}
/**
* Deserializes an {@link AbstractMsSymbol} from the {@link PdbByteReader} and returns it.
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed.

View File

@ -68,61 +68,105 @@ public class SymbolRecords {
* Deserializes the {@link SymbolRecords} from the stream noted in the DBI header.
* @param monitor {@link TaskMonitor} used for checking cancellation.
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or
* inability to read required bytes.
* @throws PdbException Upon not enough data left to parse.
* @throws CancelledException Upon user cancellation.
* inability to read required bytes
* @throws PdbException Upon not enough data left to parse
* @throws CancelledException Upon user cancellation
*/
void deserialize(TaskMonitor monitor) throws IOException, PdbException, CancelledException {
int streamNumber;
PdbByteReader reader;
processSymbols(monitor);
processModuleSymbols(monitor);
}
private void processSymbols(TaskMonitor monitor)
throws IOException, PdbException, CancelledException {
PdbDebugInfo debugInfo = pdb.getDebugInfo();
if (debugInfo == null) {
return;
}
streamNumber = debugInfo.getSymbolRecordsStreamNumber();
int streamNumber = debugInfo.getSymbolRecordsStreamNumber();
if (streamNumber <= 0) {
return;
}
reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
symbolsByOffset = deserializeSymbolRecords(pdb, reader, monitor);
}
for (AbstractModuleInformation module : debugInfo.moduleInformationList) {
streamNumber = module.getStreamNumberDebugInformation();
if (streamNumber != 0xffff) {
// System.out.println("\n\nStreamNumber: " + streamNumber);
reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
int x = reader.parseInt(); // TODO: do not know what this value is.
int sizeDebug = module.getSizeLocalSymbolsDebugInformation();
sizeDebug -= x; //TODO: seems right, but need to evaluate this
PdbByteReader debugReader = reader.getSubPdbByteReader(sizeDebug);
Map<Long, AbstractMsSymbol> oneModuleSymbolsByOffset =
deserializeSymbolRecords(pdb, debugReader, monitor);
moduleSymbolsByOffset.add(oneModuleSymbolsByOffset);
// TODO: figure out the rest of the bytes in the stream
// As of 20190618: feel that this is where we will find C11Lines or C13Lines
// information.
// PdbByteReader rest = reader.getSubPdbByteReader(reader.numRemaining());
// System.out.println(rest.dump());
}
else {
moduleSymbolsByOffset.add(new TreeMap<>());
}
// Could split this method up into separate methods: one for module symbols and the other for
// Lines processing. Note: would be processing streams more than once; lines would need to
// skip over the symbols.
private void processModuleSymbols(TaskMonitor monitor)
throws IOException, PdbException, CancelledException {
// cvSignature:
// >64K = C6
// 1 = C7
// 2 = C11 (vc5.x)
// 3 = ??? (not specified, and not marked as reserved)
// 4 = C13 (vc7.x)
// 5-64K = RESERVED
//
// Both cvdump (1660 and 1668) and mod.cpp (575) seem to indicate that the first module
// might have the cvSignature of C7 or C11 (when C7/C11), but modules thereafter will not
// or may not have the value. C13 would always have the C13 signature.
boolean getSig = true;
int cvSignature = 0;
PdbDebugInfo debugInfo = pdb.getDebugInfo();
if (debugInfo == null) {
return;
}
for (AbstractModuleInformation module : debugInfo.moduleInformationList) {
monitor.checkCanceled();
int streamNumber = module.getStreamNumberDebugInformation();
if (streamNumber == 0xffff) {
moduleSymbolsByOffset.add(new TreeMap<>());
continue;
}
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
int sizeSymbolsSection = module.getSizeLocalSymbolsDebugInformation();
PdbByteReader symbolsReader = reader.getSubPdbByteReader(sizeSymbolsSection);
// See comment above regarding getSig boolean
if (getSig) {
cvSignature = symbolsReader.parseInt();
}
switch (cvSignature) {
case 1:
case 2:
// We have no 1,2 examples to test this logic for cvSignature. Confirming
// or rejecting this logic is important for simplifying/refactoring this
// method or writing new methods to allow for extraction of information from
// individual modules. The current implementation has cross-module logic
// (setting state in the processing of the first and using this state in the
// processing of follow-on modules).
getSig = false;
break;
case 4:
break;
default:
if (cvSignature < 0x10000) {
throw new PdbException(
"Invalid module CV signature in stream " + streamNumber);
}
break;
}
Map<Long, AbstractMsSymbol> oneModuleSymbolsByOffset =
deserializeSymbolRecords(pdb, symbolsReader, monitor);
moduleSymbolsByOffset.add(oneModuleSymbolsByOffset);
}
}
/**
* Deserializes the {@link AbstractMsSymbol} symbols from the {@link PdbByteReader} and
* returns a {@link Map}&lt;{@link Long},{@link AbstractMsSymbol}&gt; of buffer offsets to
* symbols.
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed.
* @param reader {@link PdbByteReader} containing the symbol records to deserialize.
* @param monitor {@link TaskMonitor} used for checking cancellation.
* @return map of buffer offsets to {@link AbstractMsSymbol symbols}.
* @throws PdbException Upon not enough data left to parse.
* @throws CancelledException Upon user cancellation.
* symbols
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed
* @param reader {@link PdbByteReader} containing the symbol records to deserialize
* @param monitor {@link TaskMonitor} used for checking cancellation
* @return map of buffer offsets to {@link AbstractMsSymbol symbols}
* @throws PdbException Upon not enough data left to parse
* @throws CancelledException Upon user cancellation
*/
public static Map<Long, AbstractMsSymbol> deserializeSymbolRecords(AbstractPdb pdb,
PdbByteReader reader, TaskMonitor monitor) throws PdbException, CancelledException {
@ -134,11 +178,7 @@ public class SymbolRecords {
// Including length in byte array for alignment purposes.
int offset = reader.getIndex();
int recordLength = reader.parseUnsignedShortVal();
PdbByteReader recordReader = reader.getSubPdbByteReader(recordLength);
recordReader.markAlign(2);
AbstractMsSymbol symbol = SymbolParser.parse(pdb, recordReader);
AbstractMsSymbol symbol = SymbolParser.parseLengthAndSymbol(pdb, reader);
mySymbolsByOffset.put((long) offset, symbol);
}
return mySymbolsByOffset;
@ -147,7 +187,7 @@ public class SymbolRecords {
/**
* Debug method for dumping information from this Symbol Records instance.
* @param writer {@link Writer} to which to dump the information.
* @throws IOException Upon IOException writing to the {@link Writer}.
* @throws IOException Upon IOException writing to the {@link Writer}
*/
protected void dump(Writer writer) throws IOException {
writer.write("SymbolRecords-----------------------------------------------\n");
@ -166,7 +206,7 @@ public class SymbolRecords {
* Debug method for dumping the symbols from a symbol map
* @param mySymbolsByOffset the {@link Map}&lt;{@link Long},{@link AbstractMsSymbol}&gt; to dump.
* @param writer {@link Writer} to which to dump the information.
* @throws IOException Upon IOException writing to the {@link Writer}.
* @throws IOException Upon IOException writing to the {@link Writer}
*/
protected void dumpSymbolMap(Map<Long, AbstractMsSymbol> mySymbolsByOffset, Writer writer)
throws IOException {

View File

@ -0,0 +1,31 @@
/* ###
* 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.app.util.bin.format.pdb2.pdbreader;
import ghidra.util.task.TaskMonitor;
/**
* A default/unknown C13Section class that we have created for completeness (default switch).
*/
class UnknownC13Section extends AbstractUnimplementedC13Section {
static UnknownC13Section parse(PdbByteReader reader, boolean ignore, TaskMonitor monitor) {
return new UnknownC13Section(reader, ignore, monitor);
}
protected UnknownC13Section(PdbByteReader reader, boolean ignore, TaskMonitor monitor) {
super(reader, ignore, monitor);
}
}

View File

@ -43,9 +43,7 @@ public class ReferencedSymbolMsType extends AbstractMsType {
public ReferencedSymbolMsType(AbstractPdb pdb, PdbByteReader reader)
throws PdbException, CancelledException {
super(pdb, reader);
int recordLength = reader.parseUnsignedShortVal();
PdbByteReader recordReader = reader.getSubPdbByteReader(recordLength);
symbolRecord = SymbolParser.parse(pdb, recordReader);
symbolRecord = SymbolParser.parseLengthAndSymbol(pdb, reader);
}
@Override

View File

@ -75,8 +75,7 @@ public class ReferenceSymbolApplier extends MsSymbolApplier {
}
long getOffsetInReferencedSymbolGroup() {
// Adjusting offset to the offset we use for parsing the complete record.
return symbol.getOffsetActualSymbolInDollarDollarSymbols() - 4;
return symbol.getOffsetActualSymbolInDollarDollarSymbols();
}
}

View File

@ -260,16 +260,16 @@ public class PdbTestUtils {
/**
* Packs an unsigned int (java long) with values from the parameters here.
* @param language the language
* @param compiledForEditAndContinue true if compiled fro edit-and-continue
* @param compiledForEditAndContinue true if compiled for edit-and-continue
* @param notCompiledWithDebugInfo true if <b>not</b> compiled with debug info
* @param compiledWithLinkTimeCodeGeneration true if compiled with link-time code generation
* @param compiledWithBzalignNoDataAlign tru if compiled with BS align no data align
* @param managedCodeDataPresent tru if managed code data is present
* @param compiledWithBzalignNoDataAlign true if compiled with BS align no data align
* @param managedCodeDataPresent true if managed code data is present
* @param compiledWithGsBufferSecurityChecks true if compiled with GS Buffer security checks
* @param compiledWithHotPatch true if compiled with ability to hot-patch
* @param convertedWithCvtcil true if converted from (.NET IL) Common Intermediate Language Module
* @param microsoftIntermediateLanguageNetModule true if MSFT intermediate language net module
* @param compiledWithSdl true if compiledwith SDL
* @param compiledWithSdl true if compiled with SDL
* @param compiledWithLtcgPgoOrPgu true if compiled with light PGO or PGU
* @param dotExpModule true if dot exp module
* @return the flags packed into single integral form/value