mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
GP-3715 - PDB perf: resolve-as-you-go and stored types
This commit is contained in:
parent
30f6671998
commit
6f852989ca
46 changed files with 2587 additions and 3253 deletions
|
@ -16,17 +16,24 @@
|
||||||
// Text-dump all data types from the user-specified DataTypeManager to the user-specified file.
|
// Text-dump all data types from the user-specified DataTypeManager to the user-specified file.
|
||||||
//
|
//
|
||||||
//@category Data Types
|
//@category Data Types
|
||||||
|
import java.awt.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.plaf.basic.BasicHTML;
|
||||||
|
import javax.swing.text.View;
|
||||||
|
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
|
import generic.text.TextLayoutGraphics;
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.app.services.DataTypeManagerService;
|
import ghidra.app.services.DataTypeManagerService;
|
||||||
import ghidra.app.util.ToolTipUtils;
|
import ghidra.app.util.ToolTipUtils;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.*;
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.Swing;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
public class DeveloperDumpAllTypesScript extends GhidraScript {
|
public class DeveloperDumpAllTypesScript extends GhidraScript {
|
||||||
|
@ -62,7 +69,7 @@ public class DeveloperDumpAllTypesScript extends GhidraScript {
|
||||||
String pathString = dataTypePath.toString();
|
String pathString = dataTypePath.toString();
|
||||||
String htmlString = ToolTipUtils.getToolTipText(dataType);
|
String htmlString = ToolTipUtils.getToolTipText(dataType);
|
||||||
String plainString = Swing.runNow(() -> {
|
String plainString = Swing.runNow(() -> {
|
||||||
return HTMLUtilities.fromHTML(htmlString);
|
return fromHTML(htmlString);
|
||||||
});
|
});
|
||||||
fileWriter.append(pathString);
|
fileWriter.append(pathString);
|
||||||
fileWriter.append("\n");
|
fileWriter.append("\n");
|
||||||
|
@ -77,6 +84,100 @@ public class DeveloperDumpAllTypesScript extends GhidraScript {
|
||||||
Msg.info(this, message);
|
Msg.info(this, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method below copied from HTMLUtilities and modified to set a fixed size so that it
|
||||||
|
// is consistent between runs between tools over the course of time.
|
||||||
|
/**
|
||||||
|
* Checks the given string to see it is HTML, according to {@link BasicHTML} and then
|
||||||
|
* will return the text without any markup tags if it is.
|
||||||
|
*
|
||||||
|
* @param text the text to convert
|
||||||
|
* @return the converted String
|
||||||
|
*/
|
||||||
|
private static String fromHTML(String text) {
|
||||||
|
|
||||||
|
if (text == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!BasicHTML.isHTMLString(text)) {
|
||||||
|
// the message may still contain HTML, but that is something we don't handle
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Use the label's builtin handling of HTML text via the HTMLEditorKit
|
||||||
|
//
|
||||||
|
Swing.assertSwingThread("This method must be called on the Swing thread");
|
||||||
|
JLabel label = new JLabel(text) {
|
||||||
|
@Override
|
||||||
|
public void paint(Graphics g) {
|
||||||
|
// we cannot use paint, as we are not parented; change paint to call
|
||||||
|
// something that works
|
||||||
|
super.paintComponent(g);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
View v = (View) label.getClientProperty(BasicHTML.propertyKey);
|
||||||
|
if (v == null) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Use some magic to turn the painting into text
|
||||||
|
//
|
||||||
|
//Dimension size = label.getPreferredSize();
|
||||||
|
Dimension size = new Dimension(500, 500);
|
||||||
|
label.setBounds(new Rectangle(0, 0, size.width, size.height));
|
||||||
|
|
||||||
|
// Note: when laying out an unparented label, the y value will be half of the height
|
||||||
|
Rectangle bounds =
|
||||||
|
new Rectangle(-size.width, -size.height, size.width * 2, size.height * 10);
|
||||||
|
|
||||||
|
TextLayoutGraphics g = new TextLayoutGraphics();
|
||||||
|
|
||||||
|
g.setClip(bounds);
|
||||||
|
label.paint(g);
|
||||||
|
g.flush();
|
||||||
|
String raw = g.getBuffer();
|
||||||
|
raw = raw.trim(); // I can't see any reason to keep leading/trailing newlines/whitespace
|
||||||
|
|
||||||
|
String updated = replaceKnownSpecialCharacters(raw);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Unfortunately, the label adds odd artifacts to the output, like newlines after
|
||||||
|
// formatting tags (like <B>, <FONT>, etc). So, just normalize the text, not
|
||||||
|
// preserving any of the line breaks.
|
||||||
|
//
|
||||||
|
// Note: Calling this method here causes unwanted removal of newlines. If the original
|
||||||
|
// need for this call is found, this can be revisited.
|
||||||
|
// (see history for condense() code)
|
||||||
|
// String condensed = condense(updated);
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied from HTMLUtilities
|
||||||
|
/**
|
||||||
|
* A method to remove characters from the given string that are output by the HTML
|
||||||
|
* conversion process when going from HTML to plain text.
|
||||||
|
*
|
||||||
|
* @param s the string to be updated
|
||||||
|
* @return the updated String
|
||||||
|
*/
|
||||||
|
private static String replaceKnownSpecialCharacters(String s) {
|
||||||
|
StringBuilder buffy = new StringBuilder();
|
||||||
|
|
||||||
|
s.chars().forEach(c -> {
|
||||||
|
switch (c) {
|
||||||
|
case 0xA0:
|
||||||
|
buffy.append((char) 0x20);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
buffy.append((char) c);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return buffy.toString();
|
||||||
|
}
|
||||||
|
|
||||||
private DataTypeManager userChooseDataTypeManager() {
|
private DataTypeManager userChooseDataTypeManager() {
|
||||||
PluginTool tool = state.getTool();
|
PluginTool tool = state.getTool();
|
||||||
DataTypeManagerService service = tool.getService(DataTypeManagerService.class);
|
DataTypeManagerService service = tool.getService(DataTypeManagerService.class);
|
||||||
|
|
|
@ -934,7 +934,8 @@ public class DefaultCompositeMember extends CompositeMember {
|
||||||
CompositeMember lastUnionMember = unionMemberList.get(unionMemberList.size() - 1);
|
CompositeMember lastUnionMember = unionMemberList.get(unionMemberList.size() - 1);
|
||||||
if (isRelatedBitField(lastUnionMember, member)) {
|
if (isRelatedBitField(lastUnionMember, member)) {
|
||||||
if (lastUnionMember.isSingleBitFieldMember() &&
|
if (lastUnionMember.isSingleBitFieldMember() &&
|
||||||
!((DefaultCompositeMember) lastUnionMember).transformIntoStructureContainer()) {
|
!((DefaultCompositeMember) lastUnionMember)
|
||||||
|
.transformIntoStructureContainer()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return lastUnionMember.addMember(member);
|
return lastUnionMember.addMember(member);
|
||||||
|
|
|
@ -180,9 +180,6 @@ public class SymbolRecords {
|
||||||
*/
|
*/
|
||||||
public int getCvSigLength(int streamNumber)
|
public int getCvSigLength(int streamNumber)
|
||||||
throws CancelledException, IOException, PdbException {
|
throws CancelledException, IOException, PdbException {
|
||||||
// if (cvSignatureCase1and2Stream == MsfStream.NIL_STREAM_NUMBER) {
|
|
||||||
// throw new PdbException("CvSigLength not initialized");
|
|
||||||
// }
|
|
||||||
if (streamNumber == MsfStream.NIL_STREAM_NUMBER) {
|
if (streamNumber == MsfStream.NIL_STREAM_NUMBER) {
|
||||||
return 0; // returning inconsequential value; fact of NIL will be dealt with elsewhere
|
return 0; // returning inconsequential value; fact of NIL will be dealt with elsewhere
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ public abstract class TypeProgramInterface implements TPI {
|
||||||
|
|
||||||
protected int versionNumber = 0;
|
protected int versionNumber = 0;
|
||||||
|
|
||||||
private record OffLen(int offset, int length) {}; // record type for quick random access
|
private record OffLen(int offset, int length) {} // record type for quick random access
|
||||||
|
|
||||||
private List<OffLen> offLenRecords;
|
private List<OffLen> offLenRecords;
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,11 @@ public abstract class AbstractFieldListMsType extends AbstractMsType {
|
||||||
private List<MsTypeField> baseClassList = new ArrayList<>();
|
private List<MsTypeField> baseClassList = new ArrayList<>();
|
||||||
private List<MsTypeField> memberList = new ArrayList<>();
|
private List<MsTypeField> memberList = new ArrayList<>();
|
||||||
private List<MsTypeField> methodList = new ArrayList<>();
|
private List<MsTypeField> methodList = new ArrayList<>();
|
||||||
|
private List<AbstractMemberMsType> nonstaticMemberList = new ArrayList<>();
|
||||||
|
private List<AbstractStaticMemberMsType> staticMemberList = new ArrayList<>();
|
||||||
|
private List<AbstractVirtualFunctionTablePointerMsType> vftPtrList = new ArrayList<>();
|
||||||
|
private List<AbstractNestedTypeMsType> nestedTypeList = new ArrayList<>();
|
||||||
|
private List<AbstractEnumerateMsType> enumerateList = new ArrayList<>();
|
||||||
// This list contains AbstractIndexMsType instances. It seems that one of these contains
|
// This list contains AbstractIndexMsType instances. It seems that one of these contains
|
||||||
// the index to another AbstractFieldList. We do not (yet) know that if a third list is
|
// the index to another AbstractFieldList. We do not (yet) know that if a third list is
|
||||||
// needed, whether there will be a daisy-chain (last entry in second list will designate
|
// needed, whether there will be a daisy-chain (last entry in second list will designate
|
||||||
|
@ -52,27 +57,34 @@ public abstract class AbstractFieldListMsType extends AbstractMsType {
|
||||||
super(pdb, reader);
|
super(pdb, reader);
|
||||||
while (reader.hasMore()) {
|
while (reader.hasMore()) {
|
||||||
MsTypeField type = TypeParser.parseField(pdb, reader);
|
MsTypeField type = TypeParser.parseField(pdb, reader);
|
||||||
if ((type instanceof AbstractBaseClassMsType) ||
|
if (type instanceof AbstractBaseClassMsType ||
|
||||||
(type instanceof AbstractVirtualBaseClassMsType) ||
|
type instanceof AbstractVirtualBaseClassMsType ||
|
||||||
(type instanceof AbstractIndirectVirtualBaseClassMsType)) {
|
type instanceof AbstractIndirectVirtualBaseClassMsType) {
|
||||||
baseClassList.add(type);
|
baseClassList.add(type);
|
||||||
}
|
}
|
||||||
else if ((type instanceof AbstractOverloadedMethodMsType) ||
|
else if (type instanceof AbstractOverloadedMethodMsType ||
|
||||||
(type instanceof AbstractOneMethodMsType)) {
|
type instanceof AbstractOneMethodMsType) {
|
||||||
methodList.add(type);
|
methodList.add(type);
|
||||||
}
|
}
|
||||||
else if ((type instanceof AbstractMemberMsType) ||
|
else if (type instanceof AbstractMemberMsType member) {
|
||||||
(type instanceof AbstractNestedTypeMsType) ||
|
nonstaticMemberList.add(member);
|
||||||
(type instanceof AbstractStaticMemberMsType) ||
|
memberList.add(member);
|
||||||
(type instanceof AbstractVirtualFunctionTablePointerMsType) ||
|
}
|
||||||
(type instanceof AbstractEnumerateMsType)) {
|
else if (type instanceof AbstractStaticMemberMsType member) {
|
||||||
// Known types:
|
staticMemberList.add(member);
|
||||||
// AbstractMemberMsType
|
memberList.add(member);
|
||||||
// AbstractNestedTypeMsType
|
}
|
||||||
// AbstractStaticMemberMsType
|
else if (type instanceof AbstractVirtualFunctionTablePointerMsType vftPtr) {
|
||||||
// AbstractVirtualFunctionTablePointerMsType
|
vftPtrList.add(vftPtr);
|
||||||
// AbstractEnumerateMsType
|
memberList.add(vftPtr);
|
||||||
memberList.add(type);
|
}
|
||||||
|
else if (type instanceof AbstractNestedTypeMsType member) {
|
||||||
|
nestedTypeList.add(member);
|
||||||
|
memberList.add(member);
|
||||||
|
}
|
||||||
|
else if (type instanceof AbstractEnumerateMsType enumerate) {
|
||||||
|
enumerateList.add(enumerate);
|
||||||
|
memberList.add(enumerate);
|
||||||
}
|
}
|
||||||
else if (type instanceof AbstractIndexMsType) {
|
else if (type instanceof AbstractIndexMsType) {
|
||||||
indexList.add((AbstractIndexMsType) type);
|
indexList.add((AbstractIndexMsType) type);
|
||||||
|
@ -109,6 +121,42 @@ public abstract class AbstractFieldListMsType extends AbstractMsType {
|
||||||
return methodList;
|
return methodList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the (ordered?) {@link List}<{@link AbstractMsType}> of non-static members
|
||||||
|
* from this field list
|
||||||
|
* @return non-static members
|
||||||
|
*/
|
||||||
|
public List<AbstractMemberMsType> getNonStaticMembers() {
|
||||||
|
return nonstaticMemberList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the (ordered?) {@link List}<{@link AbstractMsType}> of VFT pointer records
|
||||||
|
* from this field list
|
||||||
|
* @return VFT pointer records
|
||||||
|
*/
|
||||||
|
public List<AbstractVirtualFunctionTablePointerMsType> getVftPointers() {
|
||||||
|
return vftPtrList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the (ordered?) {@link List}<{@link AbstractNestedTypeMsType}> of enumerates
|
||||||
|
* from this field list
|
||||||
|
* @return enumerates
|
||||||
|
*/
|
||||||
|
public List<AbstractNestedTypeMsType> getNestedTypes() {
|
||||||
|
return nestedTypeList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the (ordered?) {@link List}<{@link AbstractEnumerateMsType}> of enumerates
|
||||||
|
* from this field list
|
||||||
|
* @return enumerates
|
||||||
|
*/
|
||||||
|
public List<AbstractEnumerateMsType> getEnumerates() {
|
||||||
|
return enumerateList;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the (ordered?) {@link List}<{@link AbstractIndexMsType}> that we believe
|
* Returns the (ordered?) {@link List}<{@link AbstractIndexMsType}> that we believe
|
||||||
* will contain the reference only to other {@link AbstractFieldListMsType}s.
|
* will contain the reference only to other {@link AbstractFieldListMsType}s.
|
||||||
|
|
|
@ -59,7 +59,7 @@ public class BuildInfoMsType extends AbstractMsType {
|
||||||
count = reader.parseUnsignedShortVal();
|
count = reader.parseUnsignedShortVal();
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
int codeItemId = reader.parseInt();
|
int codeItemId = reader.parseInt();
|
||||||
RecordNumber itemRecordNumber = RecordNumber.make(RecordCategory.ITEM, codeItemId);
|
RecordNumber itemRecordNumber = RecordNumber.itemRecordNumber(codeItemId);
|
||||||
argsCodeItemRecordNumbers.add(itemRecordNumber);
|
argsCodeItemRecordNumbers.add(itemRecordNumber);
|
||||||
}
|
}
|
||||||
reader.skipPadding();
|
reader.skipPadding();
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.bin.format.pdb2.pdbreader.type;
|
package ghidra.app.util.bin.format.pdb2.pdbreader.type;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractPdb;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractPdb;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,6 +56,11 @@ public class PrimitiveMsType extends AbstractMsType {
|
||||||
builder.insert(0, typeString);
|
builder.insert(0, typeString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigInteger getSize() {
|
||||||
|
return BigInteger.valueOf(getTypeSize());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of this primitive type.
|
* Returns the name of this primitive type.
|
||||||
* @return Name type of the primitive type.
|
* @return Name type of the primitive type.
|
||||||
|
|
|
@ -35,6 +35,7 @@ public class PdbCategories {
|
||||||
private CategoryPath pdbUncategorizedCategory;
|
private CategoryPath pdbUncategorizedCategory;
|
||||||
private CategoryPath anonymousFunctionsCategory;
|
private CategoryPath anonymousFunctionsCategory;
|
||||||
private CategoryPath anonymousTypesCategory;
|
private CategoryPath anonymousTypesCategory;
|
||||||
|
private CategoryPath placeholderTypesCategory;
|
||||||
private CategoryPath baseModuleTypedefsCategory;
|
private CategoryPath baseModuleTypedefsCategory;
|
||||||
private List<CategoryPath> typedefCategories = new ArrayList<>();
|
private List<CategoryPath> typedefCategories = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -62,6 +63,8 @@ public class PdbCategories {
|
||||||
// anonymousFunctionCount = 0;
|
// anonymousFunctionCount = 0;
|
||||||
|
|
||||||
anonymousTypesCategory = new CategoryPath(pdbRootCategory, "!_anon_types_");
|
anonymousTypesCategory = new CategoryPath(pdbRootCategory, "!_anon_types_");
|
||||||
|
|
||||||
|
placeholderTypesCategory = new CategoryPath(pdbRootCategory, "!_placeholder_types_");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -190,6 +193,14 @@ public class PdbCategories {
|
||||||
return anonymousTypesCategory;
|
return anonymousTypesCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link CategoryPath} for Anonymous Types Category for the PDB.
|
||||||
|
* @return the {@link CategoryPath}
|
||||||
|
*/
|
||||||
|
public CategoryPath getPlaceholderTypesCategory() {
|
||||||
|
return placeholderTypesCategory;
|
||||||
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * Returns the name of what should be the next Anonymous Function (based on the count of
|
// * Returns the name of what should be the next Anonymous Function (based on the count of
|
||||||
// * the number of anonymous functions) so that there is a unique name for the function.
|
// * the number of anonymous functions) so that there is a unique name for the function.
|
||||||
|
|
|
@ -99,6 +99,9 @@ public class PdbNamespaceUtils {
|
||||||
if ("<unnamed-type>".equals(name)) {
|
if ("<unnamed-type>".equals(name)) {
|
||||||
return String.format("<unnamed-type_%08X>", index);
|
return String.format("<unnamed-type_%08X>", index);
|
||||||
}
|
}
|
||||||
|
if ("__unnamed".equals(name)) {
|
||||||
|
return String.format("__unnamed_%08X", index);
|
||||||
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,100 +17,70 @@ package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import ghidra.app.util.SymbolPath;
|
import ghidra.app.util.SymbolPath;
|
||||||
import ghidra.app.util.SymbolPathParser;
|
import ghidra.app.util.SymbolPathParser;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractComplexMsType;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractComplexMsType;
|
||||||
import ghidra.app.util.pdb.PdbNamespaceUtils;
|
import ghidra.app.util.pdb.PdbNamespaceUtils;
|
||||||
import ghidra.program.model.data.DataType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applier for {@link AbstractComplexMsType} types.
|
* Applier for {@link AbstractComplexMsType} types.
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractComplexTypeApplier extends MsTypeApplier {
|
public abstract class AbstractComplexTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
protected SymbolPath symbolPath;
|
// Intended for: AbstractComplexMsType
|
||||||
protected SymbolPath fixedSymbolPath;
|
|
||||||
|
|
||||||
protected AbstractComplexTypeApplier definitionApplier = null;
|
|
||||||
protected AbstractComplexTypeApplier forwardReferenceApplier = null;
|
|
||||||
|
|
||||||
public static AbstractComplexTypeApplier getComplexApplier(DefaultPdbApplicator applicator,
|
|
||||||
RecordNumber recordNumber) throws PdbException {
|
|
||||||
return (AbstractComplexTypeApplier) applicator.getApplierSpec(recordNumber,
|
|
||||||
AbstractComplexTypeApplier.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for complex type applier.
|
* Constructor for complex type applier.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractComplexMsType} to process.
|
|
||||||
*/
|
*/
|
||||||
public AbstractComplexTypeApplier(DefaultPdbApplicator applicator, AbstractComplexMsType msType) {
|
public AbstractComplexTypeApplier(DefaultPdbApplicator applicator) {
|
||||||
super(applicator, msType);
|
super(applicator);
|
||||||
String fullPathName = msType.getName();
|
|
||||||
symbolPath = new SymbolPath(SymbolPathParser.parse(fullPathName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolPath getSymbolPath() {
|
/**
|
||||||
return symbolPath;
|
* Returns the SymbolPath for the complex type parameter without using the record number
|
||||||
|
* @param type the MS complex PDB type
|
||||||
|
* @return the path
|
||||||
|
* @see #getFixedSymbolPath(AbstractComplexMsType type)
|
||||||
|
*/
|
||||||
|
SymbolPath getSymbolPath(AbstractComplexMsType type) {
|
||||||
|
String fullPathName = type.getName();
|
||||||
|
return new SymbolPath(SymbolPathParser.parse(fullPathName));
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isForwardReference() {
|
/**
|
||||||
return ((AbstractComplexMsType) msType).getMsProperty().isForwardReference();
|
* Returns the definition record for the specified complex type in case the record passed
|
||||||
|
* in is only its forward reference
|
||||||
|
* @param mType the MS complex PDB type
|
||||||
|
* @param type the derivative complex type class
|
||||||
|
* @param <T> the derivative class template argument
|
||||||
|
* @return the path
|
||||||
|
*/
|
||||||
|
public <T extends AbstractComplexMsType> T getDefinitionType(AbstractComplexMsType mType,
|
||||||
|
Class<T> type) {
|
||||||
|
Integer num = applicator.getNumber(mType);
|
||||||
|
Integer mappedIndex = applicator.getMappedComplexType(num);
|
||||||
|
if (mappedIndex != null) {
|
||||||
|
mType =
|
||||||
|
applicator.getPdb().getTypeRecord(RecordNumber.typeRecordNumber(mappedIndex), type);
|
||||||
|
}
|
||||||
|
return type.cast(mType);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isNested() {
|
/**
|
||||||
return ((AbstractComplexMsType) msType).getMsProperty().isNestedClass();
|
* Returns the SymbolPath for the complex type. This ensures that the SymbolPath pertains
|
||||||
|
* to the definition type in situations where the record number of the definition (vs. that
|
||||||
|
* of the forward reference) is needed for creation of the path
|
||||||
|
* @param type the MS complex PDB type
|
||||||
|
* @return the path
|
||||||
|
*/
|
||||||
|
//return mine or my def's (and set mine)
|
||||||
|
SymbolPath getFixedSymbolPath(AbstractComplexMsType type) {
|
||||||
|
SymbolPath path = getSymbolPath(type);
|
||||||
|
Integer num = applicator.getNumber(type);
|
||||||
|
Integer mappedIndex = applicator.getMappedComplexType(num);
|
||||||
|
if (mappedIndex != null) {
|
||||||
|
return PdbNamespaceUtils.convertToGhidraPathName(path, mappedIndex);
|
||||||
}
|
}
|
||||||
|
return PdbNamespaceUtils.convertToGhidraPathName(path, num);
|
||||||
boolean isFinal() {
|
|
||||||
return ((AbstractComplexMsType) msType).getMsProperty().isSealed();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setForwardReferenceApplier(AbstractComplexTypeApplier forwardReferenceApplier) {
|
|
||||||
this.forwardReferenceApplier = forwardReferenceApplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDefinitionApplier(AbstractComplexTypeApplier definitionApplier) {
|
|
||||||
this.definitionApplier = definitionApplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
<T extends AbstractComplexTypeApplier> T getDefinitionApplier(Class<T> typeClass) {
|
|
||||||
if (!typeClass.isInstance(definitionApplier)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return typeClass.cast(definitionApplier);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AbstractComplexTypeApplier getAlternativeTypeApplier() {
|
|
||||||
if (isForwardReference()) {
|
|
||||||
return definitionApplier;
|
|
||||||
}
|
|
||||||
return forwardReferenceApplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected SymbolPath getFixedSymbolPath() { //return mine or my def's (and set mine)
|
|
||||||
if (fixedSymbolPath != null) {
|
|
||||||
return fixedSymbolPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (definitionApplier != null && definitionApplier.getFixedSymbolPath() != null) {
|
|
||||||
fixedSymbolPath = definitionApplier.getFixedSymbolPath();
|
|
||||||
return fixedSymbolPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
SymbolPath fixed = PdbNamespaceUtils.convertToGhidraPathName(symbolPath, index);
|
|
||||||
if (symbolPath.equals(fixed)) {
|
|
||||||
fixedSymbolPath = symbolPath;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fixedSymbolPath = fixed;
|
|
||||||
}
|
|
||||||
return fixedSymbolPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataType getDataTypeInternal() {
|
|
||||||
return dataType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,14 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.app.util.DataTypeNamingUtil;
|
import ghidra.app.util.DataTypeNamingUtil;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.CallingConvention;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.DataType;
|
|
||||||
import ghidra.program.model.data.FunctionDefinitionDataType;
|
|
||||||
import ghidra.program.model.lang.CompilerSpec;
|
import ghidra.program.model.lang.CompilerSpec;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
@ -31,211 +32,109 @@ import ghidra.util.exception.InvalidInputException;
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractFunctionTypeApplier extends MsTypeApplier {
|
public abstract class AbstractFunctionTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
private FunctionDefinitionDataType functionDefinition;
|
// Intended for: see children
|
||||||
|
|
||||||
private MsTypeApplier returnApplier;
|
|
||||||
private ArgumentsListTypeApplier argsListApplier;
|
|
||||||
private CallingConvention callingConvention;
|
|
||||||
private boolean hasThisPointer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for the applicator that applies a "function" type, transforming it into a
|
* Constructor for the applicator that applies a "function" type, transforming it into a
|
||||||
* Ghidra DataType.
|
* Ghidra DataType.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractMsType} to processes
|
|
||||||
*/
|
*/
|
||||||
public AbstractFunctionTypeApplier(DefaultPdbApplicator applicator, AbstractMsType msType) {
|
public AbstractFunctionTypeApplier(DefaultPdbApplicator applicator) {
|
||||||
super(applicator, msType);
|
super(applicator);
|
||||||
// String funcName = applicator.getNextAnonymousFunctionName();
|
|
||||||
functionDefinition = new FunctionDefinitionDataType(
|
|
||||||
applicator.getAnonymousFunctionsCategory(), "_func", applicator.getDataTypeManager());
|
|
||||||
// Updating before trying to apply... if applyFunction fails, then this name will go
|
|
||||||
// unused for the most part, but we also will not get a conflict on the name.
|
|
||||||
// applicator.incrementNextAnonymousFunctionName();
|
|
||||||
dataType = functionDefinition;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================================
|
|
||||||
@Override
|
|
||||||
void deferredApply() throws PdbException, CancelledException {
|
|
||||||
if (isDeferred()) {
|
|
||||||
applyInternal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================================
|
|
||||||
/**
|
|
||||||
* Returns the function definition being created by this applier.
|
|
||||||
* @return the function definition.
|
|
||||||
*/
|
|
||||||
FunctionDefinitionDataType getFunctionDefinition() {
|
|
||||||
return functionDefinition;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
DataType getCycleBreakType() {
|
|
||||||
if (dataType != null) {
|
|
||||||
return dataType;
|
|
||||||
}
|
|
||||||
return functionDefinition;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the type applier of the return type
|
|
||||||
* @return the type applier
|
|
||||||
*/
|
|
||||||
MsTypeApplier getReturnTypeApplier() {
|
|
||||||
return applicator.getTypeApplier(getReturnRecordNumber());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link ArgumentsListTypeApplier}
|
|
||||||
* @return the type applier
|
|
||||||
*/
|
|
||||||
ArgumentsListTypeApplier getArgsListApplier() {
|
|
||||||
MsTypeApplier argsApplier = applicator.getTypeApplier(getArgListRecordNumber());
|
|
||||||
if (argsApplier instanceof ArgumentsListTypeApplier) {
|
|
||||||
return (ArgumentsListTypeApplier) applicator.getTypeApplier(getArgListRecordNumber());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link CallingConvention}
|
* Returns the {@link CallingConvention}
|
||||||
|
* @param type the PDB type being inspected
|
||||||
* @return the calling convention
|
* @return the calling convention
|
||||||
*/
|
*/
|
||||||
protected abstract CallingConvention getCallingConvention();
|
protected abstract CallingConvention getCallingConvention(AbstractMsType type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the function has a "this" pointer
|
* Returns the function "this" pointer
|
||||||
* @return {@code true} if it has a "this" pointer
|
* @param type the PDB type being inspected
|
||||||
|
* @param fixupContext the fixup context to use; or pass in null during fixup process
|
||||||
|
* @param breakCycle specify {@code true} when employing break-cycle logic (pointers to
|
||||||
|
* Composites within composites)
|
||||||
|
* @return the "this" pointer or null if does not have or is not a recognized type
|
||||||
|
* @throws CancelledException upon user cancellation
|
||||||
|
* @throws PdbException upon processing error
|
||||||
*/
|
*/
|
||||||
protected abstract boolean hasThisPointer();
|
protected abstract Pointer getThisPointer(AbstractMsType type, FixupContext fixupContext,
|
||||||
|
boolean breakCycle) throws CancelledException, PdbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link RecordNumber} of the function return type
|
* Returns the containing class if function member of class
|
||||||
* @return the record number
|
* @param type the PDB type being inspected
|
||||||
|
* @param fixupContext the fixup context to use; or pass in null during fixup process
|
||||||
|
* @param breakCycle specify {@code true} when employing break-cycle logic (pointers to
|
||||||
|
* Composites within composites)
|
||||||
|
* @return the containing class composite type
|
||||||
|
* @throws CancelledException upon user cancellation
|
||||||
|
* @throws PdbException upon processing error
|
||||||
*/
|
*/
|
||||||
protected abstract RecordNumber getReturnRecordNumber();
|
protected abstract Composite getContainingComplexApplier(AbstractMsType type,
|
||||||
|
FixupContext fixupContext, boolean breakCycle) throws CancelledException, PdbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link RecordNumber} of the function arguments list
|
* Processes containing class if one exists
|
||||||
* @return the record number
|
* @param type the PDB type being inspected
|
||||||
*/
|
*/
|
||||||
protected abstract RecordNumber getArgListRecordNumber();
|
protected abstract void processContainingType(AbstractMsType type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if known to be a constructor.
|
* Returns if known to be a constructor.
|
||||||
|
* @param type the PDB type being inspected
|
||||||
* @return true if constructor.
|
* @return true if constructor.
|
||||||
*/
|
*/
|
||||||
protected boolean isConstructor() {
|
protected boolean isConstructor(AbstractMsType type) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to create the {@link DataType} based upon the type indices of the calling
|
* Returns the {@link RecordNumber} of the function return type
|
||||||
* convention, return type, and arguments list.
|
* @param type the PDB type being inspected
|
||||||
* @param callingConventionParam Identification of the {@link AbstractMsType} record of the
|
* @return the record number
|
||||||
* {@link CallingConvention}.
|
|
||||||
* @param hasThisPointerParam true if has a this pointer
|
|
||||||
* @return {@link DataType} created or null upon issue.
|
|
||||||
* @throws PdbException when unexpected function internals are found.
|
|
||||||
* @throws CancelledException Upon user cancellation
|
|
||||||
*/
|
*/
|
||||||
protected DataType applyFunction(CallingConvention callingConventionParam,
|
protected abstract RecordNumber getReturnRecordNumber(AbstractMsType type);
|
||||||
boolean hasThisPointerParam) throws PdbException, CancelledException {
|
|
||||||
// String funcName = applicator.getCategoryUtils().getNextAnonymousFunctionName();
|
|
||||||
// FunctionDefinitionDataType functionDefinition = new FunctionDefinitionDataType(
|
|
||||||
// applicator.getCategoryUtils().getAnonymousFunctionsCategory(), funcName,
|
|
||||||
// applicator.getDataTypeManager());
|
|
||||||
|
|
||||||
this.callingConvention = callingConventionParam;
|
/**
|
||||||
this.hasThisPointer = hasThisPointerParam;
|
* Returns the {@link RecordNumber} of the function arguments list
|
||||||
returnApplier = getReturnTypeApplier();
|
* @param type the PDB type being inspected
|
||||||
argsListApplier = getArgsListApplier();
|
* @return the record number
|
||||||
|
*/
|
||||||
|
protected abstract RecordNumber getArgListRecordNumber(AbstractMsType type);
|
||||||
|
|
||||||
applyOrDeferForDependencies();
|
private boolean setReturnType(FunctionDefinitionDataType functionDefinition,
|
||||||
// applyInternal();
|
AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
|
throws CancelledException, PdbException {
|
||||||
// 20190725 remove for second pass in applicator
|
if (isConstructor(type)) {
|
||||||
// // TODO: what handler should we really use?
|
|
||||||
// DataType resolvedFunctionDefinition = applicator.resolve(functionDefinition);
|
|
||||||
//
|
|
||||||
// if (resolvedFunctionDefinition == null) {
|
|
||||||
// applicator.getLog().appendMsg("Function definition type not resolved for " + functionDefinition.getName());
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// if (!(resolvedFunctionDefinition instanceof FunctionDefinition)) {
|
|
||||||
// // Error... can this happen?
|
|
||||||
// // Remove what was just created?
|
|
||||||
// applicator.getLog().appendMsg("Non-function resolved for " + functionDefinition.getName());
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Only update if successful.
|
|
||||||
// applicator.getCategoryUtils().incrementNextAnonymousFunctionName();
|
|
||||||
// return resolvedFunctionDefinition;
|
|
||||||
return functionDefinition;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyOrDeferForDependencies() throws CancelledException {
|
|
||||||
if (returnApplier.isDeferred()) {
|
|
||||||
applicator.addApplierDependency(this, returnApplier);
|
|
||||||
setDeferred();
|
|
||||||
}
|
|
||||||
if (argsListApplier != null) {
|
|
||||||
argsListApplier.checkForDependencies(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isDeferred()) {
|
|
||||||
applyInternal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyInternal() throws CancelledException {
|
|
||||||
if (isApplied()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!setReturnType()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (argsListApplier != null) {
|
|
||||||
argsListApplier.applyTo(this);
|
|
||||||
}
|
|
||||||
setCallingConvention(applicator, callingConvention, hasThisPointer);
|
|
||||||
DataTypeNamingUtil.setMangledAnonymousFunctionName(functionDefinition);
|
|
||||||
setApplied();
|
|
||||||
|
|
||||||
// resolvedDataType = applicator.resolveHighUse(dataType);
|
|
||||||
// if (resolvedDataType != null) {
|
|
||||||
// resolved = true;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean setReturnType() {
|
|
||||||
|
|
||||||
if (isConstructor()) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
RecordNumber returnRecord = getReturnRecordNumber(type);
|
||||||
DataType returnDataType = returnApplier.getDataType();
|
if (returnRecord == null) {
|
||||||
if (returnDataType == null) {
|
|
||||||
applicator.appendLogMsg("Return type is null in " + functionDefinition.getName());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
functionDefinition.setReturnType(returnDataType);
|
DataType returnType =
|
||||||
|
applicator.getProcessedDataType(returnRecord, fixupContext, breakCycle);
|
||||||
|
if (returnType == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (applicator.isPlaceholderPointer(returnType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
functionDefinition.setReturnType(returnType);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCallingConvention(DefaultPdbApplicator applicator,
|
private void setCallingConvention(FunctionDefinitionDataType functionDefinition,
|
||||||
CallingConvention callingConvention, boolean hasThisPointer) {
|
CallingConvention callingConvention, Pointer thisPointer) {
|
||||||
String convention;
|
String convention;
|
||||||
if (hasThisPointer) {
|
if (thisPointer != null) {
|
||||||
convention = CompilerSpec.CALLING_CONVENTION_thiscall;
|
convention = CompilerSpec.CALLING_CONVENTION_thiscall;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Since we are a member function, we will always assume a _thiscall...
|
// Since we are a member function, we will always assume a _thiscall...
|
||||||
// but how do we know it is not a atatic member function (no "this")?
|
// but how do we know it is not a static member function (no "this")?
|
||||||
switch (callingConvention) {
|
switch (callingConvention) {
|
||||||
// TODO: figure all of these out.
|
// TODO: figure all of these out.
|
||||||
case THISCALL: // "this" passed in register (we have not yet seen this)
|
case THISCALL: // "this" passed in register (we have not yet seen this)
|
||||||
|
@ -248,10 +147,6 @@ public abstract class AbstractFunctionTypeApplier extends MsTypeApplier {
|
||||||
convention = CompilerSpec.CALLING_CONVENTION_vectorcall;
|
convention = CompilerSpec.CALLING_CONVENTION_vectorcall;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// applicator.getLog().appendMsg(
|
|
||||||
// "TODO: calling convention not implemented for value " + callingConventionVal +
|
|
||||||
// " in " + funcName);
|
|
||||||
//convention = GenericCallingConvention.cdecl;
|
|
||||||
convention = CompilerSpec.CALLING_CONVENTION_cdecl;
|
convention = CompilerSpec.CALLING_CONVENTION_cdecl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -265,4 +160,114 @@ public abstract class AbstractFunctionTypeApplier extends MsTypeApplier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean setArguments(FunctionDefinitionDataType functionDefinition, AbstractMsType type,
|
||||||
|
FixupContext fixupContext, boolean breakCycle) throws CancelledException, PdbException {
|
||||||
|
|
||||||
|
RecordNumber argsRecord = getArgListRecordNumber(type);
|
||||||
|
AbstractMsType aType = applicator.getPdb().getTypeRecord(argsRecord);
|
||||||
|
if (!(aType instanceof AbstractArgumentsListMsType argsList)) {
|
||||||
|
applicator.appendLogMsg(
|
||||||
|
"PDB Warning: expecting args list but found " + aType.getClass().getSimpleName() +
|
||||||
|
" for parameter list of " + functionDefinition.getName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasPlaceholder = false;
|
||||||
|
|
||||||
|
List<RecordNumber> args = argsList.getArgRecordNumbers();
|
||||||
|
List<ParameterDefinition> parameterDefinitionList = new ArrayList<>();
|
||||||
|
int parameterCount = 0;
|
||||||
|
for (RecordNumber arg : args) {
|
||||||
|
applicator.checkCancelled();
|
||||||
|
|
||||||
|
AbstractMsType argMsType = applicator.getPdb().getTypeRecord(arg);
|
||||||
|
if (argMsType instanceof PrimitiveMsType primitive && primitive.isNoType()) {
|
||||||
|
// Arguments list is empty. (There better not have been any arguments up until
|
||||||
|
// now.)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataType argDataType = applicator.getProcessedDataType(arg, fixupContext, breakCycle);
|
||||||
|
if (argDataType == null) {
|
||||||
|
applicator.appendLogMsg(
|
||||||
|
"PDB Warning: No type conversion for " + argMsType.toString() +
|
||||||
|
" for parameter " + parameterCount + " of " + functionDefinition.getName());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (applicator.isPlaceholderPointer(argDataType)) {
|
||||||
|
hasPlaceholder = true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ParameterDefinition parameterDefinition =
|
||||||
|
new ParameterDefinitionImpl(null, argDataType, "");
|
||||||
|
parameterDefinitionList.add(parameterDefinition);
|
||||||
|
parameterCount++;
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e) {
|
||||||
|
try {
|
||||||
|
DataType substitute =
|
||||||
|
Undefined.getUndefinedDataType(argDataType.getLength());
|
||||||
|
ParameterDefinition parameterDefinition =
|
||||||
|
new ParameterDefinitionImpl(null, substitute, "");
|
||||||
|
parameterDefinitionList.add(parameterDefinition);
|
||||||
|
parameterCount++;
|
||||||
|
applicator.appendLogMsg("PDB Warning: Could not apply type " + argDataType +
|
||||||
|
" for parameter " + parameterCount + " of " +
|
||||||
|
functionDefinition.getName() + ". Using undefined type instead.");
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e1) {
|
||||||
|
applicator.appendLogMsg("PDB Warning: Could not apply type " + argDataType +
|
||||||
|
" for parameter " + parameterCount + " of " +
|
||||||
|
functionDefinition.getName() + ". Undefined failed: " + e1);
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasPlaceholder) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
functionDefinition.setArguments(parameterDefinitionList
|
||||||
|
.toArray(new ParameterDefinition[parameterDefinitionList.size()]));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
|
throws CancelledException, PdbException {
|
||||||
|
DataType existing = applicator.getDataType(type);
|
||||||
|
if (existing != null) {
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
FunctionDefinitionDataType functionDefinition = new FunctionDefinitionDataType(
|
||||||
|
applicator.getAnonymousFunctionsCategory(), "_func", applicator.getDataTypeManager());
|
||||||
|
|
||||||
|
boolean hasPlaceholder = false;
|
||||||
|
|
||||||
|
processContainingType(type);
|
||||||
|
|
||||||
|
if (!setReturnType(functionDefinition, type, fixupContext, breakCycle)) {
|
||||||
|
hasPlaceholder = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!setArguments(functionDefinition, type, fixupContext, breakCycle)) {
|
||||||
|
hasPlaceholder = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasPlaceholder) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pointer thisPointer = getThisPointer(type, fixupContext, breakCycle);
|
||||||
|
CallingConvention convention = getCallingConvention(type);
|
||||||
|
setCallingConvention(functionDefinition, convention, thisPointer);
|
||||||
|
|
||||||
|
DataTypeNamingUtil.setMangledAnonymousFunctionName(functionDefinition);
|
||||||
|
|
||||||
|
DataType resolvedType = applicator.resolve(functionDefinition);
|
||||||
|
applicator.putDataType(type, resolvedType);
|
||||||
|
return resolvedType;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractArgumentsListMsType;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractArgumentsListMsType;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,196 +26,21 @@ import ghidra.util.exception.CancelledException;
|
||||||
*/
|
*/
|
||||||
public class ArgumentsListTypeApplier extends MsTypeApplier {
|
public class ArgumentsListTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
|
// Intended for: AbstractArgumentsListMsType
|
||||||
/**
|
/**
|
||||||
* Constructor for the applicator that applies a arguments list.
|
* Constructor for the applicator that applies a arguments list.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractArgumentsListMsType} to processes.
|
|
||||||
* @throws IllegalArgumentException Upon invalid arguments.
|
* @throws IllegalArgumentException Upon invalid arguments.
|
||||||
*/
|
*/
|
||||||
public ArgumentsListTypeApplier(DefaultPdbApplicator applicator,
|
public ArgumentsListTypeApplier(DefaultPdbApplicator applicator) throws IllegalArgumentException {
|
||||||
AbstractArgumentsListMsType msType) throws IllegalArgumentException {
|
super(applicator);
|
||||||
super(applicator, msType);
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================================
|
|
||||||
@Override
|
|
||||||
void deferredApply() throws PdbException, CancelledException {
|
|
||||||
// Do nothing... Just need dependency tie of each argument to function.
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================================
|
|
||||||
// TODO: would be nice if we did not have to implement this method. Want the applyTo() below.
|
|
||||||
@Override
|
|
||||||
void apply() throws PdbException, CancelledException {
|
|
||||||
// addMyDependenciesOnly();
|
|
||||||
// // Silently do nothing.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
BigInteger getSize() {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
return BigInteger.ZERO;
|
throws PdbException, CancelledException {
|
||||||
|
// do nothing
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private void addMyDependenciesOnly() throws CancelledException, PdbException {
|
|
||||||
// AbstractArgumentsListMsType argsList = (AbstractArgumentsListMsType) msType;
|
|
||||||
// List<AbstractTypeIndex> list = argsList.getArgTypeIndexList();
|
|
||||||
// for (AbstractTypeIndex element : list) {
|
|
||||||
// applicator.checkCancelled();
|
|
||||||
// AbstractMsTypeApplier argApplier = applicator.getTypeApplier(element.get());
|
|
||||||
//
|
|
||||||
// if (argApplier instanceof PrimitiveTypeApplier &&
|
|
||||||
// ((PrimitiveTypeApplier) argApplier).isNoType()) {
|
|
||||||
// // Arguments list is empty. (There better not have been any arguments up until
|
|
||||||
// // now.)
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (argApplier instanceof AbstractDeferrableMsTypeApplier &&
|
|
||||||
// ((AbstractDeferrableMsTypeApplier) argApplier).isDeferred()) {
|
|
||||||
// applicator.addApplierDependency(this, argApplier);
|
|
||||||
// setDeferred();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
void checkForDependencies(AbstractFunctionTypeApplier functionApplier)
|
|
||||||
throws CancelledException {
|
|
||||||
AbstractArgumentsListMsType argsList = (AbstractArgumentsListMsType) msType;
|
|
||||||
List<RecordNumber> args = argsList.getArgRecordNumbers();
|
|
||||||
for (RecordNumber arg : args) {
|
|
||||||
applicator.checkCancelled();
|
|
||||||
MsTypeApplier argApplier = applicator.getTypeApplier(arg);
|
|
||||||
|
|
||||||
if (argApplier instanceof PrimitiveTypeApplier &&
|
|
||||||
((PrimitiveTypeApplier) argApplier).isNoType()) {
|
|
||||||
// Arguments list is empty. (There better not have been any arguments up until
|
|
||||||
// now.)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (argApplier instanceof AbstractDeferrableMsTypeApplier &&
|
|
||||||
// ((AbstractDeferrableMsTypeApplier) argApplier).isDeferred()) {
|
|
||||||
// applicator.addApplierDependency(functionApplier, argApplier);
|
|
||||||
// functionApplier.setDeferred();
|
|
||||||
// }
|
|
||||||
if (argApplier.isDeferred()) {
|
|
||||||
applicator.addApplierDependency(functionApplier, argApplier);
|
|
||||||
functionApplier.setDeferred();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply this to function ({@link AbstractFunctionTypeApplier}).
|
|
||||||
* @param functionApplier the {@link AbstractFunctionTypeApplier} to which to apply the
|
|
||||||
* arguments.
|
|
||||||
* @throws CancelledException Upon user cancellation
|
|
||||||
*/
|
|
||||||
void applyTo(AbstractFunctionTypeApplier functionApplier) throws CancelledException {
|
|
||||||
FunctionDefinitionDataType functionDefinition = functionApplier.getFunctionDefinition();
|
|
||||||
|
|
||||||
AbstractArgumentsListMsType argsList = (AbstractArgumentsListMsType) msType;
|
|
||||||
List<RecordNumber> args = argsList.getArgRecordNumbers();
|
|
||||||
List<ParameterDefinition> parameterDefinitionList = new ArrayList<>();
|
|
||||||
int parameterCount = 0;
|
|
||||||
for (RecordNumber arg : args) {
|
|
||||||
applicator.checkCancelled();
|
|
||||||
MsTypeApplier argApplier = applicator.getTypeApplier(arg);
|
|
||||||
|
|
||||||
if (argApplier instanceof PrimitiveTypeApplier &&
|
|
||||||
((PrimitiveTypeApplier) argApplier).isNoType()) {
|
|
||||||
// Arguments list is empty. (There better not have been any arguments up until
|
|
||||||
// now.)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataType argDataType = argApplier.getDataType();
|
|
||||||
if (argDataType == null) {
|
|
||||||
applicator.appendLogMsg(
|
|
||||||
"PDB Warning: No type conversion for " + argApplier.getMsType().toString() +
|
|
||||||
" for parameter " + parameterCount + " of " + functionDefinition.getName());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
ParameterDefinition parameterDefinition =
|
|
||||||
new ParameterDefinitionImpl(null, argDataType, "");
|
|
||||||
parameterDefinitionList.add(parameterDefinition);
|
|
||||||
parameterCount++;
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException e) {
|
|
||||||
try {
|
|
||||||
DataType substitute =
|
|
||||||
Undefined.getUndefinedDataType(argDataType.getLength());
|
|
||||||
ParameterDefinition parameterDefinition =
|
|
||||||
new ParameterDefinitionImpl(null, substitute, "");
|
|
||||||
parameterDefinitionList.add(parameterDefinition);
|
|
||||||
parameterCount++;
|
|
||||||
applicator.appendLogMsg("PDB Warning: Could not apply type " + argDataType +
|
|
||||||
" for parameter " + parameterCount + " of " +
|
|
||||||
functionDefinition.getName() + ". Using undefined type instead.");
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException e1) {
|
|
||||||
applicator.appendLogMsg("PDB Warning: Could not apply type " + argDataType +
|
|
||||||
" for parameter " + parameterCount + " of " +
|
|
||||||
functionDefinition.getName() + ". Undefined failed: " + e1);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
functionDefinition.setArguments(parameterDefinitionList.toArray(
|
|
||||||
new ParameterDefinition[parameterDefinitionList.size()]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Apply this to function ({@link AbstractFunctionTypeApplier}).
|
|
||||||
// * @param functionApplier the {@link AbstractFunctionTypeApplier} to which to apply the
|
|
||||||
// * arguments.
|
|
||||||
// * @throws PdbException when unexpected function internals are found.
|
|
||||||
// * @throws CancelledException Upon user cancellation
|
|
||||||
// */
|
|
||||||
// public void applyTo(AbstractFunctionTypeApplier functionApplier)
|
|
||||||
// throws CancelledException, PdbException {
|
|
||||||
// FunctionDefinitionDataType functionDefinition = functionApplier.getFunctionDefinition();
|
|
||||||
//
|
|
||||||
// AbstractArgumentsListMsType argsList = (AbstractArgumentsListMsType) msType;
|
|
||||||
// List<AbstractTypeIndex> list = argsList.getArgTypeIndexList();
|
|
||||||
// List<ParameterDefinition> parameterDefinitionList = new ArrayList<>();
|
|
||||||
// int parameterCount = 0;
|
|
||||||
// for (AbstractTypeIndex element : list) {
|
|
||||||
// applicator.getMonitor().checkCancelled();
|
|
||||||
// AbstractMsTypeApplier argApplier = applicator.getTypeApplier(element.get());
|
|
||||||
//
|
|
||||||
// if (argApplier instanceof PrimitiveTypeApplier &&
|
|
||||||
// ((PrimitiveTypeApplier) argApplier).isNoType()) {
|
|
||||||
// // Arguments list is empty. (There better not have been any arguments up until
|
|
||||||
// // now.)
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (argApplier instanceof AbstractDeferrableMsTypeApplier &&
|
|
||||||
// ((AbstractDeferrableMsTypeApplier) argApplier).isDeferred()) {
|
|
||||||
// applicator.addApplierDependency(functionApplier, argApplier);
|
|
||||||
// functionApplier.setDeferred();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//// applicator.addApplierDependency(functionApplier, argApplier);
|
|
||||||
// DataType argDataType = argApplier.getDataType();
|
|
||||||
// if (argDataType == null) {
|
|
||||||
// String message =
|
|
||||||
// "PDB Warning: No type conversion for " + argApplier.getMsType().toString() +
|
|
||||||
// " for parameter " + parameterCount + " of " + functionDefinition.getName();
|
|
||||||
// applicator.getLog().appendMsg(message);
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// ParameterDefinition parameterDefinition =
|
|
||||||
// new ParameterDefinitionImpl(null, argDataType, "");
|
|
||||||
// parameterDefinitionList.add(parameterDefinition);
|
|
||||||
// parameterCount++;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// functionDefinition.setArguments(parameterDefinitionList.toArray(
|
|
||||||
// new ParameterDefinition[parameterDefinitionList.size()]));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,9 @@ package ghidra.app.util.pdb.pdbapplicator;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractArrayMsType;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractArrayMsType;
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
@ -28,107 +30,77 @@ import ghidra.util.exception.CancelledException;
|
||||||
*/
|
*/
|
||||||
public class ArrayTypeApplier extends MsTypeApplier {
|
public class ArrayTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
private MsTypeApplier underlyingTypeApplier = null;
|
// Intended for: AbstractArrayMsType
|
||||||
private boolean isFlexibleArray = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for the applicator that applies a "array" type, transforming it into a
|
* Constructor for the applicator that applies a "array" type, transforming it into a
|
||||||
* Ghidra DataType.
|
* Ghidra DataType.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractArrayMsType} to processes.
|
|
||||||
*/
|
*/
|
||||||
public ArrayTypeApplier(DefaultPdbApplicator applicator, AbstractArrayMsType msType) {
|
public ArrayTypeApplier(DefaultPdbApplicator applicator) {
|
||||||
super(applicator, msType);
|
super(applicator);
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================================
|
|
||||||
boolean isFlexibleArray() {
|
|
||||||
return isFlexibleArray;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void deferredApply() throws PdbException, CancelledException {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
// No work done here. Just deferring resolve.
|
throws PdbException, CancelledException {
|
||||||
|
return applyType((AbstractArrayMsType) type, fixupContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
boolean isFlexibleArray(AbstractMsType type) {
|
||||||
@Override
|
return BigInteger.ZERO.equals(type.getSize());
|
||||||
BigInteger getSize() {
|
|
||||||
return ((AbstractArrayMsType) msType).getSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private DataType applyType(AbstractArrayMsType type, FixupContext fixupContext)
|
||||||
void apply() throws PdbException, CancelledException {
|
throws CancelledException, PdbException {
|
||||||
applyOrDeferForDependencies();
|
if (fixupContext != null) {
|
||||||
|
DataType existingDt = applicator.getDataType(type);
|
||||||
|
if (existingDt != null) {
|
||||||
|
return existingDt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyOrDeferForDependencies() {
|
RecordNumber underlyingRecord = type.getElementTypeRecordNumber();
|
||||||
AbstractArrayMsType type = (AbstractArrayMsType) msType;
|
DataType underlyingDataType =
|
||||||
underlyingTypeApplier = applicator.getTypeApplier(type.getElementTypeRecordNumber());
|
applicator.getProcessedDataType(underlyingRecord, fixupContext, false);
|
||||||
if (underlyingTypeApplier instanceof ModifierTypeApplier) {
|
|
||||||
underlyingTypeApplier =
|
DataType dataType;
|
||||||
((ModifierTypeApplier) underlyingTypeApplier).getModifiedTypeApplier();
|
if (applicator.isPlaceholderType(underlyingDataType)) {
|
||||||
|
Long longArraySize = getSizeLong(type);
|
||||||
|
int intArraySize = longArraySize.intValue();
|
||||||
|
dataType =
|
||||||
|
applicator.getPlaceholderArray(intArraySize, underlyingDataType.getAlignment());
|
||||||
}
|
}
|
||||||
underlyingTypeApplier = underlyingTypeApplier.getDependencyApplier();
|
else {
|
||||||
applyType(type); // applying now, but resolve() might get deferred.
|
int numElements = calculateNumElements(type, underlyingDataType);
|
||||||
|
if (numElements == -1) {
|
||||||
|
// There was a math calculation problem (probably have the wrong underlying type,
|
||||||
|
// which we still need to figure out; i.e., better composite mapper) so we
|
||||||
|
// will change the underlying type for now...
|
||||||
|
underlyingDataType = Undefined1DataType.dataType;
|
||||||
|
numElements = getSizeInt(type); // array size (but divided by 1) is array size
|
||||||
|
}
|
||||||
|
dataType = new ArrayDataType(underlyingDataType, numElements, -1,
|
||||||
|
applicator.getDataTypeManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
// private void recurseAddDependency(AbstractMsTypeApplier dependee)
|
DataType resolvedType = applicator.resolve(dataType);
|
||||||
// throws CancelledException, PdbException {
|
applicator.putDataType(type, resolvedType);
|
||||||
// if (dependee instanceof ModifierTypeApplier) {
|
return resolvedType;
|
||||||
// ModifierTypeApplier modifierApplier = (ModifierTypeApplier) dependee;
|
|
||||||
// recurseAddDependency(modifierApplier.getModifiedTypeApplier());
|
|
||||||
// }
|
|
||||||
// else if (dependee instanceof CompositeTypeApplier) {
|
|
||||||
// CompositeTypeApplier defApplier =
|
|
||||||
// ((CompositeTypeApplier) dependee).getDefinitionApplier();
|
|
||||||
// if (defApplier != null) {
|
|
||||||
// applicator.addApplierDependency(this, defApplier);
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// applicator.addApplierDependency(this, dependee);
|
|
||||||
// }
|
|
||||||
// setDeferred();
|
|
||||||
// }
|
|
||||||
// else if (dependee instanceof ArrayTypeApplier) {
|
|
||||||
// applicator.addApplierDependency(this, dependee);
|
|
||||||
// setDeferred();
|
|
||||||
// }
|
|
||||||
// else if (dependee instanceof BitfieldTypeApplier) {
|
|
||||||
// int x =
|
|
||||||
// ((AbstractBitfieldMsType) ((BitfieldTypeApplier) dependee).getMsType()).getElementTypeIndex();
|
|
||||||
// AbstractMsTypeApplier underlyingApplier = applicator.getTypeApplier(x);
|
|
||||||
// if (underlyingApplier instanceof EnumTypeApplier) {
|
|
||||||
// applicator.addApplierDependency(this, underlyingApplier);
|
|
||||||
// setDeferred();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// //We are assuming that bitfields on typedefs will not be defined.
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
|
|
||||||
private void applyType(AbstractArrayMsType type) {
|
|
||||||
applyArrayMsType((AbstractArrayMsType) msType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyArrayMsType(AbstractArrayMsType type) {
|
private int calculateNumElements(AbstractArrayMsType type, DataType underlyingDataType) {
|
||||||
if (isApplied()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
long longUnderlyingSize =
|
|
||||||
DefaultPdbApplicator.bigIntegerToLong(applicator, underlyingTypeApplier.getSize());
|
|
||||||
DataType underlyingDataType = underlyingTypeApplier.getDataType();
|
|
||||||
|
|
||||||
if (underlyingDataType == null) {
|
if (underlyingDataType == null) {
|
||||||
Long v = longUnderlyingSize;
|
// TODO: test and clean up... can this happen?
|
||||||
underlyingDataType = Undefined.getUndefinedDataType(v.intValue());
|
underlyingDataType = Undefined1DataType.dataType;
|
||||||
String msg = "PDB Type index " + index + ":\n Null underlying data type for " +
|
String msg = "PDB Type index " + type.getRecordNumber().getNumber() +
|
||||||
underlyingTypeApplier.getClass().getSimpleName() + ":\n " +
|
":\n Null underlying data type for " + type.getClass().getSimpleName() +
|
||||||
underlyingTypeApplier + "\n Using " + underlyingDataType;
|
":\n " + type.getName() + "\n Using " + underlyingDataType;
|
||||||
Msg.warn(this, msg);
|
Msg.warn(this, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long longUnderlyingSize = underlyingDataType.getLength();
|
||||||
|
|
||||||
if (longUnderlyingSize > Integer.MAX_VALUE) {
|
if (longUnderlyingSize > Integer.MAX_VALUE) {
|
||||||
String msg = "PDB " + type.getClass().getSimpleName() + ": Underlying type too large " +
|
String msg = "PDB " + type.getClass().getSimpleName() + ": Underlying type too large " +
|
||||||
underlyingDataType.getName();
|
underlyingDataType.getName();
|
||||||
|
@ -137,14 +109,10 @@ public class ArrayTypeApplier extends MsTypeApplier {
|
||||||
longUnderlyingSize = 1L;
|
longUnderlyingSize = 1L;
|
||||||
}
|
}
|
||||||
else if (longUnderlyingSize == 0L) {
|
else if (longUnderlyingSize == 0L) {
|
||||||
String msg = "PDB " + type.getClass().getSimpleName() +
|
|
||||||
": Zero-sized underlying type " + underlyingDataType.getName();
|
|
||||||
Msg.warn(this, msg);
|
|
||||||
underlyingDataType = Undefined1DataType.dataType;
|
|
||||||
longUnderlyingSize = 1L;
|
longUnderlyingSize = 1L;
|
||||||
}
|
}
|
||||||
|
|
||||||
long longArraySize = getSizeLong();
|
long longArraySize = getSizeLong(type);
|
||||||
long longNumElements = longArraySize / longUnderlyingSize;
|
long longNumElements = longArraySize / longUnderlyingSize;
|
||||||
|
|
||||||
if (longNumElements > Integer.MAX_VALUE) {
|
if (longNumElements > Integer.MAX_VALUE) {
|
||||||
|
@ -163,31 +131,12 @@ public class ArrayTypeApplier extends MsTypeApplier {
|
||||||
longUnderlyingSize;
|
longUnderlyingSize;
|
||||||
Msg.warn(this, msg);
|
Msg.warn(this, msg);
|
||||||
// bad calculation. Underlying type does not evenly fit into array total size.
|
// bad calculation. Underlying type does not evenly fit into array total size.
|
||||||
underlyingDataType = Undefined1DataType.dataType;
|
return -1;
|
||||||
longUnderlyingSize = 1L;
|
|
||||||
longNumElements = longArraySize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int numElements = (int) longNumElements;
|
int numElements = (int) longNumElements;
|
||||||
|
|
||||||
ArrayDataType arrayDataType;
|
return numElements;
|
||||||
|
|
||||||
// TODO: Need to find way to pass errorComment on to encompassing composite or other
|
|
||||||
if (numElements == 0) {
|
|
||||||
// flexible array
|
|
||||||
arrayDataType = new ArrayDataType(underlyingDataType, 1, underlyingDataType.getLength(),
|
|
||||||
applicator.getDataTypeManager());
|
|
||||||
isFlexibleArray = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
arrayDataType = new ArrayDataType(underlyingDataType, numElements, -1,
|
|
||||||
applicator.getDataTypeManager());
|
|
||||||
isFlexibleArray = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
setApplied();
|
|
||||||
|
|
||||||
dataType = arrayDataType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,108 +27,38 @@ import ghidra.util.exception.CancelledException;
|
||||||
*/
|
*/
|
||||||
public class BaseClassTypeApplier extends MsTypeApplier {
|
public class BaseClassTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
|
// Intended for: AbstractBaseClassMsType, AbstractVirtualBaseClassMsType, or
|
||||||
|
// AbstractIndirectVirtualBaseClassMsType
|
||||||
/**
|
/**
|
||||||
* Constructor for base class applier.
|
* Constructor for base class applier.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractBaseClassMsType}, {@link AbstractVirtualBaseClassMsType}, or
|
|
||||||
* {@link AbstractIndirectVirtualBaseClassMsType} to processes.
|
|
||||||
* @throws IllegalArgumentException Upon invalid arguments.
|
* @throws IllegalArgumentException Upon invalid arguments.
|
||||||
*/
|
*/
|
||||||
public BaseClassTypeApplier(DefaultPdbApplicator applicator, AbstractMsType msType)
|
public BaseClassTypeApplier(DefaultPdbApplicator applicator)
|
||||||
throws IllegalArgumentException {
|
throws IllegalArgumentException {
|
||||||
super(applicator, validateType(msType));
|
super(applicator);
|
||||||
}
|
|
||||||
|
|
||||||
// The MsTypes for which we are working do not have a size in and of themselves, but the
|
|
||||||
// classes/structures to which they refer have a size, even if zero.
|
|
||||||
// For here, we are only reporting what "we" have, not what the underlying sizes are.
|
|
||||||
// ...and a value of zero is our "don't know" and "not represented" value.
|
|
||||||
@Override
|
|
||||||
BigInteger getSize() {
|
|
||||||
return BigInteger.ZERO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the offset of the Base Class within the inheriting class.
|
* Returns the record number of the base class
|
||||||
* @return the offset.
|
* @param type the PDB type being inspected
|
||||||
* @throws PdbException if field is not available.
|
* @return the record number
|
||||||
*/
|
*/
|
||||||
BigInteger getOffset() throws PdbException {
|
RecordNumber getBaseClassRecordNumber(AbstractMsType type) {
|
||||||
if (msType instanceof AbstractBaseClassMsType) {
|
if (type instanceof AbstractBaseClassMsType baseType) {
|
||||||
return ((AbstractBaseClassMsType) msType).getOffset();
|
return baseType.getBaseClassRecordNumber();
|
||||||
}
|
}
|
||||||
throw new PdbException("Offset is not a valid field");
|
else if (type instanceof AbstractVirtualBaseClassMsType virtualType) {
|
||||||
|
return virtualType.getBaseClassRecordNumber();
|
||||||
}
|
}
|
||||||
|
return ((AbstractIndirectVirtualBaseClassMsType) type).getBaseClassRecordNumber();
|
||||||
/**
|
|
||||||
* Returns the offset of the base base pointer within the class.
|
|
||||||
* @return the offset.
|
|
||||||
* @throws PdbException if field is not available.
|
|
||||||
*/
|
|
||||||
BigInteger getBasePointerOffset() throws PdbException {
|
|
||||||
if (msType instanceof AbstractBaseClassMsType) {
|
|
||||||
throw new PdbException("Base Pointer Offset is not valid field");
|
|
||||||
}
|
|
||||||
else if (msType instanceof AbstractVirtualBaseClassMsType) {
|
|
||||||
return ((AbstractVirtualBaseClassMsType) msType).getBasePointerOffset();
|
|
||||||
}
|
|
||||||
return ((AbstractIndirectVirtualBaseClassMsType) msType).getBasePointerOffset();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the attributes of the base class within the inheriting class.
|
|
||||||
* @return the attributes;
|
|
||||||
*/
|
|
||||||
ClassFieldMsAttributes getAttributes() {
|
|
||||||
if (msType instanceof AbstractBaseClassMsType) {
|
|
||||||
return ((AbstractBaseClassMsType) msType).getAttributes();
|
|
||||||
}
|
|
||||||
else if (msType instanceof AbstractVirtualBaseClassMsType) {
|
|
||||||
return ((AbstractVirtualBaseClassMsType) msType).getAttributes();
|
|
||||||
}
|
|
||||||
return ((AbstractIndirectVirtualBaseClassMsType) msType).getAttributes();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the record number of the base class.
|
|
||||||
* @return the record number;
|
|
||||||
*/
|
|
||||||
RecordNumber getBaseClassRecordNumber() {
|
|
||||||
if (msType instanceof AbstractBaseClassMsType) {
|
|
||||||
return ((AbstractBaseClassMsType) msType).getBaseClassRecordNumber();
|
|
||||||
}
|
|
||||||
else if (msType instanceof AbstractVirtualBaseClassMsType) {
|
|
||||||
return ((AbstractVirtualBaseClassMsType) msType).getBaseClassRecordNumber();
|
|
||||||
}
|
|
||||||
return ((AbstractIndirectVirtualBaseClassMsType) msType).getBaseClassRecordNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether there is a Virtual Base Pointer type index available.
|
|
||||||
* @return {@code true} if available.
|
|
||||||
*/
|
|
||||||
boolean hasVirtualBasePointerTypeIndex() {
|
|
||||||
return (!(msType instanceof AbstractBaseClassMsType));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the record number of the virtual base pointer.
|
|
||||||
* @return the record number;
|
|
||||||
* @throws PdbException if not a virtual base class.
|
|
||||||
*/
|
|
||||||
RecordNumber getVirtualBasePointerRecordNumber() throws PdbException {
|
|
||||||
if (msType instanceof AbstractVirtualBaseClassMsType) {
|
|
||||||
return ((AbstractVirtualBaseClassMsType) msType).getVirtualBasePointerRecordNumber();
|
|
||||||
}
|
|
||||||
else if (msType instanceof AbstractIndirectVirtualBaseClassMsType) {
|
|
||||||
return ((AbstractIndirectVirtualBaseClassMsType) msType).getVirtualBasePointerRecordNumber();
|
|
||||||
}
|
|
||||||
throw new PdbException("Not a virtual base class");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void apply() throws PdbException, CancelledException {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
// do nothing at the moment.
|
throws PdbException, CancelledException {
|
||||||
|
// do nothing
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AbstractMsType validateType(AbstractMsType type)
|
private static AbstractMsType validateType(AbstractMsType type)
|
||||||
|
|
|
@ -15,11 +15,11 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb.PdbBitField;
|
import ghidra.app.util.bin.format.pdb.PdbBitField;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractBitfieldMsType;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractBitfieldMsType;
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.data.InvalidDataTypeException;
|
import ghidra.program.model.data.InvalidDataTypeException;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
@ -28,63 +28,37 @@ import ghidra.util.exception.CancelledException;
|
||||||
* Applier for {@link AbstractBitfieldMsType} types.
|
* Applier for {@link AbstractBitfieldMsType} types.
|
||||||
*/
|
*/
|
||||||
public class BitfieldTypeApplier extends MsTypeApplier {
|
public class BitfieldTypeApplier extends MsTypeApplier {
|
||||||
private MsTypeApplier elementTypeApplier = null;
|
|
||||||
|
|
||||||
|
// Intended for: AbstractBitfieldMsType
|
||||||
/**
|
/**
|
||||||
* Constructor for bitfield applier.
|
* Constructor for bitfield applier.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractBitfieldMsType} to processes
|
|
||||||
*/
|
*/
|
||||||
public BitfieldTypeApplier(DefaultPdbApplicator applicator, AbstractBitfieldMsType msType) {
|
public BitfieldTypeApplier(DefaultPdbApplicator applicator) {
|
||||||
super(applicator, msType);
|
super(applicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
BigInteger getSize() {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
if (elementTypeApplier == null) {
|
throws PdbException, CancelledException {
|
||||||
return BigInteger.ZERO;
|
AbstractBitfieldMsType mType = (AbstractBitfieldMsType) type;
|
||||||
}
|
RecordNumber elementRecordNumber = mType.getElementRecordNumber();
|
||||||
return elementTypeApplier.getSize();
|
DataType baseDataType =
|
||||||
}
|
applicator.getProcessedDataType(elementRecordNumber, fixupContext, breakCycle);
|
||||||
|
DataType bitFieldDataType;
|
||||||
@Override
|
|
||||||
void apply() throws PdbException, CancelledException {
|
|
||||||
// The bitfield does not get resolved/commited to the DataTypeManager.
|
|
||||||
dataType = applyBitfieldMsType((AbstractBitfieldMsType) msType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private DataType applyBitfieldMsType(AbstractBitfieldMsType type) {
|
|
||||||
elementTypeApplier = applicator.getTypeApplier(type.getElementRecordNumber());
|
|
||||||
if (elementTypeApplier instanceof ModifierTypeApplier) {
|
|
||||||
elementTypeApplier =
|
|
||||||
((ModifierTypeApplier) elementTypeApplier).getModifiedTypeApplier();
|
|
||||||
}
|
|
||||||
if (!(elementTypeApplier instanceof PrimitiveTypeApplier ||
|
|
||||||
(elementTypeApplier instanceof EnumTypeApplier))) {
|
|
||||||
applicator.appendLogMsg(
|
|
||||||
"Unable to process underlying type for Bitfield: " + type.getName());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
DataType baseDataType = elementTypeApplier.getDataType();
|
|
||||||
|
|
||||||
DataType bitFieldDataType = null;
|
|
||||||
try {
|
try {
|
||||||
bitFieldDataType = new Pdb2BitField(baseDataType.clone(applicator.getDataTypeManager()),
|
bitFieldDataType = new Pdb2BitField(baseDataType.clone(applicator.getDataTypeManager()),
|
||||||
type.getBitLength(), type.getBitPosition());
|
mType.getBitLength(), mType.getBitPosition());
|
||||||
}
|
}
|
||||||
catch (InvalidDataTypeException e) {
|
catch (InvalidDataTypeException e) {
|
||||||
applicator.appendLogMsg(
|
applicator.appendLogMsg(
|
||||||
"Problem creating PdbBitField for " + type.getName() + ", error: " + e.toString());
|
"Problem creating PdbBitField for " + type.getName() + ", error: " + e.toString());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// do not resolve bit-fields!
|
||||||
return bitFieldDataType;
|
return bitFieldDataType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
void resolve() {
|
|
||||||
// Do not resolve Bitfield Types... will be resolved with composite!!!
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>Pdb2BitField</code> provides ability to hang onto bitfield as a datatype.
|
* <code>Pdb2BitField</code> provides ability to hang onto bitfield as a datatype.
|
||||||
* This will be transformed to a normal BitFieldDataType when cloned.
|
* This will be transformed to a normal BitFieldDataType when cloned.
|
||||||
|
|
|
@ -29,19 +29,6 @@ public class ClassTypeUtils {
|
||||||
private ClassTypeUtils() {
|
private ClassTypeUtils() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an "internals" CategoryPath within the datatype managed by the applier
|
|
||||||
* @param applier for the owning composite datatype of the internals path
|
|
||||||
* @return the CategoryPath
|
|
||||||
*/
|
|
||||||
public static CategoryPath getInternalsCategoryPath(CompositeTypeApplier applier) {
|
|
||||||
DataType dt = applier.getDataType();
|
|
||||||
if (dt instanceof Composite composite) {
|
|
||||||
return getInternalsCategoryPath(composite);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Eventually consider changing Composite argument below as model is refined.
|
// TODO: Eventually consider changing Composite argument below as model is refined.
|
||||||
/**
|
/**
|
||||||
* Returns an "internals" CategoryPath for the owning composite datatype
|
* Returns an "internals" CategoryPath for the owning composite datatype
|
||||||
|
@ -54,18 +41,12 @@ public class ClassTypeUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a DataTypePath for the named type within the "internals" category of the type
|
* Returns an "internals" CategoryPath for the owning composite datatype
|
||||||
* managed byte the applier
|
* @param categoryPath path of the composite
|
||||||
* @param applier the applier
|
* @return the CategoryPath
|
||||||
* @param name the name of the type for the DataTypePath
|
|
||||||
* @return the DataTypePath
|
|
||||||
*/
|
*/
|
||||||
public static DataTypePath getInternalsDataTypePath(CompositeTypeApplier applier, String name) {
|
public static CategoryPath getInternalsCategoryPath(CategoryPath categoryPath) {
|
||||||
CategoryPath cp = getInternalsCategoryPath(applier);
|
return categoryPath.extend(INTERNALS);
|
||||||
if (cp == null || StringUtils.isAllBlank(name)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new DataTypePath(cp, name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Eventually consider changing Composite argument below as model is refined.
|
// TODO: Eventually consider changing Composite argument below as model is refined.
|
||||||
|
|
|
@ -1,273 +0,0 @@
|
||||||
/* ###
|
|
||||||
* 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.pdb.pdbapplicator;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import ghidra.app.util.SymbolPath;
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.TypeProgramInterface;
|
|
||||||
import ghidra.util.Msg;
|
|
||||||
import ghidra.util.exception.CancelledException;
|
|
||||||
import ghidra.util.task.TaskMonitor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Two-way Maps forward references with corresponding definitions for composites and enums.
|
|
||||||
* Uses the forward reference and definition members of the AbstractComplexTypeApplier.
|
|
||||||
*/
|
|
||||||
// We have probably tried 5 or more ways of doing this, all with mixed results. The current
|
|
||||||
// implementation seems to yield the best results at the moment. Keeping some of the old code
|
|
||||||
// around until we are solid on our algorithm and until we document some of the various algorithms
|
|
||||||
// tried.
|
|
||||||
public class ComplexTypeApplierMapper {
|
|
||||||
|
|
||||||
private DefaultPdbApplicator applicator;
|
|
||||||
|
|
||||||
// private Map<SymbolPath, AbstractComplexTypeApplier> complexTypeAppliersBySymbolPath;
|
|
||||||
private Map<SymbolPath, LinkedList<AbstractComplexTypeApplier>> compositeAppliersQueueBySymbolPath;
|
|
||||||
private Map<SymbolPath, LinkedList<AbstractComplexTypeApplier>> enumAppliersQueueBySymbolPath;
|
|
||||||
|
|
||||||
//==============================================================================================
|
|
||||||
public ComplexTypeApplierMapper(DefaultPdbApplicator applicator) {
|
|
||||||
Objects.requireNonNull(applicator, "applicator cannot be null");
|
|
||||||
this.applicator = applicator;
|
|
||||||
// complexTypeAppliersBySymbolPath = new HashMap<>();
|
|
||||||
compositeAppliersQueueBySymbolPath = new HashMap<>();
|
|
||||||
enumAppliersQueueBySymbolPath = new HashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================================
|
|
||||||
//==============================================================================================
|
|
||||||
void mapAppliers(ComplexTypeMapper typeMapper, TaskMonitor monitor) throws CancelledException {
|
|
||||||
Objects.requireNonNull(typeMapper, "typeMapper cannot be null");
|
|
||||||
TypeProgramInterface typeProgramInterface = applicator.getPdb().getTypeProgramInterface();
|
|
||||||
if (typeProgramInterface == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (Map.Entry<Integer, Integer> entry : typeMapper.getMap().entrySet()) {
|
|
||||||
monitor.checkCancelled();
|
|
||||||
int fwdNum = entry.getKey();
|
|
||||||
int defNum = entry.getValue();
|
|
||||||
MsTypeApplier fwd = applicator.getTypeApplier(RecordNumber.typeRecordNumber(fwdNum));
|
|
||||||
MsTypeApplier def = applicator.getTypeApplier(RecordNumber.typeRecordNumber(defNum));
|
|
||||||
if (!(fwd instanceof AbstractComplexTypeApplier fwdApplier)) {
|
|
||||||
Msg.error(this, "Applier not complex type: " + fwd.toString());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!(def instanceof AbstractComplexTypeApplier defApplier)) {
|
|
||||||
Msg.error(this, "Applier not complex type: " + def.toString());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
fwdApplier.setDefinitionApplier(defApplier);
|
|
||||||
defApplier.setForwardReferenceApplier(fwdApplier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================================
|
|
||||||
//==============================================================================================
|
|
||||||
void mapAppliers(TaskMonitor monitor) throws CancelledException {
|
|
||||||
TypeProgramInterface typeProgramInterface = applicator.getPdb().getTypeProgramInterface();
|
|
||||||
if (typeProgramInterface == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int indexLimit = typeProgramInterface.getTypeIndexMaxExclusive();
|
|
||||||
int indexNumber = typeProgramInterface.getTypeIndexMin();
|
|
||||||
monitor.initialize(indexLimit - indexNumber);
|
|
||||||
monitor.setMessage("PDB: Mapping Composites...");
|
|
||||||
while (indexNumber < indexLimit) {
|
|
||||||
monitor.checkCancelled();
|
|
||||||
//PdbResearch.checkBreak(indexNumber);
|
|
||||||
MsTypeApplier applier =
|
|
||||||
applicator.getTypeApplier(RecordNumber.typeRecordNumber(indexNumber++));
|
|
||||||
// From real data, we know that an enum and a composite both had the same SymbolPath,
|
|
||||||
// so enums and composites must be maintained separately so they do not get matched
|
|
||||||
// with each other.
|
|
||||||
if (applier instanceof CompositeTypeApplier) {
|
|
||||||
// mapComplexApplierBySymbolPath(compositeAppliersFwdRefQueueBySymbolPath,
|
|
||||||
// (AbstractComplexTypeApplier) applier);
|
|
||||||
mapComplexApplierTwoWayBySymbolPath(compositeAppliersQueueBySymbolPath,
|
|
||||||
(AbstractComplexTypeApplier) applier);
|
|
||||||
}
|
|
||||||
else if (applier instanceof EnumTypeApplier) {
|
|
||||||
// mapComplexApplierBySymbolPath(enumAppliersFwdRefQueueBySymbolPath,
|
|
||||||
// (AbstractComplexTypeApplier) applier);
|
|
||||||
mapComplexApplierTwoWayBySymbolPath(enumAppliersQueueBySymbolPath,
|
|
||||||
(AbstractComplexTypeApplier) applier);
|
|
||||||
}
|
|
||||||
// if (applier instanceof AbstractComplexTypeApplier) {
|
|
||||||
// mapComplexApplierByQueue((AbstractComplexTypeApplier) applier);
|
|
||||||
// //mapComplexApplierForwardOnly((AbstractComplexTypeApplier) applier);
|
|
||||||
// //mapComplexApplier((AbstractComplexTypeApplier) applier);
|
|
||||||
// }
|
|
||||||
monitor.incrementProgress(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mapComplexApplierTwoWayBySymbolPath(
|
|
||||||
Map<SymbolPath, LinkedList<AbstractComplexTypeApplier>> applierQueueBySymbolPath,
|
|
||||||
AbstractComplexTypeApplier complexApplier) {
|
|
||||||
SymbolPath symbolPath = complexApplier.getSymbolPath();
|
|
||||||
Objects.requireNonNull(symbolPath, "SymbolPath may not be null");
|
|
||||||
|
|
||||||
LinkedList<AbstractComplexTypeApplier> appliers = applierQueueBySymbolPath.get(symbolPath);
|
|
||||||
if (appliers == null) {
|
|
||||||
appliers = new LinkedList<>();
|
|
||||||
applierQueueBySymbolPath.put(symbolPath, appliers);
|
|
||||||
// Putting forward reference or definition (doesn't matter which it is)
|
|
||||||
if (!appliers.add(complexApplier)) {
|
|
||||||
// Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (appliers.peekFirst().isForwardReference() == complexApplier.isForwardReference()) {
|
|
||||||
// Only need to look at first on list, as all on list are the same forward reference
|
|
||||||
// of definition.
|
|
||||||
// If same as what is on list, add to the list.
|
|
||||||
if (!appliers.add(complexApplier)) {
|
|
||||||
// Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// int fwd;
|
|
||||||
// int def;
|
|
||||||
if (complexApplier.isForwardReference()) {
|
|
||||||
AbstractComplexTypeApplier definitionApplier = appliers.removeFirst();
|
|
||||||
definitionApplier.setForwardReferenceApplier(complexApplier);
|
|
||||||
complexApplier.setDefinitionApplier(definitionApplier);
|
|
||||||
// fwd = complexApplier.getIndex();
|
|
||||||
// def = definitionApplier.getIndex();
|
|
||||||
// System.out.println(String.format("%d %s %d -> %d", (complexApplier instanceof EnumTypeApplier) ? 1 : 0, symbolPath.toString(), fwd, def ) );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
AbstractComplexTypeApplier forwardReferenceApplier = appliers.removeFirst();
|
|
||||||
forwardReferenceApplier.setDefinitionApplier(complexApplier);
|
|
||||||
complexApplier.setForwardReferenceApplier(forwardReferenceApplier);
|
|
||||||
// fwd = forwardReferenceApplier.getIndex();
|
|
||||||
// def = complexApplier.getIndex();
|
|
||||||
// System.out.println(String.format("%d %s %d <- %d", (complexApplier instanceof EnumTypeApplier) ? 1 : 0, symbolPath.toString(), fwd, def ) );
|
|
||||||
}
|
|
||||||
if (appliers.isEmpty()) {
|
|
||||||
// Do not need to keep all of these around.
|
|
||||||
applierQueueBySymbolPath.remove(symbolPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// private void mapComplexApplier(AbstractComplexTypeApplier complexApplier) {
|
|
||||||
// SymbolPath symbolPath = complexApplier.getSymbolPath();
|
|
||||||
//
|
|
||||||
// AbstractComplexTypeApplier cachedComplexApplier =
|
|
||||||
// getComplexTypeApplierBySymbolPath(symbolPath, complexApplier.getClass());
|
|
||||||
// if (cachedComplexApplier == null) {
|
|
||||||
// // Setting cache if not already set or setting to definition.
|
|
||||||
// putComplexTypeApplierBySymbolPath(symbolPath, complexApplier);
|
|
||||||
// }
|
|
||||||
// else if (cachedComplexApplier.isForwardReference()) {
|
|
||||||
// if (!complexApplier.isForwardReference()) {
|
|
||||||
// cachedComplexApplier.setDefinitionApplier(complexApplier);
|
|
||||||
// complexApplier.setFwdRefApplier(cachedComplexApplier);
|
|
||||||
// }
|
|
||||||
// // Setting cache to new applier, whether fwd ref or definition.
|
|
||||||
// putComplexTypeApplierBySymbolPath(symbolPath, complexApplier);
|
|
||||||
// }
|
|
||||||
// else { // cached is definition
|
|
||||||
// if (!complexApplier.isForwardReference()) { // we are definition
|
|
||||||
// // Setting cache if not already set or setting to definition.
|
|
||||||
// putComplexTypeApplierBySymbolPath(symbolPath, complexApplier);
|
|
||||||
// }
|
|
||||||
// else { // we are forward ref
|
|
||||||
// AbstractComplexTypeApplier fwdRef =
|
|
||||||
// cachedComplexApplier.getFwdRefApplier(complexApplier.getClass());
|
|
||||||
// if (fwdRef == null) {
|
|
||||||
// // cached definition did not have a forward ref but we are one, so hook it up?
|
|
||||||
// // problem is if a definition follows... ugh. Not sure want to do this.
|
|
||||||
// complexApplier.setDefinitionApplier(cachedComplexApplier);
|
|
||||||
// cachedComplexApplier.setFwdRefApplier(complexApplier);
|
|
||||||
// // would like to cache a forward ref, but are are tying it to a previous
|
|
||||||
// // definition, so not.
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// // Setting cache if not already set or setting to definition.
|
|
||||||
// putComplexTypeApplierBySymbolPath(symbolPath, complexApplier);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Only caching forward ref and then mapping only following def to forward reference.
|
|
||||||
// // Clearing cache after that def so next def does not map.
|
|
||||||
// private void mapComplexApplierForwardOnly(AbstractComplexTypeApplier complexApplier) {
|
|
||||||
// SymbolPath symbolPath = complexApplier.getSymbolPath();
|
|
||||||
//
|
|
||||||
// if (complexApplier.isForwardReference()) {
|
|
||||||
// putComplexTypeApplierBySymbolPath(symbolPath, complexApplier);
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// AbstractComplexTypeApplier cachedComplexApplier =
|
|
||||||
// getComplexTypeApplierBySymbolPath(symbolPath, complexApplier.getClass());
|
|
||||||
// if (cachedComplexApplier != null) {
|
|
||||||
// cachedComplexApplier.setDefinitionApplier(complexApplier);
|
|
||||||
// complexApplier.setFwdRefApplier(cachedComplexApplier);
|
|
||||||
// // set cache back to null
|
|
||||||
// complexTypeAppliersBySymbolPath.remove(symbolPath);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private void putComplexTypeApplierBySymbolPath(SymbolPath symbolPath,
|
|
||||||
// AbstractComplexTypeApplier applier) {
|
|
||||||
// Objects.requireNonNull(symbolPath, "SymbolPath may not be null");
|
|
||||||
// Objects.requireNonNull(applier, "CompositeTypeApplier may not be null");
|
|
||||||
// complexTypeAppliersBySymbolPath.put(symbolPath, applier);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private <T extends AbstractComplexTypeApplier> T getComplexTypeApplierBySymbolPath(
|
|
||||||
// SymbolPath symbolPath, Class<T> typeClass) {
|
|
||||||
// Objects.requireNonNull(symbolPath, "SymbolPath may not be null");
|
|
||||||
// Objects.requireNonNull(typeClass, "typeClass may not be null");
|
|
||||||
// AbstractComplexTypeApplier applier = complexTypeAppliersBySymbolPath.get(symbolPath);
|
|
||||||
// if (!typeClass.isInstance(applier)) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// return typeClass.cast(applier);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// //==============================================================================================
|
|
||||||
// private void mapComplexApplierBySymbolPath(
|
|
||||||
// Map<SymbolPath, LinkedList<AbstractComplexTypeApplier>> applierQueueBySymbolPath,
|
|
||||||
// AbstractComplexTypeApplier complexApplier) {
|
|
||||||
// SymbolPath symbolPath = complexApplier.getSymbolPath();
|
|
||||||
// Objects.requireNonNull(symbolPath, "SymbolPath may not be null");
|
|
||||||
//
|
|
||||||
// LinkedList<AbstractComplexTypeApplier> fwdList = applierQueueBySymbolPath.get(symbolPath);
|
|
||||||
// if (fwdList == null) {
|
|
||||||
// fwdList = new LinkedList<>();
|
|
||||||
// applierQueueBySymbolPath.put(symbolPath, fwdList);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (complexApplier.isForwardReference()) {
|
|
||||||
// if (!fwdList.add(complexApplier)) {
|
|
||||||
// // Error
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else if (!fwdList.isEmpty()) {
|
|
||||||
// AbstractComplexTypeApplier fwdApplier = fwdList.removeFirst();
|
|
||||||
// fwdApplier.setDefinitionApplier(complexApplier);
|
|
||||||
// complexApplier.setFwdRefApplier(fwdApplier);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
|
|
||||||
}
|
|
|
@ -66,13 +66,6 @@ public class ComplexTypeMapper {
|
||||||
return map.getOrDefault(recordNumber, recordNumber);
|
return map.getOrDefault(recordNumber, recordNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temporary method while switching over processing mechanisms and still using
|
|
||||||
// ComplexTypeApplierMapper (vs. this ComplexTypeMapper).
|
|
||||||
@Deprecated
|
|
||||||
Map<Integer, Integer> getMap() {
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Storing type (isFwd or isDef) so that if we decide to parse Types on demand, we will not
|
// Storing type (isFwd or isDef) so that if we decide to parse Types on demand, we will not
|
||||||
// have to parse it again to see if it is a fwdref or def.
|
// have to parse it again to see if it is a fwdref or def.
|
||||||
private record NumFwdRef(int number, boolean isFwd) {}
|
private record NumFwdRef(int number, boolean isFwd) {}
|
||||||
|
@ -100,10 +93,9 @@ public class ComplexTypeMapper {
|
||||||
// more definitions come in the input stream. If the FIFO empties of forward references,
|
// more definitions come in the input stream. If the FIFO empties of forward references,
|
||||||
// and another definition is found in the input stream, then the FIFO starts storing
|
// and another definition is found in the input stream, then the FIFO starts storing
|
||||||
// definitions instead.
|
// definitions instead.
|
||||||
// Specifically using LinkedList in Map, as not all Queues are appropriate
|
// All we need for the Deque is a simple FIFO.
|
||||||
// (e.g., PriorityQueue).
|
Map<SymbolPath, Deque<NumFwdRef>> compositeFIFOsByPath = new HashMap<>();
|
||||||
Map<SymbolPath, LinkedList<NumFwdRef>> compositeFIFOsByPath = new HashMap<>();
|
Map<SymbolPath, Deque<NumFwdRef>> enumFIFOsByPath = new HashMap<>();
|
||||||
Map<SymbolPath, LinkedList<NumFwdRef>> enumFIFOsByPath = new HashMap<>();
|
|
||||||
|
|
||||||
// Map is used for combo of Composites and Enums, but the FIFOs above had to be
|
// Map is used for combo of Composites and Enums, but the FIFOs above had to be
|
||||||
// separated (or get complicated in other ways by adding more to the FIFO values).
|
// separated (or get complicated in other ways by adding more to the FIFO values).
|
||||||
|
@ -134,15 +126,15 @@ public class ComplexTypeMapper {
|
||||||
|
|
||||||
// Always mapping higher index to lower index, as we are assuming we will processing indices
|
// Always mapping higher index to lower index, as we are assuming we will processing indices
|
||||||
// in an increasing order later.
|
// in an increasing order later.
|
||||||
private void mapComplexTypesByPath(Map<SymbolPath, LinkedList<NumFwdRef>> typeFIFOsByPath,
|
private void mapComplexTypesByPath(Map<SymbolPath, Deque<NumFwdRef>> typeFIFOsByPath,
|
||||||
int indexNumber, AbstractComplexMsType complexType) {
|
int indexNumber, AbstractComplexMsType complexType) {
|
||||||
|
|
||||||
SymbolPath symbolPath = new SymbolPath(SymbolPathParser.parse(complexType.getName()));
|
SymbolPath symbolPath = new SymbolPath(SymbolPathParser.parse(complexType.getName()));
|
||||||
boolean isFwdRef = complexType.getMsProperty().isForwardReference();
|
boolean isFwdRef = complexType.getMsProperty().isForwardReference();
|
||||||
|
|
||||||
LinkedList<NumFwdRef> numTypeFIFO = typeFIFOsByPath.get(symbolPath);
|
Deque<NumFwdRef> numTypeFIFO = typeFIFOsByPath.get(symbolPath);
|
||||||
if (numTypeFIFO == null) {
|
if (numTypeFIFO == null) {
|
||||||
numTypeFIFO = new LinkedList<>();
|
numTypeFIFO = new ArrayDeque<>();
|
||||||
typeFIFOsByPath.put(symbolPath, numTypeFIFO);
|
typeFIFOsByPath.put(symbolPath, numTypeFIFO);
|
||||||
|
|
||||||
// Putting forward reference or definition (doesn't matter which it is)
|
// Putting forward reference or definition (doesn't matter which it is)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -52,13 +52,12 @@ public class DataSymbolApplier extends MsSymbolApplier {
|
||||||
void applyTo(MsSymbolApplier applyToApplier) throws PdbException, CancelledException {
|
void applyTo(MsSymbolApplier applyToApplier) throws PdbException, CancelledException {
|
||||||
if (applyToApplier instanceof FunctionSymbolApplier) {
|
if (applyToApplier instanceof FunctionSymbolApplier) {
|
||||||
FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applyToApplier;
|
FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applyToApplier;
|
||||||
MsTypeApplier applier = getTypeApplier();
|
DataType dataType = applicator.getCompletedDataType(symbol.getTypeRecordNumber());
|
||||||
DataType dataType = applier.getDataType();
|
|
||||||
if (dataType == null) { // TODO: check that we can have null here.
|
if (dataType == null) { // TODO: check that we can have null here.
|
||||||
return; // silently return.
|
return; // silently return.
|
||||||
}
|
}
|
||||||
Address address = applicator.getAddress(symbol);
|
Address address = applicator.getAddress(symbol);
|
||||||
if (!createData(address, applier)) {
|
if (!createData(address, dataType)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
functionSymbolApplier.setLocalVariable(address, symbol.getName(), dataType);
|
functionSymbolApplier.setLocalVariable(address, symbol.getName(), dataType);
|
||||||
|
@ -82,29 +81,16 @@ public class DataSymbolApplier extends MsSymbolApplier {
|
||||||
return applicator.getTypeApplier(symbol.getTypeRecordNumber());
|
return applicator.getTypeApplier(symbol.getTypeRecordNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean createData(Address address, RecordNumber typeRecordNumber) {
|
boolean createData(Address address, RecordNumber typeRecordNumber)
|
||||||
MsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber);
|
throws CancelledException, PdbException {
|
||||||
if (applier == null) {
|
DataType dataType = applicator.getCompletedDataType(symbol.getTypeRecordNumber());
|
||||||
applicator.appendLogMsg("Error: Failed to resolve datatype RecordNumber " +
|
return createData(address, dataType);
|
||||||
typeRecordNumber + " at " + address);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return createData(address, applier);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean createData(Address address, MsTypeApplier applier) {
|
boolean createData(Address address, DataType dataType) {
|
||||||
if (applicator.isInvalidAddress(address, symbol.getName())) {
|
if (applicator.isInvalidAddress(address, symbol.getName())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
DataType dataType = applier.getDataType();
|
|
||||||
if (dataType == null) {
|
|
||||||
if (!(applier instanceof PrimitiveTypeApplier) ||
|
|
||||||
!((PrimitiveTypeApplier) applier).isNoType()) {
|
|
||||||
applicator.appendLogMsg("Error: Failed to resolve datatype " +
|
|
||||||
applier.getMsType().getName() + " at " + address);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (applicator.getImageBase().equals(address) &&
|
if (applicator.getImageBase().equals(address) &&
|
||||||
!"_IMAGE_DOS_HEADER".equals(dataType.getName())) {
|
!"_IMAGE_DOS_HEADER".equals(dataType.getName())) {
|
||||||
return false; // Squash some noise
|
return false; // Squash some noise
|
||||||
|
@ -170,13 +156,11 @@ public class DataSymbolApplier extends MsSymbolApplier {
|
||||||
try {
|
try {
|
||||||
applicator.getProgram()
|
applicator.getProgram()
|
||||||
.getListing()
|
.getListing()
|
||||||
.clearCodeUnits(address,
|
.clearCodeUnits(address, address.add(dataTypeLength - 1), false);
|
||||||
address.add(dataTypeLength - 1), false);
|
|
||||||
if (dataType.getLength() == -1) {
|
if (dataType.getLength() == -1) {
|
||||||
applicator.getProgram()
|
applicator.getProgram()
|
||||||
.getListing()
|
.getListing()
|
||||||
.createData(address, dataType,
|
.createData(address, dataType, dataTypeLength);
|
||||||
dataTypeLength);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
applicator.getProgram().getListing().createData(address, dataType);
|
applicator.getProgram().getListing().createData(address, dataType);
|
||||||
|
@ -191,8 +175,7 @@ public class DataSymbolApplier extends MsSymbolApplier {
|
||||||
try {
|
try {
|
||||||
applicator.getProgram()
|
applicator.getProgram()
|
||||||
.getListing()
|
.getListing()
|
||||||
.clearCodeUnits(address,
|
.clearCodeUnits(address, address.add(dataTypeLength - 1), false);
|
||||||
address.add(dataTypeLength - 1), false);
|
|
||||||
applicator.getProgram().getListing().createData(address, dataType, dataTypeLength);
|
applicator.getProgram().getListing().createData(address, dataType, dataTypeLength);
|
||||||
}
|
}
|
||||||
catch (CodeUnitInsertionException e) {
|
catch (CodeUnitInsertionException e) {
|
||||||
|
|
|
@ -35,9 +35,6 @@ import ghidra.app.util.bin.format.pe.cli.tables.CliAbstractTableRow;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.app.util.pdb.PdbCategories;
|
import ghidra.app.util.pdb.PdbCategories;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.graph.*;
|
|
||||||
import ghidra.graph.algo.GraphNavigator;
|
|
||||||
import ghidra.graph.jung.JungDirectedGraph;
|
|
||||||
import ghidra.program.disassemble.DisassemblerContextImpl;
|
import ghidra.program.disassemble.DisassemblerContextImpl;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSet;
|
import ghidra.program.model.address.AddressSet;
|
||||||
|
@ -77,36 +74,34 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
/**
|
/**
|
||||||
* Returns integer value of BigInteger or Long.MAX_VALUE if does not fit
|
* Returns integer value of BigInteger or Long.MAX_VALUE if does not fit
|
||||||
* @param myApplicator PdbApplicator for which we are working
|
|
||||||
* @param big BigInteger value to convert
|
* @param big BigInteger value to convert
|
||||||
* @return the integer value
|
* @return the integer value
|
||||||
*/
|
*/
|
||||||
static long bigIntegerToLong(DefaultPdbApplicator myApplicator, BigInteger big) {
|
long bigIntegerToLong(BigInteger big) {
|
||||||
try {
|
try {
|
||||||
return big.longValueExact();
|
return big.longValueExact();
|
||||||
}
|
}
|
||||||
catch (ArithmeticException e) {
|
catch (ArithmeticException e) {
|
||||||
String msg = "BigInteger value greater than max Long: " + big;
|
String msg = "BigInteger value greater than max Long: " + big;
|
||||||
PdbLog.message(msg);
|
PdbLog.message(msg);
|
||||||
myApplicator.appendLogMsg(msg);
|
appendLogMsg(msg);
|
||||||
return Long.MAX_VALUE;
|
return Long.MAX_VALUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns integer value of BigInteger or Integer.MAX_VALUE if does not fit
|
* Returns integer value of BigInteger or Integer.MAX_VALUE if does not fit
|
||||||
* @param myApplicator PdbApplicator for which we are working
|
|
||||||
* @param big BigInteger value to convert
|
* @param big BigInteger value to convert
|
||||||
* @return the integer value
|
* @return the integer value
|
||||||
*/
|
*/
|
||||||
static int bigIntegerToInt(DefaultPdbApplicator myApplicator, BigInteger big) {
|
int bigIntegerToInt(BigInteger big) {
|
||||||
try {
|
try {
|
||||||
return big.intValueExact();
|
return big.intValueExact();
|
||||||
}
|
}
|
||||||
catch (ArithmeticException e) {
|
catch (ArithmeticException e) {
|
||||||
String msg = "BigInteger value greater than max Integer: " + big;
|
String msg = "BigInteger value greater than max Integer: " + big;
|
||||||
PdbLog.message(msg);
|
PdbLog.message(msg);
|
||||||
myApplicator.appendLogMsg(msg);
|
appendLogMsg(msg);
|
||||||
return Integer.MAX_VALUE;
|
return Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,9 +141,10 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
private PdbCategories categoryUtils;
|
private PdbCategories categoryUtils;
|
||||||
private PdbPrimitiveTypeApplicator pdbPrimitiveTypeApplicator;
|
private PdbPrimitiveTypeApplicator pdbPrimitiveTypeApplicator;
|
||||||
private TypeApplierFactory typeApplierParser;
|
private TypeApplierFactory typeApplierParser;
|
||||||
|
private Map<Integer, Long> dataTypeIdByMsTypeNum;
|
||||||
|
private Map<Integer, DataTypeImpl> dataTypeImplByMsTypeNum;
|
||||||
|
private Map<Integer, CppCompositeType> classTypeByMsTypeNum;
|
||||||
private ComplexTypeMapper complexTypeMapper;
|
private ComplexTypeMapper complexTypeMapper;
|
||||||
private ComplexTypeApplierMapper complexApplierMapper;
|
|
||||||
private JungDirectedGraph<MsTypeApplier, GEdge<MsTypeApplier>> applierDependencyGraph;
|
|
||||||
/**
|
/**
|
||||||
* This namespace map documents as follows:
|
* This namespace map documents as follows:
|
||||||
* <PRE>
|
* <PRE>
|
||||||
|
@ -252,30 +248,39 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
*/
|
*/
|
||||||
private void disassembleFunctions() throws CancelledException {
|
private void disassembleFunctions() throws CancelledException {
|
||||||
|
|
||||||
|
TaskMonitor monitor = getMonitor();
|
||||||
Listing listing = program.getListing();
|
Listing listing = program.getListing();
|
||||||
DisassemblerContextImpl seedContext =
|
DisassemblerContextImpl seedContext =
|
||||||
new DisassemblerContextImpl(program.getProgramContext());
|
new DisassemblerContextImpl(program.getProgramContext());
|
||||||
AddressSet revisedSet = new AddressSet();
|
AddressSet revisedSet = new AddressSet();
|
||||||
|
long num = disassembleAddresses.getNumAddresses();
|
||||||
|
monitor.initialize(num);
|
||||||
|
monitor.setMessage("PDB: Determining disassembly context for " + num + " addresses...");
|
||||||
for (Address address : disassembleAddresses.getAddresses(true)) {
|
for (Address address : disassembleAddresses.getAddresses(true)) {
|
||||||
cancelOnlyWrappingMonitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
address = PseudoDisassembler.setTargetContextForDisassembly(seedContext, address);
|
address = PseudoDisassembler.setTargetContextForDisassembly(seedContext, address);
|
||||||
Function myFunction = listing.getFunctionAt(address);
|
Function myFunction = listing.getFunctionAt(address);
|
||||||
// If no function or not a full function, add it to set for disassembly.
|
// If no function or not a full function, add it to set for disassembly.
|
||||||
if (myFunction == null || myFunction.getBody().getNumAddresses() <= 1) {
|
if (myFunction == null || myFunction.getBody().getNumAddresses() <= 1) {
|
||||||
revisedSet.add(address);
|
revisedSet.add(address);
|
||||||
}
|
}
|
||||||
|
monitor.incrementProgress(1);
|
||||||
}
|
}
|
||||||
// Do disassembly and ensure functions are created appropriately.
|
// Do disassembly and ensure functions are created appropriately.
|
||||||
|
num = revisedSet.getNumAddresses();
|
||||||
|
monitor.setMessage("PDB: Bulk disassembly at " + num + " addresses...");
|
||||||
DisassembleCommand cmd = new DisassembleCommand(revisedSet, null, true);
|
DisassembleCommand cmd = new DisassembleCommand(revisedSet, null, true);
|
||||||
cmd.setSeedContext(seedContext);
|
cmd.setSeedContext(seedContext);
|
||||||
cmd.applyTo(program, cancelOnlyWrappingMonitor);
|
cmd.applyTo(program, monitor);
|
||||||
|
monitor.initialize(num);
|
||||||
|
monitor.setMessage("PDB: Disassembly fix-up for " + num + " addresses...");
|
||||||
for (Address address : revisedSet.getAddresses(true)) {
|
for (Address address : revisedSet.getAddresses(true)) {
|
||||||
cancelOnlyWrappingMonitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
Function function = listing.getFunctionAt(address);
|
Function function = listing.getFunctionAt(address);
|
||||||
if (function != null) {
|
if (function != null) {
|
||||||
CreateFunctionCmd.fixupFunctionBody(program, function, cancelOnlyWrappingMonitor);
|
CreateFunctionCmd.fixupFunctionBody(program, function, cancelOnlyWrappingMonitor);
|
||||||
}
|
}
|
||||||
|
monitor.incrementProgress(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,10 +311,7 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
// PdbResearch.studyCompositeFwdRefDef(pdb, monitor);
|
// PdbResearch.studyCompositeFwdRefDef(pdb, monitor);
|
||||||
// PdbResearch.study1(pdb, monitor);
|
// PdbResearch.study1(pdb, monitor);
|
||||||
|
|
||||||
// complexApplierMapper.mapAppliers(monitor);
|
|
||||||
|
|
||||||
complexTypeMapper.mapTypes(this);
|
complexTypeMapper.mapTypes(this);
|
||||||
complexApplierMapper.mapAppliers(complexTypeMapper, monitor);
|
|
||||||
|
|
||||||
processSequentially();
|
processSequentially();
|
||||||
|
|
||||||
|
@ -317,10 +319,6 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
|
|
||||||
// PdbResearch.developerDebugOrder(this, monitor);
|
// PdbResearch.developerDebugOrder(this, monitor);
|
||||||
|
|
||||||
processDeferred();
|
|
||||||
|
|
||||||
resolveSequentially();
|
|
||||||
|
|
||||||
Msg.info(this, "resolveCount: " + resolveCount);
|
Msg.info(this, "resolveCount: " + resolveCount);
|
||||||
|
|
||||||
// Currently, defining classes needs to have a program. When this is no longer true,
|
// Currently, defining classes needs to have a program. When this is no longer true,
|
||||||
|
@ -427,11 +425,13 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
pdbAddressManager = new PdbAddressManager(this, imageBase);
|
pdbAddressManager = new PdbAddressManager(this, imageBase);
|
||||||
|
|
||||||
categoryUtils = setPdbCatogoryUtils(pdb.getFilename());
|
categoryUtils = setPdbCatogoryUtils(pdb.getFilename());
|
||||||
|
initializePlaceholders();
|
||||||
pdbPrimitiveTypeApplicator = new PdbPrimitiveTypeApplicator(dataTypeManager);
|
pdbPrimitiveTypeApplicator = new PdbPrimitiveTypeApplicator(dataTypeManager);
|
||||||
typeApplierParser = new TypeApplierFactory(this);
|
dataTypeIdByMsTypeNum = new HashMap<>();
|
||||||
|
dataTypeImplByMsTypeNum = new HashMap<>();
|
||||||
|
classTypeByMsTypeNum = new HashMap<>();
|
||||||
complexTypeMapper = new ComplexTypeMapper();
|
complexTypeMapper = new ComplexTypeMapper();
|
||||||
complexApplierMapper = new ComplexTypeApplierMapper(this);
|
typeApplierParser = new TypeApplierFactory(this);
|
||||||
applierDependencyGraph = new JungDirectedGraph<>();
|
|
||||||
isClassByNamespace = new TreeMap<>();
|
isClassByNamespace = new TreeMap<>();
|
||||||
|
|
||||||
symbolApplierParser = new SymbolApplierFactory(this);
|
symbolApplierParser = new SymbolApplierFactory(this);
|
||||||
|
@ -672,6 +672,14 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
return categoryUtils.getAnonymousTypesCategory();
|
return categoryUtils.getAnonymousTypesCategory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link CategoryPath} for Placeholder Types Category for the PDB
|
||||||
|
* @return the {@link CategoryPath}
|
||||||
|
*/
|
||||||
|
CategoryPath getPlaceholderTypesCategory() {
|
||||||
|
return categoryUtils.getPlaceholderTypesCategory();
|
||||||
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * Returns the name of what should be the next Anonymous Function (based on the count of
|
// * Returns the name of what should be the next Anonymous Function (based on the count of
|
||||||
// * the number of anonymous functions) so that there is a unique name for the function.
|
// * the number of anonymous functions) so that there is a unique name for the function.
|
||||||
|
@ -710,44 +718,8 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
// Applier-based-DataType-dependency-related methods.
|
|
||||||
//==============================================================================================
|
|
||||||
void addApplierDependency(MsTypeApplier depender) {
|
|
||||||
Objects.requireNonNull(depender);
|
|
||||||
applierDependencyGraph.addVertex(depender.getDependencyApplier());
|
|
||||||
}
|
|
||||||
|
|
||||||
void addApplierDependency(MsTypeApplier depender, MsTypeApplier dependee) {
|
|
||||||
Objects.requireNonNull(depender);
|
|
||||||
Objects.requireNonNull(dependee);
|
|
||||||
// TODO: Possibly do checks on dependee and depender types for actual creation
|
|
||||||
// of dependency--making this the one-stop-shop of this logic. Then make calls to
|
|
||||||
// this method from all possibly places. (Perhaps, for example, if depender is a
|
|
||||||
// pointer, then the logic would say "no.")
|
|
||||||
//
|
|
||||||
// Examples of where dependency should possibly be created (by not doing it, we are
|
|
||||||
// getting .conflict data types) include:
|
|
||||||
// structure or enum as a function return type or argument type.
|
|
||||||
//
|
|
||||||
applierDependencyGraph.addEdge(
|
|
||||||
new DefaultGEdge<>(depender.getDependencyApplier(), dependee.getDependencyApplier()));
|
|
||||||
}
|
|
||||||
|
|
||||||
List<MsTypeApplier> getVerticesInPostOrder() {
|
|
||||||
TaskMonitor monitor = getMonitor();
|
|
||||||
monitor.setMessage("PDB: Determining data type dependency order...");
|
|
||||||
return GraphAlgorithms.getVerticesInPostOrder(applierDependencyGraph,
|
|
||||||
GraphNavigator.topDownNavigator());
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
//==============================================================================================
|
|
||||||
MsTypeApplier getApplierSpec(RecordNumber recordNumber, Class<? extends MsTypeApplier> expected)
|
|
||||||
throws PdbException {
|
|
||||||
return typeApplierParser.getApplierSpec(recordNumber, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
MsTypeApplier getApplierOrNoTypeSpec(RecordNumber recordNumber,
|
MsTypeApplier getApplierOrNoTypeSpec(RecordNumber recordNumber,
|
||||||
Class<? extends MsTypeApplier> expected) throws PdbException {
|
Class<? extends MsTypeApplier> expected) throws PdbException {
|
||||||
return typeApplierParser.getApplierOrNoTypeSpec(recordNumber, expected);
|
return typeApplierParser.getApplierOrNoTypeSpec(recordNumber, expected);
|
||||||
|
@ -762,6 +734,342 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
return typeApplierParser.getTypeApplier(type);
|
return typeApplierParser.getTypeApplier(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MsTypeApplier getTypeApplier(int pdbId) {
|
||||||
|
return typeApplierParser.getTypeApplier(pdbId);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================================
|
||||||
|
//==============================================================================================
|
||||||
|
//==============================================================================================
|
||||||
|
|
||||||
|
private Map<Integer, Pointer> placeholderPointers;
|
||||||
|
private Set<Long> pointerIDs;
|
||||||
|
// Structure used to mock placeholder array.
|
||||||
|
private Map<PlaceholderArrayKey, Structure> placeholderArrays;
|
||||||
|
private Set<Long> arrayIDs;
|
||||||
|
|
||||||
|
private void initializePlaceholders() {
|
||||||
|
placeholderPointers = new HashMap<>();
|
||||||
|
pointerIDs = new HashSet<>();
|
||||||
|
placeholderArrays = new HashMap<>();
|
||||||
|
arrayIDs = new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanUpPlaceholders() throws CancelledException {
|
||||||
|
|
||||||
|
TaskMonitor monitor = getMonitor();
|
||||||
|
DataTypeManager dtm = getDataTypeManager();
|
||||||
|
|
||||||
|
// Remove placeholder arrays from DTM and from the Set
|
||||||
|
for (long id : arrayIDs) {
|
||||||
|
checkCancelled();
|
||||||
|
DataType dt = dtm.getDataType(id);
|
||||||
|
Collection<DataType> parents = dt.getParents();
|
||||||
|
if (parents.size() == 0) {
|
||||||
|
dtm.remove(dt, monitor);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Msg.warn(this,
|
||||||
|
"PDB: Could not eliminate parented placeholder array: " + dt.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arrayIDs.clear();
|
||||||
|
arrayIDs = null;
|
||||||
|
|
||||||
|
// Eliminate array placeholder map
|
||||||
|
placeholderArrays.clear();
|
||||||
|
placeholderArrays = null;
|
||||||
|
|
||||||
|
// Not removing placeholder pointers from DTM, but we are eliminating them from the Set
|
||||||
|
pointerIDs.clear();
|
||||||
|
pointerIDs = null;
|
||||||
|
|
||||||
|
// Eliminate pointer placeholder map
|
||||||
|
placeholderPointers.clear();
|
||||||
|
placeholderPointers = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pointer getPlaceholderPointer(int size) throws PdbException {
|
||||||
|
Pointer pointer = placeholderPointers.get(size);
|
||||||
|
if (pointer != null) {
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
DataTypeManager dtm = getDataTypeManager();
|
||||||
|
pointer = new PointerDataType(null, size, dtm);
|
||||||
|
pointer = (Pointer) resolve(pointer);
|
||||||
|
long id = dtm.getID(pointer);
|
||||||
|
if (id == -1) {
|
||||||
|
throw new PdbException("Could not create placeholder pointer.");
|
||||||
|
}
|
||||||
|
placeholderPointers.put(size, pointer);
|
||||||
|
pointerIDs.add(id);
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isPlaceholderPointer(DataType pointer) {
|
||||||
|
// need this check for unresolved member types (such as primitives or bit-fields)
|
||||||
|
if (pointer instanceof DataTypeImpl || pointer instanceof BitFieldDataType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
long id = getDataTypeManager().getID(pointer);
|
||||||
|
return pointerIDs.contains(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private record PlaceholderArrayKey(int arraySize, int alignment) {}
|
||||||
|
|
||||||
|
// Using a structure as a mock array because we can set both size and alignment, which
|
||||||
|
// is what needs to be consistent with the final real array when used in a containing
|
||||||
|
// composite.
|
||||||
|
DataType getPlaceholderArray(int arraySize, int alignment) throws PdbException {
|
||||||
|
PlaceholderArrayKey key = new PlaceholderArrayKey(arraySize, alignment);
|
||||||
|
Structure placeholderArray = placeholderArrays.get(key);
|
||||||
|
if (placeholderArray != null) {
|
||||||
|
return placeholderArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypeManager dtm = getDataTypeManager();
|
||||||
|
String name = String.format("placeholder_array_%08x_%02x", arraySize, alignment);
|
||||||
|
placeholderArray =
|
||||||
|
new StructureDataType(getPlaceholderTypesCategory(), name, arraySize, dtm);
|
||||||
|
placeholderArray.align(alignment);
|
||||||
|
if (arraySize == 0) {
|
||||||
|
// For the zero-length, we need to enable packing to prevent the placeholder array
|
||||||
|
// (actual structure) from reporting itself as "not yet defined."
|
||||||
|
placeholderArray.setPackingEnabled(true);
|
||||||
|
}
|
||||||
|
placeholderArray = (Structure) resolve(placeholderArray);
|
||||||
|
|
||||||
|
long id = dtm.getID(placeholderArray);
|
||||||
|
if (id == -1) {
|
||||||
|
throw new PdbException("Could not create array placeholder.");
|
||||||
|
}
|
||||||
|
placeholderArrays.put(key, placeholderArray);
|
||||||
|
arrayIDs.add(id);
|
||||||
|
return placeholderArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isPlaceholderArray(DataType array) {
|
||||||
|
return array.getCategoryPath().equals(getPlaceholderTypesCategory());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isPlaceholderType(DataType type) {
|
||||||
|
return isPlaceholderPointer(type) || isPlaceholderArray(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================================
|
||||||
|
//==============================================================================================
|
||||||
|
//==============================================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the processed Ghidra class type associated with the PDB type record number. Causes
|
||||||
|
* the type to be processed if it already has not been.
|
||||||
|
* <p>
|
||||||
|
* This method is intended to be used by "Consumers" that need the type after all type
|
||||||
|
* creation is complete.
|
||||||
|
* @param recordNumber the record number of the type needed
|
||||||
|
* @return the Ghidra data type
|
||||||
|
* @throws CancelledException upon user cancellation
|
||||||
|
* @throws PdbException upon processing error
|
||||||
|
* @see #getDataType(AbstractMsType)
|
||||||
|
* @see #getDataType(RecordNumber)
|
||||||
|
*/
|
||||||
|
DataType getCompletedDataType(RecordNumber recordNumber) //************************************************ 5 REFS
|
||||||
|
throws CancelledException, PdbException {
|
||||||
|
DataType dataType = getDataType(recordNumber);
|
||||||
|
if (dataType instanceof DataTypeImpl) {
|
||||||
|
if (!(dataType instanceof BuiltInDataType)) {
|
||||||
|
AbstractMsType type = getPdb().getTypeRecord(recordNumber);
|
||||||
|
Msg.info(this, "Type not resolved for record: " + recordNumber + "; " +
|
||||||
|
type.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (dataType == null) {
|
||||||
|
AbstractMsType type = getPdb().getTypeRecord(recordNumber);
|
||||||
|
Msg.info(this, "Type not completed for record: " + recordNumber + "; " +
|
||||||
|
type.getClass().getSimpleName());
|
||||||
|
FixupContext fixupContext = new FixupContext();
|
||||||
|
fixupContext.addStagedRecord(recordNumber.getNumber());
|
||||||
|
dataType = getProcessedDataType(recordNumber, fixupContext, false);
|
||||||
|
}
|
||||||
|
return dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the Ghidra data type associated with the PDB data type.
|
||||||
|
* This method is intended to be used by appliers that work on this specific type, not by
|
||||||
|
* appliers that need the data type
|
||||||
|
* @param msType the PdbReader type pertaining to the type
|
||||||
|
* @param dataType the data type to store
|
||||||
|
*/
|
||||||
|
void putDataType(AbstractMsType msType, DataType dataType) {
|
||||||
|
Integer number = getNumber(msType);
|
||||||
|
putDataType(number, dataType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the Ghidra data type associated with the PDB data type.
|
||||||
|
* This method is intended to be used by appliers that work on this specific type, not by
|
||||||
|
* appliers that need the data type
|
||||||
|
* @param number number of type record
|
||||||
|
* @param dataType the data type to store
|
||||||
|
*/
|
||||||
|
void putDataType(Integer number, DataType dataType) {
|
||||||
|
DataType existing = getDataType(number); // could be null
|
||||||
|
if (existing == dataType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (existing != null) {
|
||||||
|
if (dataType.isEquivalent(existing)) {
|
||||||
|
if (!(existing instanceof DataTypeImpl) || dataType instanceof DataTypeImpl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isDefinedComposite(existing)) {
|
||||||
|
//TODO: Need to investigate how to deal with this.... we are only storing one, so
|
||||||
|
// how do we know we have the correct one... we should know by what the fwdref was...
|
||||||
|
// record-number-wise.
|
||||||
|
if (isDefinedComposite(dataType)) {
|
||||||
|
appendLogMsg("Existing and Replacement datatypes are both keepers:\n" +
|
||||||
|
existing + "\n" + dataType + "\n");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
putDataTypeInternal(number, dataType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Ghidra data type associated with the PDB data type.
|
||||||
|
* This method is intended to be used by appliers that work on this specific type, not by
|
||||||
|
* appliers that need the data type
|
||||||
|
* @param msType the PdbReader type pertaining to the type
|
||||||
|
* @return the Ghidra data type
|
||||||
|
*/
|
||||||
|
DataType getDataType(AbstractMsType msType) {
|
||||||
|
Integer number = getNumber(msType);
|
||||||
|
if (number == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getDataType(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Ghidra data type associated with the PDB type record number.
|
||||||
|
* <p>
|
||||||
|
* This method is intended to be used by appliers that work on this specific type, not by
|
||||||
|
* appliers that need the data type
|
||||||
|
* @param recordNumber the record number of the type needed
|
||||||
|
* @return the Ghidra data type
|
||||||
|
* @see #getDataType(AbstractMsType)
|
||||||
|
*/
|
||||||
|
DataType getDataType(RecordNumber recordNumber) {
|
||||||
|
if (recordNumber.getCategory() != RecordCategory.TYPE) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getDataType(recordNumber.getNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Ghidra data type associated with the PDB data type number.
|
||||||
|
* This method is intended to be used by appliers that work on this specific type, not by
|
||||||
|
* appliers that need the data type
|
||||||
|
* @param number the PDB type record number
|
||||||
|
* @return the Ghidra data type
|
||||||
|
*/
|
||||||
|
DataType getDataType(Integer number) {
|
||||||
|
Integer mappedNumber = getMappedComplexType(number);
|
||||||
|
Long ID = dataTypeIdByMsTypeNum.get(mappedNumber);
|
||||||
|
if (ID == null) {
|
||||||
|
return dataTypeImplByMsTypeNum.get(mappedNumber);
|
||||||
|
}
|
||||||
|
return dataTypeManager.getDataType(ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDefinedComposite(DataType dt) {
|
||||||
|
return (dt instanceof Composite comp && comp.getNumDefinedComponents() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putDataTypeInternal(Integer number, DataType dataType) {
|
||||||
|
Integer mappedNumber = getMappedComplexType(number);
|
||||||
|
if (dataType instanceof DataTypeImpl impl) {
|
||||||
|
if (!(dataType instanceof BuiltInDataType)) {
|
||||||
|
Msg.warn(this, "PDB: Unexpected Impl storage: " + impl.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
dataTypeImplByMsTypeNum.put(mappedNumber, impl);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
long dataTypeID = dataTypeManager.getID(dataType);
|
||||||
|
if (dataTypeID == -1) {
|
||||||
|
// Error, such as DataType is not DB version
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dataTypeIdByMsTypeNum.put(mappedNumber, dataTypeID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================================
|
||||||
|
/**
|
||||||
|
* Stores the Ghidra class type associated with the PDB data type.
|
||||||
|
* This method is intended to be used by appliers that work on this specific type, not by
|
||||||
|
* appliers that need the data type
|
||||||
|
* @param msType the PdbReader type pertaining to the type
|
||||||
|
* @param classType the class to store
|
||||||
|
*/
|
||||||
|
void putClassType(AbstractMsType msType, CppCompositeType classType) {
|
||||||
|
Integer number = getNumber(msType);
|
||||||
|
CppCompositeType existing = getClassType(number);
|
||||||
|
if (existing == classType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (existing != null) {
|
||||||
|
appendLogMsg(
|
||||||
|
"Existing class type; not replacing:\n" + existing + "\n" + classType + "\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
putClassType(number, classType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Ghidra class type associated with the PDB class type.
|
||||||
|
* <p>
|
||||||
|
* This method is intended to be used by appliers that work on this specific type, not by
|
||||||
|
* appliers that need the data type
|
||||||
|
* @param msType the PdbReader type pertaining to the type
|
||||||
|
* @return the Ghidra class type
|
||||||
|
* @see #getDataType(RecordNumber)
|
||||||
|
*/
|
||||||
|
CppCompositeType getClassType(AbstractMsType msType) {
|
||||||
|
Integer number = getNumber(msType);
|
||||||
|
return getClassType(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CppCompositeType getClassType(Integer number) {
|
||||||
|
return classTypeByMsTypeNum.get(getMappedComplexType(number));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putClassType(Integer number, CppCompositeType classType) {
|
||||||
|
Integer mappedNumber = getMappedComplexType(number);
|
||||||
|
classTypeByMsTypeNum.put(mappedNumber, classType);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================================
|
||||||
|
// Might change this to private if removed use from CompositeTypeApplier
|
||||||
|
Integer getNumber(AbstractMsType msType) {
|
||||||
|
if (msType == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
RecordNumber recordNumber = msType.getRecordNumber();
|
||||||
|
if (recordNumber == null || recordNumber.getCategory() != RecordCategory.TYPE) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return recordNumber.getNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Might change this to private if removed use from CompositeTypeApplier
|
||||||
|
Integer getMappedComplexType(Integer input) {
|
||||||
|
return complexTypeMapper.getMapped(input);
|
||||||
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
@ -783,7 +1091,7 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
private void processDataTypesSequentially() throws CancelledException, PdbException {
|
private void processAndResolveDataTypesSequentially() throws CancelledException, PdbException {
|
||||||
TypeProgramInterface tpi = pdb.getTypeProgramInterface();
|
TypeProgramInterface tpi = pdb.getTypeProgramInterface();
|
||||||
if (tpi == null) {
|
if (tpi == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -795,12 +1103,99 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
for (int indexNumber = tpi.getTypeIndexMin(); indexNumber < tpi
|
for (int indexNumber = tpi.getTypeIndexMin(); indexNumber < tpi
|
||||||
.getTypeIndexMaxExclusive(); indexNumber++) {
|
.getTypeIndexMaxExclusive(); indexNumber++) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
//PdbResearch.checkBreak(indexNumber);
|
processAndResolve(indexNumber);
|
||||||
MsTypeApplier applier = getTypeApplier(RecordNumber.typeRecordNumber(indexNumber));
|
|
||||||
//PdbResearch.checkBreak(indexNumber, applier);
|
|
||||||
applier.apply();
|
|
||||||
monitor.incrementProgress(1);
|
monitor.incrementProgress(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Might need to do this later (after typedefs and symbols)... TODO: figure this out
|
||||||
|
cleanUpPlaceholders();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processAndResolve(int indexNumber) throws CancelledException, PdbException {
|
||||||
|
DataType dt = getDataType(indexNumber);
|
||||||
|
if (dt != null && !(dt instanceof DataTypeImpl)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RecordNumber recordNumber = RecordNumber.typeRecordNumber(indexNumber);
|
||||||
|
AbstractMsType msType = pdb.getTypeRecord(recordNumber);
|
||||||
|
MsTypeApplier applier = getTypeApplier(recordNumber);
|
||||||
|
if (applier instanceof CompositeTypeApplier) {
|
||||||
|
FixupContext fixupContext = new FixupContext();
|
||||||
|
int mappedNumber = getMappedComplexType(indexNumber);
|
||||||
|
fixupContext.moveToHeadProcessRecord(mappedNumber);
|
||||||
|
DataType dataType = applier.apply(msType, fixupContext, false);
|
||||||
|
fixupContext.moveProcessToFixupsRecord(mappedNumber, dataType);
|
||||||
|
fixUpTypes(fixupContext);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DataType dataType = applier.apply(msType, null, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DataType getProcessedDataType(RecordNumber recordNumber, FixupContext fixupContext,
|
||||||
|
boolean breakCycle) throws CancelledException, PdbException {
|
||||||
|
int mappedNumber = getMappedComplexType(recordNumber.getNumber());
|
||||||
|
AbstractMsType type = pdb.getTypeRecord(RecordNumber.typeRecordNumber(mappedNumber));
|
||||||
|
MsTypeApplier applier = getTypeApplier(recordNumber);
|
||||||
|
|
||||||
|
if (fixupContext == null) {
|
||||||
|
return applier.apply(type, fixupContext, breakCycle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(applier instanceof CompositeTypeApplier) &&
|
||||||
|
!(applier instanceof ModifierTypeApplier)) {
|
||||||
|
return applier.apply(type, fixupContext, breakCycle);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataType dataType = getDataType(mappedNumber);
|
||||||
|
if (dataType != null) {
|
||||||
|
return dataType;
|
||||||
|
}
|
||||||
|
dataType = fixupContext.getFixupDataType(mappedNumber);
|
||||||
|
if (dataType != null) {
|
||||||
|
return dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
fixupContext.ensureInContext(mappedNumber);
|
||||||
|
if (breakCycle) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fixupContext.moveToHeadProcessRecord(mappedNumber);
|
||||||
|
dataType = applier.apply(type, fixupContext, breakCycle);
|
||||||
|
fixupContext.moveProcessToFixupsRecord(mappedNumber, dataType);
|
||||||
|
|
||||||
|
return dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fixUpTypes(FixupContext fixupContext) throws PdbException, CancelledException {
|
||||||
|
|
||||||
|
Integer recordToProcess;
|
||||||
|
while ((recordToProcess = fixupContext.peekStagedRecord()) != null) {
|
||||||
|
checkCancelled();
|
||||||
|
RecordNumber recordNumber = RecordNumber.typeRecordNumber(recordToProcess);
|
||||||
|
AbstractMsType msType = pdb.getTypeRecord(recordNumber);
|
||||||
|
MsTypeApplier applier = getTypeApplier(recordNumber);
|
||||||
|
fixupContext.moveFromStagedToProcessRecord();
|
||||||
|
DataType dataType = applier.apply(msType, fixupContext, false);
|
||||||
|
fixupContext.moveProcessToFixupsRecord(recordToProcess, dataType);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((recordToProcess = fixupContext.peekFixupsRecord()) != null) {
|
||||||
|
checkCancelled();
|
||||||
|
RecordNumber recordNumber = RecordNumber.typeRecordNumber(recordToProcess);
|
||||||
|
AbstractMsType msType = pdb.getTypeRecord(recordNumber);
|
||||||
|
MsTypeApplier applier = getTypeApplier(recordNumber);
|
||||||
|
if (applier instanceof CompositeTypeApplier fixupApplier) {
|
||||||
|
DataType dataType = applier.apply(msType, fixupContext, false);
|
||||||
|
if (dataType instanceof DataTypeImpl) {
|
||||||
|
appendLogMsg("Unexpected resolve for: " + dataType.getClass().getSimpleName());
|
||||||
|
dataType = resolve(dataType);
|
||||||
|
}
|
||||||
|
fixupApplier.fixUp(fixupContext);
|
||||||
|
}
|
||||||
|
fixupContext.popFixupsRecord();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
@ -863,65 +1258,29 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
for (int indexNumber = ipi.getTypeIndexMin(); indexNumber < ipi
|
for (int indexNumber = ipi.getTypeIndexMin(); indexNumber < ipi
|
||||||
.getTypeIndexMaxExclusive(); indexNumber++) {
|
.getTypeIndexMaxExclusive(); indexNumber++) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
MsTypeApplier applier = getTypeApplier(RecordNumber.itemRecordNumber(indexNumber));
|
RecordNumber recordNumber = RecordNumber.itemRecordNumber(indexNumber);
|
||||||
applier.apply();
|
AbstractMsType msType = pdb.getTypeRecord(recordNumber);
|
||||||
|
MsTypeApplier applier = getTypeApplier(recordNumber);
|
||||||
|
FixupContext fixupContext = new FixupContext();
|
||||||
|
fixupContext.addStagedRecord(indexNumber);
|
||||||
|
applier.apply(msType, fixupContext, false); // fixupContext and breakCycle meaningless here?
|
||||||
monitor.incrementProgress(1);
|
monitor.incrementProgress(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
private void processSequentially() throws CancelledException, PdbException {
|
private void processSequentially() throws CancelledException, PdbException {
|
||||||
processDataTypesSequentially();
|
processAndResolveDataTypesSequentially();
|
||||||
processItemTypesSequentially();
|
processItemTypesSequentially();
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
|
||||||
private void processDeferred() throws CancelledException, PdbException {
|
|
||||||
List<MsTypeApplier> verticesInPostOrder = getVerticesInPostOrder();
|
|
||||||
TaskMonitor monitor = getMonitor();
|
|
||||||
monitor.initialize(verticesInPostOrder.size());
|
|
||||||
monitor.setMessage("PDB: Processing " + verticesInPostOrder.size() +
|
|
||||||
" deferred data type dependencies...");
|
|
||||||
for (MsTypeApplier applier : verticesInPostOrder) {
|
|
||||||
monitor.checkCancelled();
|
|
||||||
//PdbResearch.checkBreak(applier.index);
|
|
||||||
//checkBreak(applier.index, applier);
|
|
||||||
if (applier.isDeferred()) {
|
|
||||||
applier.deferredApply();
|
|
||||||
}
|
|
||||||
monitor.incrementProgress(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================================
|
|
||||||
private void resolveSequentially() throws CancelledException {
|
|
||||||
TypeProgramInterface tpi = pdb.getTypeProgramInterface();
|
|
||||||
if (tpi == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int num = tpi.getTypeIndexMaxExclusive() - tpi.getTypeIndexMin();
|
|
||||||
TaskMonitor monitor = getMonitor();
|
|
||||||
monitor.initialize(num);
|
|
||||||
monitor.setMessage("PDB: Resolving " + num + " data type components...");
|
|
||||||
long longStart = System.currentTimeMillis();
|
|
||||||
for (int indexNumber = tpi.getTypeIndexMin(); indexNumber < tpi
|
|
||||||
.getTypeIndexMaxExclusive(); indexNumber++) {
|
|
||||||
monitor.checkCancelled();
|
|
||||||
//PdbResearch.checkBreak(indexNumber);
|
|
||||||
MsTypeApplier applier = getTypeApplier(RecordNumber.typeRecordNumber(indexNumber));
|
|
||||||
//PdbResearch.checkBreak(indexNumber, applier);
|
|
||||||
applier.resolve();
|
|
||||||
monitor.incrementProgress(1);
|
|
||||||
}
|
|
||||||
long longStop = System.currentTimeMillis();
|
|
||||||
long timeDiff = longStop - longStart;
|
|
||||||
Msg.info(this, "Resolve time: " + timeDiff + " mS");
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
DataType resolve(DataType dataType) {
|
DataType resolve(DataType dataType) {
|
||||||
|
if (!(dataType instanceof DataTypeImpl)) {
|
||||||
|
return dataType;
|
||||||
|
}
|
||||||
DataType resolved = getDataTypeManager().resolve(dataType,
|
DataType resolved = getDataTypeManager().resolve(dataType,
|
||||||
DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER);
|
DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER);
|
||||||
resolveCount++;
|
resolveCount++;
|
||||||
|
@ -1700,6 +2059,7 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
log.appendMsg(
|
log.appendMsg(
|
||||||
"PDB Warning: Because parent namespace does not exist, failed to define " +
|
"PDB Warning: Because parent namespace does not exist, failed to define " +
|
||||||
type + ": " + path);
|
type + ": " + path);
|
||||||
|
monitor.incrementProgress(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
defineNamespace(parentNamespace, path.getName(), isClass);
|
defineNamespace(parentNamespace, path.getName(), isClass);
|
||||||
|
|
|
@ -15,9 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb.*;
|
import ghidra.app.util.bin.format.pdb.*;
|
||||||
|
import ghidra.app.util.pdb.pdbapplicator.CppCompositeType.*;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
|
@ -27,67 +26,57 @@ import ghidra.util.exception.CancelledException;
|
||||||
*/
|
*/
|
||||||
public class DefaultPdbUniversalMember extends PdbMember {
|
public class DefaultPdbUniversalMember extends PdbMember {
|
||||||
|
|
||||||
private MsTypeApplier applier;
|
|
||||||
private DataType dataType;
|
private DataType dataType;
|
||||||
|
private ClassFieldAttributes attributes;
|
||||||
|
private boolean isZeroLengthArray;
|
||||||
|
|
||||||
|
private static final ClassFieldAttributes blankAtttributes =
|
||||||
|
new ClassFieldAttributes(Access.BLANK, Property.BLANK);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default PDB member construction
|
* Default PDB member construction
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which we are working.
|
|
||||||
* @param name member field name. For bitfields this also conveys the bit-size
|
|
||||||
* and optionally the bit-offset.
|
|
||||||
* @param applier fieldApplier for the field datatype or base datatype associated with the
|
|
||||||
* bitfield.
|
|
||||||
* @param offset member's byte offset within the root composite.
|
|
||||||
*/
|
|
||||||
DefaultPdbUniversalMember(DefaultPdbApplicator applicator, String name, MsTypeApplier applier,
|
|
||||||
int offset) {
|
|
||||||
this(applicator, name, applier, offset, null);
|
|
||||||
dataType = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default PDB member construction
|
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which we are working.
|
|
||||||
* @param name member field name. For bitfields this also conveys the bit-size
|
|
||||||
* and optionally the bit-offset.
|
|
||||||
* @param applier fieldApplier for the field datatype or base datatype associated with the
|
|
||||||
* bitfield.
|
|
||||||
* @param offset member's byte offset within the root composite.
|
|
||||||
* @param memberComment comment for member field
|
|
||||||
*/
|
|
||||||
DefaultPdbUniversalMember(DefaultPdbApplicator applicator, String name, MsTypeApplier applier,
|
|
||||||
int offset, String memberComment) {
|
|
||||||
super(name, applier.getDataType().getName(), offset, memberComment);
|
|
||||||
this.applier = applier;
|
|
||||||
dataType = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default PDB member construction
|
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which we are working.
|
|
||||||
* @param name member field name. For bitfields this also conveys the bit-size
|
* @param name member field name. For bitfields this also conveys the bit-size
|
||||||
* and optionally the bit-offset.
|
* and optionally the bit-offset.
|
||||||
* @param dataType for the field.
|
* @param dataType for the field.
|
||||||
* @param offset member's byte offset within the root composite.
|
* @param offset member's byte offset within the root composite.
|
||||||
*/
|
*/
|
||||||
DefaultPdbUniversalMember(DefaultPdbApplicator applicator, String name, DataType dataType,
|
DefaultPdbUniversalMember(String name, DataType dataType, int offset) {
|
||||||
int offset) {
|
|
||||||
super(name, dataType.getName(), offset, null);
|
super(name, dataType.getName(), offset, null);
|
||||||
this.applier = null;
|
|
||||||
this.dataType = dataType;
|
this.dataType = dataType;
|
||||||
|
this.attributes = blankAtttributes;
|
||||||
|
this.isZeroLengthArray = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MsTypeApplier getApplier() {
|
/**
|
||||||
return applier;
|
* Default PDB member construction
|
||||||
|
* @param name member field name. For bitfields this also conveys the bit-size
|
||||||
|
* and optionally the bit-offset.
|
||||||
|
* @param dataType for the field.
|
||||||
|
* @param isZeroLengthArray indicates if, when an array, it is a zero-length (flex) array
|
||||||
|
* @param offset member's byte offset within the root composite.
|
||||||
|
* @param attributes the attributes of the member
|
||||||
|
* @param memberComment optional member comment (may be null)
|
||||||
|
*/
|
||||||
|
DefaultPdbUniversalMember(String name, DataType dataType, boolean isZeroLengthArray, int offset,
|
||||||
|
ClassFieldAttributes attributes, String memberComment) {
|
||||||
|
super(name, dataType.getName(), offset, memberComment);
|
||||||
|
this.dataType = dataType;
|
||||||
|
this.attributes = attributes;
|
||||||
|
this.isZeroLengthArray = isZeroLengthArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataType getDataTypeInternal() {
|
private DataType getDataTypeInternal() {
|
||||||
if (applier != null) {
|
|
||||||
return applier.getDataType();
|
|
||||||
}
|
|
||||||
return dataType;
|
return dataType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isZeroLengthArray() {
|
||||||
|
return isZeroLengthArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassFieldAttributes getAttributes() {
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDataTypeName() {
|
public String getDataTypeName() {
|
||||||
return getDataTypeInternal().getName();
|
return getDataTypeInternal().getName();
|
||||||
|
@ -123,12 +112,7 @@ public class DefaultPdbUniversalMember extends PdbMember {
|
||||||
@Override
|
@Override
|
||||||
protected WrappedDataType getDataType() throws CancelledException {
|
protected WrappedDataType getDataType() throws CancelledException {
|
||||||
DataType dt = getDataTypeInternal();
|
DataType dt = getDataTypeInternal();
|
||||||
if (applier != null && applier instanceof ArrayTypeApplier) {
|
return new WrappedDataType(dt, isZeroLengthArray, false);
|
||||||
if (BigInteger.ZERO.compareTo(applier.getSize()) == 0) {
|
|
||||||
return new WrappedDataType(dt, true, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new WrappedDataType(dt, false, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,13 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.app.util.SymbolPath;
|
import ghidra.app.util.SymbolPath;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractEnumMsType;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.MsProperty;
|
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
import ghidra.program.model.data.Enum;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
|
@ -31,33 +30,19 @@ import ghidra.util.exception.CancelledException;
|
||||||
*/
|
*/
|
||||||
public class EnumTypeApplier extends AbstractComplexTypeApplier {
|
public class EnumTypeApplier extends AbstractComplexTypeApplier {
|
||||||
|
|
||||||
//private AbstractMsTypeApplier underlyingApplier = null;
|
// Intended for: AbstractEnumMsType
|
||||||
|
|
||||||
// private int length = 0;
|
|
||||||
// private boolean isSigned = false;
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for enum type applier, for transforming a enum into a
|
* Constructor for enum type applier, for transforming a enum into a
|
||||||
* Ghidra DataType.
|
* Ghidra DataType.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractEnumMsType} to process.
|
|
||||||
*/
|
*/
|
||||||
public EnumTypeApplier(DefaultPdbApplicator applicator, AbstractEnumMsType msType) {
|
public EnumTypeApplier(DefaultPdbApplicator applicator) {
|
||||||
super(applicator, msType);
|
super(applicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private long getMask(AbstractEnumMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
BigInteger getSize() {
|
throws CancelledException, PdbException {
|
||||||
MsTypeApplier underlyingApplier = getUnderlyingTypeApplier();
|
switch (getLength(type, fixupContext, breakCycle)) {
|
||||||
if (underlyingApplier == null) {
|
|
||||||
return BigInteger.ZERO;
|
|
||||||
}
|
|
||||||
return underlyingApplier.getSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getMask() {
|
|
||||||
switch (getLength()) {
|
|
||||||
case 1:
|
case 1:
|
||||||
return 0xffL;
|
return 0xffL;
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -69,25 +54,24 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getLength() {
|
private int getLength(AbstractEnumMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
// Minimum length allowed by Ghidra is 1 for enum, so all returns are min 1.
|
throws CancelledException, PdbException {
|
||||||
MsTypeApplier underlyingApplier = getUnderlyingTypeApplier();
|
DataType underlyingDataType = getUnderlyingDataType(type, fixupContext, breakCycle);
|
||||||
if (underlyingApplier == null) {
|
if (underlyingDataType == null) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
DataType underlyingType = underlyingApplier.getDataType();
|
return Integer.max(underlyingDataType.getLength(), 1);
|
||||||
if (underlyingType == null) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return Integer.max(underlyingType.getLength(), 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isSigned() {
|
private DataType getUnderlyingDataType(AbstractEnumMsType type, FixupContext fixupContext,
|
||||||
MsTypeApplier underlyingApplier = getUnderlyingTypeApplier();
|
boolean breakCycle) throws CancelledException, PdbException {
|
||||||
if (underlyingApplier == null) {
|
RecordNumber underlyingRecordNumber = type.getUnderlyingRecordNumber();
|
||||||
return false;
|
return applicator.getProcessedDataType(underlyingRecordNumber, fixupContext, breakCycle);
|
||||||
}
|
}
|
||||||
DataType underlyingType = underlyingApplier.getDataType();
|
|
||||||
|
boolean isSigned(AbstractEnumMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
|
throws CancelledException, PdbException {
|
||||||
|
DataType underlyingType = getUnderlyingDataType(type, fixupContext, breakCycle);
|
||||||
if (underlyingType == null) {
|
if (underlyingType == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -97,205 +81,85 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private EnumDataType createEmptyEnum(AbstractEnumMsType type, FixupContext fixupContext,
|
||||||
EnumTypeApplier getDependencyApplier() {
|
boolean breakCycle) throws CancelledException, PdbException {
|
||||||
if (definitionApplier != null && definitionApplier instanceof EnumTypeApplier) {
|
|
||||||
return (EnumTypeApplier) definitionApplier;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getName() {
|
AbstractEnumMsType defType = getDefinitionType(type);
|
||||||
return getMsType().getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
SymbolPath fixedPath = getFixedSymbolPath(defType);
|
||||||
DataType getDataType() {
|
|
||||||
getOrCreateEnum();
|
|
||||||
return dataType;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MsTypeApplier getUnderlyingTypeApplier() {
|
|
||||||
MsTypeApplier under = null;
|
|
||||||
MsTypeApplier applier = (definitionApplier != null) ? definitionApplier : this;
|
|
||||||
RecordNumber underlyingRecordNumber =
|
|
||||||
((AbstractEnumMsType) applier.getMsType()).getUnderlyingRecordNumber();
|
|
||||||
under = applicator.getTypeApplier(underlyingRecordNumber);
|
|
||||||
if (under == null) {
|
|
||||||
applicator.appendLogMsg("Missing applier for underlying type index " +
|
|
||||||
underlyingRecordNumber + " in Enum " + msType.getName());
|
|
||||||
}
|
|
||||||
return under;
|
|
||||||
}
|
|
||||||
|
|
||||||
private EnumDataType createEmptyEnum(AbstractEnumMsType type) {
|
|
||||||
|
|
||||||
SymbolPath fixedPath = getFixedSymbolPath();
|
|
||||||
CategoryPath categoryPath = applicator.getCategory(fixedPath.getParent());
|
CategoryPath categoryPath = applicator.getCategory(fixedPath.getParent());
|
||||||
|
|
||||||
// MsProperty property = type.getMsProperty();
|
EnumDataType enumDataType = new EnumDataType(categoryPath, fixedPath.getName(),
|
||||||
// if (property.isForwardReference()) {
|
getLength(defType, fixupContext, breakCycle), applicator.getDataTypeManager());
|
||||||
// // investigate this
|
|
||||||
// }
|
|
||||||
//// RecordNumber underlyingRecordNumber = type.getUnderlyingRecordNumber();
|
|
||||||
//// underlyingApplier = applicator.getApplier(underlyingRecordNumber);
|
|
||||||
// determineUnderlyingTypeApplier();
|
|
||||||
//
|
|
||||||
// if (underlyingApplier == null) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// DataType underlyingType = underlyingApplier.getDataType();
|
|
||||||
// if (underlyingType != null) {
|
|
||||||
// length = underlyingType.getLength();
|
|
||||||
// if (underlyingType instanceof AbstractIntegerDataType) {
|
|
||||||
// isSigned = ((AbstractIntegerDataType) underlyingType).isSigned();
|
|
||||||
// }
|
|
||||||
// else if (!(underlyingType instanceof VoidDataType)) {
|
|
||||||
// pdbLogAndInfoMessage(this, "Cannot processes enum with underlying type: " +
|
|
||||||
// underlyingType.getClass().getSimpleName());
|
|
||||||
// throw new PdbException(msg);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// AbstractMsType underlying = underlyingApplier.getMsType();
|
|
||||||
// if (underlying instanceof PrimitiveMsType) {
|
|
||||||
// length = ((PrimitiveMsType) underlying).getTypeSize();
|
|
||||||
// //TODO: can we set isSigned in here? ((PrimitiveMsType) underlying)
|
|
||||||
// // TODO: there might be more
|
|
||||||
// // TODO: investigate getSize() on AbstractMsType?
|
|
||||||
// // then: length = underlying.getSize();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // Ghidra does not like size of zero.
|
|
||||||
// length = Integer.max(length, 1);
|
|
||||||
|
|
||||||
EnumDataType enumDataType = new EnumDataType(categoryPath, fixedPath.getName(), getLength(),
|
|
||||||
applicator.getDataTypeManager());
|
|
||||||
|
|
||||||
return enumDataType;
|
return enumDataType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void apply() throws PdbException, CancelledException {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
getOrCreateEnum();
|
throws PdbException, CancelledException {
|
||||||
|
//Ghidra cannot handle fwdrefs and separate definitions for enumerates as it can for
|
||||||
|
// composites. Thus, we will just try to provide the defined version now.
|
||||||
|
Integer number = applicator.getNumber(type);
|
||||||
|
Integer mapped = applicator.getMappedComplexType(number);
|
||||||
|
AbstractEnumMsType definedEnum = (AbstractEnumMsType) applicator.getPdb()
|
||||||
|
.getTypeRecord(RecordNumber.typeRecordNumber(mapped));
|
||||||
|
|
||||||
AbstractEnumMsType type = (AbstractEnumMsType) msType;
|
DataType existingDt = applicator.getDataType(mapped);
|
||||||
MsProperty property = type.getMsProperty();
|
if (existingDt != null) {
|
||||||
if (property.isForwardReference()) {
|
if (!(existingDt instanceof Enum)) {
|
||||||
return;
|
throw new PdbException("PDB error retrieving Enum type");
|
||||||
|
}
|
||||||
|
return existingDt;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyEnumMsType((AbstractEnumMsType) msType);
|
EnumDataType enumDataType = createEmptyEnum(definedEnum, fixupContext, breakCycle);
|
||||||
|
applyEnumMsType(enumDataType, definedEnum, fixupContext, breakCycle);
|
||||||
|
|
||||||
|
DataType dataType = applicator.resolve(enumDataType);
|
||||||
|
applicator.putDataType(mapped, dataType);
|
||||||
|
return dataType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private EnumDataType applyEnumMsType(EnumDataType enumDataType, AbstractEnumMsType type,
|
||||||
void resolve() {
|
FixupContext fixupContext, boolean breakCycle) throws PdbException, CancelledException {
|
||||||
if (!isForwardReference()) {
|
|
||||||
super.resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mapping of fwdRef/def must be done prior to this call.
|
if (enumDataType.getCount() != 0) {
|
||||||
private void getOrCreateEnum() {
|
//already applied
|
||||||
AbstractEnumMsType neededType = (AbstractEnumMsType) msType;
|
return enumDataType;
|
||||||
if (dataType != null) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (isForwardReference()) {
|
|
||||||
if (definitionApplier != null) {
|
|
||||||
dataType = definitionApplier.getDataTypeInternal();
|
|
||||||
if (dataType != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
neededType = (AbstractEnumMsType) definitionApplier.getMsType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (forwardReferenceApplier != null) {
|
|
||||||
dataType = forwardReferenceApplier.getDataTypeInternal();
|
|
||||||
if (dataType != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dataType = createEmptyEnum(neededType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private EnumDataType applyEnumMsType(AbstractEnumMsType type) throws PdbException {
|
|
||||||
|
|
||||||
String fullPathName = type.getName();
|
String fullPathName = type.getName();
|
||||||
|
|
||||||
// // TODO: evaluate whether we do full SymbolPath... see others
|
|
||||||
// SymbolPath fixedPath = getFixedSymbolPath();
|
|
||||||
//
|
|
||||||
// RecordNumber underlyingRecordNumber = type.getUnderlyingRecordNumber();
|
|
||||||
// MsProperty property = type.getMsProperty();
|
|
||||||
// if (property.isForwardReference()) {
|
|
||||||
// // investigate this
|
|
||||||
// }
|
|
||||||
// underlyingApplier = applicator.getApplier(underlyingRecordNumber);
|
|
||||||
//
|
|
||||||
// if (underlyingApplier == null) {
|
|
||||||
// applicator.appendLogMsg("Missing applier for underlying type index " +
|
|
||||||
// underlyingRecordNumber + " in Enum " + fullPathName);
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// DataType underlyingType = underlyingApplier.getDataType();
|
|
||||||
// int length = 0;
|
|
||||||
// if (underlyingType != null) {
|
|
||||||
// length = underlyingType.getLength();
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// AbstractMsType underlying = underlyingApplier.getMsType();
|
|
||||||
// if (underlying instanceof PrimitiveMsType) {
|
|
||||||
// length = ((PrimitiveMsType) underlying).getTypeSize();
|
|
||||||
// // TODO: there might be more
|
|
||||||
// // TODO: investigate getSize() on AbstractMsType?
|
|
||||||
// // then: length = underlying.getSize();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // Ghidra does not like size of zero.
|
|
||||||
// length = Integer.max(length, 1);
|
|
||||||
//
|
|
||||||
// CategoryPath categoryPath = applicator.getCategory(fixedPath.getParent());
|
|
||||||
// EnumDataType enumDataType = new EnumDataType(categoryPath, fixedPath.getName(), length,
|
|
||||||
// applicator.getDataTypeManager());
|
|
||||||
//
|
|
||||||
|
|
||||||
RecordNumber fieldListRecordNumber = type.getFieldDescriptorListRecordNumber();
|
RecordNumber fieldListRecordNumber = type.getFieldDescriptorListRecordNumber();
|
||||||
FieldListTypeApplier fieldListApplier =
|
FieldListTypeApplier fieldListApplier =
|
||||||
FieldListTypeApplier.getFieldListApplierSpecial(applicator, fieldListRecordNumber);
|
FieldListTypeApplier.getFieldListApplierSpecial(applicator, fieldListRecordNumber);
|
||||||
|
|
||||||
|
FieldListTypeApplier.FieldLists lists =
|
||||||
|
fieldListApplier.getFieldLists(fieldListRecordNumber);
|
||||||
|
|
||||||
// Note: not doing anything with getNamespaceList() or getMethodsList() at this time.
|
// Note: not doing anything with getNamespaceList() or getMethodsList() at this time.
|
||||||
List<MsTypeApplier> memberList = fieldListApplier.getMemberList();
|
List<AbstractEnumerateMsType> enumerates = lists.enumerates();
|
||||||
|
|
||||||
int numElements = type.getNumElements();
|
int numElements = type.getNumElements();
|
||||||
if (memberList.size() != numElements) {
|
if (enumerates.size() != numElements) {
|
||||||
pdbLogAndInfoMessage(this, "Enum expecting " + numElements + " elements, but only " +
|
pdbLogAndInfoMessage(this, "Enum expecting " + numElements + " elements, but only " +
|
||||||
memberList.size() + " available for " + fullPathName);
|
enumerates.size() + " available for " + fullPathName);
|
||||||
}
|
|
||||||
EnumDataType enumDataType = (EnumDataType) dataType;
|
|
||||||
int length = getLength();
|
|
||||||
boolean isSigned = isSigned();
|
|
||||||
for (MsTypeApplier memberApplier : memberList) {
|
|
||||||
if (memberApplier instanceof EnumerateTypeApplier) {
|
|
||||||
EnumerateTypeApplier enumerateApplier = (EnumerateTypeApplier) memberApplier;
|
|
||||||
SymbolPath memberSymbolPath = new SymbolPath(enumerateApplier.getName());
|
|
||||||
enumDataType.add(memberSymbolPath.getName(),
|
|
||||||
narrowingConversion(length, isSigned, enumerateApplier.getNumeric()));
|
|
||||||
}
|
|
||||||
else { // (member instanceof AbstractMemberMsType)
|
|
||||||
// I do not believe (until proven otherwise) that an Enum will have members of
|
|
||||||
// type AbstractMemberMsType.
|
|
||||||
pdbLogAndInfoMessage(this, getClass().getSimpleName() + ": unexpected " +
|
|
||||||
memberApplier.getClass().getSimpleName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int length = getLength(type, fixupContext, breakCycle);
|
||||||
|
boolean isSigned = isSigned(type, fixupContext, breakCycle);
|
||||||
|
for (AbstractEnumerateMsType enumerateType : enumerates) {
|
||||||
|
SymbolPath memberSymbolPath = new SymbolPath(enumerateType.getName());
|
||||||
|
enumDataType.add(memberSymbolPath.getName(), narrowingConversion(type, length, isSigned,
|
||||||
|
enumerateType.getNumeric(), fixupContext, breakCycle));
|
||||||
}
|
}
|
||||||
return enumDataType;
|
return enumDataType;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long narrowingConversion(int outputSize, boolean outputSigned, Numeric numeric) {
|
private long narrowingConversion(AbstractEnumMsType type, int outputSize, boolean outputSigned,
|
||||||
|
Numeric numeric, FixupContext fixupContext, boolean breakCycle)
|
||||||
|
throws CancelledException, PdbException {
|
||||||
if (!numeric.isIntegral()) {
|
if (!numeric.isIntegral()) {
|
||||||
Msg.info(this, "Non-integral numeric found: " + numeric);
|
Msg.info(this, "Non-integral numeric found: " + numeric);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -304,9 +168,11 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier {
|
||||||
pdbLogAndInfoMessage(this, "Using zero in place of non-integral enumerate: " + numeric);
|
pdbLogAndInfoMessage(this, "Using zero in place of non-integral enumerate: " + numeric);
|
||||||
return 0L; //
|
return 0L; //
|
||||||
}
|
}
|
||||||
return numeric.getIntegral().longValue() & getMask();
|
return numeric.getIntegral().longValue() & getMask(type, fixupContext, breakCycle);
|
||||||
// return NarrowingConverter.narrowBigToLong(outputSize, outputSigned, numeric.getSize(),
|
}
|
||||||
// numeric.isSigned(), numeric.getIntegral());
|
|
||||||
|
private AbstractEnumMsType getDefinitionType(AbstractComplexMsType type) {
|
||||||
|
return getDefinitionType(type, AbstractEnumMsType.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,64 +15,58 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.Numeric;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.Numeric;
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractEnumerateMsType;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractEnumerateMsType;
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||||
import ghidra.app.util.pdb.PdbNamespaceUtils;
|
import ghidra.app.util.pdb.PdbNamespaceUtils;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applier for {@link AbstractEnumerateMsType} types.
|
* Applier for {@link AbstractEnumerateMsType} types.
|
||||||
*/
|
*/
|
||||||
public class EnumerateTypeApplier extends MsTypeApplier {
|
public class EnumerateTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
private String fieldName;
|
// Intended for: AbstractEnumerateMsType
|
||||||
private Numeric numeric;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for enumerate type applier, for transforming a enumerate into a
|
* Constructor for enumerate type applier, for transforming a enumerate into a
|
||||||
* Ghidra DataType.
|
* Ghidra DataType.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractEnumerateMsType} to process.
|
|
||||||
*/
|
*/
|
||||||
public EnumerateTypeApplier(DefaultPdbApplicator applicator, AbstractEnumerateMsType msType) {
|
public EnumerateTypeApplier(DefaultPdbApplicator applicator) {
|
||||||
super(applicator, msType);
|
super(applicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
BigInteger getSize() {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
return BigInteger.ZERO;
|
throws PdbException, CancelledException {
|
||||||
|
DataType dataType = applyEnumerateMsType((AbstractEnumerateMsType) type);
|
||||||
|
//dataType is null for now... so no resolve
|
||||||
|
//return applicator.resolve(dataType);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
String getName(AbstractEnumerateMsType type) {
|
||||||
void apply() {
|
return PdbNamespaceUtils.fixUnnamed(type.getName(), type.getRecordNumber().getNumber());
|
||||||
dataType = applyEnumerateMsType((AbstractEnumerateMsType) msType);
|
|
||||||
// DataType dataType = applyEnumerateMsType((AbstractEnumerateMsType) msType);
|
|
||||||
// ghDataType = dataType; // temporary while below is commented-out
|
|
||||||
// TODO: uncomment when above method not returning null
|
|
||||||
// ghDataTypeDB = applicator.resolve(dataType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String getName() {
|
Numeric getNumeric(AbstractEnumerateMsType type) {
|
||||||
return fieldName;
|
return type.getNumeric();
|
||||||
}
|
|
||||||
|
|
||||||
Numeric getNumeric() {
|
|
||||||
return numeric;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataType applyEnumerateMsType(AbstractEnumerateMsType type) {
|
private DataType applyEnumerateMsType(AbstractEnumerateMsType type) {
|
||||||
|
|
||||||
//TODO: currently dropping these on the floor. The access methods above do the same work.
|
//TODO: currently dropping these on the floor. The access methods above do the same work.
|
||||||
|
|
||||||
fieldName = PdbNamespaceUtils.fixUnnamed(type.getName(), index);
|
String fieldName =
|
||||||
|
PdbNamespaceUtils.fixUnnamed(type.getName(), type.getRecordNumber().getNumber());
|
||||||
|
|
||||||
// TODO: Need to build test sample with these.
|
// TODO: Need to build test sample with these.
|
||||||
// TODO: Need to see if can do real number; need to modify Numeric for both
|
// TODO: Need to see if can do real number; need to modify Numeric for both
|
||||||
// integral and real numbers. Possibly need to make Numeric a "type" instead
|
// integral and real numbers. Possibly need to make Numeric a "type" instead
|
||||||
// of just something to read using ByteReader.
|
// of just something to read using ByteReader.
|
||||||
numeric = type.getNumeric();
|
Numeric numeric = type.getNumeric();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,11 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
@ -30,148 +30,102 @@ import ghidra.util.exception.CancelledException;
|
||||||
*/
|
*/
|
||||||
public class FieldListTypeApplier extends MsTypeApplier {
|
public class FieldListTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
private List<MsTypeApplier> baseClassList = new ArrayList<>();
|
//TODO: evaluate the static method and multiple constructors... what can be cleaned up with
|
||||||
private List<MsTypeApplier> memberList = new ArrayList<>();
|
// regard to these and the possible NoType record???
|
||||||
private List<MsTypeApplier> methodList = new ArrayList<>();
|
|
||||||
private boolean isEmpty;
|
|
||||||
|
|
||||||
static FieldListTypeApplier getFieldListApplierSpecial(DefaultPdbApplicator applicator,
|
static FieldListTypeApplier getFieldListApplierSpecial(DefaultPdbApplicator applicator,
|
||||||
RecordNumber recordNumber) throws PdbException {
|
RecordNumber recordNumber) throws PdbException {
|
||||||
MsTypeApplier applier =
|
if (recordNumber.isNoType()) {
|
||||||
applicator.getApplierOrNoTypeSpec(recordNumber, FieldListTypeApplier.class);
|
// We can use any Field List MS type, as they use the same applier
|
||||||
|
return (FieldListTypeApplier) applicator.getTypeApplier(FieldListMsType.PDB_ID);
|
||||||
|
}
|
||||||
|
MsTypeApplier applier = applicator.getTypeApplier(recordNumber);
|
||||||
if (applier instanceof FieldListTypeApplier fieldListApplier) {
|
if (applier instanceof FieldListTypeApplier fieldListApplier) {
|
||||||
return fieldListApplier;
|
return fieldListApplier;
|
||||||
}
|
}
|
||||||
// Only the NoType spec should fall through to here
|
|
||||||
if (recordNumber.getCategory() == RecordCategory.TYPE) {
|
|
||||||
try {
|
|
||||||
return new FieldListTypeApplier(applicator,
|
|
||||||
applicator.getPdb().getTypeRecord(recordNumber), true);
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException e) {
|
|
||||||
applicator.appendLogMsg(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new PdbException("Problem creating field list");
|
throw new PdbException("Problem creating field list");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractFieldListMsType} or {@link PrimitiveMsType} of {@code NO_TYPE}
|
|
||||||
* @throws IllegalArgumentException Upon invalid arguments.
|
* @throws IllegalArgumentException Upon invalid arguments.
|
||||||
*/
|
*/
|
||||||
public FieldListTypeApplier(DefaultPdbApplicator applicator, AbstractMsType msType)
|
public FieldListTypeApplier(DefaultPdbApplicator applicator) throws IllegalArgumentException {
|
||||||
throws IllegalArgumentException {
|
super(applicator);
|
||||||
this(applicator, msType, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor with override for NO_TYPE Primitive.
|
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
|
||||||
* @param msType {@link AbstractFieldListMsType} or {@link PrimitiveMsType} of {@code NO_TYPE}
|
|
||||||
* @param noType {@code true} to specify that {@code msType} is NO_TYPE.
|
|
||||||
* @throws IllegalArgumentException Upon invalid arguments.
|
|
||||||
*/
|
|
||||||
public FieldListTypeApplier(DefaultPdbApplicator applicator, AbstractMsType msType,
|
|
||||||
boolean noType) throws IllegalArgumentException {
|
|
||||||
super(applicator, msType);
|
|
||||||
if (noType && msType instanceof PrimitiveMsType && ((PrimitiveMsType) msType).isNoType()) {
|
|
||||||
this.isEmpty = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!(msType instanceof AbstractFieldListMsType)) {
|
|
||||||
throw new IllegalArgumentException("PDB Incorrectly applying " +
|
|
||||||
msType.getClass().getSimpleName() + " to " + this.getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
this.isEmpty = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that the list is empty
|
|
||||||
* @return {@code true} if list is empty.
|
|
||||||
*/
|
|
||||||
boolean isEmpty() {
|
|
||||||
return isEmpty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
BigInteger getSize() {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
return BigInteger.ZERO;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void apply() throws PdbException, CancelledException {
|
|
||||||
if (!isEmpty()) {
|
|
||||||
dataType = applyFieldListMsType((AbstractFieldListMsType) msType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<MsTypeApplier> getBaseClassList() {
|
|
||||||
return baseClassList;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<MsTypeApplier> getMemberList() {
|
|
||||||
return memberList;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<MsTypeApplier> getMethodList() {
|
|
||||||
return methodList;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DataType applyFieldListMsType(AbstractFieldListMsType type)
|
|
||||||
throws PdbException, CancelledException {
|
throws PdbException, CancelledException {
|
||||||
|
// do nothing
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
applyBaseClasses(type.getBaseClassList());
|
//==============================================================================================
|
||||||
applyMembers(type.getMemberList());
|
|
||||||
applyMethods(type.getMethodList());
|
|
||||||
|
|
||||||
for (AbstractIndexMsType indexType : type.getIndexList()) {
|
record FieldLists(List<AbstractMsType> bases, List<AbstractMsType> members,
|
||||||
|
List<AbstractMemberMsType> nonstaticMembers,
|
||||||
|
List<AbstractVirtualFunctionTablePointerMsType> vftPtrs, List<AbstractMsType> methods,
|
||||||
|
List<AbstractNestedTypeMsType> nestedTypes, List<AbstractEnumerateMsType> enumerates) {}
|
||||||
|
|
||||||
|
//==============================================================================================
|
||||||
|
|
||||||
|
FieldLists getFieldLists(RecordNumber recordNumber) throws PdbException {
|
||||||
|
AbstractMsType type = applicator.getPdb().getTypeRecord(recordNumber);
|
||||||
|
if (type instanceof PrimitiveMsType primitive && primitive.isNoType()) {
|
||||||
|
return new FieldLists(new ArrayList<>(), new ArrayList<>(), new ArrayList<>(),
|
||||||
|
new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
|
||||||
|
}
|
||||||
|
else if (type instanceof AbstractFieldListMsType fieldListType) {
|
||||||
|
return getFieldLists(fieldListType);
|
||||||
|
}
|
||||||
|
throw new PdbException(type.getClass().getSimpleName() + " seen where " +
|
||||||
|
FieldListMsType.class.getSimpleName() + " expected for record number " + recordNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldLists getFieldLists(AbstractFieldListMsType fieldListType) throws PdbException {
|
||||||
|
List<AbstractMsType> bases = new ArrayList<>();
|
||||||
|
List<AbstractMsType> members = new ArrayList<>();
|
||||||
|
List<AbstractMsType> methods = new ArrayList<>();
|
||||||
|
for (MsTypeField typeIterated : fieldListType.getBaseClassList()) {
|
||||||
|
bases.add((AbstractMsType) typeIterated);
|
||||||
|
}
|
||||||
|
for (MsTypeField typeIterated : fieldListType.getMemberList()) {
|
||||||
|
members.add((AbstractMsType) typeIterated);
|
||||||
|
}
|
||||||
|
for (MsTypeField typeIterated : fieldListType.getMethodList()) {
|
||||||
|
methods.add((AbstractMsType) typeIterated);
|
||||||
|
}
|
||||||
|
List<AbstractMemberMsType> nonstaticMembers =
|
||||||
|
new ArrayList<>(fieldListType.getNonStaticMembers());
|
||||||
|
List<AbstractVirtualFunctionTablePointerMsType> vftPtrs =
|
||||||
|
new ArrayList<>(fieldListType.getVftPointers());
|
||||||
|
List<AbstractNestedTypeMsType> nestedTypes =
|
||||||
|
new ArrayList<>(fieldListType.getNestedTypes());
|
||||||
|
List<AbstractEnumerateMsType> enumerates = new ArrayList<>(fieldListType.getEnumerates());
|
||||||
|
|
||||||
|
for (AbstractIndexMsType indexType : fieldListType.getIndexList()) {
|
||||||
|
RecordNumber subRecordNumber = indexType.getReferencedRecordNumber();
|
||||||
MsTypeApplier referencedTypeApplier =
|
MsTypeApplier referencedTypeApplier =
|
||||||
applicator.getTypeApplier(indexType.getReferencedRecordNumber());
|
applicator.getTypeApplier(indexType.getReferencedRecordNumber());
|
||||||
if (referencedTypeApplier instanceof FieldListTypeApplier) {
|
if (referencedTypeApplier instanceof FieldListTypeApplier fieldListApplier) {
|
||||||
FieldListTypeApplier subApplier = (FieldListTypeApplier) referencedTypeApplier;
|
FieldListTypeApplier.FieldLists lists =
|
||||||
baseClassList.addAll(subApplier.getBaseClassList());
|
fieldListApplier.getFieldLists(subRecordNumber);
|
||||||
memberList.addAll(subApplier.getMemberList());
|
bases.addAll(lists.bases());
|
||||||
methodList.addAll(subApplier.getMethodList());
|
members.addAll(lists.members());
|
||||||
|
methods.addAll(lists.methods());
|
||||||
|
nonstaticMembers.addAll(lists.nonstaticMembers());
|
||||||
|
vftPtrs.addAll(lists.vftPtrs());
|
||||||
|
nestedTypes.addAll(lists.nestedTypes());
|
||||||
|
enumerates.addAll(lists.enumerates());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pdbLogAndInfoMessage(this, "referenceTypeApplier is not FieldListTypeApplier");
|
pdbLogAndInfoMessage(this, "referenceTypeApplier is not FieldListTypeApplier");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyBaseClasses(List<MsTypeField> baseClasses)
|
return new FieldLists(bases, members, nonstaticMembers, vftPtrs, methods, nestedTypes,
|
||||||
throws CancelledException, PdbException {
|
enumerates);
|
||||||
for (MsTypeField typeIterated : baseClasses) {
|
|
||||||
// Use dummy index of zero.
|
|
||||||
MsTypeApplier applier = applicator.getTypeApplier((AbstractMsType) typeIterated);
|
|
||||||
applier.apply(); // Need to apply here, as these are embedded records
|
|
||||||
baseClassList.add(applier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyMembers(List<MsTypeField> members) throws CancelledException, PdbException {
|
|
||||||
for (MsTypeField typeIterated : members) {
|
|
||||||
// Use dummy index of zero.
|
|
||||||
MsTypeApplier applier = applicator.getTypeApplier((AbstractMsType) typeIterated);
|
|
||||||
applier.apply(); // Need to apply here, as these are embedded records
|
|
||||||
memberList.add(applier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyMethods(List<MsTypeField> methods) throws CancelledException, PdbException {
|
|
||||||
for (MsTypeField typeIterated : methods) {
|
|
||||||
// Use dummy index of zero.
|
|
||||||
MsTypeApplier applier = applicator.getTypeApplier((AbstractMsType) typeIterated);
|
|
||||||
// TODO: note that these are likely NoTypeAppliers at the moment, as we had not
|
|
||||||
// yet implemented appliers for AbstractOneMethodMsType and
|
|
||||||
// AbstractOverloadedMethodMsType
|
|
||||||
applier.apply(); // Need to apply here, as these are embedded records
|
|
||||||
methodList.add(applier);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,313 @@
|
||||||
|
/* ###
|
||||||
|
* 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.pdb.pdbapplicator;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applier context used for fixups of data types
|
||||||
|
*/
|
||||||
|
public class FixupContext {
|
||||||
|
|
||||||
|
private Deque<Integer> stagedRecordFifo = new ArrayDeque<>();
|
||||||
|
private Deque<Integer> inProgressRecordStack = new ArrayDeque<>();
|
||||||
|
private Deque<Integer> fixupRecordFifo = new ArrayDeque<>();
|
||||||
|
|
||||||
|
private Map<Integer, List<Integer>> map = new HashMap<>();
|
||||||
|
private Map<Integer, DataType> fixupTypes = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that record is already being processed and, if not, adds it to the Staged state
|
||||||
|
* @param record the number of the record
|
||||||
|
* @throws PdbException upon the record already in the process or fixup state
|
||||||
|
*/
|
||||||
|
void ensureInContext(int record) throws PdbException {
|
||||||
|
if (inProgressRecordStack.contains(record)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fixupRecordFifo.contains(record)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addStagedRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataType getFixupDataType(int record) {
|
||||||
|
return fixupTypes.get(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds record to the Staged state if not already there
|
||||||
|
* @param recordNumber the number of the record
|
||||||
|
* @throws PdbException upon the record already in the process or fixup state
|
||||||
|
*/
|
||||||
|
void addStagedRecord(int recordNumber) throws PdbException {
|
||||||
|
if (stagedRecordFifo.contains(recordNumber)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (inProgressRecordStack.contains(recordNumber)) {
|
||||||
|
throw new PdbException("Record Number in process state: " + recordNumber);
|
||||||
|
}
|
||||||
|
if (fixupRecordFifo.contains(recordNumber)) {
|
||||||
|
throw new PdbException("Record Number in fixup state: " + recordNumber);
|
||||||
|
}
|
||||||
|
if (map.containsKey(recordNumber)) {
|
||||||
|
throw new PdbException("Record Number already exists: " + recordNumber);
|
||||||
|
}
|
||||||
|
map.put(recordNumber, new ArrayList<>());
|
||||||
|
putStagedRecord(recordNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the next record in the Staged state to the process state and returns its number
|
||||||
|
* @return the number of the record moved
|
||||||
|
* @throws PdbException if the record happens to be in another state (should not happen if
|
||||||
|
* in the Staged state)
|
||||||
|
*/
|
||||||
|
Integer moveFromStagedToProcessRecord() throws PdbException {
|
||||||
|
Integer record = getStagedRecord();
|
||||||
|
if (record != null) {
|
||||||
|
putProcessRecord(record);
|
||||||
|
}
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts the specified record number from the Staged state to the Process state
|
||||||
|
* @param number the number of the record
|
||||||
|
* @throws PdbException if the record is not in the Staged state
|
||||||
|
*/
|
||||||
|
void moveFromStagedToProcessRecord(int number) throws PdbException {
|
||||||
|
if (!stagedRecordFifo.remove(number)) {
|
||||||
|
throw new PdbException("Number not in Staged state: " + number);
|
||||||
|
}
|
||||||
|
putProcessRecord(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts the specified record to the head of the Process state. If the record had been
|
||||||
|
* in the Staged state or anywhere else in the Process state, it is moved to the head of the
|
||||||
|
* Process state
|
||||||
|
* @param number the number of the record
|
||||||
|
* @throws PdbException if the records is not in the Staged state
|
||||||
|
*/
|
||||||
|
void moveToHeadProcessRecord(int number) throws PdbException {
|
||||||
|
if (stagedRecordFifo.contains(number)) {
|
||||||
|
stagedRecordFifo.remove(number);
|
||||||
|
}
|
||||||
|
else if (inProgressRecordStack.contains(number)) {
|
||||||
|
inProgressRecordStack.remove(number);
|
||||||
|
inProgressRecordStack.offerFirst(number);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
map.put(number, new ArrayList<>());
|
||||||
|
}
|
||||||
|
putProcessRecord(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the specified record from the Process state to the Fixup state
|
||||||
|
* @param number the number of the record
|
||||||
|
* @param dataType the type that has been created for this in-progress type
|
||||||
|
* @throws PdbException if the record is not in the Process state
|
||||||
|
*/
|
||||||
|
void moveProcessToFixupsRecord(int number, DataType dataType) throws PdbException {
|
||||||
|
if (!inProgressRecordStack.remove(number)) {
|
||||||
|
throw new PdbException("Number not in process state: " + number);
|
||||||
|
}
|
||||||
|
if (fixupTypes.containsKey(number)) {
|
||||||
|
throw new PdbException("Number already in progress: " + number);
|
||||||
|
}
|
||||||
|
putFixupsRecord(number);
|
||||||
|
fixupTypes.put(number, dataType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the next record from the Fixup state and returns the number
|
||||||
|
* @return the number
|
||||||
|
*/
|
||||||
|
Integer popFixupsRecord() {
|
||||||
|
Integer record = getFixupsRecord();
|
||||||
|
if (record != null) {
|
||||||
|
if (map.containsKey(record)) {
|
||||||
|
map.remove(record);
|
||||||
|
}
|
||||||
|
if (fixupTypes.containsKey(record)) {
|
||||||
|
fixupTypes.remove(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not sure we will use this method
|
||||||
|
/**
|
||||||
|
* Removes the head of the Process state and returns the number. The number is not moved
|
||||||
|
* to the Fixup state
|
||||||
|
* @return the number
|
||||||
|
*/
|
||||||
|
Integer popProcessRecord() {
|
||||||
|
Integer record = getProcessRecord();
|
||||||
|
if (record != null) {
|
||||||
|
if (map.containsKey(record)) {
|
||||||
|
map.remove(record);
|
||||||
|
}
|
||||||
|
// Since pop from current, not adding to fixups
|
||||||
|
}
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putStagedRecord(int record) throws PdbException {
|
||||||
|
if (stagedRecordFifo.contains(record)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (inProgressRecordStack.contains(record)) {
|
||||||
|
throw new PdbException("Record exists in another state: " + record);
|
||||||
|
}
|
||||||
|
if (fixupRecordFifo.contains(record)) {
|
||||||
|
throw new PdbException("Record exists in another state: " + record);
|
||||||
|
}
|
||||||
|
stagedRecordFifo.addFirst(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer getStagedRecord() {
|
||||||
|
return stagedRecordFifo.pollLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Peeks at and returns the record number of the head of the Staged state
|
||||||
|
* @return the record number
|
||||||
|
*/
|
||||||
|
Integer peekStagedRecord() {
|
||||||
|
return stagedRecordFifo.peekLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putProcessRecord(int record) throws PdbException {
|
||||||
|
if (inProgressRecordStack.contains(record)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (stagedRecordFifo.contains(record)) {
|
||||||
|
throw new PdbException("Record exists in another state: " + record);
|
||||||
|
}
|
||||||
|
if (fixupRecordFifo.contains(record)) {
|
||||||
|
throw new PdbException("Record exists in another state: " + record);
|
||||||
|
}
|
||||||
|
inProgressRecordStack.addFirst(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer getProcessRecord() {
|
||||||
|
return inProgressRecordStack.pollFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putFixupsRecord(int record) throws PdbException {
|
||||||
|
if (fixupRecordFifo.contains(record)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (stagedRecordFifo.contains(record)) {
|
||||||
|
throw new PdbException("Record exists in another state: " + record);
|
||||||
|
}
|
||||||
|
if (inProgressRecordStack.contains(record)) {
|
||||||
|
throw new PdbException("Record exists in another state: " + record);
|
||||||
|
}
|
||||||
|
fixupRecordFifo.addFirst(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Peeks at and returns the record number of the head of the Process state
|
||||||
|
* @return the record number
|
||||||
|
*/
|
||||||
|
Integer peekProcessRecord() {
|
||||||
|
return inProgressRecordStack.peekFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes and returns the record number of the head of the Fixup state
|
||||||
|
* @return the record number
|
||||||
|
*/
|
||||||
|
Integer getFixupsRecord() {
|
||||||
|
return fixupRecordFifo.pollLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Peeks at and returns the record number of the head of the Fixup state
|
||||||
|
* @return the record number
|
||||||
|
*/
|
||||||
|
Integer peekFixupsRecord() {
|
||||||
|
return fixupRecordFifo.peekLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts the fixup index into the fixups for the current head of the Process state
|
||||||
|
* @param fixupIndex the fixup index
|
||||||
|
* @throws PdbException if the head of the Process state is empty or is fixups cannot be found
|
||||||
|
*/
|
||||||
|
void putFixup(int fixupIndex) throws PdbException {
|
||||||
|
List<Integer> fixups = getProcessFixups();
|
||||||
|
fixups.add(fixupIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the fixups for the current head of the Process state is empty
|
||||||
|
* @return {@code true} if empty
|
||||||
|
* @throws PdbException if there is no head of the Process state or its fixups cannot be found
|
||||||
|
*/
|
||||||
|
boolean processFixupsIsEmpty() throws PdbException {
|
||||||
|
List<Integer> fixups = getProcessFixups();
|
||||||
|
return fixups.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Peeks at and returns head of the Fixup state
|
||||||
|
* @return the number of the record
|
||||||
|
*/
|
||||||
|
Integer peekFixupRecord() {
|
||||||
|
return peekFixupsRecord();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the fixups for the head of the Fixups state
|
||||||
|
* @return the fixup indices
|
||||||
|
* @throws PdbException if the head of the Fixups state does not exist or its fixups cannot be
|
||||||
|
* found
|
||||||
|
*/
|
||||||
|
List<Integer> getFixups() throws PdbException {
|
||||||
|
Integer record = peekFixupsRecord();
|
||||||
|
if (record == null) {
|
||||||
|
throw new PdbException("Empty fixups retrieval");
|
||||||
|
}
|
||||||
|
List<Integer> fixups = map.get(record);
|
||||||
|
if (fixups == null) {
|
||||||
|
throw new PdbException("Fixups not found on retrieval");
|
||||||
|
}
|
||||||
|
return fixups;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Integer> getProcessFixups() throws PdbException {
|
||||||
|
Integer record = peekProcessRecord();
|
||||||
|
if (record == null) {
|
||||||
|
throw new PdbException("Context empty on fixups retrieval");
|
||||||
|
}
|
||||||
|
List<Integer> fixups = map.get(record);
|
||||||
|
if (fixups == null) {
|
||||||
|
throw new PdbException("Fixups not found");
|
||||||
|
}
|
||||||
|
return fixups;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ import ghidra.app.cmd.function.ApplyFunctionSignatureCmd;
|
||||||
import ghidra.app.cmd.function.CallDepthChangeInfo;
|
import ghidra.app.cmd.function.CallDepthChangeInfo;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*;
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSet;
|
import ghidra.program.model.address.AddressSet;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
|
@ -86,8 +87,8 @@ public class FunctionSymbolApplier extends MsSymbolApplier
|
||||||
procedureSymbol = (AbstractProcedureStartIa64MsSymbol) abstractSymbol;
|
procedureSymbol = (AbstractProcedureStartIa64MsSymbol) abstractSymbol;
|
||||||
specifiedAddress = applicator.getRawAddress(procedureSymbol);
|
specifiedAddress = applicator.getRawAddress(procedureSymbol);
|
||||||
address = applicator.getAddress(procedureSymbol);
|
address = applicator.getAddress(procedureSymbol);
|
||||||
isNonReturning = ((AbstractProcedureStartIa64MsSymbol) procedureSymbol).getFlags()
|
isNonReturning =
|
||||||
.doesNotReturn();
|
((AbstractProcedureStartIa64MsSymbol) procedureSymbol).getFlags().doesNotReturn();
|
||||||
}
|
}
|
||||||
else if (abstractSymbol instanceof AbstractProcedureStartMipsMsSymbol) {
|
else if (abstractSymbol instanceof AbstractProcedureStartMipsMsSymbol) {
|
||||||
procedureSymbol = (AbstractProcedureStartMipsMsSymbol) abstractSymbol;
|
procedureSymbol = (AbstractProcedureStartMipsMsSymbol) abstractSymbol;
|
||||||
|
@ -260,7 +261,7 @@ public class FunctionSymbolApplier extends MsSymbolApplier
|
||||||
applicator.createSymbol(varAddress, varName, true, plateAddition);
|
applicator.createSymbol(varAddress, varName, true, plateAddition);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean applyFunction(TaskMonitor monitor) {
|
private boolean applyFunction(TaskMonitor monitor) throws CancelledException, PdbException {
|
||||||
function = applicator.getExistingOrCreateOneByteFunction(address);
|
function = applicator.getExistingOrCreateOneByteFunction(address);
|
||||||
if (function == null) {
|
if (function == null) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -285,11 +286,14 @@ public class FunctionSymbolApplier extends MsSymbolApplier
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns true only if we set a function signature
|
* Sets function signature
|
||||||
* @param monitor monitor
|
* @param monitor monitor
|
||||||
* @return true if function signature was set
|
* @return true if function signature was set
|
||||||
|
* @throws CancelledException upon user cancellation
|
||||||
|
* @throws PdbException upon processing error
|
||||||
*/
|
*/
|
||||||
private boolean setFunctionDefinition(TaskMonitor monitor) {
|
private boolean setFunctionDefinition(TaskMonitor monitor)
|
||||||
|
throws CancelledException, PdbException {
|
||||||
if (procedureSymbol == null) {
|
if (procedureSymbol == null) {
|
||||||
// TODO: is there anything we can do with thunkSymbol?
|
// TODO: is there anything we can do with thunkSymbol?
|
||||||
// long x = thunkSymbol.getParentPointer();
|
// long x = thunkSymbol.getParentPointer();
|
||||||
|
@ -298,21 +302,16 @@ public class FunctionSymbolApplier extends MsSymbolApplier
|
||||||
// Rest presumes procedureSymbol.
|
// Rest presumes procedureSymbol.
|
||||||
RecordNumber typeRecordNumber = procedureSymbol.getTypeRecordNumber();
|
RecordNumber typeRecordNumber = procedureSymbol.getTypeRecordNumber();
|
||||||
MsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber);
|
MsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber);
|
||||||
if (applier == null) {
|
AbstractMsType fType = applicator.getPdb().getTypeRecord(typeRecordNumber);
|
||||||
applicator.appendLogMsg("Error: Failed to resolve datatype RecordNumber " +
|
|
||||||
typeRecordNumber + " at " + address);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!(applier instanceof AbstractFunctionTypeApplier)) {
|
if (!(applier instanceof AbstractFunctionTypeApplier)) {
|
||||||
if (!((applier instanceof PrimitiveTypeApplier) &&
|
if (!((applier instanceof PrimitiveTypeApplier prim) && prim.isNoType(fType))) {
|
||||||
((PrimitiveTypeApplier) applier).isNoType())) {
|
|
||||||
applicator.appendLogMsg("Error: Failed to resolve datatype RecordNumber " +
|
applicator.appendLogMsg("Error: Failed to resolve datatype RecordNumber " +
|
||||||
typeRecordNumber + " at " + address);
|
typeRecordNumber + " at " + address);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType dataType = applier.getDataType();
|
DataType dataType = applicator.getCompletedDataType(typeRecordNumber);
|
||||||
// Since we know the applier is an AbstractionFunctionTypeApplier, then dataType is either
|
// Since we know the applier is an AbstractionFunctionTypeApplier, then dataType is either
|
||||||
// FunctionDefinition or no type (typedef).
|
// FunctionDefinition or no type (typedef).
|
||||||
if (!(dataType instanceof FunctionDefinition)) {
|
if (!(dataType instanceof FunctionDefinition)) {
|
||||||
|
|
|
@ -15,14 +15,11 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import ghidra.app.util.SymbolPath;
|
import ghidra.app.util.SymbolPath;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMemberFunctionMsType;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.CallingConvention;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.DataType;
|
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,238 +27,105 @@ import ghidra.util.exception.CancelledException;
|
||||||
*/
|
*/
|
||||||
public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier {
|
public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier {
|
||||||
|
|
||||||
private MsTypeApplier thisPointerApplier = null;
|
// Intended for: AbstractMemberFunctionMsType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for the applicator that applies {@link AbstractMemberFunctionMsType},
|
* Constructor for the applicator that applies {@link AbstractMemberFunctionMsType},
|
||||||
* transforming it into a Ghidra {@link DataType}.
|
* transforming it into a Ghidra {@link DataType}.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractMemberFunctionMsType} to processes.
|
|
||||||
* @throws IllegalArgumentException Upon type mismatch.
|
* @throws IllegalArgumentException Upon type mismatch.
|
||||||
*/
|
*/
|
||||||
public MemberFunctionTypeApplier(DefaultPdbApplicator applicator,
|
public MemberFunctionTypeApplier(DefaultPdbApplicator applicator)
|
||||||
AbstractMemberFunctionMsType msType) throws IllegalArgumentException {
|
throws IllegalArgumentException {
|
||||||
super(applicator, msType);
|
super(applicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
BigInteger getSize() {
|
|
||||||
return BigInteger.ZERO;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected CallingConvention getCallingConvention() {
|
|
||||||
return ((AbstractMemberFunctionMsType) msType).getCallingConvention();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean hasThisPointer() {
|
|
||||||
MsTypeApplier applier = applicator.getTypeApplier(
|
|
||||||
((AbstractMemberFunctionMsType) msType).getThisPointerRecordNumber());
|
|
||||||
if ((applier instanceof PrimitiveTypeApplier &&
|
|
||||||
((PrimitiveTypeApplier) applier).isNoType())) {
|
|
||||||
return false; // such as for static member functions
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected RecordNumber getReturnRecordNumber() {
|
|
||||||
return ((AbstractMemberFunctionMsType) msType).getReturnRecordNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected RecordNumber getArgListRecordNumber() {
|
|
||||||
return ((AbstractMemberFunctionMsType) msType).getArgListRecordNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isConstructor() {
|
|
||||||
return ((AbstractMemberFunctionMsType) msType).isConstructor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void apply() throws PdbException, CancelledException {
|
|
||||||
predefineClasses();
|
|
||||||
applyFunction(getCallingConvention(), hasThisPointer());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void predefineClasses() throws CancelledException, PdbException {
|
|
||||||
AbstractMemberFunctionMsType procType = (AbstractMemberFunctionMsType) msType;
|
|
||||||
if (hasThisPointer()) {
|
|
||||||
thisPointerApplier = getThisPointerApplier(procType);
|
|
||||||
applicator.getPdbApplicatorMetrics().witnessMemberFunctionThisPointer(
|
|
||||||
thisPointerApplier);
|
|
||||||
if (thisPointerApplier instanceof PointerTypeApplier) {
|
|
||||||
MsTypeApplier underlyingApplier =
|
|
||||||
getThisUnderlyingApplier((PointerTypeApplier) thisPointerApplier);
|
|
||||||
applicator.getPdbApplicatorMetrics().witnessMemberFunctionThisPointerUnderlyingType(
|
|
||||||
underlyingApplier);
|
|
||||||
if (underlyingApplier instanceof CompositeTypeApplier) {
|
|
||||||
predefineClass((CompositeTypeApplier) underlyingApplier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractComplexTypeApplier containingApplier = getContainingComplexApplier(procType);
|
|
||||||
applicator.getPdbApplicatorMetrics().witnessMemberFunctionContainingType(containingApplier);
|
|
||||||
if (containingApplier instanceof CompositeTypeApplier) {
|
|
||||||
// Do nothing at this time if Enum or something else
|
|
||||||
predefineClass((CompositeTypeApplier) containingApplier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void predefineClass(CompositeTypeApplier applier) {
|
|
||||||
SymbolPath containingClassSymbolPath = applier.getFixedSymbolPath();
|
|
||||||
applicator.predefineClass(containingClassSymbolPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// private AbstractPointerMsType getThisType(AbstractMemberFunctionMsType procType)
|
|
||||||
// throws CancelledException, PdbException {
|
|
||||||
// int thisPointerTypeIndex = procType.getThisPointerTypeIndex();
|
|
||||||
// AbstractMsTypeApplier applier = applicator.getTypeApplier(thisPointerTypeIndex);
|
|
||||||
//
|
|
||||||
// if ((applier instanceof PrimitiveTypeApplier &&
|
|
||||||
// ((PrimitiveTypeApplier) applier).isNoType())) {
|
|
||||||
// return null; // such as for static member functions
|
|
||||||
// }
|
|
||||||
// if (!(applier instanceof PointerTypeApplier)) {
|
|
||||||
// applicator.getLog().appendMsg("thisApplier is invalid type for " + msType.getName());
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// AbstractMsType thisMsType = applier.getMsType();
|
|
||||||
// // shouldn't need to do this next test, as an applier should only get this type
|
|
||||||
// if (!(thisMsType instanceof AbstractPointerMsType)) {
|
|
||||||
// applicator.getLog().appendMsg("thisMsType is invalid type for " + msType.getName());
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// return (AbstractPointerMsType) thisMsType;
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private void processContainingClass(AbstractMemberFunctionMsType procType)
|
|
||||||
// throws CancelledException, PdbException {
|
|
||||||
// int containingClassTypeIndex = procType.getContainingClassTypeIndex();
|
|
||||||
//
|
|
||||||
// CompositeTypeApplier containingCompositeApplier =
|
|
||||||
// applicator.getCompositeApplier(containingClassTypeIndex);
|
|
||||||
////
|
|
||||||
//// ApplyCompositeType containingCompositeApplier =
|
|
||||||
//// (ApplyCompositeType) applicator.getExpectedTypeApplier(containingClassTypeIndex,
|
|
||||||
//// ApplyCompositeType.class);
|
|
||||||
//
|
|
||||||
//// AbstractApplyMsType containingTypeApplier =
|
|
||||||
//// applicator.getTypeApplier(containingClassTypeIndex, false);
|
|
||||||
//// if (containingTypeApplier == null) {
|
|
||||||
//// applicator.getLog().appendMsg(
|
|
||||||
//// "containingClassApplier is null for " + msType.getName());
|
|
||||||
//// return null;
|
|
||||||
//// }
|
|
||||||
//// if (!(containingTypeApplier instanceof ApplyCompositeType)) {
|
|
||||||
//// applicator.getLog().appendMsg(
|
|
||||||
//// "containingClassApplier is invalid type for " + msType.getName());
|
|
||||||
//// return null;
|
|
||||||
//// }
|
|
||||||
//// ApplyCompositeType containingCompositeApplier = (ApplyCompositeType) containingTypeApplier;
|
|
||||||
// SymbolPath containingClassSymbolPath = containingCompositeApplier.getFixedSymbolPath();
|
|
||||||
// applicator.predefineClass(containingClassSymbolPath);
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private boolean hasThisPointer(AbstractMemberFunctionMsType procType)
|
|
||||||
// throws CancelledException, PdbException {
|
|
||||||
// int thisPointerTypeIndex = procType.getThisPointerTypeIndex();
|
|
||||||
// AbstractMsTypeApplier applier = applicator.getTypeApplier(thisPointerTypeIndex);
|
|
||||||
// if ((applier instanceof PrimitiveTypeApplier &&
|
|
||||||
// ((PrimitiveTypeApplier) applier).isNoType())) {
|
|
||||||
// return false; // such as for static member functions
|
|
||||||
// }
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
private MsTypeApplier getThisPointerApplier(AbstractMemberFunctionMsType procType) {
|
private MsTypeApplier getThisPointerApplier(AbstractMemberFunctionMsType procType) {
|
||||||
MsTypeApplier applier = applicator.getTypeApplier(procType.getThisPointerRecordNumber());
|
MsTypeApplier applier = applicator.getTypeApplier(procType.getThisPointerRecordNumber());
|
||||||
|
|
||||||
// if ((applier instanceof PrimitiveTypeApplier &&
|
|
||||||
// ((PrimitiveTypeApplier) applier).isNoType())) {
|
|
||||||
// return null; // such as for static member functions
|
|
||||||
// }
|
|
||||||
// // Cannot just check of PointerTypeApplier because could instead be a
|
|
||||||
// // PrimitiveTypeApplier with PointerDataType as dataType
|
|
||||||
// if (!(applier.getDataType() instanceof PointerDataType)) {
|
|
||||||
// applicator.appendLogMsg(applier.getMsType().getClass().getSimpleName() +
|
|
||||||
// " this type is invalid type for " + msType.getClass().getSimpleName());
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
applicator.addApplierDependency(this, applier);
|
|
||||||
return applier;
|
return applier;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MsTypeApplier getThisUnderlyingApplier(PointerTypeApplier thisApplier) {
|
@Override
|
||||||
return thisApplier.getUnmodifiedUnderlyingTypeApplier();
|
protected CallingConvention getCallingConvention(AbstractMsType type) {
|
||||||
|
return ((AbstractMemberFunctionMsType) type).getCallingConvention();
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbstractComplexTypeApplier getContainingComplexApplier(
|
@Override
|
||||||
AbstractMemberFunctionMsType procType) throws PdbException {
|
protected Pointer getThisPointer(AbstractMsType type, FixupContext fixupContext,
|
||||||
return AbstractComplexTypeApplier.getComplexApplier(applicator,
|
boolean breakCycle) throws CancelledException, PdbException {
|
||||||
procType.getContainingClassRecordNumber());
|
RecordNumber ptrRecord = ((AbstractMemberFunctionMsType) type).getThisPointerRecordNumber();
|
||||||
|
if (ptrRecord == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
AbstractMsType mType = applicator.getPdb().getTypeRecord(ptrRecord);
|
||||||
|
if (mType instanceof PrimitiveMsType primitive && primitive.isNoType()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (mType instanceof AbstractPointerMsType msPtr) {
|
||||||
|
predefineClass(msPtr.getUnderlyingRecordNumber());
|
||||||
|
}
|
||||||
|
applicator.getPdbApplicatorMetrics().witnessMemberFunctionThisPointer(mType);
|
||||||
|
DataType dt = applicator.getProcessedDataType(ptrRecord, fixupContext, breakCycle);
|
||||||
|
if (dt instanceof Pointer ptr) {
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Composite getContainingComplexApplier(AbstractMsType type, FixupContext fixupContext,
|
||||||
|
boolean breakCycle) throws CancelledException, PdbException {
|
||||||
|
RecordNumber containerRecord =
|
||||||
|
((AbstractMemberFunctionMsType) type).getContainingClassRecordNumber();
|
||||||
|
if (containerRecord == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
AbstractMsType mType = applicator.getPdb().getTypeRecord(containerRecord);
|
||||||
|
applicator.getPdbApplicatorMetrics().witnessMemberFunctionContainingType(mType);
|
||||||
|
DataType dt = applicator.getProcessedDataType(containerRecord, fixupContext, breakCycle);
|
||||||
|
if (dt instanceof Composite composite) {
|
||||||
|
return composite;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processContainingType(AbstractMsType type) {
|
||||||
|
RecordNumber containerRecord =
|
||||||
|
((AbstractMemberFunctionMsType) type).getContainingClassRecordNumber();
|
||||||
|
if (containerRecord == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
predefineClass(containerRecord);
|
||||||
|
AbstractMsType mType = applicator.getPdb().getTypeRecord(containerRecord);
|
||||||
|
applicator.getPdbApplicatorMetrics().witnessMemberFunctionContainingType(mType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void predefineClass(RecordNumber recordNumber) {
|
||||||
|
AbstractMsType type = applicator.getPdb().getTypeRecord(recordNumber);
|
||||||
|
if (!(type instanceof AbstractCompositeMsType msComposite)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MsTypeApplier applier = applicator.getTypeApplier(recordNumber);
|
||||||
|
if (!(applier instanceof CompositeTypeApplier compApplier)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SymbolPath sp = compApplier.getFixedSymbolPath(msComposite);
|
||||||
|
applicator.predefineClass(sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isConstructor(AbstractMsType type) {
|
||||||
|
return ((AbstractMemberFunctionMsType) type).isConstructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RecordNumber getReturnRecordNumber(AbstractMsType type) {
|
||||||
|
return ((AbstractMemberFunctionMsType) type).getReturnRecordNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RecordNumber getArgListRecordNumber(AbstractMsType type) {
|
||||||
|
return ((AbstractMemberFunctionMsType) type).getArgListRecordNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
// private void processPointerUnderlyingType()
|
|
||||||
// throws CancelledException, PdbException {
|
|
||||||
//
|
|
||||||
// AbstractMsTypeApplier thisUnderlyingTypeApplier = thisPointerApplier.getUnmodifiedUnderlyingTypeApplier();
|
|
||||||
//
|
|
||||||
// if (!(thisUnderlyingTypeApplier instanceof CompositeTypeApplier)) {
|
|
||||||
// applicator.getLog().appendMsg(
|
|
||||||
// "thisUnderlyingTypeApplier is invalid type for " + msType.getName());
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// CompositeTypeApplier thisUnderlyingCompositeApplier =
|
|
||||||
// (CompositeTypeApplier) thisUnderlyingTypeApplier;
|
|
||||||
// SymbolPath thisUnderlyingClassSymbolPath =
|
|
||||||
// thisUnderlyingCompositeApplier.getFixedSymbolPath();
|
|
||||||
// applicator.predefineClass(thisUnderlyingClassSymbolPath);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private AbstractPointerMsType processThisPointer(AbstractMemberFunctionMsType procType)
|
|
||||||
// throws CancelledException, PdbException {
|
|
||||||
// int thisPointerTypeIndex = procType.getThisPointerTypeIndex();
|
|
||||||
// AbstractMsTypeApplier thisPointerApplier = applicator.getTypeApplier(thisPointerTypeIndex);
|
|
||||||
//
|
|
||||||
// if ((thisPointerApplier instanceof PrimitiveTypeApplier &&
|
|
||||||
// ((PrimitiveTypeApplier) thisPointerApplier).isNoType())) {
|
|
||||||
// return null; // such as for static member functions
|
|
||||||
// }
|
|
||||||
// if (!(thisPointerApplier instanceof PointerTypeApplier)) {
|
|
||||||
// applicator.getLog().appendMsg("thisApplier is invalid type for " + msType.getName());
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// return (AbstractPointerMsType) thisPointerApplier.getMsType();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private void processPointerUnderlyingType(AbstractPointerMsType thisPointerMsType)
|
|
||||||
// throws CancelledException, PdbException {
|
|
||||||
//
|
|
||||||
// int thisUnderlyingTypeIndex = thisPointerMsType.getUnderlyingTypeIndex();
|
|
||||||
// AbstractMsTypeApplier thisUnderlyingTypeApplier =
|
|
||||||
// applicator.getTypeApplier(thisUnderlyingTypeIndex);
|
|
||||||
//
|
|
||||||
// // TODO: does not recurse below one level of modifiers... consider doing a recursion.
|
|
||||||
// if (thisUnderlyingTypeApplier instanceof ModifierTypeApplier) {
|
|
||||||
// ModifierTypeApplier x = (ModifierTypeApplier) thisUnderlyingTypeApplier;
|
|
||||||
// int y = ((AbstractModifierMsType) (x.getMsType())).getModifiedTypeIndex();
|
|
||||||
// thisUnderlyingTypeApplier = applicator.getTypeApplier(y);
|
|
||||||
// }
|
|
||||||
// if (!(thisUnderlyingTypeApplier instanceof CompositeTypeApplier)) {
|
|
||||||
// applicator.getLog().appendMsg(
|
|
||||||
// "thisUnderlyingTypeApplier is invalid type for " + msType.getName());
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// CompositeTypeApplier thisUnderlyingCompositeApplier =
|
|
||||||
// (CompositeTypeApplier) thisUnderlyingTypeApplier;
|
|
||||||
// SymbolPath thisUnderlyingClassSymbolPath =
|
|
||||||
// thisUnderlyingCompositeApplier.getFixedSymbolPath();
|
|
||||||
// applicator.predefineClass(thisUnderlyingClassSymbolPath);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,9 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMemberMsType;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMemberMsType;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.ClassFieldMsAttributes;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
|
@ -28,60 +26,19 @@ import ghidra.util.exception.CancelledException;
|
||||||
*/
|
*/
|
||||||
public class MemberTypeApplier extends MsTypeApplier {
|
public class MemberTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
|
// Intended for: AbstractMemberMsType
|
||||||
/**
|
/**
|
||||||
* Constructor for member type applier.
|
* Constructor for member type applier.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractMemberMsType} to process.
|
|
||||||
*/
|
*/
|
||||||
public MemberTypeApplier(DefaultPdbApplicator applicator, AbstractMemberMsType msType) {
|
public MemberTypeApplier(DefaultPdbApplicator applicator) {
|
||||||
super(applicator, msType);
|
super(applicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
BigInteger getSize() {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
return BigInteger.ZERO;
|
throws PdbException, CancelledException {
|
||||||
}
|
// do nothing
|
||||||
|
|
||||||
@Override
|
|
||||||
void apply() throws PdbException, CancelledException {
|
|
||||||
dataType = applyMemberMsType((AbstractMemberMsType) msType);
|
|
||||||
// DataType dataType = applyMemberMsType((AbstractMemberMsType) msType);
|
|
||||||
// ghDataType = dataType; // temporary while below is commented-out
|
|
||||||
// TODO: uncomment when above method not returning null
|
|
||||||
// ghDataTypeDB = applicator.resolve(dataType);
|
|
||||||
}
|
|
||||||
|
|
||||||
String getName() {
|
|
||||||
return ((AbstractMemberMsType) msType).getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
BigInteger getOffset() {
|
|
||||||
return ((AbstractMemberMsType) msType).getOffset();
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassFieldMsAttributes getAttribute() {
|
|
||||||
return ((AbstractMemberMsType) msType).getAttribute();
|
|
||||||
}
|
|
||||||
|
|
||||||
MsTypeApplier getFieldTypeApplier() {
|
|
||||||
return applicator.getTypeApplier(
|
|
||||||
((AbstractMemberMsType) msType).getFieldTypeRecordNumber());
|
|
||||||
}
|
|
||||||
|
|
||||||
private DataType applyMemberMsType(AbstractMemberMsType type) {
|
|
||||||
|
|
||||||
// String memberName = type.getName();
|
|
||||||
// BigInteger memberOffset = type.getOffset();
|
|
||||||
// ClassFieldMsAttributes memberAttributes = type.getAttribute();
|
|
||||||
// int fieldTypeIndex = type.getFieldTypeRecordIndex();
|
|
||||||
//
|
|
||||||
// AbstractMsTypeApplier fieldTypeApplier = applicator.getTypeApplier(fieldTypeIndex);
|
|
||||||
//
|
|
||||||
// DataType fieldDataType = fieldTypeApplier.getDataType();
|
|
||||||
//
|
|
||||||
//// DataType fieldDataType = getConvertedDataType(applicator, fieldTypeIndex);
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractModifierMsType;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractModifierMsType;
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
|
@ -27,84 +27,59 @@ import ghidra.util.exception.CancelledException;
|
||||||
*/
|
*/
|
||||||
public class ModifierTypeApplier extends MsTypeApplier {
|
public class ModifierTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
private MsTypeApplier modifiedTypeApplier = null;
|
// Intended for: AbstractModifierMsType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for modifier type applier.
|
* Constructor for modifier type applier.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractModifierMsType} to processes.
|
|
||||||
*/
|
*/
|
||||||
public ModifierTypeApplier(DefaultPdbApplicator applicator, AbstractModifierMsType msType) {
|
public ModifierTypeApplier(DefaultPdbApplicator applicator) {
|
||||||
super(applicator, msType);
|
super(applicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
RecordNumber getUnderlyingNonModifierRecordNumber(RecordNumber underlyingRecord) {
|
||||||
@Override
|
return getUnderlyingNonModifierRecordNumber(applicator, underlyingRecord);
|
||||||
void deferredApply() throws PdbException, CancelledException {
|
|
||||||
// Do nothing. Already applied. Just needs late resolve
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
static RecordNumber getUnderlyingNonModifierRecordNumber(DefaultPdbApplicator applicator,
|
||||||
@Override
|
RecordNumber underlyingRecord) {
|
||||||
BigInteger getSize() {
|
AbstractMsType underlyingType = applicator.getPdb().getTypeRecord(underlyingRecord);
|
||||||
if (modifiedTypeApplier == null) {
|
while (underlyingType instanceof AbstractModifierMsType modifierType) {
|
||||||
return BigInteger.ZERO;
|
RecordNumber modifiedRecord = modifierType.getModifiedRecordNumber();
|
||||||
|
underlyingType = applicator.getPdb().getTypeRecord(modifiedRecord);
|
||||||
}
|
}
|
||||||
return modifiedTypeApplier.getSize();
|
return underlyingType.getRecordNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void apply() throws PdbException, CancelledException {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
// dataType = applyModifierMsType((AbstractModifierMsType) msType);
|
throws PdbException, CancelledException {
|
||||||
applyOrDeferForDependencies();
|
AbstractModifierMsType modifierType = (AbstractModifierMsType) type;
|
||||||
}
|
RecordNumber modifiedRecord = modifierType.getModifiedRecordNumber();
|
||||||
|
|
||||||
private void applyOrDeferForDependencies() {
|
DataType modifiedType =
|
||||||
AbstractModifierMsType type = (AbstractModifierMsType) msType;
|
applicator.getProcessedDataType(modifiedRecord, fixupContext, false);
|
||||||
applyModifierMsType(type);
|
|
||||||
MsTypeApplier modifiedApplier = applicator.getTypeApplier(type.getModifiedRecordNumber());
|
|
||||||
if (modifiedApplier.isDeferred()) {
|
|
||||||
applicator.addApplierDependency(this, modifiedApplier);
|
|
||||||
setDeferred();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// applyModifierMsType(type);
|
|
||||||
// defer(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// If Ghidra eventually has a modified type (const, volatile) in its model, then we can
|
||||||
DataType getDataType() {
|
// perform the applicator.getDataType(modifierType) here, and the
|
||||||
return modifiedTypeApplier.getDataType();
|
// applicator.put(modifierType,dataType) before the return.
|
||||||
|
// Obviously, we would also need to process and apply the modifier attributes.
|
||||||
|
|
||||||
|
// If ghidra has modified types in the future, we will likely not perform a pass-through
|
||||||
|
// of the underlying type. We might actually need to do a fixup or be able to pass the
|
||||||
|
// cycle-break information to a pointer or handle cycle-break information information
|
||||||
|
// in this modifier type. Lots of things to consider. Would we want to create a typedef
|
||||||
|
// for modifier type as a short-gap solution??? Not sure.
|
||||||
|
|
||||||
|
// Note:
|
||||||
|
// Pointers normally have their own modifiers, so would not necessarily expect to see
|
||||||
|
// the underlying type of a Modifier to be a pointer. However, MSFT primitives include
|
||||||
|
// pointers to primitives, so in these cases we could see a const pointer to primitive
|
||||||
|
// where the const comes from the Modifier type.
|
||||||
|
|
||||||
|
// if (modifiedType != null && !applicator.isPlaceholderType(modifiedType)) {
|
||||||
|
if (modifiedType != null) {
|
||||||
|
applicator.putDataType(modifierType, modifiedType);
|
||||||
}
|
}
|
||||||
|
return modifiedType;
|
||||||
private DataType applyModifierMsType(AbstractModifierMsType type) {
|
|
||||||
modifiedTypeApplier = applicator.getTypeApplier(type.getModifiedRecordNumber());
|
|
||||||
|
|
||||||
return modifiedTypeApplier.getDataType();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ghDataTypeDB = applicator.resolve(dataType);
|
|
||||||
|
|
||||||
// boolean underlyingIsCycleBreakable() {
|
|
||||||
// // TODO: need to deal with InterfaceTypeApplier (will it be incorporated into
|
|
||||||
// // CompostieTypeapplier?) Is it in this list of places to break (i.e., can it contain)?
|
|
||||||
// return (modifiedTypeApplier != null &&
|
|
||||||
// (modifiedTypeApplier instanceof CompositeTypeApplier ||
|
|
||||||
// modifiedTypeApplier instanceof EnumTypeApplier));
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
DataType getCycleBreakType() {
|
|
||||||
// hope to eliminate the null check if/when modifierTypeApplier is created at time of
|
|
||||||
// construction
|
|
||||||
if (modifiedTypeApplier == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return modifiedTypeApplier.getCycleBreakType();
|
|
||||||
}
|
|
||||||
|
|
||||||
MsTypeApplier getModifiedTypeApplier() {
|
|
||||||
return modifiedTypeApplier;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,57 +15,34 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import java.util.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog;
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class representing the applier for a specific {@link AbstractMsType}. The
|
* Abstract class representing the applier for a specific PDB_ID type. The
|
||||||
* {@link #apply()} method creates an associated {@link DataType}, if applicable.
|
* {@link #apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)} method
|
||||||
|
* creates an associated {@link DataType}, if applicable, The latter of these forces the
|
||||||
|
* creation of the defined type when and forward reference type is not appropriate for the
|
||||||
|
* consumer. Note that this should only be used when sanctioned and not on a whim. Currently,
|
||||||
|
* such situations include when ghidra needs a defined type for the underlying type of an array,
|
||||||
|
* when used as a base class of a class or when needed as a member of another class/composite.
|
||||||
* Methods associated with the {@link MsTypeApplier} or derived class will
|
* Methods associated with the {@link MsTypeApplier} or derived class will
|
||||||
* make fields available to the user, first by trying to get them from the {@link DataType},
|
* make fields available to the user, first by trying to get them from the {@link DataType},
|
||||||
* otherwise getting them from the {@link AbstractMsType}.
|
* otherwise getting them from the {@link AbstractMsType} argument.
|
||||||
*/
|
*/
|
||||||
public abstract class MsTypeApplier {
|
public abstract class MsTypeApplier {
|
||||||
|
|
||||||
protected DefaultPdbApplicator applicator;
|
protected DefaultPdbApplicator applicator;
|
||||||
protected AbstractMsType msType;
|
|
||||||
protected int index;
|
|
||||||
protected DataType dataType;
|
|
||||||
// separate copy for now. Might eventually just replace dataType (above)--would have to
|
|
||||||
// change getDataType().
|
|
||||||
protected DataType resolvedDataType;
|
|
||||||
protected boolean resolved = false;
|
|
||||||
protected boolean applied = false;
|
|
||||||
|
|
||||||
private boolean isDeferred = false;
|
|
||||||
|
|
||||||
protected Set<MsTypeApplier> waitSet = new HashSet<>();
|
|
||||||
|
|
||||||
public int getIndex() {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractMsType} to apply.
|
|
||||||
*/
|
*/
|
||||||
public MsTypeApplier(DefaultPdbApplicator applicator, AbstractMsType msType) {
|
public MsTypeApplier(DefaultPdbApplicator applicator) {
|
||||||
this.applicator = applicator;
|
this.applicator = applicator;
|
||||||
this.msType = msType;
|
|
||||||
RecordNumber recordNumber = msType.getRecordNumber();
|
|
||||||
if (recordNumber != null) {
|
|
||||||
index = recordNumber.getNumber();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
index = -1;
|
|
||||||
}
|
|
||||||
dataType = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,181 +54,54 @@ public abstract class MsTypeApplier {
|
||||||
applicator.pdbLogAndInfoMessage(originator, message);
|
applicator.pdbLogAndInfoMessage(originator, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns {@code true} if the type has been applied
|
|
||||||
* @return {@code true} if applied.
|
|
||||||
*/
|
|
||||||
boolean isApplied() {
|
|
||||||
return applied;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the {@code applied} flag to {@code true}
|
|
||||||
*/
|
|
||||||
void setApplied() {
|
|
||||||
applied = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the isDeferred flag to indicate that the application of the information should be
|
|
||||||
* done when the {@link @deferredApply()} method is called
|
|
||||||
*/
|
|
||||||
void setDeferred() {
|
|
||||||
isDeferred = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns {@code true} if the application as been deferred (during the {@link #apply()}
|
|
||||||
* method. The {@link #deferredApply()} method will need to be applied at the appropriate
|
|
||||||
* place in the processing sequence (depending on data dependency ordering) as determined
|
|
||||||
* and driven by the {@link DefaultPdbApplicator}.
|
|
||||||
* @return {@code true} if application was deferred
|
|
||||||
*/
|
|
||||||
boolean isDeferred() {
|
|
||||||
return isDeferred;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs the work required in a deferred application of the data type. This method
|
|
||||||
* is used by the {@link DefaultPdbApplicator} in the correct data dependency sequence.
|
|
||||||
* @throws PdbException on error applying the data type
|
|
||||||
* @throws CancelledException on user cancellation
|
|
||||||
*/
|
|
||||||
void deferredApply() throws PdbException, CancelledException {
|
|
||||||
// default is to do nothing, as most appliers are not deferrable (or should not be).
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the applier for this type that needs to be called when the data type is processed
|
|
||||||
* in dependency order. This will usually return "this," except in cases where there can be
|
|
||||||
* forward references and definition appliers for the same type.
|
|
||||||
* @return the applier to be used for doing the real applier work when dependency order
|
|
||||||
* matters.
|
|
||||||
*/
|
|
||||||
MsTypeApplier getDependencyApplier() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolves the type through the DataTypeManager and makes the resolved type primary.
|
|
||||||
*/
|
|
||||||
void resolve() {
|
|
||||||
if (resolved) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (dataType != null) {
|
|
||||||
resolvedDataType = applicator.resolve(dataType);
|
|
||||||
}
|
|
||||||
resolved = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link AbstractMsType} associated with this applier/wrapper.
|
|
||||||
* @return {@link AbstractMsType} associated with this applier/wrapper.
|
|
||||||
*/
|
|
||||||
AbstractMsType getMsType() {
|
|
||||||
return msType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link DataType} associated with this applier/wrapper.
|
|
||||||
* @return {@link DataType} associated with this applier/wrapper.
|
|
||||||
*/
|
|
||||||
DataType getDataType() {
|
|
||||||
if (resolved) {
|
|
||||||
return resolvedDataType;
|
|
||||||
}
|
|
||||||
return dataType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns either a DataTypeDB or an type (IMPL that might be an empty container) that
|
|
||||||
* suffices to break cyclical dependencies in data type generation.
|
|
||||||
* @return the data type.
|
|
||||||
*/
|
|
||||||
DataType getCycleBreakType() {
|
|
||||||
return getDataType();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply the {@link AbstractMsType} in an attempt to create a Ghidra type.
|
* Apply the {@link AbstractMsType} in an attempt to create a Ghidra type.
|
||||||
|
* @param type the PDB type to work on
|
||||||
|
* @param fixupContext the fixup context to use; or pass in null during fixup process
|
||||||
|
* @param breakCycle TODO
|
||||||
|
* @return the resultant DataType
|
||||||
* @throws PdbException if there was a problem processing the data.
|
* @throws PdbException if there was a problem processing the data.
|
||||||
* @throws CancelledException upon user cancellation
|
* @throws CancelledException upon user cancellation
|
||||||
*/
|
*/
|
||||||
abstract void apply() throws PdbException, CancelledException;
|
abstract DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
|
throws PdbException, CancelledException;
|
||||||
/**
|
|
||||||
* Returns the size of the type or 0 if unknown.
|
|
||||||
* @return the size; zero if unknown.
|
|
||||||
*/
|
|
||||||
abstract BigInteger getSize();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the (long) size of the type or 0 if unknown. Or Long.MAX_VALUE if too large.
|
* Returns the (long) size of the type or 0 if unknown. Or Long.MAX_VALUE if too large.
|
||||||
|
* @param type the PDB type being inspected
|
||||||
* @return the size; zero if unknown.
|
* @return the size; zero if unknown.
|
||||||
*/
|
*/
|
||||||
long getSizeLong() {
|
long getSizeLong(AbstractMsType type) {
|
||||||
return DefaultPdbApplicator.bigIntegerToLong(applicator, getSize());
|
return applicator.bigIntegerToLong(type.getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the (int) size of the type or 0 if unknown. Or Integer.MAX_VALUE if too large.
|
* Returns the (int) size of the type or 0 if unknown. Or Integer.MAX_VALUE if too large.
|
||||||
|
* @param type the PDB type being inspected
|
||||||
* @return the size; zero if unknown.
|
* @return the size; zero if unknown.
|
||||||
*/
|
*/
|
||||||
int getSizeInt() {
|
int getSizeInt(AbstractMsType type) {
|
||||||
return DefaultPdbApplicator.bigIntegerToInt(applicator, getSize());
|
return applicator.bigIntegerToInt(type.getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
//==============================================================================================
|
||||||
public String toString() {
|
// TODO: Need to investigate if we adopt the following... if so, should use them consistently.
|
||||||
return msType.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
result = prime * result + index;
|
|
||||||
result = prime * result + msType.getClass().getSimpleName().hashCode();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (obj == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (getClass() != obj.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
MsTypeApplier other = (MsTypeApplier) obj;
|
|
||||||
if (index != other.index) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!msType.getClass().getSimpleName().equals(other.msType.getClass().getSimpleName())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void waitSetPut(MsTypeApplier applier) {
|
|
||||||
waitSet.add(applier);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean waitSetRemove(MsTypeApplier applier) {
|
|
||||||
return waitSet.remove(applier);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean waitSetIsEmpty() {
|
|
||||||
return waitSet.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected MsTypeApplier waitSetGetNext() {
|
|
||||||
List<MsTypeApplier> list = new ArrayList<>(waitSet);
|
|
||||||
return list.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Convenience method for getting the {@link DataType} from the applicator pertaining
|
||||||
|
// * to this PDB type
|
||||||
|
// * @param type the PDB type
|
||||||
|
// * @return the ghidra data type
|
||||||
|
// */
|
||||||
|
// DataType getDataType(AbstractMsType type) {
|
||||||
|
// return applicator.getDataType(type);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected int getIndex(AbstractMsType type) {
|
||||||
|
// RecordNumber recordNumber = type.getRecordNumber();
|
||||||
|
// if (recordNumber != null) {
|
||||||
|
// return recordNumber.getNumber();
|
||||||
|
// }
|
||||||
|
// return -1;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||||
|
@ -28,136 +26,50 @@ import ghidra.util.exception.CancelledException;
|
||||||
*/
|
*/
|
||||||
public class NestedTypeApplier extends MsTypeApplier {
|
public class NestedTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
private MsTypeApplier nestedTypeDefinitionApplier = null;
|
// Intended for: AbstractNestedTypeMsType or AbstractNestedTypeExtMsType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for nested type applier
|
* Constructor for nested type applier
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working
|
||||||
* @param msType {@link AbstractNestedTypeMsType} or {@link AbstractNestedTypeExtMsType} to
|
|
||||||
* process
|
|
||||||
* @throws IllegalArgumentException upon invalid arguments
|
* @throws IllegalArgumentException upon invalid arguments
|
||||||
*/
|
*/
|
||||||
public NestedTypeApplier(DefaultPdbApplicator applicator, AbstractMsType msType)
|
public NestedTypeApplier(DefaultPdbApplicator applicator)
|
||||||
throws IllegalArgumentException {
|
throws IllegalArgumentException {
|
||||||
super(applicator, validateType(msType));
|
super(applicator);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
BigInteger getSize() {
|
|
||||||
if (nestedTypeDefinitionApplier == null) {
|
|
||||||
return BigInteger.ZERO;
|
|
||||||
}
|
|
||||||
return nestedTypeDefinitionApplier.getSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the name of this nested type
|
|
||||||
* @return name of the nested type
|
|
||||||
*/
|
|
||||||
String getTypeName() {
|
|
||||||
if (nestedTypeDefinitionApplier == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return nestedTypeDefinitionApplier.getMsType().getName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the nested (member?) name for this nested type
|
* Returns the nested (member?) name for this nested type
|
||||||
|
* @param type the PDB type being inspected
|
||||||
* @return (member?) name for the nested type
|
* @return (member?) name for the nested type
|
||||||
*/
|
*/
|
||||||
String getMemberName() {
|
String getMemberName(AbstractMsType type) {
|
||||||
if (nestedTypeDefinitionApplier == null) {
|
|
||||||
|
if (type instanceof AbstractNestedTypeMsType nested) {
|
||||||
|
return nested.getName();
|
||||||
|
}
|
||||||
|
else if (type instanceof AbstractNestedTypeExtMsType nestedExt) {
|
||||||
|
return nestedExt.getName();
|
||||||
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
if (msType instanceof AbstractNestedTypeMsType) {
|
|
||||||
return ((AbstractNestedTypeMsType) msType).getName();
|
|
||||||
}
|
|
||||||
return ((AbstractNestedTypeExtMsType) msType).getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
MsTypeApplier getNestedTypeDefinitionApplier() {
|
|
||||||
return applicator.getTypeApplier(getNestedTypeDefinitionRecordNumber());
|
|
||||||
}
|
|
||||||
|
|
||||||
RecordNumber getNestedTypeDefinitionRecordNumber() {
|
|
||||||
if (msType instanceof AbstractNestedTypeMsType) {
|
|
||||||
return ((AbstractNestedTypeMsType) msType).getNestedTypeDefinitionRecordNumber();
|
|
||||||
}
|
|
||||||
return ((AbstractNestedTypeExtMsType) msType).getNestedTypeDefinitionRecordNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates if there are attributes. Returns false if not "applied" yet
|
|
||||||
* @return {@code true} if there are attributes
|
|
||||||
*/
|
|
||||||
boolean hasAttributes() {
|
|
||||||
if (nestedTypeDefinitionApplier == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (nestedTypeDefinitionApplier.getMsType() instanceof AbstractNestedTypeMsType) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the attributes if they exist
|
|
||||||
* @return the attributes or null if they do not exist
|
|
||||||
*/
|
|
||||||
ClassFieldMsAttributes getAttributes() {
|
|
||||||
AbstractMsType type = nestedTypeDefinitionApplier.getMsType();
|
|
||||||
if (type instanceof AbstractNestedTypeExtMsType) {
|
|
||||||
return ((AbstractNestedTypeExtMsType) type).getClassFieldAttributes();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void apply() throws PdbException, CancelledException {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
if (msType instanceof AbstractNestedTypeMsType) {
|
throws PdbException, CancelledException {
|
||||||
dataType = applyNestedTypeMsType((AbstractNestedTypeMsType) msType);
|
RecordNumber typeRecordNumber;
|
||||||
|
if (type instanceof AbstractNestedTypeMsType nestedType) {
|
||||||
|
typeRecordNumber = nestedType.getNestedTypeDefinitionRecordNumber();
|
||||||
|
}
|
||||||
|
else if (type instanceof AbstractNestedTypeExtMsType extNestedType) {
|
||||||
|
typeRecordNumber = extNestedType.getNestedTypeDefinitionRecordNumber();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dataType = applyNestedTypeExtMsType((AbstractNestedTypeExtMsType) msType);
|
throw new PdbException(
|
||||||
|
"Unexpected nested type in field list: " + type.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
}
|
AbstractMsType mType = applicator.getPdb().getTypeRecord(typeRecordNumber);
|
||||||
|
MsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber);
|
||||||
private DataType applyNestedTypeMsType(AbstractNestedTypeMsType type) {
|
return applier.apply(mType, fixupContext, breakCycle);
|
||||||
nestedTypeDefinitionApplier =
|
|
||||||
applicator.getTypeApplier(type.getNestedTypeDefinitionRecordNumber());
|
|
||||||
return nestedTypeDefinitionApplier.getDataType();
|
|
||||||
}
|
|
||||||
|
|
||||||
private DataType applyNestedTypeExtMsType(AbstractNestedTypeExtMsType type) {
|
|
||||||
nestedTypeDefinitionApplier =
|
|
||||||
applicator.getTypeApplier(type.getNestedTypeDefinitionRecordNumber());
|
|
||||||
return nestedTypeDefinitionApplier.getDataType();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ghDataTypeDB = applicator.resolve(dataType);
|
|
||||||
|
|
||||||
// boolean underlyingIsCycleBreakable() {
|
|
||||||
// // TODO: need to deal with InterfaceTypeApplier (will it be incorporated into
|
|
||||||
// // CompostieTypeapplier?) Is it in this list of places to break (i.e., can it contain)?
|
|
||||||
// return (modifiedTypeApplier != null &&
|
|
||||||
// (modifiedTypeApplier instanceof CompositeTypeApplier ||
|
|
||||||
// modifiedTypeApplier instanceof EnumTypeApplier));
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
DataType getCycleBreakType() {
|
|
||||||
// hope to eliminate the null check if/when modifierTypeApplier is created at time of
|
|
||||||
// construction
|
|
||||||
//TODO: look into this
|
|
||||||
return dataType;
|
|
||||||
// if (modifiedTypeApplier == null) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// return modifiedTypeApplier.getCycleBreakType(applicator);
|
|
||||||
}
|
|
||||||
|
|
||||||
MsTypeApplier getNestedTypeApplier() {
|
|
||||||
return nestedTypeDefinitionApplier;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AbstractMsType validateType(AbstractMsType type)
|
private static AbstractMsType validateType(AbstractMsType type)
|
||||||
|
@ -169,5 +81,4 @@ public class NestedTypeApplier extends MsTypeApplier {
|
||||||
}
|
}
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for creating a wrapper for when there is not associated type to the PDB type (or if we
|
* Used for creating a wrapper for when there is not associated type to the PDB type (or if we
|
||||||
|
@ -25,26 +26,21 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||||
*/
|
*/
|
||||||
public class NoTypeApplier extends MsTypeApplier {
|
public class NoTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
|
// Intended for: AbstractMsType
|
||||||
/**
|
/**
|
||||||
* Constructor for nested type applier.
|
* Constructor for nested type applier.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractMsType} to process.
|
|
||||||
* @throws IllegalArgumentException Upon invalid arguments.
|
* @throws IllegalArgumentException Upon invalid arguments.
|
||||||
*/
|
*/
|
||||||
public NoTypeApplier(DefaultPdbApplicator applicator, AbstractMsType msType)
|
public NoTypeApplier(DefaultPdbApplicator applicator)
|
||||||
throws IllegalArgumentException {
|
throws IllegalArgumentException {
|
||||||
super(applicator, msType);
|
super(applicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
BigInteger getSize() {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
return BigInteger.ZERO;
|
throws PdbException, CancelledException {
|
||||||
|
// do nothing
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
void apply() {
|
|
||||||
// Do nothing (maybe should log something... not sure)
|
|
||||||
// applicator.getLog().appendMsg("");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import java.util.Set;
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||||
import ghidra.program.model.data.DataTypeManager;
|
import ghidra.program.model.data.DataTypeManager;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
@ -167,36 +167,43 @@ public class PdbApplicatorMetrics {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to capture unusual this pointer types.
|
* Method to capture unusual this pointer types.
|
||||||
* @param applier The {@AbstractMsTypeApplier} for the supposed this pointer.
|
* @param type the {@AbstractMsType} for the supposed this pointer
|
||||||
*/
|
*/
|
||||||
void witnessMemberFunctionThisPointer(MsTypeApplier applier) {
|
void witnessMemberFunctionThisPointer(AbstractMsType type) {
|
||||||
// We know that we have seen PrimitiveMsTypes that are pointer types.
|
// We know that we have seen PrimitiveMsTypes that are pointer types.
|
||||||
if (applier instanceof PointerTypeApplier) {
|
if (type == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unexpectedMemberFunctionThisPointerTypes.add(applier.getMsType().getClass());
|
if (type instanceof AbstractPointerMsType ptrType) {
|
||||||
|
witnessMemberFunctionThisPointerUnderlyingType(ptrType.getUnderlyingType());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unexpectedMemberFunctionThisPointerTypes.add(type.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to capture unusual underlying types for a normal pointer for this pointer.
|
* Method to capture unusual underlying types for a normal pointer for this pointer.
|
||||||
* @param applier The {@AbstractMsTypeApplier} for the supposed this pointer.
|
* @param type the {@AbstractMsType} for the supposed this pointer
|
||||||
*/
|
*/
|
||||||
void witnessMemberFunctionThisPointerUnderlyingType(MsTypeApplier applier) {
|
void witnessMemberFunctionThisPointerUnderlyingType(AbstractMsType type) {
|
||||||
if (applier instanceof CompositeTypeApplier) {
|
if (type == null || type instanceof AbstractCompositeMsType) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unexpectedMemberFunctionThisPointerUnderlyingTypes.add(applier.getMsType().getClass());
|
if (type instanceof AbstractModifierMsType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unexpectedMemberFunctionThisPointerUnderlyingTypes.add(type.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to capture unusual containing types for a member function.
|
* Method to capture unusual containing types for a member function
|
||||||
* @param applier The {@AbstractMsTypeApplier} for the supposed this pointer.
|
* @param type the {@AbstractMsType} for the supposed this container
|
||||||
*/
|
*/
|
||||||
void witnessMemberFunctionContainingType(MsTypeApplier applier) {
|
void witnessMemberFunctionContainingType(AbstractMsType type) {
|
||||||
if (applier instanceof CompositeTypeApplier) {
|
if (type == null || type instanceof AbstractCompositeMsType) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unexpectedMemberFunctionContainerTypes.add(applier.getMsType().getClass());
|
unexpectedMemberFunctionContainerTypes.add(type.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
|
|
@ -326,29 +326,6 @@ public class PdbResearch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Developmental method for breakpoints. TODO: will delete this from production.
|
|
||||||
* @param recordNumber the record number tha is being processed (set negative to ignore)
|
|
||||||
* @param applier the applier that might have additional, such as the name of the type of
|
|
||||||
* interest
|
|
||||||
*/
|
|
||||||
static void checkBreak(int recordNumber, MsTypeApplier applier) {
|
|
||||||
|
|
||||||
String nn = applier.getMsType().getName();
|
|
||||||
if ("std::__1::__map_value_compare<std::__1::basic_string<char>,std::__1::__value_type<std::__1::basic_string<char>,std::__1::basic_string<wchar_t> >,std::__1::less<void>,1>"
|
|
||||||
.equals(nn)) {
|
|
||||||
doNothingSetBreakPointHere();
|
|
||||||
}
|
|
||||||
if ("class std::__1::__iostream_category".equals(nn)) {
|
|
||||||
doNothingSetBreakPointHere();
|
|
||||||
}
|
|
||||||
if ("std::__1::__do_message".equals(nn)) {
|
|
||||||
doNothingSetBreakPointHere();
|
|
||||||
}
|
|
||||||
|
|
||||||
//checkBreak(recordNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
static private void initDeveloperOrderRecordNumbers() {
|
static private void initDeveloperOrderRecordNumbers() {
|
||||||
|
@ -401,9 +378,10 @@ public class PdbResearch {
|
||||||
for (int indexNumber : developerDebugOrderIndexNumbers) {
|
for (int indexNumber : developerDebugOrderIndexNumbers) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
PdbResearch.checkBreak(indexNumber);
|
PdbResearch.checkBreak(indexNumber);
|
||||||
MsTypeApplier applier =
|
FixupContext fixupContext = new FixupContext();
|
||||||
applicator.getTypeApplier(RecordNumber.typeRecordNumber(indexNumber));
|
fixupContext.addStagedRecord(indexNumber);
|
||||||
applier.apply();
|
applicator.getProcessedDataType(RecordNumber.typeRecordNumber(indexNumber),
|
||||||
|
fixupContext, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -448,10 +426,10 @@ public class PdbResearch {
|
||||||
MsSymbolApplier applier = applicator.getSymbolApplier(iter);
|
MsSymbolApplier applier = applicator.getSymbolApplier(iter);
|
||||||
if (applier instanceof TypedefSymbolApplier) {
|
if (applier instanceof TypedefSymbolApplier) {
|
||||||
TypedefSymbolApplier typedefApplier = (TypedefSymbolApplier) applier;
|
TypedefSymbolApplier typedefApplier = (TypedefSymbolApplier) applier;
|
||||||
MsTypeApplier typeApplier =
|
RecordNumber typeNumber = typedefApplier.getTypeRecordNumber();
|
||||||
applicator.getTypeApplier(typedefApplier.getTypeRecordNumber());
|
AbstractMsType type = applicator.getPdb().getTypeRecord(typeNumber);
|
||||||
System.out.println("UDT " + typedefApplier.getName() + " depends on " +
|
System.out
|
||||||
typeApplier.getMsType().toString());
|
.println("UDT " + typedefApplier.getName() + " depends on " + type.toString());
|
||||||
// applier.apply();
|
// applier.apply();
|
||||||
// procSym(symbolGroup);
|
// procSym(symbolGroup);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import ghidra.app.util.SymbolPath;
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||||
|
@ -28,124 +27,143 @@ import ghidra.util.exception.CancelledException;
|
||||||
*/
|
*/
|
||||||
public class PointerTypeApplier extends MsTypeApplier {
|
public class PointerTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
private String memberComment = null;
|
// Intended for: AbstractPointerMsType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for pointer type applier, for transforming a enum into a
|
* Constructor for pointer type applier, for transforming a enum into a
|
||||||
* Ghidra DataType.
|
* Ghidra DataType.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractPointerMsType} to process
|
|
||||||
* @throws IllegalArgumentException Upon invalid arguments.
|
* @throws IllegalArgumentException Upon invalid arguments.
|
||||||
*/
|
*/
|
||||||
public PointerTypeApplier(DefaultPdbApplicator applicator, AbstractPointerMsType msType)
|
public PointerTypeApplier(DefaultPdbApplicator applicator)
|
||||||
throws IllegalArgumentException {
|
throws IllegalArgumentException {
|
||||||
super(applicator, msType);
|
super(applicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comment field if this type is used as a structure member. This method could go away later
|
* Comment field if this type is used as a structure member. This method could go away later
|
||||||
* if we develop member pointers into the Ghidra framework; this method exists to pass some
|
* if we develop member pointers into the Ghidra framework; this method exists to pass some
|
||||||
* pertinent information along to the user
|
* pertinent information along to the user
|
||||||
|
* @param type the PDB type being inspected
|
||||||
|
* @param fixupContext the fixup context to use; or pass in null during fixup process
|
||||||
* @return comment string or null
|
* @return comment string or null
|
||||||
|
* @throws CancelledException upon user cancellation
|
||||||
|
* @throws PdbException upon processing error
|
||||||
*/
|
*/
|
||||||
String getPointerCommentField() {
|
String getPointerCommentField(AbstractPointerMsType type, FixupContext fixupContext)
|
||||||
return memberComment;
|
throws CancelledException, PdbException {
|
||||||
|
AbstractPointerMsType.PointerMode pointerMode = type.getPointerMode();
|
||||||
|
if (pointerMode == AbstractPointerMsType.PointerMode.MEMBER_FUNCTION_POINTER) {
|
||||||
|
// We are no longer able to get underlying type in time due to cycle breaks unless
|
||||||
|
// we start doing fixups on pmf/pdm pointers.
|
||||||
|
// TODO: consider fixups on these later... maybe after we understand contents of
|
||||||
|
// pmf/pdm and evaluate whether there is another way of passing this information to
|
||||||
|
// the user.
|
||||||
|
//DataType underlyingType = getUnderlyingType(type, fixupContext);
|
||||||
|
//return "\"::*\" (pmf) to type: " + underlyingType;
|
||||||
|
return "\"::*\" (pmf)";
|
||||||
|
}
|
||||||
|
else if (pointerMode == AbstractPointerMsType.PointerMode.MEMBER_DATA_POINTER) {
|
||||||
|
// We are no longer able to get underlying type in time due to cycle breaks unless
|
||||||
|
// we start doing fixups on pmf/pdm pointers.
|
||||||
|
// TODO: consider fixups on these later... maybe after we understand contents of
|
||||||
|
// pmf/pdm and evaluate whether there is another way of passing this information to
|
||||||
|
// the user.
|
||||||
|
//DataType underlyingType = getUnderlyingType(type, fixupContext);
|
||||||
|
//return "\"::*\" (pdm) to type: " + underlyingType;
|
||||||
|
return "\"::*\" (pdm)";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
BigInteger getSize() {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
return ((AbstractPointerMsType) msType).getSize();
|
throws PdbException, CancelledException {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
DataType dataType;
|
||||||
void apply() throws PdbException, CancelledException {
|
if (fixupContext != null) {
|
||||||
if (msType instanceof DummyMsType) {
|
// The next line will only return null until we start putting in a DB version of the
|
||||||
|
// pointer, below. Need to work that out. TODO: take care of this
|
||||||
|
dataType = applicator.getDataType(type);
|
||||||
|
if (dataType != null) {
|
||||||
|
return dataType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type instanceof DummyMsType) {
|
||||||
dataType = new PointerDataType(applicator.getDataTypeManager());
|
dataType = new PointerDataType(applicator.getDataTypeManager());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dataType = applyAbstractPointerMsType((AbstractPointerMsType) msType);
|
dataType = applyAbstractPointerMsType((AbstractPointerMsType) type, fixupContext);
|
||||||
}
|
}
|
||||||
|
dataType = applicator.resolve(dataType);
|
||||||
|
applicator.putDataType(type, dataType);
|
||||||
|
return dataType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private DataType getUnderlyingType(AbstractPointerMsType type, FixupContext fixupContext)
|
||||||
void resolve() {
|
throws CancelledException, PdbException {
|
||||||
// Do not resolve pointer types... will be resolved naturally, as needed
|
RecordNumber underlyingRecord = type.getUnderlyingRecordNumber();
|
||||||
|
return applicator.getProcessedDataType(underlyingRecord, fixupContext, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
MsTypeApplier getUnmodifiedUnderlyingTypeApplier() {
|
private DataType applyAbstractPointerMsType(AbstractPointerMsType type,
|
||||||
MsTypeApplier thisUnderlyingTypeApplier =
|
FixupContext fixupContext) throws CancelledException, PdbException {
|
||||||
applicator.getTypeApplier(((AbstractPointerMsType) msType).getUnderlyingRecordNumber());
|
|
||||||
|
|
||||||
// TODO: does not recurse below one level of modifiers... consider doing a recursion.
|
|
||||||
if (thisUnderlyingTypeApplier instanceof ModifierTypeApplier) {
|
|
||||||
ModifierTypeApplier x = (ModifierTypeApplier) thisUnderlyingTypeApplier;
|
|
||||||
RecordNumber recNum =
|
|
||||||
((AbstractModifierMsType) (x.getMsType())).getModifiedRecordNumber();
|
|
||||||
thisUnderlyingTypeApplier = applicator.getTypeApplier(recNum);
|
|
||||||
}
|
|
||||||
return thisUnderlyingTypeApplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DataType getUnderlyingType(AbstractPointerMsType type) {
|
|
||||||
MsTypeApplier underlyingApplier =
|
|
||||||
applicator.getTypeApplier(type.getUnderlyingRecordNumber());
|
|
||||||
DataType underlyingType = underlyingApplier.getCycleBreakType();
|
|
||||||
return underlyingType;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DataType applyAbstractPointerMsType(AbstractPointerMsType type) {
|
|
||||||
|
|
||||||
AbstractPointerMsType.PointerMode pointerMode = type.getPointerMode();
|
AbstractPointerMsType.PointerMode pointerMode = type.getPointerMode();
|
||||||
if (pointerMode == AbstractPointerMsType.PointerMode.MEMBER_DATA_POINTER ||
|
if (pointerMode == AbstractPointerMsType.PointerMode.MEMBER_DATA_POINTER ||
|
||||||
pointerMode == AbstractPointerMsType.PointerMode.MEMBER_FUNCTION_POINTER) {
|
pointerMode == AbstractPointerMsType.PointerMode.MEMBER_FUNCTION_POINTER) {
|
||||||
return processMemberPointer(type);
|
return processMemberPointer(type, fixupContext);
|
||||||
}
|
}
|
||||||
return processPointer(type);
|
return processPointer(type, fixupContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataType processMemberPointer(AbstractPointerMsType type) {
|
private DataType processMemberPointer(AbstractPointerMsType type, FixupContext fixupContext)
|
||||||
DataType underlyingType = getUnderlyingType(type);
|
throws CancelledException, PdbException {
|
||||||
|
|
||||||
|
// future use
|
||||||
|
DataType underlyingType = getUnderlyingType(type, fixupContext);
|
||||||
int size = type.getSize().intValueExact();
|
int size = type.getSize().intValueExact();
|
||||||
RecordNumber memberPointerContainingClassRecordNumber =
|
|
||||||
type.getMemberPointerContainingClassRecordNumber();
|
|
||||||
MsTypeApplier containingClassApplier =
|
|
||||||
applicator.getTypeApplier(memberPointerContainingClassRecordNumber);
|
|
||||||
|
|
||||||
DataType dt = null;
|
|
||||||
String name;
|
String name;
|
||||||
AbstractPointerMsType.PointerMode pointerMode = type.getPointerMode();
|
AbstractPointerMsType.PointerMode pointerMode = type.getPointerMode();
|
||||||
if (pointerMode == AbstractPointerMsType.PointerMode.MEMBER_FUNCTION_POINTER) {
|
if (pointerMode == AbstractPointerMsType.PointerMode.MEMBER_FUNCTION_POINTER) {
|
||||||
name = String.format("pmf_%08x", type.toString().hashCode());
|
name = String.format("pmf_%08x", type.toString().hashCode());
|
||||||
memberComment = "\"::*\" (pmf) to type: " + underlyingType;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
name = String.format("pdm_%08x", type.toString().hashCode());
|
name = String.format("pdm_%08x", type.toString().hashCode());
|
||||||
memberComment = "\"::*\" (pdm) to type: " + underlyingType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (containingClassApplier instanceof CompositeTypeApplier cta) {
|
RecordNumber containingClassRecordNumber =
|
||||||
DataTypePath dtp = ClassTypeUtils.getInternalsDataTypePath(cta, name);
|
type.getMemberPointerContainingClassRecordNumber();
|
||||||
if (dtp != null) {
|
CategoryPath storagePath = getCategoryPathForMemberPointer(containingClassRecordNumber);
|
||||||
dt = applicator.getDataTypeManager().getDataType(dtp);
|
DataType dt = new StructureDataType(storagePath, name, size);
|
||||||
if (dt == null) {
|
|
||||||
dt = new StructureDataType(dtp.getCategoryPath(), dtp.getDataTypeName(), size);
|
|
||||||
dt.setDescription(type.toString());
|
dt.setDescription(type.toString());
|
||||||
}
|
|
||||||
}
|
return applicator.resolve(dt);
|
||||||
}
|
|
||||||
if (dt == null) {
|
|
||||||
dt = Undefined.getUndefinedDataType(size);
|
|
||||||
}
|
|
||||||
return dt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataType processPointer(AbstractPointerMsType type) {
|
private CategoryPath getCategoryPathForMemberPointer(RecordNumber containingClassRecordNumber) {
|
||||||
memberComment = null;
|
AbstractMsType containingType =
|
||||||
DataType underlyingType = getUnderlyingType(type);
|
applicator.getPdb().getTypeRecord(containingClassRecordNumber);
|
||||||
|
MsTypeApplier applier = applicator.getTypeApplier(containingClassRecordNumber);
|
||||||
|
if (containingType instanceof AbstractCompositeMsType compositeMsType &&
|
||||||
|
applier instanceof CompositeTypeApplier compositeApplier) {
|
||||||
|
SymbolPath symbolPath = compositeApplier.getFixedSymbolPath(compositeMsType);
|
||||||
|
CategoryPath categoryPath = applicator.getCategory(symbolPath);
|
||||||
|
return ClassTypeUtils.getInternalsCategoryPath(categoryPath);
|
||||||
|
}
|
||||||
|
return applicator.getAnonymousTypesCategory();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataType processPointer(AbstractPointerMsType type, FixupContext fixupContext)
|
||||||
|
throws CancelledException, PdbException {
|
||||||
|
DataType underlyingType = getUnderlyingType(type, fixupContext);
|
||||||
int size = type.getSize().intValueExact();
|
int size = type.getSize().intValueExact();
|
||||||
if (size == applicator.getDataOrganization().getPointerSize()) {
|
if (size == applicator.getDataOrganization().getPointerSize()) {
|
||||||
size = -1; // Use default
|
size = -1; // Use default
|
||||||
}
|
}
|
||||||
|
if (underlyingType == null || applicator.isPlaceholderType(underlyingType)) {
|
||||||
|
return applicator.getPlaceholderPointer(size);
|
||||||
|
}
|
||||||
return new PointerDataType(underlyingType, size, applicator.getDataTypeManager());
|
return new PointerDataType(underlyingType, size, applicator.getDataTypeManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,39 +15,35 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.PrimitiveMsType;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.PrimitiveMsType;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applier for {@link PrimitiveMsType} types.
|
* Applier for {@link PrimitiveMsType} types.
|
||||||
*/
|
*/
|
||||||
public class PrimitiveTypeApplier extends MsTypeApplier {
|
public class PrimitiveTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
|
// Intended for: PrimitiveMsType
|
||||||
/**
|
/**
|
||||||
* Constructor for primitive type applier, for transforming a primitive into a
|
* Constructor for primitive type applier, for transforming a primitive into a
|
||||||
* Ghidra DataType.
|
* Ghidra DataType.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link PrimitiveMsType} to process.
|
|
||||||
*/
|
*/
|
||||||
public PrimitiveTypeApplier(DefaultPdbApplicator applicator, PrimitiveMsType msType) {
|
public PrimitiveTypeApplier(DefaultPdbApplicator applicator) {
|
||||||
super(applicator, msType);
|
super(applicator);
|
||||||
apply(); // Only apply in constructor for primitives
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
BigInteger getSize() {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
return BigInteger.valueOf(((PrimitiveMsType) msType).getTypeSize());
|
throws PdbException, CancelledException {
|
||||||
|
return applyPrimitiveMsType((PrimitiveMsType) type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
boolean isNoType(AbstractMsType type) {
|
||||||
void apply() {
|
return (((PrimitiveMsType) type).getNumber() == 0);
|
||||||
dataType = applyPrimitiveMsType((PrimitiveMsType) msType);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isNoType() {
|
|
||||||
return (((PrimitiveMsType) msType).getNumber() == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataType applyPrimitiveMsType(PrimitiveMsType type) {
|
private DataType applyPrimitiveMsType(PrimitiveMsType type) {
|
||||||
|
@ -62,9 +58,15 @@ public class PrimitiveTypeApplier extends MsTypeApplier {
|
||||||
// return dataType.clone(applicatorDataTypeManager);
|
// return dataType.clone(applicatorDataTypeManager);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
int indexNumber = type.getNumber();
|
||||||
|
DataType existingDt = applicator.getDataType(indexNumber);
|
||||||
|
if (existingDt != null) {
|
||||||
|
return existingDt;
|
||||||
|
}
|
||||||
|
|
||||||
PdbPrimitiveTypeApplicator primitiveApplicator = applicator.getPdbPrimitiveTypeApplicator();
|
PdbPrimitiveTypeApplicator primitiveApplicator = applicator.getPdbPrimitiveTypeApplicator();
|
||||||
|
|
||||||
switch (type.getNumber()) {
|
switch (indexNumber) {
|
||||||
//=======================================
|
//=======================================
|
||||||
// Special types
|
// Special types
|
||||||
//=======================================
|
//=======================================
|
||||||
|
@ -2060,6 +2062,9 @@ public class PrimitiveTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
primitiveDataType = applicator.resolve(primitiveDataType);
|
||||||
|
applicator.putDataType(indexNumber, primitiveDataType);
|
||||||
|
|
||||||
return primitiveDataType;
|
return primitiveDataType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,13 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractProcedureMsType;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.CallingConvention;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.DataType;
|
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,53 +26,47 @@ import ghidra.util.exception.CancelledException;
|
||||||
*/
|
*/
|
||||||
public class ProcedureTypeApplier extends AbstractFunctionTypeApplier {
|
public class ProcedureTypeApplier extends AbstractFunctionTypeApplier {
|
||||||
|
|
||||||
|
// Intended for: AbstractProcedureMsType
|
||||||
/**
|
/**
|
||||||
* Constructor for the applicator that applies {@link AbstractProcedureMsType},
|
* Constructor for the applicator that applies {@link AbstractProcedureMsType},
|
||||||
* transforming it into a Ghidra {@link DataType}.
|
* transforming it into a Ghidra {@link DataType}.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractProcedureMsType} to processes.
|
|
||||||
* @throws IllegalArgumentException Upon invalid arguments.
|
* @throws IllegalArgumentException Upon invalid arguments.
|
||||||
*/
|
*/
|
||||||
public ProcedureTypeApplier(DefaultPdbApplicator applicator, AbstractProcedureMsType msType)
|
public ProcedureTypeApplier(DefaultPdbApplicator applicator) throws IllegalArgumentException {
|
||||||
throws IllegalArgumentException {
|
super(applicator);
|
||||||
super(applicator, msType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
BigInteger getSize() {
|
protected CallingConvention getCallingConvention(AbstractMsType type) {
|
||||||
return BigInteger.ZERO;
|
return ((AbstractProcedureMsType) type).getCallingConvention();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected CallingConvention getCallingConvention() {
|
protected Pointer getThisPointer(AbstractMsType type, FixupContext fixupContext,
|
||||||
return ((AbstractProcedureMsType) msType).getCallingConvention();
|
boolean breakCycle) throws CancelledException, PdbException {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean hasThisPointer() {
|
protected Composite getContainingComplexApplier(AbstractMsType type, FixupContext fixupContext,
|
||||||
return false;
|
boolean breakCycle) throws CancelledException, PdbException {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected RecordNumber getReturnRecordNumber() {
|
protected void processContainingType(AbstractMsType type) {
|
||||||
return ((AbstractProcedureMsType) msType).getReturnRecordNumber();
|
return; // do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected RecordNumber getArgListRecordNumber() {
|
protected RecordNumber getReturnRecordNumber(AbstractMsType type) {
|
||||||
return ((AbstractProcedureMsType) msType).getArgListRecordNumber();
|
return ((AbstractProcedureMsType) type).getReturnRecordNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void apply() throws PdbException, CancelledException {
|
protected RecordNumber getArgListRecordNumber(AbstractMsType type) {
|
||||||
applyFunction(getCallingConvention(), hasThisPointer());
|
return ((AbstractProcedureMsType) type).getArgListRecordNumber();
|
||||||
|
|
||||||
// AbstractProcedureMsType procType = (AbstractProcedureMsType) msType;
|
|
||||||
// applyFunction(procType.getCallingConvention(), false, procType.getReturnTypeIndex(),
|
|
||||||
// procType.getArgListTypeIndex());
|
|
||||||
// DataType definition = applyFunction(procType.getCallingConvention(), false,
|
|
||||||
// procType.getReturnTypeIndex(), procType.getArgListTypeIndex());
|
|
||||||
// ghDataTypeDB = applicator.resolve(definition);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.util.Objects;
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractRegisterRelativeAddressMsSymbol;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractRegisterRelativeAddressMsSymbol;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
|
@ -67,7 +68,8 @@ public class RegisterRelativeSymbolApplier extends MsSymbolApplier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean createFunctionVariable(FunctionSymbolApplier applier) {
|
private boolean createFunctionVariable(FunctionSymbolApplier applier)
|
||||||
|
throws CancelledException, PdbException {
|
||||||
Objects.requireNonNull(applier, "FunctionSymbolApplier cannot be null");
|
Objects.requireNonNull(applier, "FunctionSymbolApplier cannot be null");
|
||||||
Function function = applier.getFunction();
|
Function function = applier.getFunction();
|
||||||
|
|
||||||
|
@ -105,8 +107,8 @@ public class RegisterRelativeSymbolApplier extends MsSymbolApplier {
|
||||||
// }
|
// }
|
||||||
int offset = (int) (relativeOffset & 0xffffffffL);
|
int offset = (int) (relativeOffset & 0xffffffffL);
|
||||||
|
|
||||||
MsTypeApplier dataTypeApplier = applicator.getTypeApplier(symbol.getTypeRecordNumber());
|
RecordNumber typeRecord = symbol.getTypeRecordNumber();
|
||||||
DataType dt = dataTypeApplier.getDataType();
|
DataType dt = applicator.getCompletedDataType(typeRecord);
|
||||||
if (dt != null) {
|
if (dt != null) {
|
||||||
// Variable m16 = stackFrame.getVariableContaining(-16);
|
// Variable m16 = stackFrame.getVariableContaining(-16);
|
||||||
// Variable m8 = stackFrame.getVariableContaining(-8);
|
// Variable m8 = stackFrame.getVariableContaining(-8);
|
||||||
|
|
|
@ -30,11 +30,11 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||||
public class TypeApplierFactory {
|
public class TypeApplierFactory {
|
||||||
|
|
||||||
private DefaultPdbApplicator applicator;
|
private DefaultPdbApplicator applicator;
|
||||||
private Map<RecordNumber, MsTypeApplier> appliersByRecordNumber;
|
private Map<Integer, MsTypeApplier> appliersByPdbId;
|
||||||
|
|
||||||
TypeApplierFactory(DefaultPdbApplicator applicator) {
|
TypeApplierFactory(DefaultPdbApplicator applicator) {
|
||||||
this.applicator = applicator;
|
this.applicator = applicator;
|
||||||
appliersByRecordNumber = new HashMap<>();
|
appliersByPdbId = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
@ -51,9 +51,10 @@ public class TypeApplierFactory {
|
||||||
MsTypeApplier getApplierOrNoTypeSpec(RecordNumber recordNumber,
|
MsTypeApplier getApplierOrNoTypeSpec(RecordNumber recordNumber,
|
||||||
Class<? extends MsTypeApplier> expected) throws PdbException {
|
Class<? extends MsTypeApplier> expected) throws PdbException {
|
||||||
MsTypeApplier applier = getTypeApplier(recordNumber);
|
MsTypeApplier applier = getTypeApplier(recordNumber);
|
||||||
|
AbstractMsType type = applicator.getPdb().getTypeRecord(recordNumber);
|
||||||
if (!expected.isInstance(applier)) {
|
if (!expected.isInstance(applier)) {
|
||||||
if (!(applier instanceof PrimitiveTypeApplier &&
|
if (!(applier instanceof PrimitiveTypeApplier &&
|
||||||
((PrimitiveTypeApplier) applier).isNoType())) {
|
((PrimitiveTypeApplier) applier).isNoType(type))) {
|
||||||
throw new PdbException(applier.getClass().getSimpleName() + " seen where " +
|
throw new PdbException(applier.getClass().getSimpleName() + " seen where " +
|
||||||
expected.getSimpleName() + " expected for record number " + recordNumber);
|
expected.getSimpleName() + " expected for record number " + recordNumber);
|
||||||
}
|
}
|
||||||
|
@ -62,12 +63,7 @@ public class TypeApplierFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
MsTypeApplier getTypeApplier(RecordNumber recordNumber) {
|
MsTypeApplier getTypeApplier(RecordNumber recordNumber) {
|
||||||
MsTypeApplier applier = appliersByRecordNumber.get(recordNumber);
|
return getTypeApplier(applicator.getPdb().getTypeRecord(recordNumber));
|
||||||
if (applier == null) {
|
|
||||||
applier = getTypeApplier(applicator.getPdb().getTypeRecord(recordNumber));
|
|
||||||
appliersByRecordNumber.put(recordNumber, applier);
|
|
||||||
}
|
|
||||||
return applier;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
@ -76,44 +72,61 @@ public class TypeApplierFactory {
|
||||||
applicator.appendLogMsg("PDB Warning: No AbstractMsType for getTypeApplier");
|
applicator.appendLogMsg("PDB Warning: No AbstractMsType for getTypeApplier");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
MsTypeApplier applier = null;
|
|
||||||
|
MsTypeApplier applier = getTypeApplier(type.getPdbId());
|
||||||
|
if (applier instanceof NoTypeApplier) {
|
||||||
|
// Only adding to this cannotApplyTypes list here, and not in other
|
||||||
|
// places (above) where we might currently be using a NoTypeApplier.
|
||||||
|
// Using a NoTypeApplier in other places (above) might just be a placeholder
|
||||||
|
// until we craft the specific ways in which we would like to "apply" the
|
||||||
|
// data type information.
|
||||||
|
applicator.getPdbApplicatorMetrics().witnessCannotApplyDataType(type);
|
||||||
|
}
|
||||||
|
return applier;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================================
|
||||||
|
MsTypeApplier getTypeApplier(int pdbId) {
|
||||||
|
MsTypeApplier applier = appliersByPdbId.get(pdbId);
|
||||||
|
if (applier != null) {
|
||||||
|
return applier;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
switch (type.getPdbId()) {
|
switch (pdbId) {
|
||||||
case -1: // must be careful, as we chose the -1 for PrimitiveMsType
|
case -1: // must be careful, as we chose the -1 for PrimitiveMsType
|
||||||
applier = new PrimitiveTypeApplier(applicator, (PrimitiveMsType) type);
|
applier = new PrimitiveTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// 0x0000 block
|
// 0x0000 block
|
||||||
case Modifier16MsType.PDB_ID:
|
case Modifier16MsType.PDB_ID:
|
||||||
applier = new ModifierTypeApplier(applicator, (Modifier16MsType) type);
|
applier = new ModifierTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case Pointer16MsType.PDB_ID:
|
case Pointer16MsType.PDB_ID:
|
||||||
applier = new PointerTypeApplier(applicator, (Pointer16MsType) type);
|
applier = new PointerTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case Array16MsType.PDB_ID:
|
case Array16MsType.PDB_ID:
|
||||||
applier = new ArrayTypeApplier(applicator, (Array16MsType) type);
|
applier = new ArrayTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case Class16MsType.PDB_ID:
|
case Class16MsType.PDB_ID:
|
||||||
applier = new CompositeTypeApplier(applicator, (Class16MsType) type);
|
applier = new CompositeTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case Structure16MsType.PDB_ID:
|
case Structure16MsType.PDB_ID:
|
||||||
applier = new CompositeTypeApplier(applicator, (Structure16MsType) type);
|
applier = new CompositeTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case Union16MsType.PDB_ID:
|
case Union16MsType.PDB_ID:
|
||||||
applier = new CompositeTypeApplier(applicator, (Union16MsType) type);
|
applier = new CompositeTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case Enum16MsType.PDB_ID:
|
case Enum16MsType.PDB_ID:
|
||||||
applier = new EnumTypeApplier(applicator, (Enum16MsType) type);
|
applier = new EnumTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case Procedure16MsType.PDB_ID:
|
case Procedure16MsType.PDB_ID:
|
||||||
applier = new ProcedureTypeApplier(applicator, (Procedure16MsType) type);
|
applier = new ProcedureTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case MemberFunction16MsType.PDB_ID:
|
case MemberFunction16MsType.PDB_ID:
|
||||||
applier =
|
applier = new MemberFunctionTypeApplier(applicator);
|
||||||
new MemberFunctionTypeApplier(applicator, (MemberFunction16MsType) type);
|
|
||||||
break;
|
break;
|
||||||
case VtShapeMsType.PDB_ID:
|
case VtShapeMsType.PDB_ID:
|
||||||
applier = new VtShapeTypeApplier(applicator, (VtShapeMsType) type);
|
applier = new VtShapeTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case Cobol016MsType.PDB_ID:
|
// case Cobol016MsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
|
@ -157,8 +170,7 @@ public class TypeApplierFactory {
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case ArgumentsList16MsType.PDB_ID:
|
case ArgumentsList16MsType.PDB_ID:
|
||||||
applier =
|
applier = new ArgumentsListTypeApplier(applicator);
|
||||||
new ArgumentsListTypeApplier(applicator, (ArgumentsList16MsType) type);
|
|
||||||
break;
|
break;
|
||||||
// case DefaultArguments16MsType.PDB_ID:
|
// case DefaultArguments16MsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
|
@ -167,13 +179,13 @@ public class TypeApplierFactory {
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case FieldList16MsType.PDB_ID:
|
case FieldList16MsType.PDB_ID:
|
||||||
applier = new FieldListTypeApplier(applicator, type);
|
applier = new FieldListTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case DerivedClassList16MsType.PDB_ID:
|
// case DerivedClassList16MsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case Bitfield16MsType.PDB_ID:
|
case Bitfield16MsType.PDB_ID:
|
||||||
applier = new BitfieldTypeApplier(applicator, (Bitfield16MsType) type);
|
applier = new BitfieldTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case MethodList16MsType.PDB_ID:
|
// case MethodList16MsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
|
@ -196,16 +208,16 @@ public class TypeApplierFactory {
|
||||||
|
|
||||||
// 0x400 block
|
// 0x400 block
|
||||||
case BaseClass16MsType.PDB_ID:
|
case BaseClass16MsType.PDB_ID:
|
||||||
applier = new BaseClassTypeApplier(applicator, type);
|
applier = new BaseClassTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case VirtualBaseClass16MsType.PDB_ID:
|
case VirtualBaseClass16MsType.PDB_ID:
|
||||||
applier = new BaseClassTypeApplier(applicator, type);
|
applier = new BaseClassTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case IndirectVirtualBaseClass16MsType.PDB_ID:
|
case IndirectVirtualBaseClass16MsType.PDB_ID:
|
||||||
applier = new BaseClassTypeApplier(applicator, type);
|
applier = new BaseClassTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case EnumerateStMsType.PDB_ID:
|
case EnumerateStMsType.PDB_ID:
|
||||||
applier = new EnumerateTypeApplier(applicator, (EnumerateStMsType) type);
|
applier = new EnumerateTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case FriendFunction16MsType.PDB_ID:
|
// case FriendFunction16MsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
|
@ -214,60 +226,59 @@ public class TypeApplierFactory {
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case Member16MsType.PDB_ID:
|
case Member16MsType.PDB_ID:
|
||||||
applier = new MemberTypeApplier(applicator, (Member16MsType) type);
|
applier = new MemberTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case StaticMember16MsType.PDB_ID:
|
// case StaticMember16MsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case OverloadedMethod16MsType.PDB_ID:
|
case OverloadedMethod16MsType.PDB_ID:
|
||||||
// See note in "default" case regarding NoTypeApplier
|
// See note in "default" case regarding NoTypeApplier
|
||||||
applier = new NoTypeApplier(applicator, type);
|
applier = new NoTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case NestedType16MsType.PDB_ID:
|
case NestedType16MsType.PDB_ID:
|
||||||
applier = new NestedTypeApplier(applicator, type);
|
applier = new NestedTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case VirtualFunctionTablePointer16MsType.PDB_ID:
|
case VirtualFunctionTablePointer16MsType.PDB_ID:
|
||||||
applier = new VirtualFunctionTablePointerTypeApplier(applicator, type);
|
applier = new VirtualFunctionTablePointerTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case FriendClass16MsType.PDB_ID:
|
// case FriendClass16MsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case OneMethod16MsType.PDB_ID:
|
case OneMethod16MsType.PDB_ID:
|
||||||
// See note in "default" case regarding NoTypeApplier
|
// See note in "default" case regarding NoTypeApplier
|
||||||
applier = new NoTypeApplier(applicator, type);
|
applier = new NoTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case VirtualFunctionTablePointerWithOffset16MsType.PDB_ID:
|
case VirtualFunctionTablePointerWithOffset16MsType.PDB_ID:
|
||||||
applier = new VirtualFunctionTablePointerTypeApplier(applicator, type);
|
applier = new VirtualFunctionTablePointerTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// 0x1000 block
|
// 0x1000 block
|
||||||
case ModifierMsType.PDB_ID:
|
case ModifierMsType.PDB_ID:
|
||||||
applier = new ModifierTypeApplier(applicator, (ModifierMsType) type);
|
applier = new ModifierTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case PointerMsType.PDB_ID:
|
case PointerMsType.PDB_ID:
|
||||||
applier = new PointerTypeApplier(applicator, (PointerMsType) type);
|
applier = new PointerTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case ArrayStMsType.PDB_ID:
|
case ArrayStMsType.PDB_ID:
|
||||||
applier = new ArrayTypeApplier(applicator, (ArrayStMsType) type);
|
applier = new ArrayTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case ClassStMsType.PDB_ID:
|
case ClassStMsType.PDB_ID:
|
||||||
applier = new CompositeTypeApplier(applicator, (ClassStMsType) type);
|
applier = new CompositeTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case StructureStMsType.PDB_ID:
|
case StructureStMsType.PDB_ID:
|
||||||
applier = new CompositeTypeApplier(applicator, (StructureStMsType) type);
|
applier = new CompositeTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case UnionStMsType.PDB_ID:
|
case UnionStMsType.PDB_ID:
|
||||||
applier = new CompositeTypeApplier(applicator, (UnionStMsType) type);
|
applier = new CompositeTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case EnumStMsType.PDB_ID:
|
case EnumStMsType.PDB_ID:
|
||||||
applier = new EnumTypeApplier(applicator, (EnumStMsType) type);
|
applier = new EnumTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case ProcedureMsType.PDB_ID:
|
case ProcedureMsType.PDB_ID:
|
||||||
applier = new ProcedureTypeApplier(applicator, (ProcedureMsType) type);
|
applier = new ProcedureTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case MemberFunctionMsType.PDB_ID:
|
case MemberFunctionMsType.PDB_ID:
|
||||||
applier =
|
applier = new MemberFunctionTypeApplier(applicator);
|
||||||
new MemberFunctionTypeApplier(applicator, (MemberFunctionMsType) type);
|
|
||||||
break;
|
break;
|
||||||
// case Cobol0MsType.PDB_ID:
|
// case Cobol0MsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
|
@ -299,19 +310,19 @@ public class TypeApplierFactory {
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case ArgumentsListMsType.PDB_ID:
|
case ArgumentsListMsType.PDB_ID:
|
||||||
applier = new ArgumentsListTypeApplier(applicator, (ArgumentsListMsType) type);
|
applier = new ArgumentsListTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case DefaultArgumentsStMsType.PDB_ID:
|
// case DefaultArgumentsStMsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case FieldListMsType.PDB_ID:
|
case FieldListMsType.PDB_ID:
|
||||||
applier = new FieldListTypeApplier(applicator, type);
|
applier = new FieldListTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case DerivedClassListMsType.PDB_ID:
|
// case DerivedClassListMsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case BitfieldMsType.PDB_ID:
|
case BitfieldMsType.PDB_ID:
|
||||||
applier = new BitfieldTypeApplier(applicator, (BitfieldMsType) type);
|
applier = new BitfieldTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case MethodListMsType.PDB_ID:
|
// case MethodListMsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
|
@ -331,13 +342,13 @@ public class TypeApplierFactory {
|
||||||
|
|
||||||
// 0x1400 block
|
// 0x1400 block
|
||||||
case BaseClassMsType.PDB_ID:
|
case BaseClassMsType.PDB_ID:
|
||||||
applier = new BaseClassTypeApplier(applicator, type);
|
applier = new BaseClassTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case VirtualBaseClassMsType.PDB_ID:
|
case VirtualBaseClassMsType.PDB_ID:
|
||||||
applier = new BaseClassTypeApplier(applicator, type);
|
applier = new BaseClassTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case IndirectVirtualBaseClassMsType.PDB_ID:
|
case IndirectVirtualBaseClassMsType.PDB_ID:
|
||||||
applier = new BaseClassTypeApplier(applicator, type);
|
applier = new BaseClassTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case FriendFunctionStMsType.PDB_ID:
|
// case FriendFunctionStMsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
|
@ -346,33 +357,33 @@ public class TypeApplierFactory {
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case MemberStMsType.PDB_ID:
|
case MemberStMsType.PDB_ID:
|
||||||
applier = new MemberTypeApplier(applicator, (MemberStMsType) type);
|
applier = new MemberTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case StaticMemberStMsType.PDB_ID:
|
// case StaticMemberStMsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case OverloadedMethodStMsType.PDB_ID:
|
case OverloadedMethodStMsType.PDB_ID:
|
||||||
// See note in "default" case regarding NoTypeApplier
|
// See note in "default" case regarding NoTypeApplier
|
||||||
applier = new NoTypeApplier(applicator, type);
|
applier = new NoTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case NestedTypeStMsType.PDB_ID:
|
case NestedTypeStMsType.PDB_ID:
|
||||||
applier = new NestedTypeApplier(applicator, type);
|
applier = new NestedTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case VirtualFunctionTablePointerMsType.PDB_ID:
|
case VirtualFunctionTablePointerMsType.PDB_ID:
|
||||||
applier = new VirtualFunctionTablePointerTypeApplier(applicator, type);
|
applier = new VirtualFunctionTablePointerTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case FriendClassMsType.PDB_ID:
|
// case FriendClassMsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case OneMethodStMsType.PDB_ID:
|
case OneMethodStMsType.PDB_ID:
|
||||||
// See note in "default" case regarding NoTypeApplier
|
// See note in "default" case regarding NoTypeApplier
|
||||||
applier = new NoTypeApplier(applicator, type);
|
applier = new NoTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case VirtualFunctionTablePointerWithOffsetMsType.PDB_ID:
|
case VirtualFunctionTablePointerWithOffsetMsType.PDB_ID:
|
||||||
applier = new VirtualFunctionTablePointerTypeApplier(applicator, type);
|
applier = new VirtualFunctionTablePointerTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case NestedTypeExtStMsType.PDB_ID:
|
case NestedTypeExtStMsType.PDB_ID:
|
||||||
applier = new NestedTypeApplier(applicator, type);
|
applier = new NestedTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case MemberModifyStMsType.PDB_ID:
|
// case MemberModifyStMsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
|
@ -386,22 +397,22 @@ public class TypeApplierFactory {
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case EnumerateMsType.PDB_ID:
|
case EnumerateMsType.PDB_ID:
|
||||||
applier = new EnumerateTypeApplier(applicator, (EnumerateMsType) type);
|
applier = new EnumerateTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case ArrayMsType.PDB_ID:
|
case ArrayMsType.PDB_ID:
|
||||||
applier = new ArrayTypeApplier(applicator, (ArrayMsType) type);
|
applier = new ArrayTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case ClassMsType.PDB_ID:
|
case ClassMsType.PDB_ID:
|
||||||
applier = new CompositeTypeApplier(applicator, (ClassMsType) type);
|
applier = new CompositeTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case StructureMsType.PDB_ID:
|
case StructureMsType.PDB_ID:
|
||||||
applier = new CompositeTypeApplier(applicator, (StructureMsType) type);
|
applier = new CompositeTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case UnionMsType.PDB_ID:
|
case UnionMsType.PDB_ID:
|
||||||
applier = new CompositeTypeApplier(applicator, (UnionMsType) type);
|
applier = new CompositeTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case EnumMsType.PDB_ID:
|
case EnumMsType.PDB_ID:
|
||||||
applier = new EnumTypeApplier(applicator, (EnumMsType) type);
|
applier = new EnumTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case DimensionedArrayMsType.PDB_ID:
|
// case DimensionedArrayMsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
|
@ -419,24 +430,24 @@ public class TypeApplierFactory {
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case MemberMsType.PDB_ID:
|
case MemberMsType.PDB_ID:
|
||||||
applier = new MemberTypeApplier(applicator, (MemberMsType) type);
|
applier = new MemberTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case StaticMemberMsType.PDB_ID:
|
// case StaticMemberMsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case OverloadedMethodMsType.PDB_ID:
|
case OverloadedMethodMsType.PDB_ID:
|
||||||
// See note in "default" case regarding NoTypeApplier
|
// See note in "default" case regarding NoTypeApplier
|
||||||
applier = new NoTypeApplier(applicator, type);
|
applier = new NoTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case NestedTypeMsType.PDB_ID:
|
case NestedTypeMsType.PDB_ID:
|
||||||
applier = new NestedTypeApplier(applicator, type);
|
applier = new NestedTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case OneMethodMsType.PDB_ID:
|
case OneMethodMsType.PDB_ID:
|
||||||
// See note in "default" case regarding NoTypeApplier
|
// See note in "default" case regarding NoTypeApplier
|
||||||
applier = new NoTypeApplier(applicator, type);
|
applier = new NoTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case NestedTypeExtMsType.PDB_ID:
|
case NestedTypeExtMsType.PDB_ID:
|
||||||
applier = new NestedTypeApplier(applicator, type);
|
applier = new NestedTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case MemberModifyMsType.PDB_ID:
|
// case MemberModifyMsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
|
@ -457,7 +468,7 @@ public class TypeApplierFactory {
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case InterfaceMsType.PDB_ID:
|
case InterfaceMsType.PDB_ID:
|
||||||
applier = new CompositeTypeApplier(applicator, (InterfaceMsType) type);
|
applier = new CompositeTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// case BaseInterfaceMsType.PDB_ID:
|
// case BaseInterfaceMsType.PDB_ID:
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
|
@ -489,16 +500,16 @@ public class TypeApplierFactory {
|
||||||
// // Not evaluated/implemented yet.
|
// // Not evaluated/implemented yet.
|
||||||
// break;
|
// break;
|
||||||
case UserDefinedTypeSourceAndLineMsType.PDB_ID:
|
case UserDefinedTypeSourceAndLineMsType.PDB_ID:
|
||||||
applier = new UdtSourceLineTypeApplier(applicator, type);
|
applier = new UdtSourceLineTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case UserDefinedTypeModuleSourceAndLineMsType.PDB_ID:
|
case UserDefinedTypeModuleSourceAndLineMsType.PDB_ID:
|
||||||
applier = new UdtSourceLineTypeApplier(applicator, type);
|
applier = new UdtSourceLineTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case Class19MsType.PDB_ID:
|
case Class19MsType.PDB_ID:
|
||||||
applier = new CompositeTypeApplier(applicator, (Class19MsType) type);
|
applier = new CompositeTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
case Structure19MsType.PDB_ID:
|
case Structure19MsType.PDB_ID:
|
||||||
applier = new CompositeTypeApplier(applicator, (Structure19MsType) type);
|
applier = new CompositeTypeApplier(applicator);
|
||||||
break;
|
break;
|
||||||
// TODO: the following three types are only hypothetical and might be in the wrong
|
// TODO: the following three types are only hypothetical and might be in the wrong
|
||||||
// order with the wrong PDB_IDs and the wrong internal elements and parsing.
|
// order with the wrong PDB_IDs and the wrong internal elements and parsing.
|
||||||
|
@ -521,30 +532,16 @@ public class TypeApplierFactory {
|
||||||
// If all of the above are enabled, this should never happen (unless we missed
|
// If all of the above are enabled, this should never happen (unless we missed
|
||||||
// something or MSFT has added new in a version we do not handle.
|
// something or MSFT has added new in a version we do not handle.
|
||||||
default:
|
default:
|
||||||
applier = new NoTypeApplier(applicator, type);
|
applier = new NoTypeApplier(applicator);
|
||||||
// Only adding to this cannotApplyTypes list here, and not in other
|
|
||||||
// places (above) where we might currently be using a NoTypeApplier.
|
|
||||||
// Using a NoTypeApplier in other places (above) might just be a placeholder
|
|
||||||
// until we craft the specific ways in which we would like to "apply" the
|
|
||||||
// data type information.
|
|
||||||
applicator.getPdbApplicatorMetrics().witnessCannotApplyDataType(type);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) {
|
catch (IllegalArgumentException e) {
|
||||||
try {
|
String message = "GhidraException on PdbId " + pdbId + ": " + e.getMessage();
|
||||||
applier = new NoTypeApplier(applicator, type);
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException e2) {
|
|
||||||
// We did a null check above on type, so this state should not happen.
|
|
||||||
}
|
|
||||||
RecordNumber recNum = type.getRecordNumber();
|
|
||||||
String msg = (recNum == null) ? "record" : recNum.toString();
|
|
||||||
String message = "GhidraException on " + msg + " with PdbId " + type.getPdbId() + ": " +
|
|
||||||
e.getMessage();
|
|
||||||
applicator.appendLogMsg(message);
|
applicator.appendLogMsg(message);
|
||||||
applicator.pdbLogAndInfoMessage(this, message);
|
applicator.pdbLogAndInfoMessage(this, message);
|
||||||
}
|
}
|
||||||
|
appliersByPdbId.put(pdbId, applier);
|
||||||
return applier;
|
return applier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ import ghidra.app.util.SymbolPath;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractUserDefinedTypeMsSymbol;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractUserDefinedTypeMsSymbol;
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractComplexMsType;
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
@ -80,16 +82,18 @@ public class TypedefSymbolApplier extends MsSymbolApplier {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Typedefs
|
// Typedefs
|
||||||
private DataType applyUserDefinedTypeMsSymbol(AbstractUserDefinedTypeMsSymbol symbol) {
|
private DataType applyUserDefinedTypeMsSymbol(AbstractUserDefinedTypeMsSymbol symbol)
|
||||||
|
throws CancelledException, PdbException {
|
||||||
|
|
||||||
String name = symbol.getName();
|
String name = symbol.getName();
|
||||||
|
|
||||||
|
AbstractMsType mType = applicator.getPdb().getTypeRecord(getTypeRecordNumber());
|
||||||
MsTypeApplier applier = applicator.getTypeApplier(symbol.getTypeRecordNumber());
|
MsTypeApplier applier = applicator.getTypeApplier(symbol.getTypeRecordNumber());
|
||||||
// TODO:... NOT SURE IF WILL ALWAYS BE A DATATYPE OR WILL BE A VARIABLE OR ????
|
// TODO:... NOT SURE IF WILL ALWAYS BE A DATATYPE OR WILL BE A VARIABLE OR ????
|
||||||
if (applier == null) {
|
if (applier == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
DataType dataType = applier.getDataType();
|
DataType dataType = applicator.getCompletedDataType(getTypeRecordNumber());
|
||||||
if (dataType == null) {
|
if (dataType == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -101,17 +105,8 @@ public class TypedefSymbolApplier extends MsSymbolApplier {
|
||||||
// create a TypeDefDataType which uses an existing underlying DataType.
|
// create a TypeDefDataType which uses an existing underlying DataType.
|
||||||
// Note, too, that we do not compare name with dataType.getName() as the latter does not
|
// Note, too, that we do not compare name with dataType.getName() as the latter does not
|
||||||
// contain namespace information.
|
// contain namespace information.
|
||||||
if (applier instanceof CompositeTypeApplier) {
|
if (mType instanceof AbstractComplexMsType) {
|
||||||
CompositeTypeApplier compositeApplier = (CompositeTypeApplier) applier;
|
if (name.equals(mType.getName())) {
|
||||||
String compositeName = compositeApplier.getName();
|
|
||||||
if (name.equals(compositeName)) {
|
|
||||||
return dataType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (applier instanceof EnumTypeApplier) {
|
|
||||||
EnumTypeApplier enumApplier = (EnumTypeApplier) applier;
|
|
||||||
String enumName = enumApplier.getMsType().getName();
|
|
||||||
if (name.equals(enumName)) {
|
|
||||||
return dataType;
|
return dataType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,74 +27,77 @@ import ghidra.util.exception.CancelledException;
|
||||||
*/
|
*/
|
||||||
public class UdtSourceLineTypeApplier extends MsTypeApplier {
|
public class UdtSourceLineTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
|
// Intended for: UserDefinedTypeSourceAndLineMsType or UserDefinedTypeModuleSourceAndLineMsType
|
||||||
/**
|
/**
|
||||||
* Constructor for base class applier.
|
* Constructor for base class applier.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractBaseClassMsType}, {@link AbstractVirtualBaseClassMsType}, or
|
|
||||||
* {@link AbstractIndirectVirtualBaseClassMsType} to processes.
|
|
||||||
* @throws IllegalArgumentException Upon invalid arguments.
|
* @throws IllegalArgumentException Upon invalid arguments.
|
||||||
*/
|
*/
|
||||||
public UdtSourceLineTypeApplier(DefaultPdbApplicator applicator, AbstractMsType msType)
|
public UdtSourceLineTypeApplier(DefaultPdbApplicator applicator)
|
||||||
throws IllegalArgumentException {
|
throws IllegalArgumentException {
|
||||||
super(applicator, validateType(msType));
|
super(applicator);
|
||||||
}
|
|
||||||
|
|
||||||
// The MsTypes for which we are working do not have a size in and of themselves, but the
|
|
||||||
// classes/structures to which they refer have a size, even if zero.
|
|
||||||
// For here, we are only reporting what "we" have, not what the underlying sizes are.
|
|
||||||
// ...and a value of zero is our "don't know" and "not represented" value.
|
|
||||||
@Override
|
|
||||||
BigInteger getSize() {
|
|
||||||
return BigInteger.ZERO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the offset of the Base Class within the inheriting class.
|
* Returns the offset of the Base Class within the inheriting class
|
||||||
* @return the offset.
|
* @param type the PDB type being inspected
|
||||||
|
* @return the offset or -1 if problem retrieving value
|
||||||
*/
|
*/
|
||||||
int getLineNumber() {
|
int getLineNumber(AbstractMsType type) {
|
||||||
if (msType instanceof UserDefinedTypeSourceAndLineMsType) {
|
if (type instanceof UserDefinedTypeSourceAndLineMsType udtSLType) {
|
||||||
return ((UserDefinedTypeSourceAndLineMsType) msType).getLineNumber();
|
return udtSLType.getLineNumber();
|
||||||
}
|
}
|
||||||
return ((UserDefinedTypeModuleSourceAndLineMsType) msType).getLineNumber();
|
else if (type instanceof UserDefinedTypeModuleSourceAndLineMsType udtMSLType) {
|
||||||
|
return udtMSLType.getLineNumber();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the source file name.
|
* Returns the source file name
|
||||||
* @return the source file name. null if problem recovering name.
|
* @param type the PDB type being inspected
|
||||||
|
* @return the source file name or null if problem recovering name
|
||||||
*/
|
*/
|
||||||
String getSourceFileName() {
|
String getSourceFileName(AbstractMsType type) {
|
||||||
if (msType instanceof UserDefinedTypeSourceAndLineMsType) {
|
if (type instanceof UserDefinedTypeSourceAndLineMsType udtSLType) {
|
||||||
return ((UserDefinedTypeSourceAndLineMsType) msType).getSourceFileName();
|
return udtSLType.getSourceFileName();
|
||||||
}
|
}
|
||||||
return ((UserDefinedTypeModuleSourceAndLineMsType) msType).getSourceFileName();
|
else if (type instanceof UserDefinedTypeModuleSourceAndLineMsType udtMSLType) {
|
||||||
|
return udtMSLType.getSourceFileName();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the record number of the UDT.
|
* Returns the record number of the UDT
|
||||||
* @return the record number of the UDT.
|
* @param type the PDB type being inspected
|
||||||
|
* @return the record number of the UDT or null if problem retrieving value
|
||||||
*/
|
*/
|
||||||
RecordNumber getUdtRecordNumber() {
|
RecordNumber getUdtRecordNumber(AbstractMsType type) {
|
||||||
if (msType instanceof UserDefinedTypeSourceAndLineMsType) {
|
if (type instanceof UserDefinedTypeSourceAndLineMsType udtSLType) {
|
||||||
return ((UserDefinedTypeSourceAndLineMsType) msType).getUdtRecordNumber();
|
return udtSLType.getUdtRecordNumber();
|
||||||
}
|
}
|
||||||
return ((UserDefinedTypeModuleSourceAndLineMsType) msType).getUdtRecordNumber();
|
else if (type instanceof UserDefinedTypeModuleSourceAndLineMsType udtMSLType) {
|
||||||
|
return udtMSLType.getUdtRecordNumber();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void apply() throws PdbException, CancelledException {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
String filename = getSourceFileName();
|
throws PdbException, CancelledException {
|
||||||
int lineNumber = getLineNumber();
|
String filename = getSourceFileName(type);
|
||||||
RecordNumber udtRecordNumber = getUdtRecordNumber();
|
int lineNumber = getLineNumber(type);
|
||||||
|
RecordNumber udtRecordNumber = getUdtRecordNumber(type);
|
||||||
MsTypeApplier typeApplier = applicator.getTypeApplier(udtRecordNumber);
|
MsTypeApplier typeApplier = applicator.getTypeApplier(udtRecordNumber);
|
||||||
|
|
||||||
// do nothing at the moment.
|
// do nothing at the moment.
|
||||||
applicator.putRecordNumberByFileName(udtRecordNumber, filename);
|
applicator.putRecordNumberByFileName(udtRecordNumber, filename);
|
||||||
if (msType instanceof UserDefinedTypeModuleSourceAndLineMsType) {
|
if (type instanceof UserDefinedTypeModuleSourceAndLineMsType) {
|
||||||
int moduleNumber =
|
int moduleNumber = ((UserDefinedTypeModuleSourceAndLineMsType) type).getModuleNumber();
|
||||||
((UserDefinedTypeModuleSourceAndLineMsType) msType).getModuleNumber();
|
|
||||||
applicator.putRecordNumberByModuleNumber(udtRecordNumber, moduleNumber);
|
applicator.putRecordNumberByModuleNumber(udtRecordNumber, moduleNumber);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AbstractMsType validateType(AbstractMsType type)
|
private static AbstractMsType validateType(AbstractMsType type)
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||||
|
@ -30,63 +28,65 @@ import ghidra.util.exception.CancelledException;
|
||||||
*/
|
*/
|
||||||
public class VirtualFunctionTablePointerTypeApplier extends MsTypeApplier {
|
public class VirtualFunctionTablePointerTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
|
// Intended for: AbstractVirtualFunctionTablePointerMsType or
|
||||||
|
// AbstractVirtualFunctionTablePointerWithOffsetMsType
|
||||||
/**
|
/**
|
||||||
* Constructor for enum type applier, for transforming a enum into a
|
* Constructor for enum type applier, for transforming a enum into a
|
||||||
* Ghidra DataType.
|
* Ghidra DataType.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link AbstractVirtualFunctionTablePointerMsType} or
|
|
||||||
* {@link AbstractVirtualFunctionTablePointerWithOffsetMsType} to process.
|
|
||||||
* @throws IllegalArgumentException Upon invalid arguments.
|
* @throws IllegalArgumentException Upon invalid arguments.
|
||||||
*/
|
*/
|
||||||
public VirtualFunctionTablePointerTypeApplier(DefaultPdbApplicator applicator,
|
public VirtualFunctionTablePointerTypeApplier(DefaultPdbApplicator applicator) throws IllegalArgumentException {
|
||||||
AbstractMsType msType) throws IllegalArgumentException {
|
super(applicator);
|
||||||
super(applicator, validateType(msType));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
int getOffset(AbstractMsType type) {
|
||||||
BigInteger getSize() {
|
if (type instanceof AbstractVirtualFunctionTablePointerWithOffsetMsType offType) {
|
||||||
return BigInteger.valueOf(applicator.getDataOrganization().getPointerSize());
|
return offType.getOffset();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the offset of the Virtual Function Table Pointer.
|
|
||||||
* @return Name of the nested type.
|
|
||||||
*/
|
|
||||||
int getOffset() {
|
|
||||||
if (msType instanceof AbstractVirtualFunctionTablePointerWithOffsetMsType) {
|
|
||||||
return ((AbstractVirtualFunctionTablePointerWithOffsetMsType) msType).getOffset();
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name to use.
|
* Returns the name to use.
|
||||||
|
* @param type the PDB type being inspected
|
||||||
* @return Name of the pointer type.
|
* @return Name of the pointer type.
|
||||||
*/
|
*/
|
||||||
String getMemberName() {
|
String getMemberName(AbstractMsType type) {
|
||||||
return "VFTablePtr" + getOffset();
|
return "VFTablePtr" + getOffset(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void apply() throws PdbException, CancelledException {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
if (msType instanceof AbstractVirtualFunctionTablePointerWithOffsetMsType vftPtrWOffset) {
|
throws PdbException, CancelledException {
|
||||||
dataType = applyPointer(
|
|
||||||
vftPtrWOffset.getPointerTypeRecordNumber());
|
// usually no record number, so cannot retrieve or store from/to applicator
|
||||||
|
DataType dataType;
|
||||||
|
|
||||||
|
if (type instanceof AbstractVirtualFunctionTablePointerWithOffsetMsType vftPtrWOffset) {
|
||||||
|
dataType =
|
||||||
|
applyPointer(vftPtrWOffset.getPointerTypeRecordNumber(), fixupContext, breakCycle);
|
||||||
}
|
}
|
||||||
else if (msType instanceof AbstractVirtualFunctionTablePointerMsType vftPtr) {
|
else if (type instanceof AbstractVirtualFunctionTablePointerMsType vftPtr) {
|
||||||
dataType = applyPointer(vftPtr.getPointerTypeRecordNumber());
|
dataType = applyPointer(vftPtr.getPointerTypeRecordNumber(), fixupContext, breakCycle);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dataType = VoidDataType.dataType;
|
dataType = VoidDataType.dataType;
|
||||||
applicator.appendLogMsg(
|
applicator.appendLogMsg(
|
||||||
"PDB Warning: Type not handled: " + msType.getClass().getSimpleName());
|
"PDB Warning: Type not handled: " + type.getClass().getSimpleName());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataType applyPointer(RecordNumber pointerTypeRecordNumber) {
|
// unlike regular pointer, we are resolving vft pointer
|
||||||
|
dataType = applicator.resolve(dataType);
|
||||||
|
return dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataType applyPointer(RecordNumber pointerTypeRecordNumber, FixupContext fixupContext,
|
||||||
|
boolean breakCycle) throws CancelledException, PdbException {
|
||||||
MsTypeApplier rawApplier = applicator.getTypeApplier(pointerTypeRecordNumber);
|
MsTypeApplier rawApplier = applicator.getTypeApplier(pointerTypeRecordNumber);
|
||||||
if (rawApplier instanceof PointerTypeApplier pointerApplier) {
|
if (rawApplier instanceof PointerTypeApplier pointerApplier) {
|
||||||
return pointerApplier.getDataType();
|
AbstractMsType type = applicator.getPdb().getTypeRecord(pointerTypeRecordNumber);
|
||||||
|
return pointerApplier.apply(type, fixupContext, breakCycle);
|
||||||
}
|
}
|
||||||
applicator.appendLogMsg("cannot process " + rawApplier.getClass().getSimpleName() + "for " +
|
applicator.appendLogMsg("cannot process " + rawApplier.getClass().getSimpleName() + "for " +
|
||||||
getClass().getSimpleName());
|
getClass().getSimpleName());
|
||||||
|
|
|
@ -15,14 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb.DefaultCompositeMember;
|
import ghidra.app.util.bin.format.pdb.DefaultCompositeMember;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.VtShapeDescriptorMsProperty;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.VtShapeMsType;
|
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
@ -32,45 +30,42 @@ import ghidra.util.exception.CancelledException;
|
||||||
*/
|
*/
|
||||||
public class VtShapeTypeApplier extends MsTypeApplier {
|
public class VtShapeTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
|
// Intended for: VtShapeMsType
|
||||||
/**
|
/**
|
||||||
* Constructor for vtshape type applier.
|
* Constructor for vtshape type applier.
|
||||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||||
* @param msType {@link VtShapeMsType} to process.
|
|
||||||
*/
|
*/
|
||||||
public VtShapeTypeApplier(DefaultPdbApplicator applicator, VtShapeMsType msType) {
|
public VtShapeTypeApplier(DefaultPdbApplicator applicator) {
|
||||||
super(applicator, msType);
|
super(applicator);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
BigInteger getSize() {
|
|
||||||
return BigInteger.valueOf(applicator.getDataOrganization().getPointerSize() *
|
|
||||||
((VtShapeMsType) msType).getCount());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name.
|
* Returns the name
|
||||||
* @return the name.
|
* @param type the MS VtShape
|
||||||
|
* @return the name
|
||||||
*/
|
*/
|
||||||
String getName() {
|
String getName(VtShapeMsType type) {
|
||||||
return "vtshape_" + index;
|
return "vtshape_" + type.getRecordNumber().getNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void apply() throws PdbException, CancelledException {
|
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||||
|
throws PdbException, CancelledException {
|
||||||
// Note that focused investigation as shown that both the VTShape as well as the pointer
|
// Note that focused investigation as shown that both the VTShape as well as the pointer
|
||||||
// to the particular VTShapes are not specific to one class; they can be shared by
|
// to the particular VTShapes are not specific to one class; they can be shared by
|
||||||
// totally unrelated classes; moreover, no duplicates of any VTShape or pointer to a
|
// totally unrelated classes; moreover, no duplicates of any VTShape or pointer to a
|
||||||
// particular VTShape were found either. Because of this, for now, the VTShape is going
|
// particular VTShape were found either. Because of this, for now, the VTShape is going
|
||||||
// into an anonymous types category.
|
// into an anonymous types category.
|
||||||
dataType = createVtShape((VtShapeMsType) msType);
|
DataType dataType = createVtShape((VtShapeMsType) type);
|
||||||
|
// return applicator.resolve(dataType);
|
||||||
|
return dataType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are creating a structure for the vtshape.
|
// We are creating a structure for the vtshape.
|
||||||
private DataType createVtShape(VtShapeMsType msShape)
|
private DataType createVtShape(VtShapeMsType msShape) throws CancelledException {
|
||||||
throws CancelledException {
|
|
||||||
List<VtShapeDescriptorMsProperty> list = msShape.getDescriptorList();
|
List<VtShapeDescriptorMsProperty> list = msShape.getDescriptorList();
|
||||||
StructureDataType shape = new StructureDataType(applicator.getAnonymousTypesCategory(),
|
StructureDataType shape = new StructureDataType(applicator.getAnonymousTypesCategory(),
|
||||||
"vtshape" + index, 0, applicator.getDataTypeManager());
|
"vtshape" + msShape.getRecordNumber().getNumber(), 0, applicator.getDataTypeManager());
|
||||||
List<DefaultPdbUniversalMember> members = new ArrayList<>();
|
List<DefaultPdbUniversalMember> members = new ArrayList<>();
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int defaultSize = applicator.getDataTypeManager().getDataOrganization().getPointerSize();
|
int defaultSize = applicator.getDataTypeManager().getDataOrganization().getPointerSize();
|
||||||
|
@ -118,9 +113,8 @@ public class VtShapeTypeApplier extends MsTypeApplier {
|
||||||
default:
|
default:
|
||||||
// If any element type is not know, we will not return a full shape structure
|
// If any element type is not know, we will not return a full shape structure
|
||||||
// Instead, we return void type.
|
// Instead, we return void type.
|
||||||
applicator.appendLogMsg(
|
applicator.appendLogMsg("PDB Warning: No type conversion for " +
|
||||||
"PDB Warning: No type conversion for " + msShape.toString() +
|
msShape.toString() + " as underlying type for pointer. Using void.");
|
||||||
" as underlying type for pointer. Using void.");
|
|
||||||
return VoidDataType.dataType;
|
return VoidDataType.dataType;
|
||||||
}
|
}
|
||||||
int size = elementType.getLength();
|
int size = elementType.getLength();
|
||||||
|
@ -128,7 +122,7 @@ public class VtShapeTypeApplier extends MsTypeApplier {
|
||||||
elementType = PointerDataType.dataType;
|
elementType = PointerDataType.dataType;
|
||||||
}
|
}
|
||||||
DefaultPdbUniversalMember member =
|
DefaultPdbUniversalMember member =
|
||||||
new DefaultPdbUniversalMember(applicator, "", elementType, offset);
|
new DefaultPdbUniversalMember("", elementType, offset);
|
||||||
offset += size;
|
offset += size;
|
||||||
members.add(member);
|
members.add(member);
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,7 +147,7 @@ public class TypesTest extends AbstractGenericTest {
|
||||||
// Below is just a small sampling of PrimitiveMsType variations.
|
// Below is just a small sampling of PrimitiveMsType variations.
|
||||||
@Test
|
@Test
|
||||||
public void testPrimitiveMsType0000() {
|
public void testPrimitiveMsType0000() {
|
||||||
AbstractMsType type = pdb.getTypeRecord(RecordNumber.make(RecordCategory.TYPE, 0x0000));
|
AbstractMsType type = pdb.getTypeRecord(RecordNumber.typeRecordNumber(0x0000));
|
||||||
assertEquals(type instanceof PrimitiveMsType, true);
|
assertEquals(type instanceof PrimitiveMsType, true);
|
||||||
String result = type.toString().trim();
|
String result = type.toString().trim();
|
||||||
assertEquals("T_NOTYPE", result);
|
assertEquals("T_NOTYPE", result);
|
||||||
|
@ -155,7 +155,7 @@ public class TypesTest extends AbstractGenericTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPrimitiveMsType0110() {
|
public void testPrimitiveMsType0110() {
|
||||||
AbstractMsType type = pdb.getTypeRecord(RecordNumber.make(RecordCategory.TYPE, 0x0110));
|
AbstractMsType type = pdb.getTypeRecord(RecordNumber.typeRecordNumber(0x0110));
|
||||||
assertEquals(type instanceof PrimitiveMsType, true);
|
assertEquals(type instanceof PrimitiveMsType, true);
|
||||||
String result = type.toString().trim();
|
String result = type.toString().trim();
|
||||||
assertEquals("signed char near*", result);
|
assertEquals("signed char near*", result);
|
||||||
|
@ -1967,8 +1967,7 @@ public class TypesTest extends AbstractGenericTest {
|
||||||
PdbByteWriter writer = new PdbByteWriter();
|
PdbByteWriter writer = new PdbByteWriter();
|
||||||
writer.putUnsignedShort(OverloadedMethod16MsType.PDB_ID);
|
writer.putUnsignedShort(OverloadedMethod16MsType.PDB_ID);
|
||||||
int count = ((AbstractMethodListMsType) pdb
|
int count = ((AbstractMethodListMsType) pdb
|
||||||
.getTypeRecord(RecordNumber.make(RecordCategory.TYPE, methodList16MsType1)))
|
.getTypeRecord(RecordNumber.typeRecordNumber(methodList16MsType1))).getListSize();
|
||||||
.getListSize();
|
|
||||||
writer.putUnsignedShort(count);
|
writer.putUnsignedShort(count);
|
||||||
writer.putUnsignedShort(methodList16MsType1); // type index of MethodList16MsType
|
writer.putUnsignedShort(methodList16MsType1); // type index of MethodList16MsType
|
||||||
writer.putByteLengthPrefixedString("overloadedMethodName");
|
writer.putByteLengthPrefixedString("overloadedMethodName");
|
||||||
|
@ -1987,8 +1986,7 @@ public class TypesTest extends AbstractGenericTest {
|
||||||
PdbByteWriter writer = new PdbByteWriter();
|
PdbByteWriter writer = new PdbByteWriter();
|
||||||
writer.putUnsignedShort(OverloadedMethodStMsType.PDB_ID);
|
writer.putUnsignedShort(OverloadedMethodStMsType.PDB_ID);
|
||||||
int count = ((AbstractMethodListMsType) pdb
|
int count = ((AbstractMethodListMsType) pdb
|
||||||
.getTypeRecord(RecordNumber.make(RecordCategory.TYPE, methodList16MsType1)))
|
.getTypeRecord(RecordNumber.typeRecordNumber(methodList16MsType1))).getListSize();
|
||||||
.getListSize();
|
|
||||||
writer.putUnsignedShort(count);
|
writer.putUnsignedShort(count);
|
||||||
writer.putInt(methodListMsType1); // type index of MethodListMsType
|
writer.putInt(methodListMsType1); // type index of MethodListMsType
|
||||||
writer.putByteLengthPrefixedString("overloadedMethodName");
|
writer.putByteLengthPrefixedString("overloadedMethodName");
|
||||||
|
@ -2007,8 +2005,7 @@ public class TypesTest extends AbstractGenericTest {
|
||||||
PdbByteWriter writer = new PdbByteWriter();
|
PdbByteWriter writer = new PdbByteWriter();
|
||||||
writer.putUnsignedShort(OverloadedMethodMsType.PDB_ID);
|
writer.putUnsignedShort(OverloadedMethodMsType.PDB_ID);
|
||||||
int count = ((AbstractMethodListMsType) pdb
|
int count = ((AbstractMethodListMsType) pdb
|
||||||
.getTypeRecord(RecordNumber.make(RecordCategory.TYPE, methodList16MsType1)))
|
.getTypeRecord(RecordNumber.typeRecordNumber(methodList16MsType1))).getListSize();
|
||||||
.getListSize();
|
|
||||||
writer.putUnsignedShort(count);
|
writer.putUnsignedShort(count);
|
||||||
writer.putInt(methodListMsType1); // type index of MethodListMsType
|
writer.putInt(methodListMsType1); // type index of MethodListMsType
|
||||||
writer.putNullTerminatedString("overloadedMethodName");
|
writer.putNullTerminatedString("overloadedMethodName");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue