mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-1776 - PDB - C13 Sections, modules, iterators; incorporate into DebugInfo (turned off)
This commit is contained in:
parent
315e26fdd9
commit
e23bf1087b
40 changed files with 4084 additions and 87 deletions
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -54,12 +54,16 @@ public abstract class AbstractModuleInformation {
|
||||||
protected long nameIndexCompilerPdbPath; // unsigned 32-bit
|
protected long nameIndexCompilerPdbPath; // unsigned 32-bit
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
protected AbstractPdb pdb;
|
||||||
|
|
||||||
private Map<Integer, String> filenameByOffset = new HashMap<>();
|
private Map<Integer, String> filenameByOffset = new HashMap<>();
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
// API
|
// 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.
|
* 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() {
|
public int getSizeLocalSymbolsDebugInformation() {
|
||||||
return sizeLocalSymbolsDebugInformation;
|
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.
|
* Returns the name of the module.
|
||||||
* @return Name of the module.
|
* @return Name of the module.
|
||||||
|
|
|
@ -547,7 +547,7 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||||
PdbByteReader getReaderForStreamNumber(int streamNumber, int streamOffset, int numToRead,
|
PdbByteReader getReaderForStreamNumber(int streamNumber, int streamOffset, int numToRead,
|
||||||
TaskMonitor monitor) throws IOException, CancelledException {
|
TaskMonitor monitor) throws IOException, CancelledException {
|
||||||
MsfStream stream = msf.getStream(streamNumber);
|
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);
|
byte[] bytes = stream.read(streamOffset, numToRead, monitor);
|
||||||
PdbByteReader reader = new PdbByteReader(bytes);
|
PdbByteReader reader = new PdbByteReader(bytes);
|
||||||
return reader;
|
return reader;
|
||||||
|
@ -697,8 +697,10 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||||
* debugging only.
|
* debugging only.
|
||||||
* @param writer {@link Writer}.
|
* @param writer {@link Writer}.
|
||||||
* @throws IOException On issue writing to the {@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");
|
writer.write("SubStreams--------------------------------------------------\n");
|
||||||
if (typeProgramInterface != null) {
|
if (typeProgramInterface != null) {
|
||||||
writer.write("TypeProgramInterface----------------------------------------\n");
|
writer.write("TypeProgramInterface----------------------------------------\n");
|
||||||
|
|
|
@ -60,6 +60,11 @@ public abstract class AbstractSectionContribution {
|
||||||
return imod;
|
return imod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return dump();
|
||||||
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
// Abstract Methods
|
// Abstract Methods
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,15 +22,13 @@ import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* C11Lines information. As best as we know, only one of C11Lines or C13Lines (not implemented
|
* C11Lines information. As best as we know, only one of C11Lines or C13Lines can be found after
|
||||||
* yet) can be found after the symbol information in module debug streams.
|
* the symbol information in module debug streams.
|
||||||
* <P>
|
* <P>
|
||||||
* Note: we have not tested or put this to use yet.
|
* Note: we have not tested or put this to use yet.
|
||||||
*/
|
*/
|
||||||
public class C11Lines {
|
public class C11Lines {
|
||||||
|
|
||||||
private AbstractPdb pdb;
|
|
||||||
|
|
||||||
private int cFile; // unsigned short
|
private int cFile; // unsigned short
|
||||||
private int cSeg; // 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.
|
// 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<Long>>> offsets; // unsigned int
|
||||||
private List<List<List<Integer>>> lineNumbers; // unsigned short
|
private List<List<List<Integer>>> lineNumbers; // unsigned short
|
||||||
|
|
||||||
public C11Lines(AbstractPdb pdb) {
|
public static C11Lines parse(AbstractPdb pdb, PdbByteReader reader, TaskMonitor monitor)
|
||||||
this.pdb = pdb;
|
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 {
|
throws PdbException, CancelledException {
|
||||||
if (reader.numRemaining() < 4) {
|
if (reader.numRemaining() < 4) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -15,24 +15,16 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.bin.format.pdb2.pdbreader;
|
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.
|
* This class is the version of {@link AbstractModuleInformation} for Microsoft v5.00 PDB.
|
||||||
*/
|
*/
|
||||||
public class ModuleInformation500 extends AbstractModuleInformation {
|
public class ModuleInformation500 extends AbstractModuleInformation {
|
||||||
|
|
||||||
//==============================================================================================
|
|
||||||
// Internals
|
|
||||||
//==============================================================================================
|
|
||||||
private AbstractPdb pdb;
|
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
// API
|
// API
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
public ModuleInformation500(AbstractPdb pdb) {
|
public ModuleInformation500(AbstractPdb pdb) {
|
||||||
Objects.requireNonNull(pdb, "pdb cannot be null");
|
super(pdb);
|
||||||
this.pdb = pdb;
|
|
||||||
sectionContribution = new SectionContribution400();
|
sectionContribution = new SectionContribution400();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,24 +15,16 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.bin.format.pdb2.pdbreader;
|
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.
|
* This class is the version of {@link AbstractModuleInformation} for Microsoft v6.00 PDB.
|
||||||
*/
|
*/
|
||||||
public class ModuleInformation600 extends AbstractModuleInformation {
|
public class ModuleInformation600 extends AbstractModuleInformation {
|
||||||
|
|
||||||
//==============================================================================================
|
|
||||||
// Internals
|
|
||||||
//==============================================================================================
|
|
||||||
private AbstractPdb pdb;
|
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
// API
|
// API
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
public ModuleInformation600(AbstractPdb pdb) {
|
public ModuleInformation600(AbstractPdb pdb) {
|
||||||
Objects.requireNonNull(pdb, "pdb cannot be null");
|
super(pdb);
|
||||||
this.pdb = pdb;
|
|
||||||
sectionContribution = new SectionContribution600();
|
sectionContribution = new SectionContribution600();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -43,6 +43,8 @@ import ghidra.util.LittleEndianDataConverter;
|
||||||
*/
|
*/
|
||||||
public class PdbByteReader {
|
public class PdbByteReader {
|
||||||
|
|
||||||
|
public static final PdbByteReader DUMMY = new PdbByteReader(new byte[] {});
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
// Internals
|
// Internals
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
|
|
@ -73,6 +73,12 @@ public abstract class PdbDebugInfo {
|
||||||
protected GlobalSymbolInformation globalSymbolInformation;
|
protected GlobalSymbolInformation globalSymbolInformation;
|
||||||
protected PublicSymbolInformation publicSymbolInformation;
|
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
|
// API
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
@ -100,7 +106,7 @@ public abstract class PdbDebugInfo {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserializes the {@link PdbDebugInfo}-based instance.
|
* 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.
|
* of new DBI header.
|
||||||
* @param headerOnly if true only the DBI header fields will be parsed
|
* @param headerOnly if true only the DBI header fields will be parsed
|
||||||
* @param monitor {@link TaskMonitor} used for checking cancellation.
|
* @param monitor {@link TaskMonitor} used for checking cancellation.
|
||||||
|
@ -122,6 +128,12 @@ public abstract class PdbDebugInfo {
|
||||||
deserializeHeader(reader);
|
deserializeHeader(reader);
|
||||||
deserializeInternalSubstreams(reader, monitor);
|
deserializeInternalSubstreams(reader, monitor);
|
||||||
deserializeAdditionalSubstreams(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;
|
return versionNumber;
|
||||||
}
|
}
|
||||||
|
@ -518,8 +530,10 @@ public abstract class PdbDebugInfo {
|
||||||
* instance.
|
* instance.
|
||||||
* @param writer {@link Writer} to which to dump the information.
|
* @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}.
|
||||||
|
* @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");
|
writer.write("DebugInfoHeader---------------------------------------------\n");
|
||||||
dumpHeader(writer);
|
dumpHeader(writer);
|
||||||
writer.write("\nEnd DebugInfoHeader-----------------------------------------\n");
|
writer.write("\nEnd DebugInfoHeader-----------------------------------------\n");
|
||||||
|
@ -536,13 +550,22 @@ public abstract class PdbDebugInfo {
|
||||||
* {@link PdbDebugInfo}-based instance.
|
* {@link PdbDebugInfo}-based instance.
|
||||||
* @param writer {@link Writer} to which to dump the information.
|
* @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}.
|
||||||
|
* @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);
|
symbolRecords.dump(writer);
|
||||||
writer.write("\n");
|
writer.write("\n");
|
||||||
globalSymbolInformation.dump(writer);
|
globalSymbolInformation.dump(writer);
|
||||||
writer.write("\n");
|
writer.write("\n");
|
||||||
publicSymbolInformation.dump(writer);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,6 +121,11 @@ public class SegmentMapDescription {
|
||||||
segLength = substreamReader.parseUnsignedIntVal();
|
segLength = substreamReader.parseUnsignedIntVal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return dump();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dumps the {@link SegmentMapDescription}. This method is for debugging only.
|
* Dumps the {@link SegmentMapDescription}. This method is for debugging only.
|
||||||
* @return {@link String} of pretty output.
|
* @return {@link String} of pretty output.
|
||||||
|
|
|
@ -35,6 +35,23 @@ public class SymbolParser {
|
||||||
private 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.
|
* Deserializes an {@link AbstractMsSymbol} from the {@link PdbByteReader} and returns it.
|
||||||
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed.
|
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed.
|
||||||
|
|
|
@ -68,61 +68,105 @@ public class SymbolRecords {
|
||||||
* Deserializes the {@link SymbolRecords} from the stream noted in the DBI header.
|
* Deserializes the {@link SymbolRecords} from the stream noted in the DBI header.
|
||||||
* @param monitor {@link TaskMonitor} used for checking cancellation.
|
* @param monitor {@link TaskMonitor} used for checking cancellation.
|
||||||
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or
|
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or
|
||||||
* inability to read required bytes.
|
* inability to read required bytes
|
||||||
* @throws PdbException Upon not enough data left to parse.
|
* @throws PdbException Upon not enough data left to parse
|
||||||
* @throws CancelledException Upon user cancellation.
|
* @throws CancelledException Upon user cancellation
|
||||||
*/
|
*/
|
||||||
void deserialize(TaskMonitor monitor) throws IOException, PdbException, CancelledException {
|
void deserialize(TaskMonitor monitor) throws IOException, PdbException, CancelledException {
|
||||||
int streamNumber;
|
processSymbols(monitor);
|
||||||
PdbByteReader reader;
|
processModuleSymbols(monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processSymbols(TaskMonitor monitor)
|
||||||
|
throws IOException, PdbException, CancelledException {
|
||||||
PdbDebugInfo debugInfo = pdb.getDebugInfo();
|
PdbDebugInfo debugInfo = pdb.getDebugInfo();
|
||||||
if (debugInfo == null) {
|
if (debugInfo == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
streamNumber = debugInfo.getSymbolRecordsStreamNumber();
|
int streamNumber = debugInfo.getSymbolRecordsStreamNumber();
|
||||||
if (streamNumber <= 0) {
|
if (streamNumber <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
|
||||||
reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
|
|
||||||
symbolsByOffset = deserializeSymbolRecords(pdb, reader, monitor);
|
symbolsByOffset = deserializeSymbolRecords(pdb, reader, monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
for (AbstractModuleInformation module : debugInfo.moduleInformationList) {
|
||||||
streamNumber = module.getStreamNumberDebugInformation();
|
monitor.checkCanceled();
|
||||||
if (streamNumber != 0xffff) {
|
int streamNumber = module.getStreamNumberDebugInformation();
|
||||||
// System.out.println("\n\nStreamNumber: " + streamNumber);
|
if (streamNumber == 0xffff) {
|
||||||
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<>());
|
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
|
* Deserializes the {@link AbstractMsSymbol} symbols from the {@link PdbByteReader} and
|
||||||
* returns a {@link Map}<{@link Long},{@link AbstractMsSymbol}> of buffer offsets to
|
* returns a {@link Map}<{@link Long},{@link AbstractMsSymbol}> of buffer offsets to
|
||||||
* symbols.
|
* symbols
|
||||||
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed.
|
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed
|
||||||
* @param reader {@link PdbByteReader} containing the symbol records to deserialize.
|
* @param reader {@link PdbByteReader} containing the symbol records to deserialize
|
||||||
* @param monitor {@link TaskMonitor} used for checking cancellation.
|
* @param monitor {@link TaskMonitor} used for checking cancellation
|
||||||
* @return map of buffer offsets to {@link AbstractMsSymbol symbols}.
|
* @return map of buffer offsets to {@link AbstractMsSymbol symbols}
|
||||||
* @throws PdbException Upon not enough data left to parse.
|
* @throws PdbException Upon not enough data left to parse
|
||||||
* @throws CancelledException Upon user cancellation.
|
* @throws CancelledException Upon user cancellation
|
||||||
*/
|
*/
|
||||||
public static Map<Long, AbstractMsSymbol> deserializeSymbolRecords(AbstractPdb pdb,
|
public static Map<Long, AbstractMsSymbol> deserializeSymbolRecords(AbstractPdb pdb,
|
||||||
PdbByteReader reader, TaskMonitor monitor) throws PdbException, CancelledException {
|
PdbByteReader reader, TaskMonitor monitor) throws PdbException, CancelledException {
|
||||||
|
@ -134,11 +178,7 @@ public class SymbolRecords {
|
||||||
|
|
||||||
// Including length in byte array for alignment purposes.
|
// Including length in byte array for alignment purposes.
|
||||||
int offset = reader.getIndex();
|
int offset = reader.getIndex();
|
||||||
int recordLength = reader.parseUnsignedShortVal();
|
AbstractMsSymbol symbol = SymbolParser.parseLengthAndSymbol(pdb, reader);
|
||||||
|
|
||||||
PdbByteReader recordReader = reader.getSubPdbByteReader(recordLength);
|
|
||||||
recordReader.markAlign(2);
|
|
||||||
AbstractMsSymbol symbol = SymbolParser.parse(pdb, recordReader);
|
|
||||||
mySymbolsByOffset.put((long) offset, symbol);
|
mySymbolsByOffset.put((long) offset, symbol);
|
||||||
}
|
}
|
||||||
return mySymbolsByOffset;
|
return mySymbolsByOffset;
|
||||||
|
@ -147,7 +187,7 @@ public class SymbolRecords {
|
||||||
/**
|
/**
|
||||||
* Debug method for dumping information from this Symbol Records instance.
|
* Debug method for dumping information from this Symbol Records instance.
|
||||||
* @param writer {@link Writer} to which to dump the information.
|
* @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 {
|
protected void dump(Writer writer) throws IOException {
|
||||||
writer.write("SymbolRecords-----------------------------------------------\n");
|
writer.write("SymbolRecords-----------------------------------------------\n");
|
||||||
|
@ -166,7 +206,7 @@ public class SymbolRecords {
|
||||||
* Debug method for dumping the symbols from a symbol map
|
* Debug method for dumping the symbols from a symbol map
|
||||||
* @param mySymbolsByOffset the {@link Map}<{@link Long},{@link AbstractMsSymbol}> to dump.
|
* @param mySymbolsByOffset the {@link Map}<{@link Long},{@link AbstractMsSymbol}> to dump.
|
||||||
* @param writer {@link Writer} to which to dump the information.
|
* @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)
|
protected void dumpSymbolMap(Map<Long, AbstractMsSymbol> mySymbolsByOffset, Writer writer)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,9 +43,7 @@ public class ReferencedSymbolMsType extends AbstractMsType {
|
||||||
public ReferencedSymbolMsType(AbstractPdb pdb, PdbByteReader reader)
|
public ReferencedSymbolMsType(AbstractPdb pdb, PdbByteReader reader)
|
||||||
throws PdbException, CancelledException {
|
throws PdbException, CancelledException {
|
||||||
super(pdb, reader);
|
super(pdb, reader);
|
||||||
int recordLength = reader.parseUnsignedShortVal();
|
symbolRecord = SymbolParser.parseLengthAndSymbol(pdb, reader);
|
||||||
PdbByteReader recordReader = reader.getSubPdbByteReader(recordLength);
|
|
||||||
symbolRecord = SymbolParser.parse(pdb, recordReader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -75,8 +75,7 @@ public class ReferenceSymbolApplier extends MsSymbolApplier {
|
||||||
}
|
}
|
||||||
|
|
||||||
long getOffsetInReferencedSymbolGroup() {
|
long getOffsetInReferencedSymbolGroup() {
|
||||||
// Adjusting offset to the offset we use for parsing the complete record.
|
return symbol.getOffsetActualSymbolInDollarDollarSymbols();
|
||||||
return symbol.getOffsetActualSymbolInDollarDollarSymbols() - 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -260,16 +260,16 @@ public class PdbTestUtils {
|
||||||
/**
|
/**
|
||||||
* Packs an unsigned int (java long) with values from the parameters here.
|
* Packs an unsigned int (java long) with values from the parameters here.
|
||||||
* @param language the language
|
* @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 notCompiledWithDebugInfo true if <b>not</b> compiled with debug info
|
||||||
* @param compiledWithLinkTimeCodeGeneration true if compiled with link-time code generation
|
* @param compiledWithLinkTimeCodeGeneration true if compiled with link-time code generation
|
||||||
* @param compiledWithBzalignNoDataAlign tru if compiled with BS align no data align
|
* @param compiledWithBzalignNoDataAlign true if compiled with BS align no data align
|
||||||
* @param managedCodeDataPresent tru if managed code data is present
|
* @param managedCodeDataPresent true if managed code data is present
|
||||||
* @param compiledWithGsBufferSecurityChecks true if compiled with GS Buffer security checks
|
* @param compiledWithGsBufferSecurityChecks true if compiled with GS Buffer security checks
|
||||||
* @param compiledWithHotPatch true if compiled with ability to hot-patch
|
* @param compiledWithHotPatch true if compiled with ability to hot-patch
|
||||||
* @param convertedWithCvtcil true if converted from (.NET IL) Common Intermediate Language Module
|
* @param convertedWithCvtcil true if converted from (.NET IL) Common Intermediate Language Module
|
||||||
* @param microsoftIntermediateLanguageNetModule true if MSFT intermediate language net 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 compiledWithLtcgPgoOrPgu true if compiled with light PGO or PGU
|
||||||
* @param dotExpModule true if dot exp module
|
* @param dotExpModule true if dot exp module
|
||||||
* @return the flags packed into single integral form/value
|
* @return the flags packed into single integral form/value
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue