mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +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.
|
||||
//
|
||||
//@category Data Types
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
import javax.swing.text.View;
|
||||
|
||||
import docking.widgets.OptionDialog;
|
||||
import generic.text.TextLayoutGraphics;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.app.util.ToolTipUtils;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.Swing;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
public class DeveloperDumpAllTypesScript extends GhidraScript {
|
||||
|
@ -62,7 +69,7 @@ public class DeveloperDumpAllTypesScript extends GhidraScript {
|
|||
String pathString = dataTypePath.toString();
|
||||
String htmlString = ToolTipUtils.getToolTipText(dataType);
|
||||
String plainString = Swing.runNow(() -> {
|
||||
return HTMLUtilities.fromHTML(htmlString);
|
||||
return fromHTML(htmlString);
|
||||
});
|
||||
fileWriter.append(pathString);
|
||||
fileWriter.append("\n");
|
||||
|
@ -77,6 +84,100 @@ public class DeveloperDumpAllTypesScript extends GhidraScript {
|
|||
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() {
|
||||
PluginTool tool = state.getTool();
|
||||
DataTypeManagerService service = tool.getService(DataTypeManagerService.class);
|
||||
|
|
|
@ -934,7 +934,8 @@ public class DefaultCompositeMember extends CompositeMember {
|
|||
CompositeMember lastUnionMember = unionMemberList.get(unionMemberList.size() - 1);
|
||||
if (isRelatedBitField(lastUnionMember, member)) {
|
||||
if (lastUnionMember.isSingleBitFieldMember() &&
|
||||
!((DefaultCompositeMember) lastUnionMember).transformIntoStructureContainer()) {
|
||||
!((DefaultCompositeMember) lastUnionMember)
|
||||
.transformIntoStructureContainer()) {
|
||||
return false;
|
||||
}
|
||||
return lastUnionMember.addMember(member);
|
||||
|
|
|
@ -180,9 +180,6 @@ public class SymbolRecords {
|
|||
*/
|
||||
public int getCvSigLength(int streamNumber)
|
||||
throws CancelledException, IOException, PdbException {
|
||||
// if (cvSignatureCase1and2Stream == MsfStream.NIL_STREAM_NUMBER) {
|
||||
// throw new PdbException("CvSigLength not initialized");
|
||||
// }
|
||||
if (streamNumber == MsfStream.NIL_STREAM_NUMBER) {
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -32,6 +32,11 @@ public abstract class AbstractFieldListMsType extends AbstractMsType {
|
|||
private List<MsTypeField> baseClassList = new ArrayList<>();
|
||||
private List<MsTypeField> memberList = 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
|
||||
// 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
|
||||
|
@ -52,27 +57,34 @@ public abstract class AbstractFieldListMsType extends AbstractMsType {
|
|||
super(pdb, reader);
|
||||
while (reader.hasMore()) {
|
||||
MsTypeField type = TypeParser.parseField(pdb, reader);
|
||||
if ((type instanceof AbstractBaseClassMsType) ||
|
||||
(type instanceof AbstractVirtualBaseClassMsType) ||
|
||||
(type instanceof AbstractIndirectVirtualBaseClassMsType)) {
|
||||
if (type instanceof AbstractBaseClassMsType ||
|
||||
type instanceof AbstractVirtualBaseClassMsType ||
|
||||
type instanceof AbstractIndirectVirtualBaseClassMsType) {
|
||||
baseClassList.add(type);
|
||||
}
|
||||
else if ((type instanceof AbstractOverloadedMethodMsType) ||
|
||||
(type instanceof AbstractOneMethodMsType)) {
|
||||
else if (type instanceof AbstractOverloadedMethodMsType ||
|
||||
type instanceof AbstractOneMethodMsType) {
|
||||
methodList.add(type);
|
||||
}
|
||||
else if ((type instanceof AbstractMemberMsType) ||
|
||||
(type instanceof AbstractNestedTypeMsType) ||
|
||||
(type instanceof AbstractStaticMemberMsType) ||
|
||||
(type instanceof AbstractVirtualFunctionTablePointerMsType) ||
|
||||
(type instanceof AbstractEnumerateMsType)) {
|
||||
// Known types:
|
||||
// AbstractMemberMsType
|
||||
// AbstractNestedTypeMsType
|
||||
// AbstractStaticMemberMsType
|
||||
// AbstractVirtualFunctionTablePointerMsType
|
||||
// AbstractEnumerateMsType
|
||||
memberList.add(type);
|
||||
else if (type instanceof AbstractMemberMsType member) {
|
||||
nonstaticMemberList.add(member);
|
||||
memberList.add(member);
|
||||
}
|
||||
else if (type instanceof AbstractStaticMemberMsType member) {
|
||||
staticMemberList.add(member);
|
||||
memberList.add(member);
|
||||
}
|
||||
else if (type instanceof AbstractVirtualFunctionTablePointerMsType vftPtr) {
|
||||
vftPtrList.add(vftPtr);
|
||||
memberList.add(vftPtr);
|
||||
}
|
||||
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) {
|
||||
indexList.add((AbstractIndexMsType) type);
|
||||
|
@ -109,6 +121,42 @@ public abstract class AbstractFieldListMsType extends AbstractMsType {
|
|||
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
|
||||
* will contain the reference only to other {@link AbstractFieldListMsType}s.
|
||||
|
|
|
@ -59,7 +59,7 @@ public class BuildInfoMsType extends AbstractMsType {
|
|||
count = reader.parseUnsignedShortVal();
|
||||
for (int i = 0; i < count; i++) {
|
||||
int codeItemId = reader.parseInt();
|
||||
RecordNumber itemRecordNumber = RecordNumber.make(RecordCategory.ITEM, codeItemId);
|
||||
RecordNumber itemRecordNumber = RecordNumber.itemRecordNumber(codeItemId);
|
||||
argsCodeItemRecordNumbers.add(itemRecordNumber);
|
||||
}
|
||||
reader.skipPadding();
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.app.util.bin.format.pdb2.pdbreader.type;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractPdb;
|
||||
|
||||
/**
|
||||
|
@ -54,6 +56,11 @@ public class PrimitiveMsType extends AbstractMsType {
|
|||
builder.insert(0, typeString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getSize() {
|
||||
return BigInteger.valueOf(getTypeSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this primitive type.
|
||||
* @return Name type of the primitive type.
|
||||
|
|
|
@ -35,6 +35,7 @@ public class PdbCategories {
|
|||
private CategoryPath pdbUncategorizedCategory;
|
||||
private CategoryPath anonymousFunctionsCategory;
|
||||
private CategoryPath anonymousTypesCategory;
|
||||
private CategoryPath placeholderTypesCategory;
|
||||
private CategoryPath baseModuleTypedefsCategory;
|
||||
private List<CategoryPath> typedefCategories = new ArrayList<>();
|
||||
|
||||
|
@ -62,6 +63,8 @@ public class PdbCategories {
|
|||
// anonymousFunctionCount = 0;
|
||||
|
||||
anonymousTypesCategory = new CategoryPath(pdbRootCategory, "!_anon_types_");
|
||||
|
||||
placeholderTypesCategory = new CategoryPath(pdbRootCategory, "!_placeholder_types_");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -190,6 +193,14 @@ public class PdbCategories {
|
|||
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
|
||||
// * 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)) {
|
||||
return String.format("<unnamed-type_%08X>", index);
|
||||
}
|
||||
if ("__unnamed".equals(name)) {
|
||||
return String.format("__unnamed_%08X", index);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,100 +17,70 @@ package ghidra.app.util.pdb.pdbapplicator;
|
|||
|
||||
import ghidra.app.util.SymbolPath;
|
||||
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.type.AbstractComplexMsType;
|
||||
import ghidra.app.util.pdb.PdbNamespaceUtils;
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
||||
/**
|
||||
* Applier for {@link AbstractComplexMsType} types.
|
||||
*/
|
||||
public abstract class AbstractComplexTypeApplier extends MsTypeApplier {
|
||||
|
||||
protected SymbolPath symbolPath;
|
||||
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);
|
||||
}
|
||||
|
||||
// Intended for: AbstractComplexMsType
|
||||
/**
|
||||
* Constructor for complex type applier.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link AbstractComplexMsType} to process.
|
||||
*/
|
||||
public AbstractComplexTypeApplier(DefaultPdbApplicator applicator, AbstractComplexMsType msType) {
|
||||
super(applicator, msType);
|
||||
String fullPathName = msType.getName();
|
||||
symbolPath = new SymbolPath(SymbolPathParser.parse(fullPathName));
|
||||
public AbstractComplexTypeApplier(DefaultPdbApplicator applicator) {
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
boolean isNested() {
|
||||
return ((AbstractComplexMsType) msType).getMsProperty().isNestedClass();
|
||||
}
|
||||
|
||||
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;
|
||||
/**
|
||||
* 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 typeClass.cast(definitionApplier);
|
||||
return type.cast(mType);
|
||||
}
|
||||
|
||||
protected AbstractComplexTypeApplier getAlternativeTypeApplier() {
|
||||
if (isForwardReference()) {
|
||||
return definitionApplier;
|
||||
/**
|
||||
* 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 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;
|
||||
return PdbNamespaceUtils.convertToGhidraPathName(path, num);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,13 +15,14 @@
|
|||
*/
|
||||
package ghidra.app.util.pdb.pdbapplicator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.DataTypeNamingUtil;
|
||||
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.AbstractMsType;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.CallingConvention;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.FunctionDefinitionDataType;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
@ -31,211 +32,109 @@ import ghidra.util.exception.InvalidInputException;
|
|||
*/
|
||||
public abstract class AbstractFunctionTypeApplier extends MsTypeApplier {
|
||||
|
||||
private FunctionDefinitionDataType functionDefinition;
|
||||
|
||||
private MsTypeApplier returnApplier;
|
||||
private ArgumentsListTypeApplier argsListApplier;
|
||||
private CallingConvention callingConvention;
|
||||
private boolean hasThisPointer;
|
||||
|
||||
// Intended for: see children
|
||||
/**
|
||||
* Constructor for the applicator that applies a "function" type, transforming it into a
|
||||
* Ghidra DataType.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link AbstractMsType} to processes
|
||||
*/
|
||||
public AbstractFunctionTypeApplier(DefaultPdbApplicator applicator, AbstractMsType msType) {
|
||||
super(applicator, msType);
|
||||
// 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;
|
||||
public AbstractFunctionTypeApplier(DefaultPdbApplicator applicator) {
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link CallingConvention}
|
||||
* @param type the PDB type being inspected
|
||||
* @return the calling convention
|
||||
*/
|
||||
protected abstract CallingConvention getCallingConvention();
|
||||
protected abstract CallingConvention getCallingConvention(AbstractMsType type);
|
||||
|
||||
/**
|
||||
* Returns whether the function has a "this" pointer
|
||||
* @return {@code true} if it has a "this" pointer
|
||||
* Returns the function "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
|
||||
* @return the record number
|
||||
* Returns the containing class if function member of class
|
||||
* @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
|
||||
* @return the record number
|
||||
* Processes containing class if one exists
|
||||
* @param type the PDB type being inspected
|
||||
*/
|
||||
protected abstract RecordNumber getArgListRecordNumber();
|
||||
protected abstract void processContainingType(AbstractMsType type);
|
||||
|
||||
/**
|
||||
* Returns if known to be a constructor.
|
||||
* @param type the PDB type being inspected
|
||||
* @return true if constructor.
|
||||
*/
|
||||
protected boolean isConstructor() {
|
||||
protected boolean isConstructor(AbstractMsType type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create the {@link DataType} based upon the type indices of the calling
|
||||
* convention, return type, and arguments list.
|
||||
* @param callingConventionParam Identification of the {@link AbstractMsType} record of the
|
||||
* {@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
|
||||
* Returns the {@link RecordNumber} of the function return type
|
||||
* @param type the PDB type being inspected
|
||||
* @return the record number
|
||||
*/
|
||||
protected DataType applyFunction(CallingConvention callingConventionParam,
|
||||
boolean hasThisPointerParam) throws PdbException, CancelledException {
|
||||
// String funcName = applicator.getCategoryUtils().getNextAnonymousFunctionName();
|
||||
// FunctionDefinitionDataType functionDefinition = new FunctionDefinitionDataType(
|
||||
// applicator.getCategoryUtils().getAnonymousFunctionsCategory(), funcName,
|
||||
// applicator.getDataTypeManager());
|
||||
protected abstract RecordNumber getReturnRecordNumber(AbstractMsType type);
|
||||
|
||||
this.callingConvention = callingConventionParam;
|
||||
this.hasThisPointer = hasThisPointerParam;
|
||||
returnApplier = getReturnTypeApplier();
|
||||
argsListApplier = getArgsListApplier();
|
||||
/**
|
||||
* Returns the {@link RecordNumber} of the function arguments list
|
||||
* @param type the PDB type being inspected
|
||||
* @return the record number
|
||||
*/
|
||||
protected abstract RecordNumber getArgListRecordNumber(AbstractMsType type);
|
||||
|
||||
applyOrDeferForDependencies();
|
||||
// applyInternal();
|
||||
|
||||
// 20190725 remove for second pass in applicator
|
||||
// // 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()) {
|
||||
private boolean setReturnType(FunctionDefinitionDataType functionDefinition,
|
||||
AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws CancelledException, PdbException {
|
||||
if (isConstructor(type)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
DataType returnDataType = returnApplier.getDataType();
|
||||
if (returnDataType == null) {
|
||||
applicator.appendLogMsg("Return type is null in " + functionDefinition.getName());
|
||||
RecordNumber returnRecord = getReturnRecordNumber(type);
|
||||
if (returnRecord == null) {
|
||||
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;
|
||||
}
|
||||
|
||||
private void setCallingConvention(DefaultPdbApplicator applicator,
|
||||
CallingConvention callingConvention, boolean hasThisPointer) {
|
||||
private void setCallingConvention(FunctionDefinitionDataType functionDefinition,
|
||||
CallingConvention callingConvention, Pointer thisPointer) {
|
||||
String convention;
|
||||
if (hasThisPointer) {
|
||||
if (thisPointer != null) {
|
||||
convention = CompilerSpec.CALLING_CONVENTION_thiscall;
|
||||
}
|
||||
else {
|
||||
// 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) {
|
||||
// TODO: figure all of these out.
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
// applicator.getLog().appendMsg(
|
||||
// "TODO: calling convention not implemented for value " + callingConventionVal +
|
||||
// " in " + funcName);
|
||||
//convention = GenericCallingConvention.cdecl;
|
||||
convention = CompilerSpec.CALLING_CONVENTION_cdecl;
|
||||
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;
|
||||
|
||||
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.RecordNumber;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -30,196 +26,21 @@ import ghidra.util.exception.CancelledException;
|
|||
*/
|
||||
public class ArgumentsListTypeApplier extends MsTypeApplier {
|
||||
|
||||
// Intended for: AbstractArgumentsListMsType
|
||||
/**
|
||||
* Constructor for the applicator that applies a arguments list.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link AbstractArgumentsListMsType} to processes.
|
||||
* @throws IllegalArgumentException Upon invalid arguments.
|
||||
*/
|
||||
public ArgumentsListTypeApplier(DefaultPdbApplicator applicator,
|
||||
AbstractArgumentsListMsType msType) throws IllegalArgumentException {
|
||||
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.
|
||||
public ArgumentsListTypeApplier(DefaultPdbApplicator applicator) throws IllegalArgumentException {
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
BigInteger getSize() {
|
||||
return BigInteger.ZERO;
|
||||
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
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 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.AbstractMsType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
@ -28,107 +30,77 @@ import ghidra.util.exception.CancelledException;
|
|||
*/
|
||||
public class ArrayTypeApplier extends MsTypeApplier {
|
||||
|
||||
private MsTypeApplier underlyingTypeApplier = null;
|
||||
private boolean isFlexibleArray = false;
|
||||
|
||||
// Intended for: AbstractArrayMsType
|
||||
/**
|
||||
* Constructor for the applicator that applies a "array" type, transforming it into a
|
||||
* Ghidra DataType.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link AbstractArrayMsType} to processes.
|
||||
*/
|
||||
public ArrayTypeApplier(DefaultPdbApplicator applicator, AbstractArrayMsType msType) {
|
||||
super(applicator, msType);
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
boolean isFlexibleArray() {
|
||||
return isFlexibleArray;
|
||||
public ArrayTypeApplier(DefaultPdbApplicator applicator) {
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
void deferredApply() throws PdbException, CancelledException {
|
||||
// No work done here. Just deferring resolve.
|
||||
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws PdbException, CancelledException {
|
||||
return applyType((AbstractArrayMsType) type, fixupContext);
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
@Override
|
||||
BigInteger getSize() {
|
||||
return ((AbstractArrayMsType) msType).getSize();
|
||||
boolean isFlexibleArray(AbstractMsType type) {
|
||||
return BigInteger.ZERO.equals(type.getSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
void apply() throws PdbException, CancelledException {
|
||||
applyOrDeferForDependencies();
|
||||
}
|
||||
|
||||
private void applyOrDeferForDependencies() {
|
||||
AbstractArrayMsType type = (AbstractArrayMsType) msType;
|
||||
underlyingTypeApplier = applicator.getTypeApplier(type.getElementTypeRecordNumber());
|
||||
if (underlyingTypeApplier instanceof ModifierTypeApplier) {
|
||||
underlyingTypeApplier =
|
||||
((ModifierTypeApplier) underlyingTypeApplier).getModifiedTypeApplier();
|
||||
}
|
||||
underlyingTypeApplier = underlyingTypeApplier.getDependencyApplier();
|
||||
applyType(type); // applying now, but resolve() might get deferred.
|
||||
}
|
||||
|
||||
// private void recurseAddDependency(AbstractMsTypeApplier dependee)
|
||||
// throws CancelledException, PdbException {
|
||||
// if (dependee instanceof ModifierTypeApplier) {
|
||||
// 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) {
|
||||
if (isApplied()) {
|
||||
return;
|
||||
private DataType applyType(AbstractArrayMsType type, FixupContext fixupContext)
|
||||
throws CancelledException, PdbException {
|
||||
if (fixupContext != null) {
|
||||
DataType existingDt = applicator.getDataType(type);
|
||||
if (existingDt != null) {
|
||||
return existingDt;
|
||||
}
|
||||
}
|
||||
|
||||
long longUnderlyingSize =
|
||||
DefaultPdbApplicator.bigIntegerToLong(applicator, underlyingTypeApplier.getSize());
|
||||
DataType underlyingDataType = underlyingTypeApplier.getDataType();
|
||||
RecordNumber underlyingRecord = type.getElementTypeRecordNumber();
|
||||
DataType underlyingDataType =
|
||||
applicator.getProcessedDataType(underlyingRecord, fixupContext, false);
|
||||
|
||||
DataType dataType;
|
||||
if (applicator.isPlaceholderType(underlyingDataType)) {
|
||||
Long longArraySize = getSizeLong(type);
|
||||
int intArraySize = longArraySize.intValue();
|
||||
dataType =
|
||||
applicator.getPlaceholderArray(intArraySize, underlyingDataType.getAlignment());
|
||||
}
|
||||
else {
|
||||
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());
|
||||
}
|
||||
|
||||
DataType resolvedType = applicator.resolve(dataType);
|
||||
applicator.putDataType(type, resolvedType);
|
||||
return resolvedType;
|
||||
}
|
||||
|
||||
private int calculateNumElements(AbstractArrayMsType type, DataType underlyingDataType) {
|
||||
|
||||
if (underlyingDataType == null) {
|
||||
Long v = longUnderlyingSize;
|
||||
underlyingDataType = Undefined.getUndefinedDataType(v.intValue());
|
||||
String msg = "PDB Type index " + index + ":\n Null underlying data type for " +
|
||||
underlyingTypeApplier.getClass().getSimpleName() + ":\n " +
|
||||
underlyingTypeApplier + "\n Using " + underlyingDataType;
|
||||
// TODO: test and clean up... can this happen?
|
||||
underlyingDataType = Undefined1DataType.dataType;
|
||||
String msg = "PDB Type index " + type.getRecordNumber().getNumber() +
|
||||
":\n Null underlying data type for " + type.getClass().getSimpleName() +
|
||||
":\n " + type.getName() + "\n Using " + underlyingDataType;
|
||||
Msg.warn(this, msg);
|
||||
}
|
||||
|
||||
long longUnderlyingSize = underlyingDataType.getLength();
|
||||
|
||||
if (longUnderlyingSize > Integer.MAX_VALUE) {
|
||||
String msg = "PDB " + type.getClass().getSimpleName() + ": Underlying type too large " +
|
||||
underlyingDataType.getName();
|
||||
|
@ -137,14 +109,10 @@ public class ArrayTypeApplier extends MsTypeApplier {
|
|||
longUnderlyingSize = 1L;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
long longArraySize = getSizeLong();
|
||||
long longArraySize = getSizeLong(type);
|
||||
long longNumElements = longArraySize / longUnderlyingSize;
|
||||
|
||||
if (longNumElements > Integer.MAX_VALUE) {
|
||||
|
@ -163,31 +131,12 @@ public class ArrayTypeApplier extends MsTypeApplier {
|
|||
longUnderlyingSize;
|
||||
Msg.warn(this, msg);
|
||||
// bad calculation. Underlying type does not evenly fit into array total size.
|
||||
underlyingDataType = Undefined1DataType.dataType;
|
||||
longUnderlyingSize = 1L;
|
||||
longNumElements = longArraySize;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int numElements = (int) longNumElements;
|
||||
|
||||
ArrayDataType arrayDataType;
|
||||
|
||||
// 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;
|
||||
return numElements;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,11 +15,10 @@
|
|||
*/
|
||||
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.RecordNumber;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
/**
|
||||
|
@ -28,108 +27,38 @@ import ghidra.util.exception.CancelledException;
|
|||
*/
|
||||
public class BaseClassTypeApplier extends MsTypeApplier {
|
||||
|
||||
// Intended for: AbstractBaseClassMsType, AbstractVirtualBaseClassMsType, or
|
||||
// AbstractIndirectVirtualBaseClassMsType
|
||||
/**
|
||||
* Constructor for base class applier.
|
||||
* @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.
|
||||
*/
|
||||
public BaseClassTypeApplier(DefaultPdbApplicator applicator, AbstractMsType msType)
|
||||
public BaseClassTypeApplier(DefaultPdbApplicator applicator)
|
||||
throws IllegalArgumentException {
|
||||
super(applicator, validateType(msType));
|
||||
}
|
||||
|
||||
// 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;
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset of the Base Class within the inheriting class.
|
||||
* @return the offset.
|
||||
* @throws PdbException if field is not available.
|
||||
* Returns the record number of the base class
|
||||
* @param type the PDB type being inspected
|
||||
* @return the record number
|
||||
*/
|
||||
BigInteger getOffset() throws PdbException {
|
||||
if (msType instanceof AbstractBaseClassMsType) {
|
||||
return ((AbstractBaseClassMsType) msType).getOffset();
|
||||
RecordNumber getBaseClassRecordNumber(AbstractMsType type) {
|
||||
if (type instanceof AbstractBaseClassMsType baseType) {
|
||||
return baseType.getBaseClassRecordNumber();
|
||||
}
|
||||
throw new PdbException("Offset is not a valid field");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (type instanceof AbstractVirtualBaseClassMsType virtualType) {
|
||||
return virtualType.getBaseClassRecordNumber();
|
||||
}
|
||||
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");
|
||||
return ((AbstractIndirectVirtualBaseClassMsType) type).getBaseClassRecordNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
void apply() throws PdbException, CancelledException {
|
||||
// do nothing at the moment.
|
||||
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws PdbException, CancelledException {
|
||||
// do nothing
|
||||
return null;
|
||||
}
|
||||
|
||||
private static AbstractMsType validateType(AbstractMsType type)
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
*/
|
||||
package ghidra.app.util.pdb.pdbapplicator;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
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.RecordNumber;
|
||||
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.InvalidDataTypeException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
@ -28,63 +28,37 @@ import ghidra.util.exception.CancelledException;
|
|||
* Applier for {@link AbstractBitfieldMsType} types.
|
||||
*/
|
||||
public class BitfieldTypeApplier extends MsTypeApplier {
|
||||
private MsTypeApplier elementTypeApplier = null;
|
||||
|
||||
// Intended for: AbstractBitfieldMsType
|
||||
/**
|
||||
* Constructor for bitfield applier.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link AbstractBitfieldMsType} to processes
|
||||
*/
|
||||
public BitfieldTypeApplier(DefaultPdbApplicator applicator, AbstractBitfieldMsType msType) {
|
||||
super(applicator, msType);
|
||||
public BitfieldTypeApplier(DefaultPdbApplicator applicator) {
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
BigInteger getSize() {
|
||||
if (elementTypeApplier == null) {
|
||||
return BigInteger.ZERO;
|
||||
}
|
||||
return elementTypeApplier.getSize();
|
||||
}
|
||||
|
||||
@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;
|
||||
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws PdbException, CancelledException {
|
||||
AbstractBitfieldMsType mType = (AbstractBitfieldMsType) type;
|
||||
RecordNumber elementRecordNumber = mType.getElementRecordNumber();
|
||||
DataType baseDataType =
|
||||
applicator.getProcessedDataType(elementRecordNumber, fixupContext, breakCycle);
|
||||
DataType bitFieldDataType;
|
||||
try {
|
||||
bitFieldDataType = new Pdb2BitField(baseDataType.clone(applicator.getDataTypeManager()),
|
||||
type.getBitLength(), type.getBitPosition());
|
||||
mType.getBitLength(), mType.getBitPosition());
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
applicator.appendLogMsg(
|
||||
"Problem creating PdbBitField for " + type.getName() + ", error: " + e.toString());
|
||||
return null;
|
||||
}
|
||||
// do not resolve bit-fields!
|
||||
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.
|
||||
* This will be transformed to a normal BitFieldDataType when cloned.
|
||||
|
|
|
@ -29,19 +29,6 @@ public class 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.
|
||||
/**
|
||||
* 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
|
||||
* managed byte the applier
|
||||
* @param applier the applier
|
||||
* @param name the name of the type for the DataTypePath
|
||||
* @return the DataTypePath
|
||||
* Returns an "internals" CategoryPath for the owning composite datatype
|
||||
* @param categoryPath path of the composite
|
||||
* @return the CategoryPath
|
||||
*/
|
||||
public static DataTypePath getInternalsDataTypePath(CompositeTypeApplier applier, String name) {
|
||||
CategoryPath cp = getInternalsCategoryPath(applier);
|
||||
if (cp == null || StringUtils.isAllBlank(name)) {
|
||||
return null;
|
||||
}
|
||||
return new DataTypePath(cp, name);
|
||||
public static CategoryPath getInternalsCategoryPath(CategoryPath categoryPath) {
|
||||
return categoryPath.extend(INTERNALS);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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
|
||||
// have to parse it again to see if it is a fwdref or def.
|
||||
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,
|
||||
// and another definition is found in the input stream, then the FIFO starts storing
|
||||
// definitions instead.
|
||||
// Specifically using LinkedList in Map, as not all Queues are appropriate
|
||||
// (e.g., PriorityQueue).
|
||||
Map<SymbolPath, LinkedList<NumFwdRef>> compositeFIFOsByPath = new HashMap<>();
|
||||
Map<SymbolPath, LinkedList<NumFwdRef>> enumFIFOsByPath = new HashMap<>();
|
||||
// All we need for the Deque is a simple FIFO.
|
||||
Map<SymbolPath, Deque<NumFwdRef>> compositeFIFOsByPath = new HashMap<>();
|
||||
Map<SymbolPath, Deque<NumFwdRef>> enumFIFOsByPath = new HashMap<>();
|
||||
|
||||
// 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).
|
||||
|
@ -134,15 +126,15 @@ public class ComplexTypeMapper {
|
|||
|
||||
// Always mapping higher index to lower index, as we are assuming we will processing indices
|
||||
// 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) {
|
||||
|
||||
SymbolPath symbolPath = new SymbolPath(SymbolPathParser.parse(complexType.getName()));
|
||||
boolean isFwdRef = complexType.getMsProperty().isForwardReference();
|
||||
|
||||
LinkedList<NumFwdRef> numTypeFIFO = typeFIFOsByPath.get(symbolPath);
|
||||
Deque<NumFwdRef> numTypeFIFO = typeFIFOsByPath.get(symbolPath);
|
||||
if (numTypeFIFO == null) {
|
||||
numTypeFIFO = new LinkedList<>();
|
||||
numTypeFIFO = new ArrayDeque<>();
|
||||
typeFIFOsByPath.put(symbolPath, numTypeFIFO);
|
||||
|
||||
// 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 {
|
||||
if (applyToApplier instanceof FunctionSymbolApplier) {
|
||||
FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applyToApplier;
|
||||
MsTypeApplier applier = getTypeApplier();
|
||||
DataType dataType = applier.getDataType();
|
||||
DataType dataType = applicator.getCompletedDataType(symbol.getTypeRecordNumber());
|
||||
if (dataType == null) { // TODO: check that we can have null here.
|
||||
return; // silently return.
|
||||
}
|
||||
Address address = applicator.getAddress(symbol);
|
||||
if (!createData(address, applier)) {
|
||||
if (!createData(address, dataType)) {
|
||||
return;
|
||||
}
|
||||
functionSymbolApplier.setLocalVariable(address, symbol.getName(), dataType);
|
||||
|
@ -82,29 +81,16 @@ public class DataSymbolApplier extends MsSymbolApplier {
|
|||
return applicator.getTypeApplier(symbol.getTypeRecordNumber());
|
||||
}
|
||||
|
||||
boolean createData(Address address, RecordNumber typeRecordNumber) {
|
||||
MsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber);
|
||||
if (applier == null) {
|
||||
applicator.appendLogMsg("Error: Failed to resolve datatype RecordNumber " +
|
||||
typeRecordNumber + " at " + address);
|
||||
return false;
|
||||
}
|
||||
return createData(address, applier);
|
||||
boolean createData(Address address, RecordNumber typeRecordNumber)
|
||||
throws CancelledException, PdbException {
|
||||
DataType dataType = applicator.getCompletedDataType(symbol.getTypeRecordNumber());
|
||||
return createData(address, dataType);
|
||||
}
|
||||
|
||||
boolean createData(Address address, MsTypeApplier applier) {
|
||||
boolean createData(Address address, DataType dataType) {
|
||||
if (applicator.isInvalidAddress(address, symbol.getName())) {
|
||||
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) &&
|
||||
!"_IMAGE_DOS_HEADER".equals(dataType.getName())) {
|
||||
return false; // Squash some noise
|
||||
|
@ -170,13 +156,11 @@ public class DataSymbolApplier extends MsSymbolApplier {
|
|||
try {
|
||||
applicator.getProgram()
|
||||
.getListing()
|
||||
.clearCodeUnits(address,
|
||||
address.add(dataTypeLength - 1), false);
|
||||
.clearCodeUnits(address, address.add(dataTypeLength - 1), false);
|
||||
if (dataType.getLength() == -1) {
|
||||
applicator.getProgram()
|
||||
.getListing()
|
||||
.createData(address, dataType,
|
||||
dataTypeLength);
|
||||
.createData(address, dataType, dataTypeLength);
|
||||
}
|
||||
else {
|
||||
applicator.getProgram().getListing().createData(address, dataType);
|
||||
|
@ -191,8 +175,7 @@ public class DataSymbolApplier extends MsSymbolApplier {
|
|||
try {
|
||||
applicator.getProgram()
|
||||
.getListing()
|
||||
.clearCodeUnits(address,
|
||||
address.add(dataTypeLength - 1), false);
|
||||
.clearCodeUnits(address, address.add(dataTypeLength - 1), false);
|
||||
applicator.getProgram().getListing().createData(address, dataType, dataTypeLength);
|
||||
}
|
||||
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.pdb.PdbCategories;
|
||||
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.model.address.Address;
|
||||
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
|
||||
* @param myApplicator PdbApplicator for which we are working
|
||||
* @param big BigInteger value to convert
|
||||
* @return the integer value
|
||||
*/
|
||||
static long bigIntegerToLong(DefaultPdbApplicator myApplicator, BigInteger big) {
|
||||
long bigIntegerToLong(BigInteger big) {
|
||||
try {
|
||||
return big.longValueExact();
|
||||
}
|
||||
catch (ArithmeticException e) {
|
||||
String msg = "BigInteger value greater than max Long: " + big;
|
||||
PdbLog.message(msg);
|
||||
myApplicator.appendLogMsg(msg);
|
||||
appendLogMsg(msg);
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @return the integer value
|
||||
*/
|
||||
static int bigIntegerToInt(DefaultPdbApplicator myApplicator, BigInteger big) {
|
||||
int bigIntegerToInt(BigInteger big) {
|
||||
try {
|
||||
return big.intValueExact();
|
||||
}
|
||||
catch (ArithmeticException e) {
|
||||
String msg = "BigInteger value greater than max Integer: " + big;
|
||||
PdbLog.message(msg);
|
||||
myApplicator.appendLogMsg(msg);
|
||||
appendLogMsg(msg);
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
@ -146,9 +141,10 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
|||
private PdbCategories categoryUtils;
|
||||
private PdbPrimitiveTypeApplicator pdbPrimitiveTypeApplicator;
|
||||
private TypeApplierFactory typeApplierParser;
|
||||
private Map<Integer, Long> dataTypeIdByMsTypeNum;
|
||||
private Map<Integer, DataTypeImpl> dataTypeImplByMsTypeNum;
|
||||
private Map<Integer, CppCompositeType> classTypeByMsTypeNum;
|
||||
private ComplexTypeMapper complexTypeMapper;
|
||||
private ComplexTypeApplierMapper complexApplierMapper;
|
||||
private JungDirectedGraph<MsTypeApplier, GEdge<MsTypeApplier>> applierDependencyGraph;
|
||||
/**
|
||||
* This namespace map documents as follows:
|
||||
* <PRE>
|
||||
|
@ -252,30 +248,39 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
|||
*/
|
||||
private void disassembleFunctions() throws CancelledException {
|
||||
|
||||
TaskMonitor monitor = getMonitor();
|
||||
Listing listing = program.getListing();
|
||||
DisassemblerContextImpl seedContext =
|
||||
new DisassemblerContextImpl(program.getProgramContext());
|
||||
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)) {
|
||||
cancelOnlyWrappingMonitor.checkCancelled();
|
||||
monitor.checkCancelled();
|
||||
address = PseudoDisassembler.setTargetContextForDisassembly(seedContext, address);
|
||||
Function myFunction = listing.getFunctionAt(address);
|
||||
// If no function or not a full function, add it to set for disassembly.
|
||||
if (myFunction == null || myFunction.getBody().getNumAddresses() <= 1) {
|
||||
revisedSet.add(address);
|
||||
}
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
// 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);
|
||||
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)) {
|
||||
cancelOnlyWrappingMonitor.checkCancelled();
|
||||
monitor.checkCancelled();
|
||||
Function function = listing.getFunctionAt(address);
|
||||
if (function != null) {
|
||||
CreateFunctionCmd.fixupFunctionBody(program, function, cancelOnlyWrappingMonitor);
|
||||
}
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,10 +311,7 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
|||
// PdbResearch.studyCompositeFwdRefDef(pdb, monitor);
|
||||
// PdbResearch.study1(pdb, monitor);
|
||||
|
||||
// complexApplierMapper.mapAppliers(monitor);
|
||||
|
||||
complexTypeMapper.mapTypes(this);
|
||||
complexApplierMapper.mapAppliers(complexTypeMapper, monitor);
|
||||
|
||||
processSequentially();
|
||||
|
||||
|
@ -317,10 +319,6 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
|||
|
||||
// PdbResearch.developerDebugOrder(this, monitor);
|
||||
|
||||
processDeferred();
|
||||
|
||||
resolveSequentially();
|
||||
|
||||
Msg.info(this, "resolveCount: " + resolveCount);
|
||||
|
||||
// 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);
|
||||
|
||||
categoryUtils = setPdbCatogoryUtils(pdb.getFilename());
|
||||
initializePlaceholders();
|
||||
pdbPrimitiveTypeApplicator = new PdbPrimitiveTypeApplicator(dataTypeManager);
|
||||
typeApplierParser = new TypeApplierFactory(this);
|
||||
dataTypeIdByMsTypeNum = new HashMap<>();
|
||||
dataTypeImplByMsTypeNum = new HashMap<>();
|
||||
classTypeByMsTypeNum = new HashMap<>();
|
||||
complexTypeMapper = new ComplexTypeMapper();
|
||||
complexApplierMapper = new ComplexTypeApplierMapper(this);
|
||||
applierDependencyGraph = new JungDirectedGraph<>();
|
||||
typeApplierParser = new TypeApplierFactory(this);
|
||||
isClassByNamespace = new TreeMap<>();
|
||||
|
||||
symbolApplierParser = new SymbolApplierFactory(this);
|
||||
|
@ -672,6 +672,14 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
|||
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
|
||||
// * 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,
|
||||
Class<? extends MsTypeApplier> expected) throws PdbException {
|
||||
return typeApplierParser.getApplierOrNoTypeSpec(recordNumber, expected);
|
||||
|
@ -762,6 +734,342 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
|||
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();
|
||||
if (tpi == null) {
|
||||
return;
|
||||
|
@ -795,12 +1103,99 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
|||
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.apply();
|
||||
processAndResolve(indexNumber);
|
||||
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
|
||||
.getTypeIndexMaxExclusive(); indexNumber++) {
|
||||
monitor.checkCancelled();
|
||||
MsTypeApplier applier = getTypeApplier(RecordNumber.itemRecordNumber(indexNumber));
|
||||
applier.apply();
|
||||
RecordNumber recordNumber = RecordNumber.itemRecordNumber(indexNumber);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
private void processSequentially() throws CancelledException, PdbException {
|
||||
processDataTypesSequentially();
|
||||
processAndResolveDataTypesSequentially();
|
||||
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) {
|
||||
if (!(dataType instanceof DataTypeImpl)) {
|
||||
return dataType;
|
||||
}
|
||||
DataType resolved = getDataTypeManager().resolve(dataType,
|
||||
DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER);
|
||||
resolveCount++;
|
||||
|
@ -1700,6 +2059,7 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
|||
log.appendMsg(
|
||||
"PDB Warning: Because parent namespace does not exist, failed to define " +
|
||||
type + ": " + path);
|
||||
monitor.incrementProgress(1);
|
||||
continue;
|
||||
}
|
||||
defineNamespace(parentNamespace, path.getName(), isClass);
|
||||
|
|
|
@ -15,9 +15,8 @@
|
|||
*/
|
||||
package ghidra.app.util.pdb.pdbapplicator;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import ghidra.app.util.bin.format.pdb.*;
|
||||
import ghidra.app.util.pdb.pdbapplicator.CppCompositeType.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
|
@ -27,67 +26,57 @@ import ghidra.util.exception.CancelledException;
|
|||
*/
|
||||
public class DefaultPdbUniversalMember extends PdbMember {
|
||||
|
||||
private MsTypeApplier applier;
|
||||
private DataType dataType;
|
||||
private ClassFieldAttributes attributes;
|
||||
private boolean isZeroLengthArray;
|
||||
|
||||
private static final ClassFieldAttributes blankAtttributes =
|
||||
new ClassFieldAttributes(Access.BLANK, Property.BLANK);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* and optionally the bit-offset.
|
||||
* @param dataType for the field.
|
||||
* @param offset member's byte offset within the root composite.
|
||||
*/
|
||||
DefaultPdbUniversalMember(DefaultPdbApplicator applicator, String name, DataType dataType,
|
||||
int offset) {
|
||||
DefaultPdbUniversalMember(String name, DataType dataType, int offset) {
|
||||
super(name, dataType.getName(), offset, null);
|
||||
this.applier = null;
|
||||
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() {
|
||||
if (applier != null) {
|
||||
return applier.getDataType();
|
||||
}
|
||||
return dataType;
|
||||
}
|
||||
|
||||
public boolean isZeroLengthArray() {
|
||||
return isZeroLengthArray;
|
||||
}
|
||||
|
||||
public ClassFieldAttributes getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDataTypeName() {
|
||||
return getDataTypeInternal().getName();
|
||||
|
@ -123,12 +112,7 @@ public class DefaultPdbUniversalMember extends PdbMember {
|
|||
@Override
|
||||
protected WrappedDataType getDataType() throws CancelledException {
|
||||
DataType dt = getDataTypeInternal();
|
||||
if (applier != null && applier instanceof ArrayTypeApplier) {
|
||||
if (BigInteger.ZERO.compareTo(applier.getSize()) == 0) {
|
||||
return new WrappedDataType(dt, true, false);
|
||||
}
|
||||
}
|
||||
return new WrappedDataType(dt, false, false);
|
||||
return new WrappedDataType(dt, isZeroLengthArray, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,14 +15,13 @@
|
|||
*/
|
||||
package ghidra.app.util.pdb.pdbapplicator;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.SymbolPath;
|
||||
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.MsProperty;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
|
@ -31,33 +30,19 @@ import ghidra.util.exception.CancelledException;
|
|||
*/
|
||||
public class EnumTypeApplier extends AbstractComplexTypeApplier {
|
||||
|
||||
//private AbstractMsTypeApplier underlyingApplier = null;
|
||||
|
||||
// private int length = 0;
|
||||
// private boolean isSigned = false;
|
||||
//
|
||||
|
||||
// Intended for: AbstractEnumMsType
|
||||
/**
|
||||
* Constructor for enum type applier, for transforming a enum into a
|
||||
* Ghidra DataType.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link AbstractEnumMsType} to process.
|
||||
*/
|
||||
public EnumTypeApplier(DefaultPdbApplicator applicator, AbstractEnumMsType msType) {
|
||||
super(applicator, msType);
|
||||
public EnumTypeApplier(DefaultPdbApplicator applicator) {
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
BigInteger getSize() {
|
||||
MsTypeApplier underlyingApplier = getUnderlyingTypeApplier();
|
||||
if (underlyingApplier == null) {
|
||||
return BigInteger.ZERO;
|
||||
}
|
||||
return underlyingApplier.getSize();
|
||||
}
|
||||
|
||||
private long getMask() {
|
||||
switch (getLength()) {
|
||||
private long getMask(AbstractEnumMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws CancelledException, PdbException {
|
||||
switch (getLength(type, fixupContext, breakCycle)) {
|
||||
case 1:
|
||||
return 0xffL;
|
||||
case 2:
|
||||
|
@ -69,25 +54,24 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier {
|
|||
}
|
||||
}
|
||||
|
||||
private int getLength() {
|
||||
// Minimum length allowed by Ghidra is 1 for enum, so all returns are min 1.
|
||||
MsTypeApplier underlyingApplier = getUnderlyingTypeApplier();
|
||||
if (underlyingApplier == null) {
|
||||
private int getLength(AbstractEnumMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws CancelledException, PdbException {
|
||||
DataType underlyingDataType = getUnderlyingDataType(type, fixupContext, breakCycle);
|
||||
if (underlyingDataType == null) {
|
||||
return 1;
|
||||
}
|
||||
DataType underlyingType = underlyingApplier.getDataType();
|
||||
if (underlyingType == null) {
|
||||
return 1;
|
||||
}
|
||||
return Integer.max(underlyingType.getLength(), 1);
|
||||
return Integer.max(underlyingDataType.getLength(), 1);
|
||||
}
|
||||
|
||||
boolean isSigned() {
|
||||
MsTypeApplier underlyingApplier = getUnderlyingTypeApplier();
|
||||
if (underlyingApplier == null) {
|
||||
return false;
|
||||
}
|
||||
DataType underlyingType = underlyingApplier.getDataType();
|
||||
private DataType getUnderlyingDataType(AbstractEnumMsType type, FixupContext fixupContext,
|
||||
boolean breakCycle) throws CancelledException, PdbException {
|
||||
RecordNumber underlyingRecordNumber = type.getUnderlyingRecordNumber();
|
||||
return applicator.getProcessedDataType(underlyingRecordNumber, fixupContext, breakCycle);
|
||||
}
|
||||
|
||||
boolean isSigned(AbstractEnumMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws CancelledException, PdbException {
|
||||
DataType underlyingType = getUnderlyingDataType(type, fixupContext, breakCycle);
|
||||
if (underlyingType == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -97,205 +81,85 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
EnumTypeApplier getDependencyApplier() {
|
||||
if (definitionApplier != null && definitionApplier instanceof EnumTypeApplier) {
|
||||
return (EnumTypeApplier) definitionApplier;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
private EnumDataType createEmptyEnum(AbstractEnumMsType type, FixupContext fixupContext,
|
||||
boolean breakCycle) throws CancelledException, PdbException {
|
||||
|
||||
String getName() {
|
||||
return getMsType().getName();
|
||||
}
|
||||
AbstractEnumMsType defType = getDefinitionType(type);
|
||||
|
||||
@Override
|
||||
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();
|
||||
SymbolPath fixedPath = getFixedSymbolPath(defType);
|
||||
CategoryPath categoryPath = applicator.getCategory(fixedPath.getParent());
|
||||
|
||||
// MsProperty property = type.getMsProperty();
|
||||
// if (property.isForwardReference()) {
|
||||
// // 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());
|
||||
EnumDataType enumDataType = new EnumDataType(categoryPath, fixedPath.getName(),
|
||||
getLength(defType, fixupContext, breakCycle), applicator.getDataTypeManager());
|
||||
|
||||
return enumDataType;
|
||||
}
|
||||
|
||||
@Override
|
||||
void apply() throws PdbException, CancelledException {
|
||||
getOrCreateEnum();
|
||||
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
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;
|
||||
MsProperty property = type.getMsProperty();
|
||||
if (property.isForwardReference()) {
|
||||
return;
|
||||
}
|
||||
|
||||
applyEnumMsType((AbstractEnumMsType) msType);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void resolve() {
|
||||
if (!isForwardReference()) {
|
||||
super.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
// Mapping of fwdRef/def must be done prior to this call.
|
||||
private void getOrCreateEnum() {
|
||||
AbstractEnumMsType neededType = (AbstractEnumMsType) msType;
|
||||
if (dataType != null) {
|
||||
return;
|
||||
}
|
||||
if (isForwardReference()) {
|
||||
if (definitionApplier != null) {
|
||||
dataType = definitionApplier.getDataTypeInternal();
|
||||
if (dataType != null) {
|
||||
return;
|
||||
}
|
||||
neededType = (AbstractEnumMsType) definitionApplier.getMsType();
|
||||
DataType existingDt = applicator.getDataType(mapped);
|
||||
if (existingDt != null) {
|
||||
if (!(existingDt instanceof Enum)) {
|
||||
throw new PdbException("PDB error retrieving Enum type");
|
||||
}
|
||||
return existingDt;
|
||||
}
|
||||
else {
|
||||
if (forwardReferenceApplier != null) {
|
||||
dataType = forwardReferenceApplier.getDataTypeInternal();
|
||||
if (dataType != null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
dataType = createEmptyEnum(neededType);
|
||||
|
||||
EnumDataType enumDataType = createEmptyEnum(definedEnum, fixupContext, breakCycle);
|
||||
applyEnumMsType(enumDataType, definedEnum, fixupContext, breakCycle);
|
||||
|
||||
DataType dataType = applicator.resolve(enumDataType);
|
||||
applicator.putDataType(mapped, dataType);
|
||||
return dataType;
|
||||
}
|
||||
|
||||
private EnumDataType applyEnumMsType(AbstractEnumMsType type) throws PdbException {
|
||||
private EnumDataType applyEnumMsType(EnumDataType enumDataType, AbstractEnumMsType type,
|
||||
FixupContext fixupContext, boolean breakCycle) throws PdbException, CancelledException {
|
||||
|
||||
if (enumDataType.getCount() != 0) {
|
||||
//already applied
|
||||
return enumDataType;
|
||||
}
|
||||
|
||||
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();
|
||||
FieldListTypeApplier fieldListApplier =
|
||||
FieldListTypeApplier.getFieldListApplierSpecial(applicator, fieldListRecordNumber);
|
||||
|
||||
FieldListTypeApplier.FieldLists lists =
|
||||
fieldListApplier.getFieldLists(fieldListRecordNumber);
|
||||
|
||||
// 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();
|
||||
if (memberList.size() != numElements) {
|
||||
if (enumerates.size() != numElements) {
|
||||
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;
|
||||
}
|
||||
|
||||
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()) {
|
||||
Msg.info(this, "Non-integral numeric found: " + numeric);
|
||||
return 0;
|
||||
|
@ -304,9 +168,11 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier {
|
|||
pdbLogAndInfoMessage(this, "Using zero in place of non-integral enumerate: " + numeric);
|
||||
return 0L; //
|
||||
}
|
||||
return numeric.getIntegral().longValue() & getMask();
|
||||
// return NarrowingConverter.narrowBigToLong(outputSize, outputSigned, numeric.getSize(),
|
||||
// numeric.isSigned(), numeric.getIntegral());
|
||||
return numeric.getIntegral().longValue() & getMask(type, fixupContext, breakCycle);
|
||||
}
|
||||
|
||||
private AbstractEnumMsType getDefinitionType(AbstractComplexMsType type) {
|
||||
return getDefinitionType(type, AbstractEnumMsType.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,64 +15,58 @@
|
|||
*/
|
||||
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.PdbException;
|
||||
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.program.model.data.DataType;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
/**
|
||||
* Applier for {@link AbstractEnumerateMsType} types.
|
||||
*/
|
||||
public class EnumerateTypeApplier extends MsTypeApplier {
|
||||
|
||||
private String fieldName;
|
||||
private Numeric numeric;
|
||||
|
||||
// Intended for: AbstractEnumerateMsType
|
||||
/**
|
||||
* Constructor for enumerate type applier, for transforming a enumerate into a
|
||||
* Ghidra DataType.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link AbstractEnumerateMsType} to process.
|
||||
*/
|
||||
public EnumerateTypeApplier(DefaultPdbApplicator applicator, AbstractEnumerateMsType msType) {
|
||||
super(applicator, msType);
|
||||
public EnumerateTypeApplier(DefaultPdbApplicator applicator) {
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
BigInteger getSize() {
|
||||
return BigInteger.ZERO;
|
||||
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws PdbException, CancelledException {
|
||||
DataType dataType = applyEnumerateMsType((AbstractEnumerateMsType) type);
|
||||
//dataType is null for now... so no resolve
|
||||
//return applicator.resolve(dataType);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
void apply() {
|
||||
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(AbstractEnumerateMsType type) {
|
||||
return PdbNamespaceUtils.fixUnnamed(type.getName(), type.getRecordNumber().getNumber());
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
Numeric getNumeric() {
|
||||
return numeric;
|
||||
Numeric getNumeric(AbstractEnumerateMsType type) {
|
||||
return type.getNumeric();
|
||||
}
|
||||
|
||||
private DataType applyEnumerateMsType(AbstractEnumerateMsType type) {
|
||||
|
||||
//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 see if can do real number; need to modify Numeric for both
|
||||
// integral and real numbers. Possibly need to make Numeric a "type" instead
|
||||
// of just something to read using ByteReader.
|
||||
numeric = type.getNumeric();
|
||||
Numeric numeric = type.getNumeric();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
*/
|
||||
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.*;
|
||||
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.program.model.data.DataType;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
@ -30,148 +30,102 @@ import ghidra.util.exception.CancelledException;
|
|||
*/
|
||||
public class FieldListTypeApplier extends MsTypeApplier {
|
||||
|
||||
private List<MsTypeApplier> baseClassList = new ArrayList<>();
|
||||
private List<MsTypeApplier> memberList = new ArrayList<>();
|
||||
private List<MsTypeApplier> methodList = new ArrayList<>();
|
||||
private boolean isEmpty;
|
||||
|
||||
//TODO: evaluate the static method and multiple constructors... what can be cleaned up with
|
||||
// regard to these and the possible NoType record???
|
||||
static FieldListTypeApplier getFieldListApplierSpecial(DefaultPdbApplicator applicator,
|
||||
RecordNumber recordNumber) throws PdbException {
|
||||
MsTypeApplier applier =
|
||||
applicator.getApplierOrNoTypeSpec(recordNumber, FieldListTypeApplier.class);
|
||||
if (recordNumber.isNoType()) {
|
||||
// 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) {
|
||||
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");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @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.
|
||||
*/
|
||||
public FieldListTypeApplier(DefaultPdbApplicator applicator, AbstractMsType msType)
|
||||
throws IllegalArgumentException {
|
||||
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;
|
||||
public FieldListTypeApplier(DefaultPdbApplicator applicator) throws IllegalArgumentException {
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
BigInteger getSize() {
|
||||
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)
|
||||
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
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 =
|
||||
applicator.getTypeApplier(indexType.getReferencedRecordNumber());
|
||||
if (referencedTypeApplier instanceof FieldListTypeApplier) {
|
||||
FieldListTypeApplier subApplier = (FieldListTypeApplier) referencedTypeApplier;
|
||||
baseClassList.addAll(subApplier.getBaseClassList());
|
||||
memberList.addAll(subApplier.getMemberList());
|
||||
methodList.addAll(subApplier.getMethodList());
|
||||
if (referencedTypeApplier instanceof FieldListTypeApplier fieldListApplier) {
|
||||
FieldListTypeApplier.FieldLists lists =
|
||||
fieldListApplier.getFieldLists(subRecordNumber);
|
||||
bases.addAll(lists.bases());
|
||||
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 {
|
||||
pdbLogAndInfoMessage(this, "referenceTypeApplier is not FieldListTypeApplier");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void applyBaseClasses(List<MsTypeField> baseClasses)
|
||||
throws CancelledException, PdbException {
|
||||
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);
|
||||
}
|
||||
return new FieldLists(bases, members, nonstaticMembers, vftPtrs, methods, nestedTypes,
|
||||
enumerates);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.util.bin.format.pdb2.pdbreader.*;
|
||||
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.AddressSet;
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
@ -86,8 +87,8 @@ public class FunctionSymbolApplier extends MsSymbolApplier
|
|||
procedureSymbol = (AbstractProcedureStartIa64MsSymbol) abstractSymbol;
|
||||
specifiedAddress = applicator.getRawAddress(procedureSymbol);
|
||||
address = applicator.getAddress(procedureSymbol);
|
||||
isNonReturning = ((AbstractProcedureStartIa64MsSymbol) procedureSymbol).getFlags()
|
||||
.doesNotReturn();
|
||||
isNonReturning =
|
||||
((AbstractProcedureStartIa64MsSymbol) procedureSymbol).getFlags().doesNotReturn();
|
||||
}
|
||||
else if (abstractSymbol instanceof AbstractProcedureStartMipsMsSymbol) {
|
||||
procedureSymbol = (AbstractProcedureStartMipsMsSymbol) abstractSymbol;
|
||||
|
@ -260,7 +261,7 @@ public class FunctionSymbolApplier extends MsSymbolApplier
|
|||
applicator.createSymbol(varAddress, varName, true, plateAddition);
|
||||
}
|
||||
|
||||
private boolean applyFunction(TaskMonitor monitor) {
|
||||
private boolean applyFunction(TaskMonitor monitor) throws CancelledException, PdbException {
|
||||
function = applicator.getExistingOrCreateOneByteFunction(address);
|
||||
if (function == null) {
|
||||
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
|
||||
* @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) {
|
||||
// TODO: is there anything we can do with thunkSymbol?
|
||||
// long x = thunkSymbol.getParentPointer();
|
||||
|
@ -298,21 +302,16 @@ public class FunctionSymbolApplier extends MsSymbolApplier
|
|||
// Rest presumes procedureSymbol.
|
||||
RecordNumber typeRecordNumber = procedureSymbol.getTypeRecordNumber();
|
||||
MsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber);
|
||||
if (applier == null) {
|
||||
applicator.appendLogMsg("Error: Failed to resolve datatype RecordNumber " +
|
||||
typeRecordNumber + " at " + address);
|
||||
return false;
|
||||
}
|
||||
AbstractMsType fType = applicator.getPdb().getTypeRecord(typeRecordNumber);
|
||||
if (!(applier instanceof AbstractFunctionTypeApplier)) {
|
||||
if (!((applier instanceof PrimitiveTypeApplier) &&
|
||||
((PrimitiveTypeApplier) applier).isNoType())) {
|
||||
if (!((applier instanceof PrimitiveTypeApplier prim) && prim.isNoType(fType))) {
|
||||
applicator.appendLogMsg("Error: Failed to resolve datatype RecordNumber " +
|
||||
typeRecordNumber + " at " + address);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DataType dataType = applier.getDataType();
|
||||
DataType dataType = applicator.getCompletedDataType(typeRecordNumber);
|
||||
// Since we know the applier is an AbstractionFunctionTypeApplier, then dataType is either
|
||||
// FunctionDefinition or no type (typedef).
|
||||
if (!(dataType instanceof FunctionDefinition)) {
|
||||
|
|
|
@ -15,14 +15,11 @@
|
|||
*/
|
||||
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.RecordNumber;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMemberFunctionMsType;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.CallingConvention;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
/**
|
||||
|
@ -30,238 +27,105 @@ import ghidra.util.exception.CancelledException;
|
|||
*/
|
||||
public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier {
|
||||
|
||||
private MsTypeApplier thisPointerApplier = null;
|
||||
|
||||
// Intended for: AbstractMemberFunctionMsType
|
||||
/**
|
||||
* Constructor for the applicator that applies {@link AbstractMemberFunctionMsType},
|
||||
* transforming it into a Ghidra {@link DataType}.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link AbstractMemberFunctionMsType} to processes.
|
||||
* @throws IllegalArgumentException Upon type mismatch.
|
||||
*/
|
||||
public MemberFunctionTypeApplier(DefaultPdbApplicator applicator,
|
||||
AbstractMemberFunctionMsType msType) throws IllegalArgumentException {
|
||||
super(applicator, msType);
|
||||
public MemberFunctionTypeApplier(DefaultPdbApplicator applicator)
|
||||
throws IllegalArgumentException {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
private MsTypeApplier getThisUnderlyingApplier(PointerTypeApplier thisApplier) {
|
||||
return thisApplier.getUnmodifiedUnderlyingTypeApplier();
|
||||
@Override
|
||||
protected CallingConvention getCallingConvention(AbstractMsType type) {
|
||||
return ((AbstractMemberFunctionMsType) type).getCallingConvention();
|
||||
}
|
||||
|
||||
private AbstractComplexTypeApplier getContainingComplexApplier(
|
||||
AbstractMemberFunctionMsType procType) throws PdbException {
|
||||
return AbstractComplexTypeApplier.getComplexApplier(applicator,
|
||||
procType.getContainingClassRecordNumber());
|
||||
@Override
|
||||
protected Pointer getThisPointer(AbstractMsType type, FixupContext fixupContext,
|
||||
boolean breakCycle) throws CancelledException, PdbException {
|
||||
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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
// }
|
||||
@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 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;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
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.ClassFieldMsAttributes;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
|
@ -28,60 +26,19 @@ import ghidra.util.exception.CancelledException;
|
|||
*/
|
||||
public class MemberTypeApplier extends MsTypeApplier {
|
||||
|
||||
// Intended for: AbstractMemberMsType
|
||||
/**
|
||||
* Constructor for member type applier.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link AbstractMemberMsType} to process.
|
||||
*/
|
||||
public MemberTypeApplier(DefaultPdbApplicator applicator, AbstractMemberMsType msType) {
|
||||
super(applicator, msType);
|
||||
public MemberTypeApplier(DefaultPdbApplicator applicator) {
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
BigInteger getSize() {
|
||||
return BigInteger.ZERO;
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws PdbException, CancelledException {
|
||||
// do nothing
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
*/
|
||||
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.RecordNumber;
|
||||
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.util.exception.CancelledException;
|
||||
|
||||
|
@ -27,84 +27,59 @@ import ghidra.util.exception.CancelledException;
|
|||
*/
|
||||
public class ModifierTypeApplier extends MsTypeApplier {
|
||||
|
||||
private MsTypeApplier modifiedTypeApplier = null;
|
||||
|
||||
// Intended for: AbstractModifierMsType
|
||||
/**
|
||||
* Constructor for modifier type applier.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link AbstractModifierMsType} to processes.
|
||||
*/
|
||||
public ModifierTypeApplier(DefaultPdbApplicator applicator, AbstractModifierMsType msType) {
|
||||
super(applicator, msType);
|
||||
public ModifierTypeApplier(DefaultPdbApplicator applicator) {
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
@Override
|
||||
void deferredApply() throws PdbException, CancelledException {
|
||||
// Do nothing. Already applied. Just needs late resolve
|
||||
RecordNumber getUnderlyingNonModifierRecordNumber(RecordNumber underlyingRecord) {
|
||||
return getUnderlyingNonModifierRecordNumber(applicator, underlyingRecord);
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
@Override
|
||||
BigInteger getSize() {
|
||||
if (modifiedTypeApplier == null) {
|
||||
return BigInteger.ZERO;
|
||||
static RecordNumber getUnderlyingNonModifierRecordNumber(DefaultPdbApplicator applicator,
|
||||
RecordNumber underlyingRecord) {
|
||||
AbstractMsType underlyingType = applicator.getPdb().getTypeRecord(underlyingRecord);
|
||||
while (underlyingType instanceof AbstractModifierMsType modifierType) {
|
||||
RecordNumber modifiedRecord = modifierType.getModifiedRecordNumber();
|
||||
underlyingType = applicator.getPdb().getTypeRecord(modifiedRecord);
|
||||
}
|
||||
return modifiedTypeApplier.getSize();
|
||||
return underlyingType.getRecordNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
void apply() throws PdbException, CancelledException {
|
||||
// dataType = applyModifierMsType((AbstractModifierMsType) msType);
|
||||
applyOrDeferForDependencies();
|
||||
}
|
||||
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws PdbException, CancelledException {
|
||||
AbstractModifierMsType modifierType = (AbstractModifierMsType) type;
|
||||
RecordNumber modifiedRecord = modifierType.getModifiedRecordNumber();
|
||||
|
||||
private void applyOrDeferForDependencies() {
|
||||
AbstractModifierMsType type = (AbstractModifierMsType) msType;
|
||||
applyModifierMsType(type);
|
||||
MsTypeApplier modifiedApplier = applicator.getTypeApplier(type.getModifiedRecordNumber());
|
||||
if (modifiedApplier.isDeferred()) {
|
||||
applicator.addApplierDependency(this, modifiedApplier);
|
||||
setDeferred();
|
||||
DataType modifiedType =
|
||||
applicator.getProcessedDataType(modifiedRecord, fixupContext, false);
|
||||
|
||||
// If Ghidra eventually has a modified type (const, volatile) in its model, then we can
|
||||
// perform the applicator.getDataType(modifierType) here, and the
|
||||
// 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);
|
||||
}
|
||||
else {
|
||||
// applyModifierMsType(type);
|
||||
// defer(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
DataType getDataType() {
|
||||
return modifiedTypeApplier.getDataType();
|
||||
}
|
||||
|
||||
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;
|
||||
return modifiedType;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,57 +15,34 @@
|
|||
*/
|
||||
package ghidra.app.util.pdb.pdbapplicator;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
|
||||
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.PdbLog;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
/**
|
||||
* Abstract class representing the applier for a specific {@link AbstractMsType}. The
|
||||
* {@link #apply()} method creates an associated {@link DataType}, if applicable.
|
||||
* Abstract class representing the applier for a specific PDB_ID type. The
|
||||
* {@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
|
||||
* 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 {
|
||||
|
||||
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.
|
||||
* @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.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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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 CancelledException upon user cancellation
|
||||
*/
|
||||
abstract void apply() throws PdbException, CancelledException;
|
||||
|
||||
/**
|
||||
* Returns the size of the type or 0 if unknown.
|
||||
* @return the size; zero if unknown.
|
||||
*/
|
||||
abstract BigInteger getSize();
|
||||
abstract DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws PdbException, CancelledException;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
long getSizeLong() {
|
||||
return DefaultPdbApplicator.bigIntegerToLong(applicator, getSize());
|
||||
long getSizeLong(AbstractMsType type) {
|
||||
return applicator.bigIntegerToLong(type.getSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
int getSizeInt() {
|
||||
return DefaultPdbApplicator.bigIntegerToInt(applicator, getSize());
|
||||
int getSizeInt(AbstractMsType type) {
|
||||
return applicator.bigIntegerToInt(type.getSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
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);
|
||||
}
|
||||
//==============================================================================================
|
||||
// TODO: Need to investigate if we adopt the following... if so, should use them consistently.
|
||||
|
||||
// /**
|
||||
// * 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;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
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.*;
|
||||
|
@ -28,136 +26,50 @@ import ghidra.util.exception.CancelledException;
|
|||
*/
|
||||
public class NestedTypeApplier extends MsTypeApplier {
|
||||
|
||||
private MsTypeApplier nestedTypeDefinitionApplier = null;
|
||||
|
||||
// Intended for: AbstractNestedTypeMsType or AbstractNestedTypeExtMsType
|
||||
/**
|
||||
* Constructor for nested type applier
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working
|
||||
* @param msType {@link AbstractNestedTypeMsType} or {@link AbstractNestedTypeExtMsType} to
|
||||
* process
|
||||
* @throws IllegalArgumentException upon invalid arguments
|
||||
*/
|
||||
public NestedTypeApplier(DefaultPdbApplicator applicator, AbstractMsType msType)
|
||||
public NestedTypeApplier(DefaultPdbApplicator applicator)
|
||||
throws IllegalArgumentException {
|
||||
super(applicator, validateType(msType));
|
||||
}
|
||||
|
||||
@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();
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nested (member?) name for this nested type
|
||||
* @param type the PDB type being inspected
|
||||
* @return (member?) name for the nested type
|
||||
*/
|
||||
String getMemberName() {
|
||||
if (nestedTypeDefinitionApplier == null) {
|
||||
return "";
|
||||
}
|
||||
if (msType instanceof AbstractNestedTypeMsType) {
|
||||
return ((AbstractNestedTypeMsType) msType).getName();
|
||||
}
|
||||
return ((AbstractNestedTypeExtMsType) msType).getName();
|
||||
}
|
||||
String getMemberName(AbstractMsType type) {
|
||||
|
||||
MsTypeApplier getNestedTypeDefinitionApplier() {
|
||||
return applicator.getTypeApplier(getNestedTypeDefinitionRecordNumber());
|
||||
}
|
||||
|
||||
RecordNumber getNestedTypeDefinitionRecordNumber() {
|
||||
if (msType instanceof AbstractNestedTypeMsType) {
|
||||
return ((AbstractNestedTypeMsType) msType).getNestedTypeDefinitionRecordNumber();
|
||||
if (type instanceof AbstractNestedTypeMsType nested) {
|
||||
return nested.getName();
|
||||
}
|
||||
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;
|
||||
else if (type instanceof AbstractNestedTypeExtMsType nestedExt) {
|
||||
return nestedExt.getName();
|
||||
}
|
||||
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;
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
void apply() throws PdbException, CancelledException {
|
||||
if (msType instanceof AbstractNestedTypeMsType) {
|
||||
dataType = applyNestedTypeMsType((AbstractNestedTypeMsType) msType);
|
||||
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws PdbException, CancelledException {
|
||||
RecordNumber typeRecordNumber;
|
||||
if (type instanceof AbstractNestedTypeMsType nestedType) {
|
||||
typeRecordNumber = nestedType.getNestedTypeDefinitionRecordNumber();
|
||||
}
|
||||
else if (type instanceof AbstractNestedTypeExtMsType extNestedType) {
|
||||
typeRecordNumber = extNestedType.getNestedTypeDefinitionRecordNumber();
|
||||
}
|
||||
else {
|
||||
dataType = applyNestedTypeExtMsType((AbstractNestedTypeExtMsType) msType);
|
||||
throw new PdbException(
|
||||
"Unexpected nested type in field list: " + type.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
private DataType applyNestedTypeMsType(AbstractNestedTypeMsType type) {
|
||||
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;
|
||||
AbstractMsType mType = applicator.getPdb().getTypeRecord(typeRecordNumber);
|
||||
MsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber);
|
||||
return applier.apply(mType, fixupContext, breakCycle);
|
||||
}
|
||||
|
||||
private static AbstractMsType validateType(AbstractMsType type)
|
||||
|
@ -169,5 +81,4 @@ public class NestedTypeApplier extends MsTypeApplier {
|
|||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
*/
|
||||
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.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
|
||||
|
@ -25,26 +26,21 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
|||
*/
|
||||
public class NoTypeApplier extends MsTypeApplier {
|
||||
|
||||
// Intended for: AbstractMsType
|
||||
/**
|
||||
* Constructor for nested type applier.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link AbstractMsType} to process.
|
||||
* @throws IllegalArgumentException Upon invalid arguments.
|
||||
*/
|
||||
public NoTypeApplier(DefaultPdbApplicator applicator, AbstractMsType msType)
|
||||
public NoTypeApplier(DefaultPdbApplicator applicator)
|
||||
throws IllegalArgumentException {
|
||||
super(applicator, msType);
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
BigInteger getSize() {
|
||||
return BigInteger.ZERO;
|
||||
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
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.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.listing.Program;
|
||||
import ghidra.util.Msg;
|
||||
|
@ -167,36 +167,43 @@ public class PdbApplicatorMetrics {
|
|||
|
||||
/**
|
||||
* 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.
|
||||
if (applier instanceof PointerTypeApplier) {
|
||||
if (type == null) {
|
||||
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.
|
||||
* @param applier The {@AbstractMsTypeApplier} for the supposed this pointer.
|
||||
* @param type the {@AbstractMsType} for the supposed this pointer
|
||||
*/
|
||||
void witnessMemberFunctionThisPointerUnderlyingType(MsTypeApplier applier) {
|
||||
if (applier instanceof CompositeTypeApplier) {
|
||||
void witnessMemberFunctionThisPointerUnderlyingType(AbstractMsType type) {
|
||||
if (type == null || type instanceof AbstractCompositeMsType) {
|
||||
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.
|
||||
* @param applier The {@AbstractMsTypeApplier} for the supposed this pointer.
|
||||
* Method to capture unusual containing types for a member function
|
||||
* @param type the {@AbstractMsType} for the supposed this container
|
||||
*/
|
||||
void witnessMemberFunctionContainingType(MsTypeApplier applier) {
|
||||
if (applier instanceof CompositeTypeApplier) {
|
||||
void witnessMemberFunctionContainingType(AbstractMsType type) {
|
||||
if (type == null || type instanceof AbstractCompositeMsType) {
|
||||
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() {
|
||||
|
@ -401,9 +378,10 @@ public class PdbResearch {
|
|||
for (int indexNumber : developerDebugOrderIndexNumbers) {
|
||||
monitor.checkCancelled();
|
||||
PdbResearch.checkBreak(indexNumber);
|
||||
MsTypeApplier applier =
|
||||
applicator.getTypeApplier(RecordNumber.typeRecordNumber(indexNumber));
|
||||
applier.apply();
|
||||
FixupContext fixupContext = new FixupContext();
|
||||
fixupContext.addStagedRecord(indexNumber);
|
||||
applicator.getProcessedDataType(RecordNumber.typeRecordNumber(indexNumber),
|
||||
fixupContext, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -448,10 +426,10 @@ public class PdbResearch {
|
|||
MsSymbolApplier applier = applicator.getSymbolApplier(iter);
|
||||
if (applier instanceof TypedefSymbolApplier) {
|
||||
TypedefSymbolApplier typedefApplier = (TypedefSymbolApplier) applier;
|
||||
MsTypeApplier typeApplier =
|
||||
applicator.getTypeApplier(typedefApplier.getTypeRecordNumber());
|
||||
System.out.println("UDT " + typedefApplier.getName() + " depends on " +
|
||||
typeApplier.getMsType().toString());
|
||||
RecordNumber typeNumber = typedefApplier.getTypeRecordNumber();
|
||||
AbstractMsType type = applicator.getPdb().getTypeRecord(typeNumber);
|
||||
System.out
|
||||
.println("UDT " + typedefApplier.getName() + " depends on " + type.toString());
|
||||
// applier.apply();
|
||||
// procSym(symbolGroup);
|
||||
}
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
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.RecordNumber;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||
|
@ -28,124 +27,143 @@ import ghidra.util.exception.CancelledException;
|
|||
*/
|
||||
public class PointerTypeApplier extends MsTypeApplier {
|
||||
|
||||
private String memberComment = null;
|
||||
|
||||
// Intended for: AbstractPointerMsType
|
||||
/**
|
||||
* Constructor for pointer type applier, for transforming a enum into a
|
||||
* Ghidra DataType.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link AbstractPointerMsType} to process
|
||||
* @throws IllegalArgumentException Upon invalid arguments.
|
||||
*/
|
||||
public PointerTypeApplier(DefaultPdbApplicator applicator, AbstractPointerMsType msType)
|
||||
public PointerTypeApplier(DefaultPdbApplicator applicator)
|
||||
throws IllegalArgumentException {
|
||||
super(applicator, msType);
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
* @throws CancelledException upon user cancellation
|
||||
* @throws PdbException upon processing error
|
||||
*/
|
||||
String getPointerCommentField() {
|
||||
return memberComment;
|
||||
String getPointerCommentField(AbstractPointerMsType type, FixupContext fixupContext)
|
||||
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
|
||||
BigInteger getSize() {
|
||||
return ((AbstractPointerMsType) msType).getSize();
|
||||
}
|
||||
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws PdbException, CancelledException {
|
||||
|
||||
@Override
|
||||
void apply() throws PdbException, CancelledException {
|
||||
if (msType instanceof DummyMsType) {
|
||||
DataType dataType;
|
||||
if (fixupContext != null) {
|
||||
// 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());
|
||||
}
|
||||
else {
|
||||
dataType = applyAbstractPointerMsType((AbstractPointerMsType) msType);
|
||||
dataType = applyAbstractPointerMsType((AbstractPointerMsType) type, fixupContext);
|
||||
}
|
||||
dataType = applicator.resolve(dataType);
|
||||
applicator.putDataType(type, dataType);
|
||||
return dataType;
|
||||
}
|
||||
|
||||
@Override
|
||||
void resolve() {
|
||||
// Do not resolve pointer types... will be resolved naturally, as needed
|
||||
private DataType getUnderlyingType(AbstractPointerMsType type, FixupContext fixupContext)
|
||||
throws CancelledException, PdbException {
|
||||
RecordNumber underlyingRecord = type.getUnderlyingRecordNumber();
|
||||
return applicator.getProcessedDataType(underlyingRecord, fixupContext, true);
|
||||
}
|
||||
|
||||
MsTypeApplier getUnmodifiedUnderlyingTypeApplier() {
|
||||
MsTypeApplier thisUnderlyingTypeApplier =
|
||||
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) {
|
||||
private DataType applyAbstractPointerMsType(AbstractPointerMsType type,
|
||||
FixupContext fixupContext) throws CancelledException, PdbException {
|
||||
|
||||
AbstractPointerMsType.PointerMode pointerMode = type.getPointerMode();
|
||||
if (pointerMode == AbstractPointerMsType.PointerMode.MEMBER_DATA_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) {
|
||||
DataType underlyingType = getUnderlyingType(type);
|
||||
int size = type.getSize().intValueExact();
|
||||
RecordNumber memberPointerContainingClassRecordNumber =
|
||||
type.getMemberPointerContainingClassRecordNumber();
|
||||
MsTypeApplier containingClassApplier =
|
||||
applicator.getTypeApplier(memberPointerContainingClassRecordNumber);
|
||||
private DataType processMemberPointer(AbstractPointerMsType type, FixupContext fixupContext)
|
||||
throws CancelledException, PdbException {
|
||||
|
||||
// future use
|
||||
DataType underlyingType = getUnderlyingType(type, fixupContext);
|
||||
int size = type.getSize().intValueExact();
|
||||
|
||||
DataType dt = null;
|
||||
String name;
|
||||
AbstractPointerMsType.PointerMode pointerMode = type.getPointerMode();
|
||||
if (pointerMode == AbstractPointerMsType.PointerMode.MEMBER_FUNCTION_POINTER) {
|
||||
name = String.format("pmf_%08x", type.toString().hashCode());
|
||||
memberComment = "\"::*\" (pmf) to type: " + underlyingType;
|
||||
}
|
||||
else {
|
||||
name = String.format("pdm_%08x", type.toString().hashCode());
|
||||
memberComment = "\"::*\" (pdm) to type: " + underlyingType;
|
||||
}
|
||||
|
||||
if (containingClassApplier instanceof CompositeTypeApplier cta) {
|
||||
DataTypePath dtp = ClassTypeUtils.getInternalsDataTypePath(cta, name);
|
||||
if (dtp != null) {
|
||||
dt = applicator.getDataTypeManager().getDataType(dtp);
|
||||
if (dt == null) {
|
||||
dt = new StructureDataType(dtp.getCategoryPath(), dtp.getDataTypeName(), size);
|
||||
dt.setDescription(type.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dt == null) {
|
||||
dt = Undefined.getUndefinedDataType(size);
|
||||
}
|
||||
return dt;
|
||||
RecordNumber containingClassRecordNumber =
|
||||
type.getMemberPointerContainingClassRecordNumber();
|
||||
CategoryPath storagePath = getCategoryPathForMemberPointer(containingClassRecordNumber);
|
||||
DataType dt = new StructureDataType(storagePath, name, size);
|
||||
dt.setDescription(type.toString());
|
||||
|
||||
return applicator.resolve(dt);
|
||||
}
|
||||
|
||||
private DataType processPointer(AbstractPointerMsType type) {
|
||||
memberComment = null;
|
||||
DataType underlyingType = getUnderlyingType(type);
|
||||
private CategoryPath getCategoryPathForMemberPointer(RecordNumber containingClassRecordNumber) {
|
||||
AbstractMsType containingType =
|
||||
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();
|
||||
if (size == applicator.getDataOrganization().getPointerSize()) {
|
||||
size = -1; // Use default
|
||||
}
|
||||
if (underlyingType == null || applicator.isPlaceholderType(underlyingType)) {
|
||||
return applicator.getPlaceholderPointer(size);
|
||||
}
|
||||
return new PointerDataType(underlyingType, size, applicator.getDataTypeManager());
|
||||
}
|
||||
|
||||
|
|
|
@ -15,39 +15,35 @@
|
|||
*/
|
||||
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.program.model.data.DataType;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
/**
|
||||
* Applier for {@link PrimitiveMsType} types.
|
||||
*/
|
||||
public class PrimitiveTypeApplier extends MsTypeApplier {
|
||||
|
||||
// Intended for: PrimitiveMsType
|
||||
/**
|
||||
* Constructor for primitive type applier, for transforming a primitive into a
|
||||
* Ghidra DataType.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link PrimitiveMsType} to process.
|
||||
*/
|
||||
public PrimitiveTypeApplier(DefaultPdbApplicator applicator, PrimitiveMsType msType) {
|
||||
super(applicator, msType);
|
||||
apply(); // Only apply in constructor for primitives
|
||||
public PrimitiveTypeApplier(DefaultPdbApplicator applicator) {
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
BigInteger getSize() {
|
||||
return BigInteger.valueOf(((PrimitiveMsType) msType).getTypeSize());
|
||||
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws PdbException, CancelledException {
|
||||
return applyPrimitiveMsType((PrimitiveMsType) type);
|
||||
}
|
||||
|
||||
@Override
|
||||
void apply() {
|
||||
dataType = applyPrimitiveMsType((PrimitiveMsType) msType);
|
||||
}
|
||||
|
||||
boolean isNoType() {
|
||||
return (((PrimitiveMsType) msType).getNumber() == 0);
|
||||
boolean isNoType(AbstractMsType type) {
|
||||
return (((PrimitiveMsType) type).getNumber() == 0);
|
||||
}
|
||||
|
||||
private DataType applyPrimitiveMsType(PrimitiveMsType type) {
|
||||
|
@ -62,9 +58,15 @@ public class PrimitiveTypeApplier extends MsTypeApplier {
|
|||
// return dataType.clone(applicatorDataTypeManager);
|
||||
// }
|
||||
|
||||
int indexNumber = type.getNumber();
|
||||
DataType existingDt = applicator.getDataType(indexNumber);
|
||||
if (existingDt != null) {
|
||||
return existingDt;
|
||||
}
|
||||
|
||||
PdbPrimitiveTypeApplicator primitiveApplicator = applicator.getPdbPrimitiveTypeApplicator();
|
||||
|
||||
switch (type.getNumber()) {
|
||||
switch (indexNumber) {
|
||||
//=======================================
|
||||
// Special types
|
||||
//=======================================
|
||||
|
@ -2060,6 +2062,9 @@ public class PrimitiveTypeApplier extends MsTypeApplier {
|
|||
|
||||
}
|
||||
|
||||
primitiveDataType = applicator.resolve(primitiveDataType);
|
||||
applicator.putDataType(indexNumber, primitiveDataType);
|
||||
|
||||
return primitiveDataType;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,13 +15,10 @@
|
|||
*/
|
||||
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.RecordNumber;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractProcedureMsType;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.CallingConvention;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
/**
|
||||
|
@ -29,53 +26,47 @@ import ghidra.util.exception.CancelledException;
|
|||
*/
|
||||
public class ProcedureTypeApplier extends AbstractFunctionTypeApplier {
|
||||
|
||||
// Intended for: AbstractProcedureMsType
|
||||
/**
|
||||
* Constructor for the applicator that applies {@link AbstractProcedureMsType},
|
||||
* transforming it into a Ghidra {@link DataType}.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link AbstractProcedureMsType} to processes.
|
||||
* @throws IllegalArgumentException Upon invalid arguments.
|
||||
*/
|
||||
public ProcedureTypeApplier(DefaultPdbApplicator applicator, AbstractProcedureMsType msType)
|
||||
throws IllegalArgumentException {
|
||||
super(applicator, msType);
|
||||
public ProcedureTypeApplier(DefaultPdbApplicator applicator) throws IllegalArgumentException {
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
BigInteger getSize() {
|
||||
return BigInteger.ZERO;
|
||||
protected CallingConvention getCallingConvention(AbstractMsType type) {
|
||||
return ((AbstractProcedureMsType) type).getCallingConvention();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CallingConvention getCallingConvention() {
|
||||
return ((AbstractProcedureMsType) msType).getCallingConvention();
|
||||
protected Pointer getThisPointer(AbstractMsType type, FixupContext fixupContext,
|
||||
boolean breakCycle) throws CancelledException, PdbException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasThisPointer() {
|
||||
return false;
|
||||
protected Composite getContainingComplexApplier(AbstractMsType type, FixupContext fixupContext,
|
||||
boolean breakCycle) throws CancelledException, PdbException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RecordNumber getReturnRecordNumber() {
|
||||
return ((AbstractProcedureMsType) msType).getReturnRecordNumber();
|
||||
protected void processContainingType(AbstractMsType type) {
|
||||
return; // do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RecordNumber getArgListRecordNumber() {
|
||||
return ((AbstractProcedureMsType) msType).getArgListRecordNumber();
|
||||
protected RecordNumber getReturnRecordNumber(AbstractMsType type) {
|
||||
return ((AbstractProcedureMsType) type).getReturnRecordNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
void apply() throws PdbException, CancelledException {
|
||||
applyFunction(getCallingConvention(), hasThisPointer());
|
||||
|
||||
// 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);
|
||||
protected RecordNumber getArgListRecordNumber(AbstractMsType type) {
|
||||
return ((AbstractProcedureMsType) type).getArgListRecordNumber();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.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.AbstractRegisterRelativeAddressMsSymbol;
|
||||
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");
|
||||
Function function = applier.getFunction();
|
||||
|
||||
|
@ -105,8 +107,8 @@ public class RegisterRelativeSymbolApplier extends MsSymbolApplier {
|
|||
// }
|
||||
int offset = (int) (relativeOffset & 0xffffffffL);
|
||||
|
||||
MsTypeApplier dataTypeApplier = applicator.getTypeApplier(symbol.getTypeRecordNumber());
|
||||
DataType dt = dataTypeApplier.getDataType();
|
||||
RecordNumber typeRecord = symbol.getTypeRecordNumber();
|
||||
DataType dt = applicator.getCompletedDataType(typeRecord);
|
||||
if (dt != null) {
|
||||
// Variable m16 = stackFrame.getVariableContaining(-16);
|
||||
// Variable m8 = stackFrame.getVariableContaining(-8);
|
||||
|
|
|
@ -30,11 +30,11 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
|||
public class TypeApplierFactory {
|
||||
|
||||
private DefaultPdbApplicator applicator;
|
||||
private Map<RecordNumber, MsTypeApplier> appliersByRecordNumber;
|
||||
private Map<Integer, MsTypeApplier> appliersByPdbId;
|
||||
|
||||
TypeApplierFactory(DefaultPdbApplicator applicator) {
|
||||
this.applicator = applicator;
|
||||
appliersByRecordNumber = new HashMap<>();
|
||||
appliersByPdbId = new HashMap<>();
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
|
@ -51,9 +51,10 @@ public class TypeApplierFactory {
|
|||
MsTypeApplier getApplierOrNoTypeSpec(RecordNumber recordNumber,
|
||||
Class<? extends MsTypeApplier> expected) throws PdbException {
|
||||
MsTypeApplier applier = getTypeApplier(recordNumber);
|
||||
AbstractMsType type = applicator.getPdb().getTypeRecord(recordNumber);
|
||||
if (!expected.isInstance(applier)) {
|
||||
if (!(applier instanceof PrimitiveTypeApplier &&
|
||||
((PrimitiveTypeApplier) applier).isNoType())) {
|
||||
((PrimitiveTypeApplier) applier).isNoType(type))) {
|
||||
throw new PdbException(applier.getClass().getSimpleName() + " seen where " +
|
||||
expected.getSimpleName() + " expected for record number " + recordNumber);
|
||||
}
|
||||
|
@ -62,12 +63,7 @@ public class TypeApplierFactory {
|
|||
}
|
||||
|
||||
MsTypeApplier getTypeApplier(RecordNumber recordNumber) {
|
||||
MsTypeApplier applier = appliersByRecordNumber.get(recordNumber);
|
||||
if (applier == null) {
|
||||
applier = getTypeApplier(applicator.getPdb().getTypeRecord(recordNumber));
|
||||
appliersByRecordNumber.put(recordNumber, applier);
|
||||
}
|
||||
return applier;
|
||||
return getTypeApplier(applicator.getPdb().getTypeRecord(recordNumber));
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
|
@ -76,44 +72,61 @@ public class TypeApplierFactory {
|
|||
applicator.appendLogMsg("PDB Warning: No AbstractMsType for getTypeApplier");
|
||||
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 {
|
||||
switch (type.getPdbId()) {
|
||||
switch (pdbId) {
|
||||
case -1: // must be careful, as we chose the -1 for PrimitiveMsType
|
||||
applier = new PrimitiveTypeApplier(applicator, (PrimitiveMsType) type);
|
||||
applier = new PrimitiveTypeApplier(applicator);
|
||||
break;
|
||||
|
||||
// 0x0000 block
|
||||
case Modifier16MsType.PDB_ID:
|
||||
applier = new ModifierTypeApplier(applicator, (Modifier16MsType) type);
|
||||
applier = new ModifierTypeApplier(applicator);
|
||||
break;
|
||||
case Pointer16MsType.PDB_ID:
|
||||
applier = new PointerTypeApplier(applicator, (Pointer16MsType) type);
|
||||
applier = new PointerTypeApplier(applicator);
|
||||
break;
|
||||
case Array16MsType.PDB_ID:
|
||||
applier = new ArrayTypeApplier(applicator, (Array16MsType) type);
|
||||
applier = new ArrayTypeApplier(applicator);
|
||||
break;
|
||||
case Class16MsType.PDB_ID:
|
||||
applier = new CompositeTypeApplier(applicator, (Class16MsType) type);
|
||||
applier = new CompositeTypeApplier(applicator);
|
||||
break;
|
||||
case Structure16MsType.PDB_ID:
|
||||
applier = new CompositeTypeApplier(applicator, (Structure16MsType) type);
|
||||
applier = new CompositeTypeApplier(applicator);
|
||||
break;
|
||||
case Union16MsType.PDB_ID:
|
||||
applier = new CompositeTypeApplier(applicator, (Union16MsType) type);
|
||||
applier = new CompositeTypeApplier(applicator);
|
||||
break;
|
||||
case Enum16MsType.PDB_ID:
|
||||
applier = new EnumTypeApplier(applicator, (Enum16MsType) type);
|
||||
applier = new EnumTypeApplier(applicator);
|
||||
break;
|
||||
case Procedure16MsType.PDB_ID:
|
||||
applier = new ProcedureTypeApplier(applicator, (Procedure16MsType) type);
|
||||
applier = new ProcedureTypeApplier(applicator);
|
||||
break;
|
||||
case MemberFunction16MsType.PDB_ID:
|
||||
applier =
|
||||
new MemberFunctionTypeApplier(applicator, (MemberFunction16MsType) type);
|
||||
applier = new MemberFunctionTypeApplier(applicator);
|
||||
break;
|
||||
case VtShapeMsType.PDB_ID:
|
||||
applier = new VtShapeTypeApplier(applicator, (VtShapeMsType) type);
|
||||
applier = new VtShapeTypeApplier(applicator);
|
||||
break;
|
||||
// case Cobol016MsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
|
@ -157,8 +170,7 @@ public class TypeApplierFactory {
|
|||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case ArgumentsList16MsType.PDB_ID:
|
||||
applier =
|
||||
new ArgumentsListTypeApplier(applicator, (ArgumentsList16MsType) type);
|
||||
applier = new ArgumentsListTypeApplier(applicator);
|
||||
break;
|
||||
// case DefaultArguments16MsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
|
@ -167,13 +179,13 @@ public class TypeApplierFactory {
|
|||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case FieldList16MsType.PDB_ID:
|
||||
applier = new FieldListTypeApplier(applicator, type);
|
||||
applier = new FieldListTypeApplier(applicator);
|
||||
break;
|
||||
// case DerivedClassList16MsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case Bitfield16MsType.PDB_ID:
|
||||
applier = new BitfieldTypeApplier(applicator, (Bitfield16MsType) type);
|
||||
applier = new BitfieldTypeApplier(applicator);
|
||||
break;
|
||||
// case MethodList16MsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
|
@ -196,16 +208,16 @@ public class TypeApplierFactory {
|
|||
|
||||
// 0x400 block
|
||||
case BaseClass16MsType.PDB_ID:
|
||||
applier = new BaseClassTypeApplier(applicator, type);
|
||||
applier = new BaseClassTypeApplier(applicator);
|
||||
break;
|
||||
case VirtualBaseClass16MsType.PDB_ID:
|
||||
applier = new BaseClassTypeApplier(applicator, type);
|
||||
applier = new BaseClassTypeApplier(applicator);
|
||||
break;
|
||||
case IndirectVirtualBaseClass16MsType.PDB_ID:
|
||||
applier = new BaseClassTypeApplier(applicator, type);
|
||||
applier = new BaseClassTypeApplier(applicator);
|
||||
break;
|
||||
case EnumerateStMsType.PDB_ID:
|
||||
applier = new EnumerateTypeApplier(applicator, (EnumerateStMsType) type);
|
||||
applier = new EnumerateTypeApplier(applicator);
|
||||
break;
|
||||
// case FriendFunction16MsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
|
@ -214,60 +226,59 @@ public class TypeApplierFactory {
|
|||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case Member16MsType.PDB_ID:
|
||||
applier = new MemberTypeApplier(applicator, (Member16MsType) type);
|
||||
applier = new MemberTypeApplier(applicator);
|
||||
break;
|
||||
// case StaticMember16MsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case OverloadedMethod16MsType.PDB_ID:
|
||||
// See note in "default" case regarding NoTypeApplier
|
||||
applier = new NoTypeApplier(applicator, type);
|
||||
applier = new NoTypeApplier(applicator);
|
||||
break;
|
||||
case NestedType16MsType.PDB_ID:
|
||||
applier = new NestedTypeApplier(applicator, type);
|
||||
applier = new NestedTypeApplier(applicator);
|
||||
break;
|
||||
case VirtualFunctionTablePointer16MsType.PDB_ID:
|
||||
applier = new VirtualFunctionTablePointerTypeApplier(applicator, type);
|
||||
applier = new VirtualFunctionTablePointerTypeApplier(applicator);
|
||||
break;
|
||||
// case FriendClass16MsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case OneMethod16MsType.PDB_ID:
|
||||
// See note in "default" case regarding NoTypeApplier
|
||||
applier = new NoTypeApplier(applicator, type);
|
||||
applier = new NoTypeApplier(applicator);
|
||||
break;
|
||||
case VirtualFunctionTablePointerWithOffset16MsType.PDB_ID:
|
||||
applier = new VirtualFunctionTablePointerTypeApplier(applicator, type);
|
||||
applier = new VirtualFunctionTablePointerTypeApplier(applicator);
|
||||
break;
|
||||
|
||||
// 0x1000 block
|
||||
case ModifierMsType.PDB_ID:
|
||||
applier = new ModifierTypeApplier(applicator, (ModifierMsType) type);
|
||||
applier = new ModifierTypeApplier(applicator);
|
||||
break;
|
||||
case PointerMsType.PDB_ID:
|
||||
applier = new PointerTypeApplier(applicator, (PointerMsType) type);
|
||||
applier = new PointerTypeApplier(applicator);
|
||||
break;
|
||||
case ArrayStMsType.PDB_ID:
|
||||
applier = new ArrayTypeApplier(applicator, (ArrayStMsType) type);
|
||||
applier = new ArrayTypeApplier(applicator);
|
||||
break;
|
||||
case ClassStMsType.PDB_ID:
|
||||
applier = new CompositeTypeApplier(applicator, (ClassStMsType) type);
|
||||
applier = new CompositeTypeApplier(applicator);
|
||||
break;
|
||||
case StructureStMsType.PDB_ID:
|
||||
applier = new CompositeTypeApplier(applicator, (StructureStMsType) type);
|
||||
applier = new CompositeTypeApplier(applicator);
|
||||
break;
|
||||
case UnionStMsType.PDB_ID:
|
||||
applier = new CompositeTypeApplier(applicator, (UnionStMsType) type);
|
||||
applier = new CompositeTypeApplier(applicator);
|
||||
break;
|
||||
case EnumStMsType.PDB_ID:
|
||||
applier = new EnumTypeApplier(applicator, (EnumStMsType) type);
|
||||
applier = new EnumTypeApplier(applicator);
|
||||
break;
|
||||
case ProcedureMsType.PDB_ID:
|
||||
applier = new ProcedureTypeApplier(applicator, (ProcedureMsType) type);
|
||||
applier = new ProcedureTypeApplier(applicator);
|
||||
break;
|
||||
case MemberFunctionMsType.PDB_ID:
|
||||
applier =
|
||||
new MemberFunctionTypeApplier(applicator, (MemberFunctionMsType) type);
|
||||
applier = new MemberFunctionTypeApplier(applicator);
|
||||
break;
|
||||
// case Cobol0MsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
|
@ -299,19 +310,19 @@ public class TypeApplierFactory {
|
|||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case ArgumentsListMsType.PDB_ID:
|
||||
applier = new ArgumentsListTypeApplier(applicator, (ArgumentsListMsType) type);
|
||||
applier = new ArgumentsListTypeApplier(applicator);
|
||||
break;
|
||||
// case DefaultArgumentsStMsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case FieldListMsType.PDB_ID:
|
||||
applier = new FieldListTypeApplier(applicator, type);
|
||||
applier = new FieldListTypeApplier(applicator);
|
||||
break;
|
||||
// case DerivedClassListMsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case BitfieldMsType.PDB_ID:
|
||||
applier = new BitfieldTypeApplier(applicator, (BitfieldMsType) type);
|
||||
applier = new BitfieldTypeApplier(applicator);
|
||||
break;
|
||||
// case MethodListMsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
|
@ -331,13 +342,13 @@ public class TypeApplierFactory {
|
|||
|
||||
// 0x1400 block
|
||||
case BaseClassMsType.PDB_ID:
|
||||
applier = new BaseClassTypeApplier(applicator, type);
|
||||
applier = new BaseClassTypeApplier(applicator);
|
||||
break;
|
||||
case VirtualBaseClassMsType.PDB_ID:
|
||||
applier = new BaseClassTypeApplier(applicator, type);
|
||||
applier = new BaseClassTypeApplier(applicator);
|
||||
break;
|
||||
case IndirectVirtualBaseClassMsType.PDB_ID:
|
||||
applier = new BaseClassTypeApplier(applicator, type);
|
||||
applier = new BaseClassTypeApplier(applicator);
|
||||
break;
|
||||
// case FriendFunctionStMsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
|
@ -346,33 +357,33 @@ public class TypeApplierFactory {
|
|||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case MemberStMsType.PDB_ID:
|
||||
applier = new MemberTypeApplier(applicator, (MemberStMsType) type);
|
||||
applier = new MemberTypeApplier(applicator);
|
||||
break;
|
||||
// case StaticMemberStMsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case OverloadedMethodStMsType.PDB_ID:
|
||||
// See note in "default" case regarding NoTypeApplier
|
||||
applier = new NoTypeApplier(applicator, type);
|
||||
applier = new NoTypeApplier(applicator);
|
||||
break;
|
||||
case NestedTypeStMsType.PDB_ID:
|
||||
applier = new NestedTypeApplier(applicator, type);
|
||||
applier = new NestedTypeApplier(applicator);
|
||||
break;
|
||||
case VirtualFunctionTablePointerMsType.PDB_ID:
|
||||
applier = new VirtualFunctionTablePointerTypeApplier(applicator, type);
|
||||
applier = new VirtualFunctionTablePointerTypeApplier(applicator);
|
||||
break;
|
||||
// case FriendClassMsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case OneMethodStMsType.PDB_ID:
|
||||
// See note in "default" case regarding NoTypeApplier
|
||||
applier = new NoTypeApplier(applicator, type);
|
||||
applier = new NoTypeApplier(applicator);
|
||||
break;
|
||||
case VirtualFunctionTablePointerWithOffsetMsType.PDB_ID:
|
||||
applier = new VirtualFunctionTablePointerTypeApplier(applicator, type);
|
||||
applier = new VirtualFunctionTablePointerTypeApplier(applicator);
|
||||
break;
|
||||
case NestedTypeExtStMsType.PDB_ID:
|
||||
applier = new NestedTypeApplier(applicator, type);
|
||||
applier = new NestedTypeApplier(applicator);
|
||||
break;
|
||||
// case MemberModifyStMsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
|
@ -386,22 +397,22 @@ public class TypeApplierFactory {
|
|||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case EnumerateMsType.PDB_ID:
|
||||
applier = new EnumerateTypeApplier(applicator, (EnumerateMsType) type);
|
||||
applier = new EnumerateTypeApplier(applicator);
|
||||
break;
|
||||
case ArrayMsType.PDB_ID:
|
||||
applier = new ArrayTypeApplier(applicator, (ArrayMsType) type);
|
||||
applier = new ArrayTypeApplier(applicator);
|
||||
break;
|
||||
case ClassMsType.PDB_ID:
|
||||
applier = new CompositeTypeApplier(applicator, (ClassMsType) type);
|
||||
applier = new CompositeTypeApplier(applicator);
|
||||
break;
|
||||
case StructureMsType.PDB_ID:
|
||||
applier = new CompositeTypeApplier(applicator, (StructureMsType) type);
|
||||
applier = new CompositeTypeApplier(applicator);
|
||||
break;
|
||||
case UnionMsType.PDB_ID:
|
||||
applier = new CompositeTypeApplier(applicator, (UnionMsType) type);
|
||||
applier = new CompositeTypeApplier(applicator);
|
||||
break;
|
||||
case EnumMsType.PDB_ID:
|
||||
applier = new EnumTypeApplier(applicator, (EnumMsType) type);
|
||||
applier = new EnumTypeApplier(applicator);
|
||||
break;
|
||||
// case DimensionedArrayMsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
|
@ -419,24 +430,24 @@ public class TypeApplierFactory {
|
|||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case MemberMsType.PDB_ID:
|
||||
applier = new MemberTypeApplier(applicator, (MemberMsType) type);
|
||||
applier = new MemberTypeApplier(applicator);
|
||||
break;
|
||||
// case StaticMemberMsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case OverloadedMethodMsType.PDB_ID:
|
||||
// See note in "default" case regarding NoTypeApplier
|
||||
applier = new NoTypeApplier(applicator, type);
|
||||
applier = new NoTypeApplier(applicator);
|
||||
break;
|
||||
case NestedTypeMsType.PDB_ID:
|
||||
applier = new NestedTypeApplier(applicator, type);
|
||||
applier = new NestedTypeApplier(applicator);
|
||||
break;
|
||||
case OneMethodMsType.PDB_ID:
|
||||
// See note in "default" case regarding NoTypeApplier
|
||||
applier = new NoTypeApplier(applicator, type);
|
||||
applier = new NoTypeApplier(applicator);
|
||||
break;
|
||||
case NestedTypeExtMsType.PDB_ID:
|
||||
applier = new NestedTypeApplier(applicator, type);
|
||||
applier = new NestedTypeApplier(applicator);
|
||||
break;
|
||||
// case MemberModifyMsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
|
@ -457,7 +468,7 @@ public class TypeApplierFactory {
|
|||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case InterfaceMsType.PDB_ID:
|
||||
applier = new CompositeTypeApplier(applicator, (InterfaceMsType) type);
|
||||
applier = new CompositeTypeApplier(applicator);
|
||||
break;
|
||||
// case BaseInterfaceMsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
|
@ -489,16 +500,16 @@ public class TypeApplierFactory {
|
|||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
case UserDefinedTypeSourceAndLineMsType.PDB_ID:
|
||||
applier = new UdtSourceLineTypeApplier(applicator, type);
|
||||
applier = new UdtSourceLineTypeApplier(applicator);
|
||||
break;
|
||||
case UserDefinedTypeModuleSourceAndLineMsType.PDB_ID:
|
||||
applier = new UdtSourceLineTypeApplier(applicator, type);
|
||||
applier = new UdtSourceLineTypeApplier(applicator);
|
||||
break;
|
||||
case Class19MsType.PDB_ID:
|
||||
applier = new CompositeTypeApplier(applicator, (Class19MsType) type);
|
||||
applier = new CompositeTypeApplier(applicator);
|
||||
break;
|
||||
case Structure19MsType.PDB_ID:
|
||||
applier = new CompositeTypeApplier(applicator, (Structure19MsType) type);
|
||||
applier = new CompositeTypeApplier(applicator);
|
||||
break;
|
||||
// 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.
|
||||
|
@ -521,30 +532,16 @@ public class TypeApplierFactory {
|
|||
// 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.
|
||||
default:
|
||||
applier = new NoTypeApplier(applicator, type);
|
||||
// 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);
|
||||
applier = new NoTypeApplier(applicator);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
try {
|
||||
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();
|
||||
String message = "GhidraException on PdbId " + pdbId + ": " + e.getMessage();
|
||||
applicator.appendLogMsg(message);
|
||||
applicator.pdbLogAndInfoMessage(this, message);
|
||||
}
|
||||
appliersByPdbId.put(pdbId, 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.symbol.AbstractMsSymbol;
|
||||
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.util.exception.AssertException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
@ -80,16 +82,18 @@ public class TypedefSymbolApplier extends MsSymbolApplier {
|
|||
}
|
||||
|
||||
// Typedefs
|
||||
private DataType applyUserDefinedTypeMsSymbol(AbstractUserDefinedTypeMsSymbol symbol) {
|
||||
private DataType applyUserDefinedTypeMsSymbol(AbstractUserDefinedTypeMsSymbol symbol)
|
||||
throws CancelledException, PdbException {
|
||||
|
||||
String name = symbol.getName();
|
||||
|
||||
AbstractMsType mType = applicator.getPdb().getTypeRecord(getTypeRecordNumber());
|
||||
MsTypeApplier applier = applicator.getTypeApplier(symbol.getTypeRecordNumber());
|
||||
// TODO:... NOT SURE IF WILL ALWAYS BE A DATATYPE OR WILL BE A VARIABLE OR ????
|
||||
if (applier == null) {
|
||||
return null;
|
||||
}
|
||||
DataType dataType = applier.getDataType();
|
||||
DataType dataType = applicator.getCompletedDataType(getTypeRecordNumber());
|
||||
if (dataType == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -101,17 +105,8 @@ public class TypedefSymbolApplier extends MsSymbolApplier {
|
|||
// 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
|
||||
// contain namespace information.
|
||||
if (applier instanceof CompositeTypeApplier) {
|
||||
CompositeTypeApplier compositeApplier = (CompositeTypeApplier) applier;
|
||||
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)) {
|
||||
if (mType instanceof AbstractComplexMsType) {
|
||||
if (name.equals(mType.getName())) {
|
||||
return dataType;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,10 @@
|
|||
*/
|
||||
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.RecordNumber;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
/**
|
||||
|
@ -28,74 +27,77 @@ import ghidra.util.exception.CancelledException;
|
|||
*/
|
||||
public class UdtSourceLineTypeApplier extends MsTypeApplier {
|
||||
|
||||
// Intended for: UserDefinedTypeSourceAndLineMsType or UserDefinedTypeModuleSourceAndLineMsType
|
||||
/**
|
||||
* Constructor for base class applier.
|
||||
* @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.
|
||||
*/
|
||||
public UdtSourceLineTypeApplier(DefaultPdbApplicator applicator, AbstractMsType msType)
|
||||
public UdtSourceLineTypeApplier(DefaultPdbApplicator applicator)
|
||||
throws IllegalArgumentException {
|
||||
super(applicator, validateType(msType));
|
||||
}
|
||||
|
||||
// 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;
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset of the Base Class within the inheriting class.
|
||||
* @return the offset.
|
||||
* Returns the offset of the Base Class within the inheriting class
|
||||
* @param type the PDB type being inspected
|
||||
* @return the offset or -1 if problem retrieving value
|
||||
*/
|
||||
int getLineNumber() {
|
||||
if (msType instanceof UserDefinedTypeSourceAndLineMsType) {
|
||||
return ((UserDefinedTypeSourceAndLineMsType) msType).getLineNumber();
|
||||
int getLineNumber(AbstractMsType type) {
|
||||
if (type instanceof UserDefinedTypeSourceAndLineMsType udtSLType) {
|
||||
return udtSLType.getLineNumber();
|
||||
}
|
||||
return ((UserDefinedTypeModuleSourceAndLineMsType) msType).getLineNumber();
|
||||
else if (type instanceof UserDefinedTypeModuleSourceAndLineMsType udtMSLType) {
|
||||
return udtMSLType.getLineNumber();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source file name.
|
||||
* @return the source file name. null if problem recovering name.
|
||||
* Returns the source file name
|
||||
* @param type the PDB type being inspected
|
||||
* @return the source file name or null if problem recovering name
|
||||
*/
|
||||
String getSourceFileName() {
|
||||
if (msType instanceof UserDefinedTypeSourceAndLineMsType) {
|
||||
return ((UserDefinedTypeSourceAndLineMsType) msType).getSourceFileName();
|
||||
String getSourceFileName(AbstractMsType type) {
|
||||
if (type instanceof UserDefinedTypeSourceAndLineMsType udtSLType) {
|
||||
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.
|
||||
* @return the record number of the UDT.
|
||||
* Returns 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() {
|
||||
if (msType instanceof UserDefinedTypeSourceAndLineMsType) {
|
||||
return ((UserDefinedTypeSourceAndLineMsType) msType).getUdtRecordNumber();
|
||||
RecordNumber getUdtRecordNumber(AbstractMsType type) {
|
||||
if (type instanceof UserDefinedTypeSourceAndLineMsType udtSLType) {
|
||||
return udtSLType.getUdtRecordNumber();
|
||||
}
|
||||
return ((UserDefinedTypeModuleSourceAndLineMsType) msType).getUdtRecordNumber();
|
||||
else if (type instanceof UserDefinedTypeModuleSourceAndLineMsType udtMSLType) {
|
||||
return udtMSLType.getUdtRecordNumber();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
void apply() throws PdbException, CancelledException {
|
||||
String filename = getSourceFileName();
|
||||
int lineNumber = getLineNumber();
|
||||
RecordNumber udtRecordNumber = getUdtRecordNumber();
|
||||
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws PdbException, CancelledException {
|
||||
String filename = getSourceFileName(type);
|
||||
int lineNumber = getLineNumber(type);
|
||||
RecordNumber udtRecordNumber = getUdtRecordNumber(type);
|
||||
MsTypeApplier typeApplier = applicator.getTypeApplier(udtRecordNumber);
|
||||
|
||||
// do nothing at the moment.
|
||||
applicator.putRecordNumberByFileName(udtRecordNumber, filename);
|
||||
if (msType instanceof UserDefinedTypeModuleSourceAndLineMsType) {
|
||||
int moduleNumber =
|
||||
((UserDefinedTypeModuleSourceAndLineMsType) msType).getModuleNumber();
|
||||
if (type instanceof UserDefinedTypeModuleSourceAndLineMsType) {
|
||||
int moduleNumber = ((UserDefinedTypeModuleSourceAndLineMsType) type).getModuleNumber();
|
||||
applicator.putRecordNumberByModuleNumber(udtRecordNumber, moduleNumber);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static AbstractMsType validateType(AbstractMsType type)
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
*/
|
||||
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.RecordNumber;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||
|
@ -30,63 +28,65 @@ import ghidra.util.exception.CancelledException;
|
|||
*/
|
||||
public class VirtualFunctionTablePointerTypeApplier extends MsTypeApplier {
|
||||
|
||||
// Intended for: AbstractVirtualFunctionTablePointerMsType or
|
||||
// AbstractVirtualFunctionTablePointerWithOffsetMsType
|
||||
/**
|
||||
* Constructor for enum type applier, for transforming a enum into a
|
||||
* Ghidra DataType.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link AbstractVirtualFunctionTablePointerMsType} or
|
||||
* {@link AbstractVirtualFunctionTablePointerWithOffsetMsType} to process.
|
||||
* @throws IllegalArgumentException Upon invalid arguments.
|
||||
*/
|
||||
public VirtualFunctionTablePointerTypeApplier(DefaultPdbApplicator applicator,
|
||||
AbstractMsType msType) throws IllegalArgumentException {
|
||||
super(applicator, validateType(msType));
|
||||
public VirtualFunctionTablePointerTypeApplier(DefaultPdbApplicator applicator) throws IllegalArgumentException {
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
BigInteger getSize() {
|
||||
return BigInteger.valueOf(applicator.getDataOrganization().getPointerSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
int getOffset(AbstractMsType type) {
|
||||
if (type instanceof AbstractVirtualFunctionTablePointerWithOffsetMsType offType) {
|
||||
return offType.getOffset();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name to use.
|
||||
* @param type the PDB type being inspected
|
||||
* @return Name of the pointer type.
|
||||
*/
|
||||
String getMemberName() {
|
||||
return "VFTablePtr" + getOffset();
|
||||
String getMemberName(AbstractMsType type) {
|
||||
return "VFTablePtr" + getOffset(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
void apply() throws PdbException, CancelledException {
|
||||
if (msType instanceof AbstractVirtualFunctionTablePointerWithOffsetMsType vftPtrWOffset) {
|
||||
dataType = applyPointer(
|
||||
vftPtrWOffset.getPointerTypeRecordNumber());
|
||||
DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)
|
||||
throws PdbException, CancelledException {
|
||||
|
||||
// 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) {
|
||||
dataType = applyPointer(vftPtr.getPointerTypeRecordNumber());
|
||||
else if (type instanceof AbstractVirtualFunctionTablePointerMsType vftPtr) {
|
||||
dataType = applyPointer(vftPtr.getPointerTypeRecordNumber(), fixupContext, breakCycle);
|
||||
}
|
||||
else {
|
||||
dataType = VoidDataType.dataType;
|
||||
applicator.appendLogMsg(
|
||||
"PDB Warning: Type not handled: " + msType.getClass().getSimpleName());
|
||||
"PDB Warning: Type not handled: " + type.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
// unlike regular pointer, we are resolving vft pointer
|
||||
dataType = applicator.resolve(dataType);
|
||||
return dataType;
|
||||
}
|
||||
|
||||
private DataType applyPointer(RecordNumber pointerTypeRecordNumber) {
|
||||
private DataType applyPointer(RecordNumber pointerTypeRecordNumber, FixupContext fixupContext,
|
||||
boolean breakCycle) throws CancelledException, PdbException {
|
||||
MsTypeApplier rawApplier = applicator.getTypeApplier(pointerTypeRecordNumber);
|
||||
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 " +
|
||||
getClass().getSimpleName());
|
||||
|
|
|
@ -15,14 +15,12 @@
|
|||
*/
|
||||
package ghidra.app.util.pdb.pdbapplicator;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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.type.VtShapeDescriptorMsProperty;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.VtShapeMsType;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
@ -32,45 +30,42 @@ import ghidra.util.exception.CancelledException;
|
|||
*/
|
||||
public class VtShapeTypeApplier extends MsTypeApplier {
|
||||
|
||||
// Intended for: VtShapeMsType
|
||||
/**
|
||||
* Constructor for vtshape type applier.
|
||||
* @param applicator {@link DefaultPdbApplicator} for which this class is working.
|
||||
* @param msType {@link VtShapeMsType} to process.
|
||||
*/
|
||||
public VtShapeTypeApplier(DefaultPdbApplicator applicator, VtShapeMsType msType) {
|
||||
super(applicator, msType);
|
||||
}
|
||||
|
||||
@Override
|
||||
BigInteger getSize() {
|
||||
return BigInteger.valueOf(applicator.getDataOrganization().getPointerSize() *
|
||||
((VtShapeMsType) msType).getCount());
|
||||
public VtShapeTypeApplier(DefaultPdbApplicator applicator) {
|
||||
super(applicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name.
|
||||
* @return the name.
|
||||
* Returns the name
|
||||
* @param type the MS VtShape
|
||||
* @return the name
|
||||
*/
|
||||
String getName() {
|
||||
return "vtshape_" + index;
|
||||
String getName(VtShapeMsType type) {
|
||||
return "vtshape_" + type.getRecordNumber().getNumber();
|
||||
}
|
||||
|
||||
@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
|
||||
// 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
|
||||
// particular VTShape were found either. Because of this, for now, the VTShape is going
|
||||
// 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.
|
||||
private DataType createVtShape(VtShapeMsType msShape)
|
||||
throws CancelledException {
|
||||
private DataType createVtShape(VtShapeMsType msShape) throws CancelledException {
|
||||
List<VtShapeDescriptorMsProperty> list = msShape.getDescriptorList();
|
||||
StructureDataType shape = new StructureDataType(applicator.getAnonymousTypesCategory(),
|
||||
"vtshape" + index, 0, applicator.getDataTypeManager());
|
||||
"vtshape" + msShape.getRecordNumber().getNumber(), 0, applicator.getDataTypeManager());
|
||||
List<DefaultPdbUniversalMember> members = new ArrayList<>();
|
||||
int offset = 0;
|
||||
int defaultSize = applicator.getDataTypeManager().getDataOrganization().getPointerSize();
|
||||
|
@ -118,9 +113,8 @@ public class VtShapeTypeApplier extends MsTypeApplier {
|
|||
default:
|
||||
// If any element type is not know, we will not return a full shape structure
|
||||
// Instead, we return void type.
|
||||
applicator.appendLogMsg(
|
||||
"PDB Warning: No type conversion for " + msShape.toString() +
|
||||
" as underlying type for pointer. Using void.");
|
||||
applicator.appendLogMsg("PDB Warning: No type conversion for " +
|
||||
msShape.toString() + " as underlying type for pointer. Using void.");
|
||||
return VoidDataType.dataType;
|
||||
}
|
||||
int size = elementType.getLength();
|
||||
|
@ -128,7 +122,7 @@ public class VtShapeTypeApplier extends MsTypeApplier {
|
|||
elementType = PointerDataType.dataType;
|
||||
}
|
||||
DefaultPdbUniversalMember member =
|
||||
new DefaultPdbUniversalMember(applicator, "", elementType, offset);
|
||||
new DefaultPdbUniversalMember("", elementType, offset);
|
||||
offset += size;
|
||||
members.add(member);
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ public class TypesTest extends AbstractGenericTest {
|
|||
// Below is just a small sampling of PrimitiveMsType variations.
|
||||
@Test
|
||||
public void testPrimitiveMsType0000() {
|
||||
AbstractMsType type = pdb.getTypeRecord(RecordNumber.make(RecordCategory.TYPE, 0x0000));
|
||||
AbstractMsType type = pdb.getTypeRecord(RecordNumber.typeRecordNumber(0x0000));
|
||||
assertEquals(type instanceof PrimitiveMsType, true);
|
||||
String result = type.toString().trim();
|
||||
assertEquals("T_NOTYPE", result);
|
||||
|
@ -155,7 +155,7 @@ public class TypesTest extends AbstractGenericTest {
|
|||
|
||||
@Test
|
||||
public void testPrimitiveMsType0110() {
|
||||
AbstractMsType type = pdb.getTypeRecord(RecordNumber.make(RecordCategory.TYPE, 0x0110));
|
||||
AbstractMsType type = pdb.getTypeRecord(RecordNumber.typeRecordNumber(0x0110));
|
||||
assertEquals(type instanceof PrimitiveMsType, true);
|
||||
String result = type.toString().trim();
|
||||
assertEquals("signed char near*", result);
|
||||
|
@ -1967,8 +1967,7 @@ public class TypesTest extends AbstractGenericTest {
|
|||
PdbByteWriter writer = new PdbByteWriter();
|
||||
writer.putUnsignedShort(OverloadedMethod16MsType.PDB_ID);
|
||||
int count = ((AbstractMethodListMsType) pdb
|
||||
.getTypeRecord(RecordNumber.make(RecordCategory.TYPE, methodList16MsType1)))
|
||||
.getListSize();
|
||||
.getTypeRecord(RecordNumber.typeRecordNumber(methodList16MsType1))).getListSize();
|
||||
writer.putUnsignedShort(count);
|
||||
writer.putUnsignedShort(methodList16MsType1); // type index of MethodList16MsType
|
||||
writer.putByteLengthPrefixedString("overloadedMethodName");
|
||||
|
@ -1987,8 +1986,7 @@ public class TypesTest extends AbstractGenericTest {
|
|||
PdbByteWriter writer = new PdbByteWriter();
|
||||
writer.putUnsignedShort(OverloadedMethodStMsType.PDB_ID);
|
||||
int count = ((AbstractMethodListMsType) pdb
|
||||
.getTypeRecord(RecordNumber.make(RecordCategory.TYPE, methodList16MsType1)))
|
||||
.getListSize();
|
||||
.getTypeRecord(RecordNumber.typeRecordNumber(methodList16MsType1))).getListSize();
|
||||
writer.putUnsignedShort(count);
|
||||
writer.putInt(methodListMsType1); // type index of MethodListMsType
|
||||
writer.putByteLengthPrefixedString("overloadedMethodName");
|
||||
|
@ -2007,8 +2005,7 @@ public class TypesTest extends AbstractGenericTest {
|
|||
PdbByteWriter writer = new PdbByteWriter();
|
||||
writer.putUnsignedShort(OverloadedMethodMsType.PDB_ID);
|
||||
int count = ((AbstractMethodListMsType) pdb
|
||||
.getTypeRecord(RecordNumber.make(RecordCategory.TYPE, methodList16MsType1)))
|
||||
.getListSize();
|
||||
.getTypeRecord(RecordNumber.typeRecordNumber(methodList16MsType1))).getListSize();
|
||||
writer.putUnsignedShort(count);
|
||||
writer.putInt(methodListMsType1); // type index of MethodListMsType
|
||||
writer.putNullTerminatedString("overloadedMethodName");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue