mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-12-13 06:33:02 +00:00
Merge remote-tracking branch 'origin/GP-1776_ghizard_PDB_Part1_Add_C13_sections_modules_iterators_20220824--SQUASHED'
This commit is contained in:
commit
af7476b21f
@ -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 AbstractPdb pdb;
|
||||
|
||||
private Map<Integer, String> filenameByOffset = new HashMap<>();
|
||||
|
||||
//==============================================================================================
|
||||
// API
|
||||
//==============================================================================================
|
||||
public AbstractModuleInformation() {
|
||||
public AbstractModuleInformation(AbstractPdb pdb) {
|
||||
Objects.requireNonNull(pdb, "pdb cannot be null");
|
||||
this.pdb = pdb;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,12 +100,28 @@ public abstract class AbstractModuleInformation {
|
||||
|
||||
/**
|
||||
* Returns the size of the local symbols debug information.
|
||||
* @return Size of the local symbosl debug information.
|
||||
* @return Size of the local symbols debug information.
|
||||
*/
|
||||
public int getSizeLocalSymbolsDebugInformation() {
|
||||
return sizeLocalSymbolsDebugInformation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the older-style line number information
|
||||
* @return Size of the older-style line number information
|
||||
*/
|
||||
public int getSizeLineNumberDebugInformation() {
|
||||
return sizeLineNumberDebugInformation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the C13-style line number information
|
||||
* @return Size of the C13-style line number information
|
||||
*/
|
||||
public int getSizeC13StyleLineNumberInformation() {
|
||||
return sizeC13StyleLineNumberInformation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the module.
|
||||
* @return Name of the module.
|
||||
|
@ -547,7 +547,7 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||
PdbByteReader getReaderForStreamNumber(int streamNumber, int streamOffset, int numToRead,
|
||||
TaskMonitor monitor) throws IOException, CancelledException {
|
||||
MsfStream stream = msf.getStream(streamNumber);
|
||||
numToRead = Math.min(numToRead, stream.getLength());
|
||||
numToRead = Math.min(numToRead, stream.getLength() - streamOffset);
|
||||
byte[] bytes = stream.read(streamOffset, numToRead, monitor);
|
||||
PdbByteReader reader = new PdbByteReader(bytes);
|
||||
return reader;
|
||||
@ -697,8 +697,10 @@ public abstract class AbstractPdb implements AutoCloseable {
|
||||
* debugging only.
|
||||
* @param writer {@link Writer}.
|
||||
* @throws IOException On issue writing to the {@link Writer}.
|
||||
* @throws CancelledException Upon user cancellation
|
||||
* @throws PdbException Upon not enough data left to parse
|
||||
*/
|
||||
public void dumpSubStreams(Writer writer) throws IOException {
|
||||
public void dumpSubStreams(Writer writer) throws IOException, CancelledException, PdbException {
|
||||
writer.write("SubStreams--------------------------------------------------\n");
|
||||
if (typeProgramInterface != null) {
|
||||
writer.write("TypeProgramInterface----------------------------------------\n");
|
||||
|
@ -60,6 +60,11 @@ public abstract class AbstractSectionContribution {
|
||||
return imod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return dump();
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
// 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;
|
||||
|
||||
/**
|
||||
* C11Lines information. As best as we know, only one of C11Lines or C13Lines (not implemented
|
||||
* yet) can be found after the symbol information in module debug streams.
|
||||
* C11Lines information. As best as we know, only one of C11Lines or C13Lines can be found after
|
||||
* the symbol information in module debug streams.
|
||||
* <P>
|
||||
* Note: we have not tested or put this to use yet.
|
||||
*/
|
||||
public class C11Lines {
|
||||
|
||||
private AbstractPdb pdb;
|
||||
|
||||
private int cFile; // unsigned short
|
||||
private int cSeg; // unsigned short
|
||||
// array of (Windows C) unsigned long values (which is 32-bit int); we are limiting to java int.
|
||||
@ -50,11 +48,12 @@ public class C11Lines {
|
||||
private List<List<List<Long>>> offsets; // unsigned int
|
||||
private List<List<List<Integer>>> lineNumbers; // unsigned short
|
||||
|
||||
public C11Lines(AbstractPdb pdb) {
|
||||
this.pdb = pdb;
|
||||
public static C11Lines parse(AbstractPdb pdb, PdbByteReader reader, TaskMonitor monitor)
|
||||
throws PdbException, CancelledException {
|
||||
return new C11Lines(pdb, reader, monitor);
|
||||
}
|
||||
|
||||
public void parse(PdbByteReader reader, TaskMonitor monitor)
|
||||
private C11Lines(AbstractPdb pdb, PdbByteReader reader, TaskMonitor monitor)
|
||||
throws PdbException, CancelledException {
|
||||
if (reader.numRemaining() < 4) {
|
||||
return;
|
||||
|
@ -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;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class is the version of {@link AbstractModuleInformation} for Microsoft v5.00 PDB.
|
||||
*/
|
||||
public class ModuleInformation500 extends AbstractModuleInformation {
|
||||
|
||||
//==============================================================================================
|
||||
// Internals
|
||||
//==============================================================================================
|
||||
private AbstractPdb pdb;
|
||||
|
||||
//==============================================================================================
|
||||
// API
|
||||
//==============================================================================================
|
||||
public ModuleInformation500(AbstractPdb pdb) {
|
||||
Objects.requireNonNull(pdb, "pdb cannot be null");
|
||||
this.pdb = pdb;
|
||||
super(pdb);
|
||||
sectionContribution = new SectionContribution400();
|
||||
}
|
||||
|
||||
|
@ -15,24 +15,16 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.pdb2.pdbreader;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class is the version of {@link AbstractModuleInformation} for Microsoft v6.00 PDB.
|
||||
*/
|
||||
public class ModuleInformation600 extends AbstractModuleInformation {
|
||||
|
||||
//==============================================================================================
|
||||
// Internals
|
||||
//==============================================================================================
|
||||
private AbstractPdb pdb;
|
||||
|
||||
//==============================================================================================
|
||||
// API
|
||||
//==============================================================================================
|
||||
public ModuleInformation600(AbstractPdb pdb) {
|
||||
Objects.requireNonNull(pdb, "pdb cannot be null");
|
||||
this.pdb = pdb;
|
||||
super(pdb);
|
||||
sectionContribution = new SectionContribution600();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
}
|
@ -39,10 +39,12 @@ import ghidra.util.LittleEndianDataConverter;
|
||||
*
|
||||
* <P>Other utility methods exist for setting/getting the {@code index} or for moving the
|
||||
* {@code index} along to align or pad-out according to how a C/C++ structure would be padded in
|
||||
* memory.
|
||||
* memory.
|
||||
*/
|
||||
public class PdbByteReader {
|
||||
|
||||
public static final PdbByteReader DUMMY = new PdbByteReader(new byte[] {});
|
||||
|
||||
//==============================================================================================
|
||||
// Internals
|
||||
//==============================================================================================
|
||||
|
@ -73,6 +73,12 @@ public abstract class PdbDebugInfo {
|
||||
protected GlobalSymbolInformation globalSymbolInformation;
|
||||
protected PublicSymbolInformation publicSymbolInformation;
|
||||
|
||||
//==============================================================================================
|
||||
// NEW STUFF FROM REFACTOR/REWORK (can be duplicative with other stuff)... might be turned off
|
||||
// during development.
|
||||
private boolean doNewStuff = false;
|
||||
private List<Module> modules = new ArrayList<>();
|
||||
|
||||
//==============================================================================================
|
||||
// API
|
||||
//==============================================================================================
|
||||
@ -100,7 +106,7 @@ public abstract class PdbDebugInfo {
|
||||
|
||||
/**
|
||||
* Deserializes the {@link PdbDebugInfo}-based instance.
|
||||
* The pdb is updated with dbiAge and targetProcessor during deserialization
|
||||
* The PDB is updated with dbiAge and targetProcessor during deserialization
|
||||
* of new DBI header.
|
||||
* @param headerOnly if true only the DBI header fields will be parsed
|
||||
* @param monitor {@link TaskMonitor} used for checking cancellation.
|
||||
@ -122,6 +128,12 @@ public abstract class PdbDebugInfo {
|
||||
deserializeHeader(reader);
|
||||
deserializeInternalSubstreams(reader, monitor);
|
||||
deserializeAdditionalSubstreams(monitor);
|
||||
// BELOW: NEW STUFF FROM REFACTOR/REWORK (can be duplicative with other stuff)
|
||||
if (doNewStuff) {
|
||||
parseModules(monitor);
|
||||
compareSymbols(monitor); //temporary to ensure same results with previous work.
|
||||
}
|
||||
// ABOVE: NEW STUFF FROM REFACTOR/REWORK (can be duplicative with other stuff)
|
||||
}
|
||||
return versionNumber;
|
||||
}
|
||||
@ -518,8 +530,10 @@ public abstract class PdbDebugInfo {
|
||||
* instance.
|
||||
* @param writer {@link Writer} to which to dump the information.
|
||||
* @throws IOException Upon IOException writing to the {@link Writer}.
|
||||
* @throws CancelledException Upon user cancellation
|
||||
* @throws PdbException Upon not enough data left to parse
|
||||
*/
|
||||
protected void dump(Writer writer) throws IOException {
|
||||
protected void dump(Writer writer) throws IOException, CancelledException, PdbException {
|
||||
writer.write("DebugInfoHeader---------------------------------------------\n");
|
||||
dumpHeader(writer);
|
||||
writer.write("\nEnd DebugInfoHeader-----------------------------------------\n");
|
||||
@ -536,13 +550,22 @@ public abstract class PdbDebugInfo {
|
||||
* {@link PdbDebugInfo}-based instance.
|
||||
* @param writer {@link Writer} to which to dump the information.
|
||||
* @throws IOException Upon IOException writing to the {@link Writer}.
|
||||
* @throws CancelledException Upon user cancellation
|
||||
* @throws PdbException Upon not enough data left to parse
|
||||
*/
|
||||
protected void dumpAdditionalSubstreams(Writer writer) throws IOException {
|
||||
protected void dumpAdditionalSubstreams(Writer writer)
|
||||
throws IOException, CancelledException, PdbException {
|
||||
symbolRecords.dump(writer);
|
||||
writer.write("\n");
|
||||
globalSymbolInformation.dump(writer);
|
||||
writer.write("\n");
|
||||
publicSymbolInformation.dump(writer);
|
||||
if (doNewStuff) {
|
||||
dumpSymbols(writer);
|
||||
for (Module module : modules) {
|
||||
module.dump(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -586,4 +609,139 @@ public abstract class PdbDebugInfo {
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
// NEW STUFF FROM REFACTOR/REWORK (can be duplicative with other stuff)... might be turned off
|
||||
// during development.
|
||||
private void parseModules(TaskMonitor monitor) throws CancelledException {
|
||||
for (AbstractModuleInformation moduleInformation : moduleInformationList) {
|
||||
monitor.checkCanceled();
|
||||
Module module = new Module(pdb, moduleInformation, monitor);
|
||||
modules.add(module);
|
||||
}
|
||||
}
|
||||
|
||||
private int numModules() {
|
||||
return modules.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Module based upon the module number.
|
||||
* @param moduleNum the module number
|
||||
* @return the module
|
||||
*/
|
||||
public Module getModule(int moduleNum) {
|
||||
return modules.get(moduleNum);
|
||||
}
|
||||
|
||||
// NOTE: Designs are not done regarding possibly iterators for iterating only globals or publics
|
||||
/**
|
||||
* Returns the symbol iterator for general (public and global symbols.
|
||||
* @param monitor monitor for the job
|
||||
* @return an iterator over all symbols of the module
|
||||
* @throws CancelledException Upon user cancellation
|
||||
* @throws IOException upon issue reading the stream
|
||||
*/
|
||||
public MsSymbolIterator getSymbolIterator(TaskMonitor monitor)
|
||||
throws CancelledException, IOException {
|
||||
if (streamNumberSymbolRecords == 0xffff) {
|
||||
return null;
|
||||
}
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumberSymbolRecords, monitor);
|
||||
MsSymbolIterator iterator = new MsSymbolIterator(pdb, reader);
|
||||
return iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the symbol iterator symbols of the specified module.
|
||||
* @param moduleNum the module number
|
||||
* @return an iterator over all symbols of the module
|
||||
* @throws CancelledException Upon user cancellation
|
||||
* @throws PdbException Upon not enough data left to parse
|
||||
*/
|
||||
MsSymbolIterator getSymbolIterator(int moduleNum) throws CancelledException, PdbException {
|
||||
Module module = modules.get(moduleNum);
|
||||
return module.getSymbolIterator();
|
||||
}
|
||||
|
||||
private void dumpSymbols(Writer writer) throws CancelledException, IOException {
|
||||
// TODO: in GP-2367 (rename/refactor) ticket... put in appropriate monitor
|
||||
MsSymbolIterator iterator = getSymbolIterator(TaskMonitor.DUMMY);
|
||||
List<AbstractMsSymbol> symbols = new ArrayList<>();
|
||||
while (iterator.hasNext()) {
|
||||
symbols.add(iterator.next());
|
||||
}
|
||||
}
|
||||
|
||||
// This method is temporary. It only exists for ensuring results as we transition processing
|
||||
// mechanisms.
|
||||
private void compareSymbols(TaskMonitor monitor)
|
||||
throws CancelledException, PdbException, IOException {
|
||||
PdbDebugInfo debugInfo = pdb.getDebugInfo();
|
||||
if (debugInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Compare general symbols
|
||||
MsSymbolIterator iterator = getSymbolIterator(monitor);
|
||||
List<AbstractMsSymbol> symbols = new ArrayList<>();
|
||||
while (iterator.hasNext()) {
|
||||
symbols.add(iterator.next());
|
||||
}
|
||||
if (symbols.size() != symbolRecords.getSymbolsByOffset().size()) {
|
||||
// Set break-point on next line. Multiple lines here to eliminate Eclipse warning.
|
||||
int a = 1;
|
||||
a = a + 1;
|
||||
}
|
||||
int cnt = 0;
|
||||
for (Map.Entry<Long, AbstractMsSymbol> entry : symbolRecords.getSymbolsByOffset()
|
||||
.entrySet()) {
|
||||
AbstractMsSymbol msym = entry.getValue();
|
||||
AbstractMsSymbol lsym = symbols.get(cnt);
|
||||
String mstr = msym.toString();
|
||||
String lstr = lsym.toString();
|
||||
if (!mstr.equals(lstr)) {
|
||||
// Set break-point on next line. Multiple lines here to eliminate Eclipse warning.
|
||||
int b = 1;
|
||||
b = b + 1;
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
|
||||
// Compare module symbols
|
||||
for (int modnum = 0; modnum < numModules(); modnum++) {
|
||||
Module module = modules.get(modnum);
|
||||
MsSymbolIterator moduleSymbolsIterator = module.getSymbolIterator();
|
||||
cnt = 0;
|
||||
Map<Long, AbstractMsSymbol> map = symbolRecords.getModuleSymbolsByOffset(modnum);
|
||||
List<Long> keys = new ArrayList<>();
|
||||
for (Map.Entry<Long, AbstractMsSymbol> entry : map.entrySet()) {
|
||||
Long key = entry.getKey();
|
||||
keys.add(key);
|
||||
}
|
||||
Collections.sort(keys);
|
||||
for (Long key : keys) {
|
||||
AbstractMsSymbol msym = map.get(key);
|
||||
if (!moduleSymbolsIterator.hasNext()) {
|
||||
// Set break-point on next line. Multiple lines here to eliminate Eclipse warning.
|
||||
int c = 1;
|
||||
c = c + 1;
|
||||
break;
|
||||
}
|
||||
AbstractMsSymbol lsym = moduleSymbolsIterator.next();
|
||||
String mstr = msym.toString();
|
||||
String lstr = lsym.toString();
|
||||
if (!mstr.equals(lstr)) {
|
||||
// Set break-point on next line. Multiple lines here to eliminate Eclipse warning.
|
||||
int b = 1;
|
||||
b = b + 1;
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
if (moduleSymbolsIterator.hasNext()) {
|
||||
// Set break-point on next line. Multiple lines here to eliminate Eclipse warning.
|
||||
int d = 1;
|
||||
d = d + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -121,6 +121,11 @@ public class SegmentMapDescription {
|
||||
segLength = substreamReader.parseUnsignedIntVal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return dump();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the {@link SegmentMapDescription}. This method is for debugging only.
|
||||
* @return {@link String} of pretty output.
|
||||
|
@ -35,6 +35,23 @@ public class SymbolParser {
|
||||
private SymbolParser() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the record length and {@link AbstractMsSymbol} from the {@link PdbByteReader}
|
||||
* and returns the symbol.
|
||||
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed.
|
||||
* @param reader {@link PdbByteReader} from which to deserialize the symbol record.
|
||||
* @return {@link AbstractMsSymbol} that was parsed.
|
||||
* @throws PdbException upon error parsing a field.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
*/
|
||||
public static AbstractMsSymbol parseLengthAndSymbol(AbstractPdb pdb, PdbByteReader reader)
|
||||
throws PdbException, CancelledException {
|
||||
int recordLength = reader.parseUnsignedShortVal();
|
||||
PdbByteReader recordReader = reader.getSubPdbByteReader(recordLength);
|
||||
recordReader.markAlign(2);
|
||||
return parse(pdb, recordReader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes an {@link AbstractMsSymbol} from the {@link PdbByteReader} and returns it.
|
||||
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed.
|
||||
|
@ -68,61 +68,105 @@ public class SymbolRecords {
|
||||
* Deserializes the {@link SymbolRecords} from the stream noted in the DBI header.
|
||||
* @param monitor {@link TaskMonitor} used for checking cancellation.
|
||||
* @throws IOException On file seek or read, invalid parameters, bad file configuration, or
|
||||
* inability to read required bytes.
|
||||
* @throws PdbException Upon not enough data left to parse.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
* inability to read required bytes
|
||||
* @throws PdbException Upon not enough data left to parse
|
||||
* @throws CancelledException Upon user cancellation
|
||||
*/
|
||||
void deserialize(TaskMonitor monitor) throws IOException, PdbException, CancelledException {
|
||||
int streamNumber;
|
||||
PdbByteReader reader;
|
||||
processSymbols(monitor);
|
||||
processModuleSymbols(monitor);
|
||||
}
|
||||
|
||||
private void processSymbols(TaskMonitor monitor)
|
||||
throws IOException, PdbException, CancelledException {
|
||||
PdbDebugInfo debugInfo = pdb.getDebugInfo();
|
||||
if (debugInfo == null) {
|
||||
return;
|
||||
}
|
||||
streamNumber = debugInfo.getSymbolRecordsStreamNumber();
|
||||
int streamNumber = debugInfo.getSymbolRecordsStreamNumber();
|
||||
if (streamNumber <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
|
||||
symbolsByOffset = deserializeSymbolRecords(pdb, reader, monitor);
|
||||
}
|
||||
|
||||
for (AbstractModuleInformation module : debugInfo.moduleInformationList) {
|
||||
streamNumber = module.getStreamNumberDebugInformation();
|
||||
if (streamNumber != 0xffff) {
|
||||
// System.out.println("\n\nStreamNumber: " + streamNumber);
|
||||
reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
|
||||
int x = reader.parseInt(); // TODO: do not know what this value is.
|
||||
int sizeDebug = module.getSizeLocalSymbolsDebugInformation();
|
||||
sizeDebug -= x; //TODO: seems right, but need to evaluate this
|
||||
PdbByteReader debugReader = reader.getSubPdbByteReader(sizeDebug);
|
||||
Map<Long, AbstractMsSymbol> oneModuleSymbolsByOffset =
|
||||
deserializeSymbolRecords(pdb, debugReader, monitor);
|
||||
moduleSymbolsByOffset.add(oneModuleSymbolsByOffset);
|
||||
// TODO: figure out the rest of the bytes in the stream
|
||||
// As of 20190618: feel that this is where we will find C11Lines or C13Lines
|
||||
// information.
|
||||
// PdbByteReader rest = reader.getSubPdbByteReader(reader.numRemaining());
|
||||
// System.out.println(rest.dump());
|
||||
}
|
||||
else {
|
||||
moduleSymbolsByOffset.add(new TreeMap<>());
|
||||
}
|
||||
// Could split this method up into separate methods: one for module symbols and the other for
|
||||
// Lines processing. Note: would be processing streams more than once; lines would need to
|
||||
// skip over the symbols.
|
||||
private void processModuleSymbols(TaskMonitor monitor)
|
||||
throws IOException, PdbException, CancelledException {
|
||||
// cvSignature:
|
||||
// >64K = C6
|
||||
// 1 = C7
|
||||
// 2 = C11 (vc5.x)
|
||||
// 3 = ??? (not specified, and not marked as reserved)
|
||||
// 4 = C13 (vc7.x)
|
||||
// 5-64K = RESERVED
|
||||
//
|
||||
// Both cvdump (1660 and 1668) and mod.cpp (575) seem to indicate that the first module
|
||||
// might have the cvSignature of C7 or C11 (when C7/C11), but modules thereafter will not
|
||||
// or may not have the value. C13 would always have the C13 signature.
|
||||
boolean getSig = true;
|
||||
int cvSignature = 0;
|
||||
PdbDebugInfo debugInfo = pdb.getDebugInfo();
|
||||
if (debugInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (AbstractModuleInformation module : debugInfo.moduleInformationList) {
|
||||
monitor.checkCanceled();
|
||||
int streamNumber = module.getStreamNumberDebugInformation();
|
||||
if (streamNumber == 0xffff) {
|
||||
moduleSymbolsByOffset.add(new TreeMap<>());
|
||||
continue;
|
||||
}
|
||||
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNumber, monitor);
|
||||
|
||||
int sizeSymbolsSection = module.getSizeLocalSymbolsDebugInformation();
|
||||
PdbByteReader symbolsReader = reader.getSubPdbByteReader(sizeSymbolsSection);
|
||||
// See comment above regarding getSig boolean
|
||||
if (getSig) {
|
||||
cvSignature = symbolsReader.parseInt();
|
||||
}
|
||||
switch (cvSignature) {
|
||||
case 1:
|
||||
case 2:
|
||||
// We have no 1,2 examples to test this logic for cvSignature. Confirming
|
||||
// or rejecting this logic is important for simplifying/refactoring this
|
||||
// method or writing new methods to allow for extraction of information from
|
||||
// individual modules. The current implementation has cross-module logic
|
||||
// (setting state in the processing of the first and using this state in the
|
||||
// processing of follow-on modules).
|
||||
getSig = false;
|
||||
break;
|
||||
case 4:
|
||||
break;
|
||||
default:
|
||||
if (cvSignature < 0x10000) {
|
||||
throw new PdbException(
|
||||
"Invalid module CV signature in stream " + streamNumber);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Map<Long, AbstractMsSymbol> oneModuleSymbolsByOffset =
|
||||
deserializeSymbolRecords(pdb, symbolsReader, monitor);
|
||||
moduleSymbolsByOffset.add(oneModuleSymbolsByOffset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the {@link AbstractMsSymbol} symbols from the {@link PdbByteReader} and
|
||||
* returns a {@link Map}<{@link Long},{@link AbstractMsSymbol}> of buffer offsets to
|
||||
* symbols.
|
||||
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed.
|
||||
* @param reader {@link PdbByteReader} containing the symbol records to deserialize.
|
||||
* @param monitor {@link TaskMonitor} used for checking cancellation.
|
||||
* @return map of buffer offsets to {@link AbstractMsSymbol symbols}.
|
||||
* @throws PdbException Upon not enough data left to parse.
|
||||
* @throws CancelledException Upon user cancellation.
|
||||
* symbols
|
||||
* @param pdb {@link AbstractPdb} that owns the Symbols to be parsed
|
||||
* @param reader {@link PdbByteReader} containing the symbol records to deserialize
|
||||
* @param monitor {@link TaskMonitor} used for checking cancellation
|
||||
* @return map of buffer offsets to {@link AbstractMsSymbol symbols}
|
||||
* @throws PdbException Upon not enough data left to parse
|
||||
* @throws CancelledException Upon user cancellation
|
||||
*/
|
||||
public static Map<Long, AbstractMsSymbol> deserializeSymbolRecords(AbstractPdb pdb,
|
||||
PdbByteReader reader, TaskMonitor monitor) throws PdbException, CancelledException {
|
||||
@ -134,11 +178,7 @@ public class SymbolRecords {
|
||||
|
||||
// Including length in byte array for alignment purposes.
|
||||
int offset = reader.getIndex();
|
||||
int recordLength = reader.parseUnsignedShortVal();
|
||||
|
||||
PdbByteReader recordReader = reader.getSubPdbByteReader(recordLength);
|
||||
recordReader.markAlign(2);
|
||||
AbstractMsSymbol symbol = SymbolParser.parse(pdb, recordReader);
|
||||
AbstractMsSymbol symbol = SymbolParser.parseLengthAndSymbol(pdb, reader);
|
||||
mySymbolsByOffset.put((long) offset, symbol);
|
||||
}
|
||||
return mySymbolsByOffset;
|
||||
@ -147,7 +187,7 @@ public class SymbolRecords {
|
||||
/**
|
||||
* Debug method for dumping information from this Symbol Records instance.
|
||||
* @param writer {@link Writer} to which to dump the information.
|
||||
* @throws IOException Upon IOException writing to the {@link Writer}.
|
||||
* @throws IOException Upon IOException writing to the {@link Writer}
|
||||
*/
|
||||
protected void dump(Writer writer) throws IOException {
|
||||
writer.write("SymbolRecords-----------------------------------------------\n");
|
||||
@ -166,7 +206,7 @@ public class SymbolRecords {
|
||||
* Debug method for dumping the symbols from a symbol map
|
||||
* @param mySymbolsByOffset the {@link Map}<{@link Long},{@link AbstractMsSymbol}> to dump.
|
||||
* @param writer {@link Writer} to which to dump the information.
|
||||
* @throws IOException Upon IOException writing to the {@link Writer}.
|
||||
* @throws IOException Upon IOException writing to the {@link Writer}
|
||||
*/
|
||||
protected void dumpSymbolMap(Map<Long, AbstractMsSymbol> mySymbolsByOffset, Writer writer)
|
||||
throws IOException {
|
||||
|
@ -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)
|
||||
throws PdbException, CancelledException {
|
||||
super(pdb, reader);
|
||||
int recordLength = reader.parseUnsignedShortVal();
|
||||
PdbByteReader recordReader = reader.getSubPdbByteReader(recordLength);
|
||||
symbolRecord = SymbolParser.parse(pdb, recordReader);
|
||||
symbolRecord = SymbolParser.parseLengthAndSymbol(pdb, reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,8 +75,7 @@ public class ReferenceSymbolApplier extends MsSymbolApplier {
|
||||
}
|
||||
|
||||
long getOffsetInReferencedSymbolGroup() {
|
||||
// Adjusting offset to the offset we use for parsing the complete record.
|
||||
return symbol.getOffsetActualSymbolInDollarDollarSymbols() - 4;
|
||||
return symbol.getOffsetActualSymbolInDollarDollarSymbols();
|
||||
}
|
||||
|
||||
}
|
||||
|
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.
|
||||
* @param language the language
|
||||
* @param compiledForEditAndContinue true if compiled fro edit-and-continue
|
||||
* @param compiledForEditAndContinue true if compiled for edit-and-continue
|
||||
* @param notCompiledWithDebugInfo true if <b>not</b> compiled with debug info
|
||||
* @param compiledWithLinkTimeCodeGeneration true if compiled with link-time code generation
|
||||
* @param compiledWithBzalignNoDataAlign tru if compiled with BS align no data align
|
||||
* @param managedCodeDataPresent tru if managed code data is present
|
||||
* @param compiledWithBzalignNoDataAlign true if compiled with BS align no data align
|
||||
* @param managedCodeDataPresent true if managed code data is present
|
||||
* @param compiledWithGsBufferSecurityChecks true if compiled with GS Buffer security checks
|
||||
* @param compiledWithHotPatch true if compiled with ability to hot-patch
|
||||
* @param convertedWithCvtcil true if converted from (.NET IL) Common Intermediate Language Module
|
||||
* @param microsoftIntermediateLanguageNetModule true if MSFT intermediate language net module
|
||||
* @param compiledWithSdl true if compiledwith SDL
|
||||
* @param compiledWithSdl true if compiled with SDL
|
||||
* @param compiledWithLtcgPgoOrPgu true if compiled with light PGO or PGU
|
||||
* @param dotExpModule true if dot exp module
|
||||
* @return the flags packed into single integral form/value
|
||||
|
Loading…
Reference in New Issue
Block a user