From 6f852989cab6af90be210b7c2751aadf36dfaeb9 Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Fri, 18 Aug 2023 09:05:30 -0400 Subject: [PATCH] GP-3715 - PDB perf: resolve-as-you-go and stored types --- .../DeveloperDumpAllTypesScript.java | 105 +- .../format/pdb/DefaultCompositeMember.java | 3 +- .../format/pdb2/pdbreader/SymbolRecords.java | 7 +- .../pdb2/pdbreader/TypeProgramInterface.java | 6 +- .../type/AbstractFieldListMsType.java | 82 +- .../pdb2/pdbreader/type/BuildInfoMsType.java | 2 +- .../pdb2/pdbreader/type/PrimitiveMsType.java | 13 +- .../ghidra/app/util/pdb/PdbCategories.java | 11 + .../app/util/pdb/PdbNamespaceUtils.java | 9 +- .../AbstractComplexTypeApplier.java | 116 +- .../AbstractFunctionTypeApplier.java | 343 +++--- .../ArgumentsListTypeApplier.java | 197 +-- .../pdb/pdbapplicator/ArrayTypeApplier.java | 169 +-- .../pdbapplicator/BaseClassTypeApplier.java | 107 +- .../pdbapplicator/BitfieldTypeApplier.java | 54 +- .../pdb/pdbapplicator/ClassTypeUtils.java | 29 +- .../ComplexTypeApplierMapper.java | 273 ----- .../pdb/pdbapplicator/ComplexTypeMapper.java | 24 +- .../pdbapplicator/CompositeTypeApplier.java | 1072 +++++++---------- .../pdb/pdbapplicator/DataSymbolApplier.java | 41 +- .../pdbapplicator/DefaultPdbApplicator.java | 588 +++++++-- .../DefaultPdbUniversalMember.java | 84 +- .../pdb/pdbapplicator/EnumTypeApplier.java | 286 ++--- .../pdbapplicator/EnumerateTypeApplier.java | 44 +- .../pdbapplicator/FieldListTypeApplier.java | 188 ++- .../util/pdb/pdbapplicator/FixupContext.java | 313 +++++ .../pdbapplicator/FunctionSymbolApplier.java | 29 +- .../MemberFunctionTypeApplier.java | 306 ++--- .../pdb/pdbapplicator/MemberTypeApplier.java | 57 +- .../pdbapplicator/ModifierTypeApplier.java | 113 +- .../util/pdb/pdbapplicator/MsTypeApplier.java | 234 +--- .../pdb/pdbapplicator/NestedTypeApplier.java | 135 +-- .../util/pdb/pdbapplicator/NoTypeApplier.java | 24 +- .../pdbapplicator/PdbApplicatorMetrics.java | 41 +- .../util/pdb/pdbapplicator/PdbResearch.java | 42 +- .../pdb/pdbapplicator/PointerTypeApplier.java | 158 +-- .../pdbapplicator/PrimitiveTypeApplier.java | 43 +- .../pdbapplicator/ProcedureTypeApplier.java | 47 +- .../RegisterRelativeSymbolApplier.java | 8 +- .../pdb/pdbapplicator/TypeApplierFactory.java | 183 ++- .../pdbapplicator/TypedefSymbolApplier.java | 25 +- .../UdtSourceLineTypeApplier.java | 82 +- ...irtualFunctionTablePointerTypeApplier.java | 60 +- .../pdb/pdbapplicator/VtShapeTypeApplier.java | 44 +- .../format/pdb2/pdbreader/type/TypesTest.java | 13 +- .../program/database/data/StructureDB.java | 30 +- 46 files changed, 2587 insertions(+), 3253 deletions(-) delete mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FixupContext.java diff --git a/Ghidra/Features/PDB/developer_scripts/DeveloperDumpAllTypesScript.java b/Ghidra/Features/PDB/developer_scripts/DeveloperDumpAllTypesScript.java index c4fbf2c8e9..8a0ddb7711 100644 --- a/Ghidra/Features/PDB/developer_scripts/DeveloperDumpAllTypesScript.java +++ b/Ghidra/Features/PDB/developer_scripts/DeveloperDumpAllTypesScript.java @@ -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 , , 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); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/DefaultCompositeMember.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/DefaultCompositeMember.java index 4ef646b3dd..b055b98459 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/DefaultCompositeMember.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/DefaultCompositeMember.java @@ -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); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/SymbolRecords.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/SymbolRecords.java index 77fa01f537..36ba5ec90e 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/SymbolRecords.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/SymbolRecords.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -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 } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TypeProgramInterface.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TypeProgramInterface.java index 57f8a80444..a74e41d7be 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TypeProgramInterface.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TypeProgramInterface.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -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 offLenRecords; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/AbstractFieldListMsType.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/AbstractFieldListMsType.java index 133c6e6ec8..8d774dbd18 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/AbstractFieldListMsType.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/AbstractFieldListMsType.java @@ -32,6 +32,11 @@ public abstract class AbstractFieldListMsType extends AbstractMsType { private List baseClassList = new ArrayList<>(); private List memberList = new ArrayList<>(); private List methodList = new ArrayList<>(); + private List nonstaticMemberList = new ArrayList<>(); + private List staticMemberList = new ArrayList<>(); + private List vftPtrList = new ArrayList<>(); + private List nestedTypeList = new ArrayList<>(); + private List 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 getNonStaticMembers() { + return nonstaticMemberList; + } + + /** + * Returns the (ordered?) {@link List}<{@link AbstractMsType}> of VFT pointer records + * from this field list + * @return VFT pointer records + */ + public List getVftPointers() { + return vftPtrList; + } + + /** + * Returns the (ordered?) {@link List}<{@link AbstractNestedTypeMsType}> of enumerates + * from this field list + * @return enumerates + */ + public List getNestedTypes() { + return nestedTypeList; + } + + /** + * Returns the (ordered?) {@link List}<{@link AbstractEnumerateMsType}> of enumerates + * from this field list + * @return enumerates + */ + public List getEnumerates() { + return enumerateList; + } + /** * Returns the (ordered?) {@link List}<{@link AbstractIndexMsType}> that we believe * will contain the reference only to other {@link AbstractFieldListMsType}s. diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/BuildInfoMsType.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/BuildInfoMsType.java index 62d651965d..222ca83acc 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/BuildInfoMsType.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/BuildInfoMsType.java @@ -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(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/PrimitiveMsType.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/PrimitiveMsType.java index 18b010aa02..8996da53e6 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/PrimitiveMsType.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/PrimitiveMsType.java @@ -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. @@ -259,7 +266,7 @@ public class PrimitiveMsType extends AbstractMsType { //======================================= // Unsigned Character types //======================================= - // 8-bit unsigned + // 8-bit unsigned case 0x0020: typeString = "unsigned char"; typeSize = 1; @@ -396,7 +403,7 @@ public class PrimitiveMsType extends AbstractMsType { typeString = "T_CHAR16"; typeSize = 2; break; - // 16-bit pointer to a 16-bit unicode char + // 16-bit pointer to a 16-bit unicode char case 0x017a: typeString = "T_PCHAR16"; typeSize = 2; @@ -440,7 +447,7 @@ public class PrimitiveMsType extends AbstractMsType { typeString = "T_CHAR32"; typeSize = 4; break; - // 16-bit pointer to a 32-bit unicode char + // 16-bit pointer to a 32-bit unicode char case 0x017b: typeString = "T_PCHAR32"; typeSize = 2; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategories.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategories.java index 5c39a05139..3fc8d79e9d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategories.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategories.java @@ -35,6 +35,7 @@ public class PdbCategories { private CategoryPath pdbUncategorizedCategory; private CategoryPath anonymousFunctionsCategory; private CategoryPath anonymousTypesCategory; + private CategoryPath placeholderTypesCategory; private CategoryPath baseModuleTypedefsCategory; private List 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. diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java index ad526a9196..f8d3c86bd0 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java @@ -25,12 +25,12 @@ public class PdbNamespaceUtils { /** * Fixes {@link SymbolPath} name, eliminating invalid characters and making the terminal - * name of the namespace unique by the index number when necessary. For example, + * name of the namespace unique by the index number when necessary. For example, * anonymous and unnamed components such as {@code } and {@code } * are fixed up. Example: *
 	 *   {@code _SYSTEM_INFO::}
-	 * 
+ * * @param symbolPath the source {@link SymbolPath} * @param index the index number used be used as part of a unique tag name. * @return the resulting {@link SymbolPath} @@ -56,7 +56,7 @@ public class PdbNamespaceUtils { * NOTE: This could be an issue when there are multiple unnamed items, such as in, for example: *
 	 *   {@code _SYSTEM_INFO::::}
-	 * 
+ * * @param symbolPath the source {@link SymbolPath} * @param index the index number used be used as part of a unique tag name. * @return the resulting {@link SymbolPath} @@ -99,6 +99,9 @@ public class PdbNamespaceUtils { if ("".equals(name)) { return String.format("", index); } + if ("__unnamed".equals(name)) { + return String.format("__unnamed_%08X", index); + } return name; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java index 8fd28a7201..dd8cbd8cae 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java @@ -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 getDefinitionApplier(Class 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 the derivative class template argument + * @return the path + */ + public T getDefinitionType(AbstractComplexMsType mType, + Class 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); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java index c423356045..109914cb05 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java @@ -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 args = argsList.getArgRecordNumbers(); + List 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; + } + } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java index 0a77124485..15f1fdea3e 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java @@ -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 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 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 args = argsList.getArgRecordNumbers(); - List 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 list = argsList.getArgTypeIndexList(); -// List 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()])); -// } -// } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java index d37a310a20..c59765fb96 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -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; } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java index 1e931b8ffe..b0f188bf81 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java @@ -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) diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java index 1352a17292..1f6d36a830 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java @@ -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!!! - } - /** * Pdb2BitField provides ability to hang onto bitfield as a datatype. * This will be transformed to a normal BitFieldDataType when cloned. diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ClassTypeUtils.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ClassTypeUtils.java index 4236ff2a69..8de7471d64 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ClassTypeUtils.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ClassTypeUtils.java @@ -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. diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java deleted file mode 100644 index 5f6c5b452b..0000000000 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java +++ /dev/null @@ -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 complexTypeAppliersBySymbolPath; - private Map> compositeAppliersQueueBySymbolPath; - private Map> 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 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> applierQueueBySymbolPath, - AbstractComplexTypeApplier complexApplier) { - SymbolPath symbolPath = complexApplier.getSymbolPath(); - Objects.requireNonNull(symbolPath, "SymbolPath may not be null"); - - LinkedList 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 getComplexTypeApplierBySymbolPath( -// SymbolPath symbolPath, Class 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> applierQueueBySymbolPath, -// AbstractComplexTypeApplier complexApplier) { -// SymbolPath symbolPath = complexApplier.getSymbolPath(); -// Objects.requireNonNull(symbolPath, "SymbolPath may not be null"); -// -// LinkedList 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); -// } -// } -// - -} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeMapper.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeMapper.java index 9b346f106e..6672cead48 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeMapper.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeMapper.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -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 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> compositeFIFOsByPath = new HashMap<>(); - Map> enumFIFOsByPath = new HashMap<>(); + // All we need for the Deque is a simple FIFO. + Map> compositeFIFOsByPath = new HashMap<>(); + Map> 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> typeFIFOsByPath, + private void mapComplexTypesByPath(Map> typeFIFOsByPath, int indexNumber, AbstractComplexMsType complexType) { SymbolPath symbolPath = new SymbolPath(SymbolPathParser.parse(complexType.getName())); boolean isFwdRef = complexType.getMsProperty().isForwardReference(); - LinkedList numTypeFIFO = typeFIFOsByPath.get(symbolPath); + Deque 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) diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java index 8f4fb74c34..1bb6ce1351 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,7 +19,6 @@ import java.math.BigInteger; import java.util.*; import ghidra.app.util.SymbolPath; -import ghidra.app.util.SymbolPathParser; import ghidra.app.util.bin.format.pdb.DefaultCompositeMember; import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; @@ -42,77 +41,34 @@ import ghidra.util.exception.CancelledException; */ public class CompositeTypeApplier extends AbstractComplexTypeApplier { - // DO NOT DELETE. Might eliminate one path or might make an analyzer option. - private static boolean applyBaseClasses = true; - //private static boolean applyBaseClasses = false; - - private CppCompositeType classType; - -// private final static DataType NO_TYPE_DATATYPE = -// new TypedefDataType("", Undefined1DataType.dataType); -// - private Map componentComments; - - private List members; - + // Intended for: AbstractCompositeMsType /** * Constructor for composite type applier, for transforming a composite into a - * Ghidra DataType. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. - * @param msType {@link AbstractCompositeMsType} to process. + * Ghidra DataType + * @param applicator {@link DefaultPdbApplicator} for which this class is working */ - public CompositeTypeApplier(DefaultPdbApplicator applicator, AbstractCompositeMsType msType) { - super(applicator, msType); - String fullPathName = msType.getName(); - symbolPath = new SymbolPath(SymbolPathParser.parse(fullPathName)); + public CompositeTypeApplier(DefaultPdbApplicator applicator) { + super(applicator); } - CppCompositeType getClassType() { - if (definitionApplier != null) { - return ((CompositeTypeApplier) definitionApplier).getClassTypeInternal(); - } - return classType; + CppCompositeType getClassType(AbstractMsType type) { + return applicator.getClassType(type); } - CppCompositeType getClassTypeInternal() { - return classType; + private ComboType create(AbstractCompositeMsType type) { + AbstractCompositeMsType defType = getDefinitionType(type, AbstractCompositeMsType.class); + SymbolPath fixedSp = getFixedSymbolPath(defType); + CategoryPath categoryPath = applicator.getCategory(fixedSp.getParent()); + return createComposite(applicator, fixedSp.getName(), defType, categoryPath, fixedSp); } - List getMembers() { - return members; - } - - // Mapping of forwardReference/definition must be done prior to this call. - private void getOrCreateComposite() { - if (dataType != null) { - return; - } - - AbstractComplexTypeApplier alternativeApplier = getAlternativeTypeApplier(); - if (alternativeApplier != null) { - dataType = alternativeApplier.getDataTypeInternal(); - classType = ((CompositeTypeApplier) alternativeApplier).getClassTypeInternal(); - } - if (dataType != null) { - return; - } - - SymbolPath sp = getFixedSymbolPath(); - CategoryPath categoryPath = applicator.getCategory(sp.getParent()); - ComboType c = getOrCreateComposite(applicator, this, (AbstractCompositeMsType) msType, - categoryPath, sp); - dataType = c.dt(); - classType = c.ct(); - } - - private record ComboType(DataType dt, CppCompositeType ct) { - } + private record ComboType(Composite dt, CppCompositeType ct) {} // DefaultPdbApplicator is passed in for bigIntegerToInt... // TODO: find a better way... maybe eventually eliminate PdbMsgLog - private static ComboType getOrCreateComposite(DefaultPdbApplicator myApplicator, - AbstractComplexTypeApplier myCompositeApplier, AbstractCompositeMsType compositeMsType, - CategoryPath categoryPath, SymbolPath fixedSymbolPath) { + private static ComboType createComposite(DefaultPdbApplicator myApplicator, String name, + AbstractCompositeMsType compositeMsType, CategoryPath categoryPath, + SymbolPath fixedSymbolPath) { Composite myComposite; CppCompositeType myClassType; @@ -144,248 +100,69 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { myApplicator.appendLogMsg(message); return null; } - myClassType.setName(myCompositeApplier.getMsType().getName()); - myClassType.setSize( - DefaultPdbApplicator.bigIntegerToInt(myApplicator, myCompositeApplier.getSize())); + myClassType.setName(name); + myClassType.setSize(myApplicator.bigIntegerToInt(compositeMsType.getSize())); myClassType.setFinal(compositeMsType.getMsProperty().isSealed()); return new ComboType(myComposite, myClassType); } @Override - void apply() throws PdbException, CancelledException { - - getOrCreateComposite(); - - Composite composite = (Composite) dataType; - - AbstractCompositeMsType type = (AbstractCompositeMsType) msType; - MsProperty property = type.getMsProperty(); - if (property.isForwardReference() && definitionApplier != null) { - return; - } - if (!(composite instanceof CompositeDataTypeImpl)) { - return; // A resolved version exists (multiple definitions). - } - applyOrDeferForDependencies(); + DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) + throws PdbException, CancelledException { + return apply((AbstractCompositeMsType) type, fixupContext, breakCycle); } - @Override - void resolve() { - - // NOTE: Until we know better we do not want to explicitly - // apply nested composite datatypes and allow them to be - // created as-needed (e.g., function definition). This is - // done to minimize duplication of anonymous/unnamed nested - // composites since the parent composite reconstruction performed - // by DefaultCompositeMember will generate such nested composites. - - // TODO: Dome some output comparisons with and without the !isNested() - // test which is intended to ignore nested anonymous composites. - - if (!isForwardReference() && !isNested() && !isUnnamed()) { - super.resolve(); - } - } - - private boolean isUnnamed() { - if (msType instanceof AbstractClassMsType) { - return false; - } - return "__unnamed".equals(((AbstractComplexMsType) msType).getName()); - } - - private void applyOrDeferForDependencies() throws PdbException, CancelledException { - AbstractCompositeMsType type = (AbstractCompositeMsType) msType; - MsProperty property = type.getMsProperty(); - if (property.isForwardReference() && definitionApplier != null) { - return; - } - - // Add self - applicator.addApplierDependency(this); - - // Add any dependees: base classes and members - FieldListTypeApplier fieldListApplier = FieldListTypeApplier.getFieldListApplierSpecial( - applicator, type.getFieldDescriptorListRecordNumber()); - - // Currently do not need this dependency, as we currently do not need any contents - // of the base class for filling in this class - for (MsTypeApplier baseApplierIterated : fieldListApplier.getBaseClassList()) { - if (baseApplierIterated instanceof BaseClassTypeApplier) { - BaseClassTypeApplier baseTypeApplier = (BaseClassTypeApplier) baseApplierIterated; - MsTypeApplier applier = - applicator.getTypeApplier(baseTypeApplier.getBaseClassRecordNumber()); - if (applier instanceof CompositeTypeApplier) { - CompositeTypeApplier dependencyApplier = - ((CompositeTypeApplier) applier).getDependencyApplier(); - applicator.addApplierDependency(this, dependencyApplier); -// CompositeTypeApplier defApplier = -// ((CompositeTypeApplier) applier).getDefinitionApplier(); -// if (defApplier != null) { -// applicator.addApplierDependency(this, defApplier); -// } -// else { -// applicator.addApplierDependency(this, applier); -// } - setDeferred(); - } - } - } - for (MsTypeApplier memberTypeApplierIterated : fieldListApplier.getMemberList()) { - applicator.checkCancelled(); - if (memberTypeApplierIterated instanceof MemberTypeApplier) { - MemberTypeApplier memberTypeApplier = (MemberTypeApplier) memberTypeApplierIterated; - MsTypeApplier fieldApplier = memberTypeApplier.getFieldTypeApplier(); - recurseAddDependency(fieldApplier); - } -// if (memberTypeApplierIterated instanceof NestedTypeApplier) { -// recurseAddDependency(memberTypeApplierIterated); -// } - else if (memberTypeApplierIterated instanceof VirtualFunctionTablePointerTypeApplier) { - applicator.addApplierDependency(this, memberTypeApplierIterated); - } - } - if (!isDeferred() || isUnnamed()) { - applyInternal(); - } - } - - private void recurseAddDependency(MsTypeApplier dependee) - throws CancelledException, PdbException { - // TODO: evaluate this and make changes... this work might be being taken care of in - // ModifierTypeApplier - if (dependee instanceof ModifierTypeApplier) { - ModifierTypeApplier modifierApplier = (ModifierTypeApplier) dependee; - recurseAddDependency(modifierApplier.getModifiedTypeApplier()); - } - else if (dependee instanceof CompositeTypeApplier) { - CompositeTypeApplier defApplier = - ((CompositeTypeApplier) dependee).getDefinitionApplier(CompositeTypeApplier.class); - if (defApplier != null) { - applicator.addApplierDependency(this, defApplier); - } - else { - applicator.addApplierDependency(this, dependee); - } - setDeferred(); - } - // TODO: evaluate this and make changes... this work might be being taken care of in - // ArrayTypeApplier - else if (dependee instanceof ArrayTypeApplier) { - applicator.addApplierDependency(this, dependee); - setDeferred(); - } -// else if (dependee instanceof NestedTypeApplier) { -// NestedTypeApplier nestedTypeApplier = (NestedTypeApplier) dependee; -// AbstractMsTypeApplier nestedDefinitionApplier = -// nestedTypeApplier.getNestedTypeDefinitionApplier(); -// // Need to make sure that "this" class id dependent on all elements composing the -// // nested definition, but we need to create the nested definition during the -// // creation of this class. (NestedTypeApplier and NestedTypeMsType do not really -// // have their own RecordNumber). -// applicator.addApplierDependency(this, nestedDefinitionApplier); -// setDeferred(); -// } - else if (dependee instanceof BitfieldTypeApplier) { - RecordNumber recNum = - ((AbstractBitfieldMsType) ((BitfieldTypeApplier) dependee).getMsType()).getElementRecordNumber(); - MsTypeApplier underlyingApplier = applicator.getTypeApplier(recNum); - if (underlyingApplier instanceof EnumTypeApplier) { - applicator.addApplierDependency(this, underlyingApplier); - setDeferred(); - } - } - //We are assuming that bitfields on typedefs will not be defined. - } - - private void applyInternal() throws CancelledException, PdbException { - - if (isApplied()) { - return; - } - applyInternal((Composite) dataType); - setApplied(); - } - - private void applyInternal(Composite composite) throws CancelledException, PdbException { - - AbstractCompositeMsType type = (AbstractCompositeMsType) msType; - - boolean applyCpp = applyBaseClasses; + private void applyInternal(ComboType combo, AbstractCompositeMsType type, + FixupContext fixupContext, boolean breakCycle) throws CancelledException, PdbException { + FieldListTypeApplier fieldListApplier = FieldListTypeApplier + .getFieldListApplierSpecial(applicator, type.getFieldDescriptorListRecordNumber()); + FieldListTypeApplier.FieldLists lists = + fieldListApplier.getFieldLists(type.getFieldDescriptorListRecordNumber()); if (type instanceof AbstractUnionMsType) { - applyCpp = false; - if (hasBaseClasses()) { - pdbLogAndInfoMessage(this, - "Unexpected base classes for union type: " + type.getName()); - } - } - if (isUnnamed()) { - applyCpp = false; - } - - if (applyCpp) { - applyCpp(composite, type); + applyBasic(combo, type, lists, fixupContext, breakCycle); } else { - applyBasic(composite, type); + applyCpp(combo, type, lists, fixupContext, breakCycle); } } //============================================================================================== - private void applyBasic(Composite composite, AbstractCompositeMsType type) + private void applyBasic(ComboType combo, AbstractCompositeMsType type, + FieldListTypeApplier.FieldLists lists, FixupContext fixupContext, boolean breakCycle) throws CancelledException, PdbException { - - //boolean isClass = (type instanceof AbstractClassMsType || actsLikeClass(applicator, type)); + Composite composite = combo.dt(); + CppCompositeType classType = combo.ct(); boolean isClass = (type instanceof AbstractClassMsType); - - int size = getSizeInt(); - - // Fill in composite definition details. - FieldListTypeApplier fieldListApplier = FieldListTypeApplier.getFieldListApplierSpecial( - applicator, type.getFieldDescriptorListRecordNumber()); - + int size = getSizeInt(type); clearComponents(composite); - members = new ArrayList<>(); - componentComments = new HashMap<>(); + List myMembers = new ArrayList<>(); + addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers, fixupContext, + breakCycle); + addMembers(composite, classType, lists.nonstaticMembers(), type, myMembers, fixupContext, + breakCycle); - addMembers(composite, fieldListApplier); - - if (!DefaultCompositeMember.applyDataTypeMembers(composite, isClass, size, members, - msg -> reconstructionWarn(msg), applicator.getCancelOnlyWrappingMonitor())) { + if (!DefaultCompositeMember.applyDataTypeMembers(composite, isClass, size, myMembers, + msg -> reconstructionWarn(msg, hasHiddenComponents(lists)), + applicator.getCancelOnlyWrappingMonitor())) { clearComponents(composite); } - - setComponentComments(composite); - } - - private void setComponentComments(Composite composite) { - if (composite instanceof Structure) { - Structure structure = (Structure) composite; - for (Map.Entry entry : componentComments.entrySet()) { - DataTypeComponent component = structure.getComponentAt(entry.getKey()); - if (component == null) { - pdbLogAndInfoMessage(this, "Could not set comment for 'missing' componenent " + - entry.getKey() + " for: " + structure.getName()); - return; - } - component.setComment(entry.getValue()); - } - } } //============================================================================================== - private void applyCpp(Composite composite, AbstractCompositeMsType type) + private void applyCpp(ComboType combo, AbstractCompositeMsType type, + FieldListTypeApplier.FieldLists lists, FixupContext fixupContext, boolean breakCycle) throws PdbException, CancelledException { - // Fill in composite definition details. - FieldListTypeApplier fieldListApplier = FieldListTypeApplier.getFieldListApplierSpecial( - applicator, type.getFieldDescriptorListRecordNumber()); + Composite composite = combo.dt(); + CppCompositeType classType = combo.ct(); clearComponents(composite); - members = new ArrayList<>(); // TODO: temporary for old "basic" mechanism - componentComments = new HashMap<>(); // TODO: temporary for old "basic" mechanism - - addClassTypeBaseClasses(composite, fieldListApplier); - addMembers(composite, fieldListApplier); + List myMembers = new ArrayList<>(); + addClassTypeBaseClassesNew(composite, classType, lists.bases(), type, fixupContext, + breakCycle); + addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers, fixupContext, + breakCycle); + addMembers(composite, classType, lists.nonstaticMembers(), type, myMembers, fixupContext, + breakCycle); if (!classType.validate()) { // TODO: Investigate. We should do this check for some classes somewhere. Should @@ -396,89 +173,17 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } //============================================================================================== - private void reconstructionWarn(String msg) { - //TODO: if statement/contents temporary - if (msg.contains("failed to align") && hasHiddenComponents()) { + private void reconstructionWarn(String msg, boolean hasHiddenComponents) { + if (msg.contains("failed to align") && hasHiddenComponents) { msg = msg.replaceFirst("PDB", "PDB CLASS"); } Msg.warn(this, msg); } //============================================================================================== - @Override - void deferredApply() throws PdbException, CancelledException { - if (isDeferred()) { - applyInternal(); - } - } - - //============================================================================================== - //============================================================================================== - @Override - CompositeTypeApplier getDependencyApplier() { - if (definitionApplier != null && definitionApplier instanceof CompositeTypeApplier) { - return (CompositeTypeApplier) definitionApplier; - } - return this; - } - - String getName() { - return getMsType().getName(); - } - - @Override - DataType getDataType() { - if (resolved) { - return resolvedDataType; - } - getOrCreateComposite(); - return dataType; - } - - /** - * Returns a datatype or a newly minted datatype if it is an unnamed datatype. In the latter - * case, the type is put into an internal category of the parent and the name is given - * a suffix based on the ordinal within the parent - * @param categoryPath the CategoryPath - * @param ordinal the ordinal - * @return the Datatype - * @throws CancelledException upon user cancellation - * @throws PdbException upon error - */ - DataType getDataType(CategoryPath categoryPath, int ordinal) - throws CancelledException, PdbException { - if (!isUnnamed()) { - return getDataType(); - } - return mintNestedUnnamedDataType(categoryPath, ordinal); - } - - private DataType mintNestedUnnamedDataType(CategoryPath categoryPath, int ordinal) - throws CancelledException, PdbException { - SymbolPath sp = getFixedSymbolPath(); - SymbolPath modifiedSymbolPath = - new SymbolPath(sp.getParent(), sp.getName() + "_" + ordinal); - ComboType c = getOrCreateComposite(applicator, this, (AbstractCompositeMsType) msType, - categoryPath, modifiedSymbolPath); - applyInternal((Composite) c.dt()); - return c.dt(); - } - - @Override - DataType getCycleBreakType() { - if (isForwardReference() && definitionApplier != null && definitionApplier.isApplied()) { - return definitionApplier.getDataType(); - } - return dataType; - } - - boolean hasUniqueName() { - return ((AbstractCompositeMsType) msType).getMsProperty().hasUniqueName(); - } - - @Override - BigInteger getSize() { - return ((AbstractCompositeMsType) getDependencyApplier().getMsType()).getSize(); + BigInteger getSize(AbstractCompositeMsType type) { + AbstractCompositeMsType definition = getDefinitionType(type); + return definition.getSize(); } // TODO: @@ -496,146 +201,101 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } } - private boolean hasBaseClasses() { - AbstractCompositeMsType defType; - if (definitionApplier == null) { - if (isForwardReference()) { - return false; - } - defType = (AbstractCompositeMsType) msType; - } - else { - defType = (AbstractCompositeMsType) definitionApplier.getMsType(); - } - MsTypeApplier applier = - applicator.getTypeApplier(defType.getFieldDescriptorListRecordNumber()); - if (!(applier instanceof FieldListTypeApplier)) { - return false; - } - FieldListTypeApplier fieldListApplier = (FieldListTypeApplier) applier; - AbstractFieldListMsType fieldListType = - ((AbstractFieldListMsType) fieldListApplier.getMsType()); - if (fieldListType.getBaseClassList().size() != 0) { - return true; - } - return (fieldListType.getBaseClassList().size() != 0); + private boolean hasHiddenComponents(FieldListTypeApplier.FieldLists lists) { + return (lists.methods().size() != 0 || lists.bases().size() != 0); } - private boolean hasHiddenComponents() { - AbstractCompositeMsType defType; - if (definitionApplier == null) { - if (isForwardReference()) { - return false; - } - defType = (AbstractCompositeMsType) msType; - } - else { - defType = (AbstractCompositeMsType) definitionApplier.getMsType(); - } + private void addClassTypeBaseClassesNew(Composite composite, CppCompositeType myClassType, + List msBases, AbstractMsType type, FixupContext fixupContext, + boolean breakCycle) throws PdbException, CancelledException { - // Note: if a "class" only has structure fields--does not have member functions, base - // class, virtual inheritance, etc., then it acts like a structure, meaning that there - // should be no extra fields for pvft, pvbt, base and virtual class components. - // So... it might not be good to return "true" for just checking if the type is an - // instanceof AbstractClassMsType. + AbstractCompositeMsType cType = (AbstractCompositeMsType) type; - MsTypeApplier applier = - applicator.getTypeApplier(defType.getFieldDescriptorListRecordNumber()); - if (!(applier instanceof FieldListTypeApplier)) { - return false; - } - FieldListTypeApplier fieldListApplier = (FieldListTypeApplier) applier; - AbstractFieldListMsType fieldListType = - ((AbstractFieldListMsType) fieldListApplier.getMsType()); + for (AbstractMsType baseType : msBases) { - return (fieldListType.getMethodList().size() != 0 || - fieldListType.getBaseClassList().size() != 0); - } - - private void addClassTypeBaseClasses(Composite composite, FieldListTypeApplier fieldListApplier) - throws PdbException { - - AbstractCompositeMsType type = (AbstractCompositeMsType) msType; - - for (MsTypeApplier baseApplierIterated : fieldListApplier.getBaseClassList()) { - if (!(baseApplierIterated instanceof BaseClassTypeApplier)) { - applicator.appendLogMsg(baseApplierIterated.getClass().getSimpleName() + - " seen where BaseClassTypeApplier expected for " + type.getName()); - continue; - } - BaseClassTypeApplier baseTypeApplier = (BaseClassTypeApplier) baseApplierIterated; - MsTypeApplier baseClassTypeApplier = - applicator.getTypeApplier(baseTypeApplier.getBaseClassRecordNumber()); - if (!(baseClassTypeApplier instanceof CompositeTypeApplier)) { - applicator.appendLogMsg(baseApplierIterated.getClass().getSimpleName() + - " seen where CompositeTypeApplier expected for " + type.getName()); + MsTypeApplier baseApplier = applicator.getTypeApplier(baseType); + if (!(baseApplier instanceof BaseClassTypeApplier baseTypeApplier)) { + applicator.appendLogMsg(baseApplier.getClass().getSimpleName() + + " seen where BaseClassTypeApplier expected for " + cType.getName()); continue; } - AbstractMsType baseClassMsType = baseTypeApplier.getMsType(); - if (baseClassMsType instanceof AbstractBaseClassMsType) { - applyDirectBaseClass((AbstractBaseClassMsType) baseClassMsType); + if (baseType instanceof AbstractBaseClassMsType baseClassType) { + applyDirectBaseClass(baseClassType, myClassType, fixupContext); } - else if (baseClassMsType instanceof AbstractVirtualBaseClassMsType) { - applyDirectVirtualBaseClass((AbstractVirtualBaseClassMsType) baseClassMsType); + else if (baseType instanceof AbstractVirtualBaseClassMsType virtualBaseClassType) { + applyDirectVirtualBaseClass(virtualBaseClassType, myClassType, fixupContext, + breakCycle); } - else if (baseClassMsType instanceof AbstractIndirectVirtualBaseClassMsType) { - applyIndirectVirtualBaseClass( - (AbstractIndirectVirtualBaseClassMsType) baseClassMsType); + else if (baseType instanceof AbstractIndirectVirtualBaseClassMsType indirectVirtualBaseClassType) { + applyIndirectVirtualBaseClass(indirectVirtualBaseClassType, myClassType, + fixupContext, breakCycle); } else { throw new AssertException( - "Unknown base class type: " + baseClassMsType.getClass().getSimpleName()); + "Unknown base class type: " + baseType.getClass().getSimpleName()); } } } - private void applyDirectBaseClass(AbstractBaseClassMsType base) throws PdbException { + private void applyDirectBaseClass(AbstractBaseClassMsType base, CppCompositeType myClassType, + FixupContext fixupContext) throws PdbException, CancelledException { CppCompositeType underlyingClassType = - getUnderlyingClassType(base.getBaseClassRecordNumber()); + getUnderlyingClassType(base.getBaseClassRecordNumber(), fixupContext); if (underlyingClassType == null) { return; } ClassFieldMsAttributes atts = base.getAttributes(); - int offset = DefaultPdbApplicator.bigIntegerToInt(applicator, base.getOffset()); - classType.addDirectBaseClass(underlyingClassType, convertAttributes(atts), offset); + int offset = applicator.bigIntegerToInt(base.getOffset()); + myClassType.addDirectBaseClass(underlyingClassType, convertAttributes(atts), offset); } - private void applyDirectVirtualBaseClass(AbstractVirtualBaseClassMsType base) - throws PdbException { - CppCompositeType underlyingCt = getUnderlyingClassType(base.getBaseClassRecordNumber()); + private void applyDirectVirtualBaseClass(AbstractVirtualBaseClassMsType base, + CppCompositeType myClassType, FixupContext fixupContext, boolean breakCycle) + throws PdbException, CancelledException { + CppCompositeType underlyingCt = + getUnderlyingClassType(base.getBaseClassRecordNumber(), fixupContext); if (underlyingCt == null) { return; } - DataType vbtptr = - getVirtualBaseTablePointerDataType(base.getVirtualBasePointerRecordNumber()); + DataType vbtptr = getVirtualBaseTablePointerDataType( + base.getVirtualBasePointerRecordNumber(), fixupContext, breakCycle); ClassFieldMsAttributes atts = base.getAttributes(); - int basePointerOffset = - DefaultPdbApplicator.bigIntegerToInt(applicator, base.getBasePointerOffset()); - int offsetFromVbt = - DefaultPdbApplicator.bigIntegerToInt(applicator, base.getBaseOffsetFromVbt()); - classType.addDirectVirtualBaseClass(underlyingCt, convertAttributes(atts), + int basePointerOffset = applicator.bigIntegerToInt(base.getBasePointerOffset()); + int offsetFromVbt = applicator.bigIntegerToInt(base.getBaseOffsetFromVbt()); + myClassType.addDirectVirtualBaseClass(underlyingCt, convertAttributes(atts), basePointerOffset, vbtptr, offsetFromVbt); } - private void applyIndirectVirtualBaseClass(AbstractIndirectVirtualBaseClassMsType base) - throws PdbException { - CppCompositeType underlyingCt = getUnderlyingClassType(base.getBaseClassRecordNumber()); + private void applyIndirectVirtualBaseClass(AbstractIndirectVirtualBaseClassMsType base, + CppCompositeType myClassType, FixupContext fixupContext, boolean breakCycle) + throws PdbException, CancelledException { + CppCompositeType underlyingCt = + getUnderlyingClassType(base.getBaseClassRecordNumber(), fixupContext); if (underlyingCt == null) { return; } - DataType vbtptr = - getVirtualBaseTablePointerDataType(base.getVirtualBasePointerRecordNumber()); + DataType vbtptr = getVirtualBaseTablePointerDataType( + base.getVirtualBasePointerRecordNumber(), fixupContext, breakCycle); ClassFieldMsAttributes atts = base.getAttributes(); - int basePointerOffset = - DefaultPdbApplicator.bigIntegerToInt(applicator, base.getBasePointerOffset()); - int offsetFromVbt = - DefaultPdbApplicator.bigIntegerToInt(applicator, base.getBaseOffsetFromVbt()); - classType.addIndirectVirtualBaseClass(underlyingCt, convertAttributes(atts), + int basePointerOffset = applicator.bigIntegerToInt(base.getBasePointerOffset()); + int offsetFromVbt = applicator.bigIntegerToInt(base.getBaseOffsetFromVbt()); + myClassType.addIndirectVirtualBaseClass(underlyingCt, convertAttributes(atts), basePointerOffset, vbtptr, offsetFromVbt); } - private CppCompositeType getUnderlyingClassType(RecordNumber recordNumber) { + private CppCompositeType getUnderlyingClassType(RecordNumber recordNumber, + FixupContext fixupContext) throws CancelledException, PdbException { + + AbstractMsType type = applicator.getPdb().getTypeRecord(recordNumber); + if (!(type instanceof AbstractCompositeMsType comp)) { + applicator.appendLogMsg(type.getClass().getSimpleName() + + " seen where Composite Type expected for base class."); + return null; + } + // not sure if need to do this. TODO: evaluate + applicator.getProcessedDataType(recordNumber, fixupContext, false); + MsTypeApplier baseUnderlyingApplier = applicator.getTypeApplier(recordNumber); if (!(baseUnderlyingApplier instanceof CompositeTypeApplier)) { applicator.appendLogMsg(baseUnderlyingApplier.getClass().getSimpleName() + @@ -643,19 +303,18 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { return null; } CompositeTypeApplier baseApplier = (CompositeTypeApplier) baseUnderlyingApplier; - CppCompositeType underlyingClassType = baseApplier.getClassType(); + CppCompositeType underlyingClassType = baseApplier.getClassType(type); if (underlyingClassType == null) { applicator.appendLogMsg("Underlying base class type is null."); } return underlyingClassType; } - private DataType getVirtualBaseTablePointerDataType(RecordNumber recordNumber) { - MsTypeApplier vbptrApplier = applicator.getTypeApplier(recordNumber); - if (vbptrApplier != null) { - if (vbptrApplier instanceof PointerTypeApplier) { - return vbptrApplier.getDataType(); - } + private DataType getVirtualBaseTablePointerDataType(RecordNumber recordNumber, + FixupContext fixupContext, boolean breakCycle) throws CancelledException, PdbException { + DataType dt = applicator.getProcessedDataType(recordNumber, fixupContext, breakCycle); + if (dt != null) { + return dt; } applicator.appendLogMsg("Generating a generic Virtual Base Table Pointer."); return new PointerDataType(); @@ -696,179 +355,346 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { return new CppCompositeType.ClassFieldAttributes(myAccess, myProperty); } - private void addMembers(Composite composite, FieldListTypeApplier fieldListApplier) + private void addMembers(Composite composite, CppCompositeType myClassType, + List msMembers, AbstractCompositeMsType type, + List myMembers, FixupContext fixupContext, + boolean breakCycle) throws CancelledException, PdbException { + + for (int index = 0; index < msMembers.size(); index++) { + applicator.checkCancelled(); + AbstractMemberMsType memberType = msMembers.get(index); + DefaultPdbUniversalMember member = + getNonStaticMember(composite, memberType, index, fixupContext, breakCycle); + DataType dt = member.getDataType().getDataType(); + if (applicator.isPlaceholderType(dt)) { + fixupContext.putFixup(index); + } + myMembers.add(member); + myClassType.addMember(member.getName(), dt, member.isZeroLengthArray(), + member.getAttributes(), member.getOffset(), member.getComment()); + } + } + + private void addVftPtrs(Composite composite, CppCompositeType myClassType, + List msVftPtrs, AbstractCompositeMsType type, + List myMembers, FixupContext fixupContext, + boolean breakCycle) throws CancelledException, PdbException { + for (AbstractVirtualFunctionTablePointerMsType vftPtr : msVftPtrs) { + MsTypeApplier applierIterated = applicator.getTypeApplier(vftPtr); + if (applierIterated instanceof VirtualFunctionTablePointerTypeApplier vtPtrApplier) { + DefaultPdbUniversalMember member = + getVftPtrMember(vftPtr, vtPtrApplier, fixupContext, breakCycle); + myMembers.add(member); + myClassType.addVirtualFunctionTablePointer(member.getName(), + member.getDataType().getDataType(), member.getOffset()); + } + } + } + + // We broke up the big addMembers() method that had static and non-static members, along with + // vftptrs, and the items in this method. These were not really processed in the older + // method, but we wanted to capture the types that still possible + private void addOthers(Composite composite, CppCompositeType myClassType, + List msMembers, AbstractCompositeMsType type, + List myMembers, FixupContext fixupContext) throws CancelledException, PdbException { - AbstractCompositeMsType type = (AbstractCompositeMsType) msType; - - for (MsTypeApplier memberTypeApplierIterated : fieldListApplier.getMemberList()) { - boolean handled = true; - if (memberTypeApplierIterated instanceof MemberTypeApplier) { - MemberTypeApplier memberTypeApplier = (MemberTypeApplier) memberTypeApplierIterated; - String memberName = memberTypeApplier.getName(); - - int offset = - DefaultPdbApplicator.bigIntegerToInt(applicator, memberTypeApplier.getOffset()); - ClassFieldMsAttributes memberAttributes = memberTypeApplier.getAttribute(); - memberAttributes.getAccess(); // TODO: do something with this and other attributes - MsTypeApplier fieldApplier = memberTypeApplier.getFieldTypeApplier(); - - DataType fieldDataType = null; - if (fieldApplier instanceof CompositeTypeApplier) { - CompositeTypeApplier defApplier = - ((CompositeTypeApplier) fieldApplier).getDefinitionApplier( - CompositeTypeApplier.class); - if (defApplier != null) { - fieldApplier = defApplier; - } - fieldDataType = ((CompositeTypeApplier) fieldApplier).getDataType( - ClassTypeUtils.getInternalsCategoryPath(this), members.size()); - } - if (fieldDataType == null) { - fieldDataType = fieldApplier.getDataType(); - } - boolean isFlexibleArray; - if (fieldApplier instanceof ArrayTypeApplier) { - isFlexibleArray = ((ArrayTypeApplier) fieldApplier).isFlexibleArray(); - } - else { - isFlexibleArray = false; - } - if (fieldApplier instanceof CompositeTypeApplier && - ((CompositeTypeApplier) fieldApplier).isUnnamed()) { - DefaultPdbUniversalMember member = new DefaultPdbUniversalMember(applicator, - memberName, fieldDataType, offset); - members.add(member); - } - else if (fieldDataType == null) { - if (fieldApplier instanceof PrimitiveTypeApplier && - ((PrimitiveTypeApplier) fieldApplier).isNoType()) { - DefaultPdbUniversalMember member = new DefaultPdbUniversalMember(applicator, - memberName, fieldApplier, offset); - members.add(member); - componentComments.put(offset, "NO_TYPE"); - } - else { - applicator.appendLogMsg("PDB Warning: No conversion for " + memberName + - " " + fieldApplier.getMsType().getClass().getSimpleName() + - " in composite " + composite.getName()); - } - } - else { - String memberComment = null; - if (fieldApplier instanceof PointerTypeApplier ptrApplier) { - memberComment = ptrApplier.getPointerCommentField(); - } - DefaultPdbUniversalMember member = new DefaultPdbUniversalMember(applicator, - memberName, fieldApplier, offset, memberComment); - members.add(member); - classType.addMember(memberName, fieldDataType, isFlexibleArray, - convertAttributes(memberAttributes), offset, memberComment); - } + for (AbstractMsType typeIterated : msMembers) { + MsTypeApplier applierIterated = applicator.getTypeApplier(typeIterated); + if (applierIterated instanceof EnumerateTypeApplier enumerateApplier && + typeIterated instanceof AbstractEnumerateMsType enumerateType) { + processEnumerate(type, enumerateApplier, enumerateType); } - else if (memberTypeApplierIterated instanceof EnumerateTypeApplier) { - EnumerateTypeApplier enumerateTypeApplier = - (EnumerateTypeApplier) memberTypeApplierIterated; - String fieldName = enumerateTypeApplier.getName(); - Numeric numeric = enumerateTypeApplier.getNumeric(); - // TODO: some work - pdbLogAndInfoMessage(this, - "Don't know how to apply EnumerateTypeApplier fieldName " + fieldName + - " and value " + numeric + " within " + msType.getName()); + else if (applierIterated instanceof NestedTypeApplier nestedTypeApplier) { + processNestedType(type, nestedTypeApplier, typeIterated); } - else if (memberTypeApplierIterated instanceof VirtualFunctionTablePointerTypeApplier) { - VirtualFunctionTablePointerTypeApplier vtPtrApplier = - (VirtualFunctionTablePointerTypeApplier) memberTypeApplierIterated; - String vftPtrMemberName = vtPtrApplier.getMemberName(); - int offset = vtPtrApplier.getOffset(); - DefaultPdbUniversalMember member = new DefaultPdbUniversalMember(applicator, - vftPtrMemberName, vtPtrApplier, offset); - members.add(member); - //classType.addMember(vftPtrMemberName, vtPtrApplier.getDataType(), false, offset); - classType.addVirtualFunctionTablePointer(vftPtrMemberName, - vtPtrApplier.getDataType(), offset); - } - else if (memberTypeApplierIterated instanceof NestedTypeApplier) { - // Need to make sure that "this" class id dependent on all elements composing the - // nested definition, but we need to create the nested definition during the - // creation of this class. (NestedTypeApplier and NestedTypeMsType do not really - // have their own RecordNumber). - // 20200114: think this is a nested typedef. - NestedTypeApplier nestedTypeApplier = (NestedTypeApplier) memberTypeApplierIterated; - String memberTypeName = nestedTypeApplier.getTypeName(); - String memberName = nestedTypeApplier.getMemberName(); // use this - // TODO: we are assuming that the offset is zero (0) for the call. Need to dig - // more to confirm this. Is ever anything but just one nested type? The pdb.exe - // generates these all at offset 0. - // TODO: Nested types are currently an issue for - // DefaultCompositeMember.applyDataTypeMembers(). - // Need to investigate what to do here. It could be just when the specific - // composite is a member of itself. - if (type.getName().equals(memberTypeName)) { - // We are skipping because we've had issues and do not know what is going on - // at the moment. (I think they were dependency issues... been a while.) - // See not above the "if" condition. -// pdbLogAndInfoMessage(this, "Skipping Composite Nested type member: " + -// memberName + " within " + type.getName()); - // TODO: Investigate. What does it mean when the internally defined type - // conficts with the name of the outer type. - continue; - } - // TODO: believe the thing to do is to show that these are types that are - // defined within the namespace of this containing type. This might be - // the place to do it... that is if we don't identify them separately - // falling under the namespace of this composite. - -// AbstractMsTypeApplier nestedDefinitionApplier = -// nestedTypeApplier.getNestedTypeDefinitionApplier().getDependencyApplier(); -// -// DataType ndt = nestedDefinitionApplier.getDataType(); //use this -// int ndtl = ndt.getLength(); //use this -// -// AbstractMsType ndms = nestedTypeApplier.getMsType(); -// -// BigInteger val = nestedTypeApplier.getSize(); -// int offset = 0; // ???? TODO.., -// DataType nt = nestedTypeApplier.getDataType(); -// ClassFieldMsAttributes a = nestedTypeApplier.getAttributes(); -// -// // TODO: hoping this is right... 20200521... how/where do we get offset? -// Default2PdbMember member = -// new Default2PdbMember(applicator, memberName, nestedDefinitionApplier, offset); -// members.add(member); - } - else if (memberTypeApplierIterated instanceof NoTypeApplier) { - AbstractMsType msNoType = memberTypeApplierIterated.getMsType(); - if (msNoType instanceof AbstractStaticMemberMsType) { + else if (applierIterated instanceof NoTypeApplier) { + if (typeIterated instanceof AbstractStaticMemberMsType) { // TODO: Investigate anything that hits here (set break point), see if we // see dot apply the information. If so, probably should create an applier // for the contained MS type. } else { - handled = false; + processNotHandled(composite, applierIterated, typeIterated); } } else { - handled = false; - } - if (!handled) { - applicator.appendLogMsg( - memberTypeApplierIterated.getClass().getSimpleName() + " with contained " + - memberTypeApplierIterated.getMsType().getClass().getSimpleName() + - " unexpected for " + msType.getName()); + processNotHandled(composite, applierIterated, typeIterated); } } + + } + + private DefaultPdbUniversalMember getNonStaticMember(Composite container, + AbstractMemberMsType memberMsType, int ordinal, FixupContext fixupContext, + boolean breakCycle) throws CancelledException, PdbException { + + MsTypeApplier applier = applicator.getTypeApplier(memberMsType); + if (!(applier instanceof MemberTypeApplier memberApplier)) { + throw new PdbException("Member applier expected"); + } + + String memberName = memberMsType.getName(); + int offset = applicator.bigIntegerToInt(memberMsType.getOffset()); + + ClassFieldMsAttributes memberAttributes = memberMsType.getAttribute(); + memberAttributes.getAccess(); // TODO: do something with this and other attributes + + AbstractMsType fieldType = + applicator.getPdb().getTypeRecord(memberMsType.getFieldTypeRecordNumber()); + MsTypeApplier fieldApplier = applicator.getTypeApplier(fieldType); + + String memberComment = null; + DataType fieldDataType = applicator.getProcessedDataType( + memberMsType.getFieldTypeRecordNumber(), fixupContext, breakCycle); + if (fieldApplier instanceof PointerTypeApplier ptrApplier) { + AbstractPointerMsType pointerType = (AbstractPointerMsType) fieldType; + memberComment = ptrApplier.getPointerCommentField(pointerType, fixupContext); + } + + boolean isZeroLengthArray = (fieldDataType instanceof Array && + fieldApplier instanceof ArrayTypeApplier arrayApplier && + arrayApplier.isFlexibleArray(fieldType)); + + DefaultPdbUniversalMember member = new DefaultPdbUniversalMember(memberName, fieldDataType, + isZeroLengthArray, offset, convertAttributes(memberAttributes), memberComment); + return member; + } + + private DefaultPdbUniversalMember getVftPtrMember( + AbstractVirtualFunctionTablePointerMsType type, + VirtualFunctionTablePointerTypeApplier vtPtrApplier, FixupContext fixupContext, + boolean breakCycle) throws CancelledException, PdbException { + String vftPtrMemberName = vtPtrApplier.getMemberName(type); + int offset = vtPtrApplier.getOffset(type); + DataType dt = vtPtrApplier.apply(type, fixupContext, breakCycle); + return new DefaultPdbUniversalMember(vftPtrMemberName, dt, offset); + } + + private void processEnumerate(AbstractCompositeMsType type, EnumerateTypeApplier applier, + AbstractEnumerateMsType enumerateType) { + String fieldName = enumerateType.getName(); + Numeric numeric = enumerateType.getNumeric(); + // TODO: some work + pdbLogAndInfoMessage(this, "Don't know how to apply EnumerateTypeApplier fieldName " + + fieldName + " and value " + numeric + "."); + } + + private void processNestedType(AbstractCompositeMsType type, + NestedTypeApplier nestedTypeApplier, AbstractMsType enumerateType) { + // Need to make sure that "this" class id dependent on all elements composing the + // nested definition, but we need to create the nested definition during the + // creation of this class. (NestedTypeApplier and NestedTypeMsType do not really + // have their own RecordNumber). + // 20200114: think this is a nested typedef. + String memberTypeName = enumerateType.getName(); +// String memberName = nestedTypeApplier.getMemberName(); // use this + // TODO: we are assuming that the offset is zero (0) for the call. Need to dig + // more to confirm this. Is ever anything but just one nested type? The pdb.exe + // generates these all at offset 0. + // TODO: Nested types are currently an issue for + // DefaultCompositeMember.applyDataTypeMembers(). + // Need to investigate what to do here. It could be just when the specific + // composite is a member of itself. + if (type.getName().equals(memberTypeName)) { + // We are skipping because we've had issues and do not know what is going on + // at the moment. (I think they were dependency issues... been a while.) + // See not above the "if" condition. +// pdbLogAndInfoMessage(this, "Skipping Composite Nested type member: " + +// memberName + " within " + type.getName()); + // TODO: Investigate. What does it mean when the internally defined type + // conflicts with the name of the outer type. + } + // TODO: believe the thing to do is to show that these are types that are + // defined within the namespace of this containing type. This might be + // the place to do it... that is if we don't identify them separately + // falling under the namespace of this composite. + + } + + private void processNotHandled(Composite composite, MsTypeApplier applier, + AbstractMsType memberType) { + applicator.appendLogMsg(applier.getClass().getSimpleName() + " with contained " + + memberType.getClass().getSimpleName() + " unexpected for " + composite.getName()); + } + + //============================================================================================== + DataType fixup(AbstractCompositeMsType type, Map contextMap) + throws CancelledException, PdbException { + DataType dt = applicator.getDataType(type); + if (dt instanceof DataTypeImpl || !(dt instanceof Composite)) { + throw new PdbException("Can only fixup Composite DB "); + } + return null; + } + + //============================================================================================== + DataType apply(AbstractCompositeMsType type, FixupContext fixupContext, boolean breakCycle) + throws CancelledException, PdbException { + + int typeNumber = type.getRecordNumber().getNumber(); + int mappedNumber = applicator.getMappedComplexType(typeNumber); + DataType existingDt = applicator.getDataType(mappedNumber); + if (existingDt != null) { + return existingDt; + } + + AbstractMsType msType = + applicator.getPdb().getTypeRecord(RecordNumber.typeRecordNumber(mappedNumber)); + if (!(msType instanceof AbstractCompositeMsType)) { + throw new PdbException("PDB processing error"); + } + type = (AbstractCompositeMsType) msType; + + CppCompositeType myClassType = getClassType(type); + ComboType combo; + Composite composite; + if (myClassType == null) { + combo = create(type); + composite = combo.dt(); + myClassType = combo.ct(); + applicator.putClassType(type, myClassType); + } + else { + composite = myClassType.getComposite(); + combo = new ComboType(composite, myClassType); + } + + applyInternal(combo, type, fixupContext, breakCycle); + + composite = (Composite) applicator.resolve(composite); + applicator.putDataType(mappedNumber, composite); + return composite; + } + + private AbstractCompositeMsType getDefinitionType(AbstractComplexMsType type) { + return getDefinitionType(type, AbstractCompositeMsType.class); + } + + public void fixUp(FixupContext fixupContext) throws PdbException, CancelledException { + + Integer indexNumber = fixupContext.peekFixupRecord(); + if (indexNumber == null) { + return; + } + + AbstractMsType t = + applicator.getPdb().getTypeRecord(RecordNumber.typeRecordNumber(indexNumber)); + if (!(t instanceof AbstractComplexMsType type)) { + throw new PdbException("error"); + } + AbstractCompositeMsType defType = getDefinitionType(type); + + DataType dataType = applicator.getDataType(indexNumber); + if (dataType == null) { + applicator.appendLogMsg("Null type for index: " + indexNumber); + return; + } + if (dataType instanceof DataTypeImpl) { + applicator.appendLogMsg("Impl type for index: " + indexNumber); + return; + } + if (!(dataType instanceof Composite compositeDB)) { + applicator.appendLogMsg("Composite expected type for index: " + indexNumber); + return; + } + + FieldListTypeApplier fieldListApplier = FieldListTypeApplier.getFieldListApplierSpecial( + applicator, defType.getFieldDescriptorListRecordNumber()); + FieldListTypeApplier.FieldLists lists = + fieldListApplier.getFieldLists(defType.getFieldDescriptorListRecordNumber()); + + List msMembers = lists.nonstaticMembers(); + + List fixupIndices = fixupContext.getFixups(); + for (int index : fixupIndices) { + applicator.checkCancelled(); + AbstractMemberMsType memberType = msMembers.get(index); + // Using a null FixupContext signifies "doing" vs. creating fixups. + DefaultPdbUniversalMember member = + getNonStaticMember(compositeDB, memberType, index, null, false); + replaceComponentDataType(compositeDB, member); + } + } + + private void replaceComponentDataType(Composite compositeDB, DefaultPdbUniversalMember member) + throws CancelledException, PdbException { + DataType dt = member.getDataType().getDataType(); + if (applicator.isPlaceholderPointer(dt)) { + throw new PdbException("Placeholder pointer not expected"); + } + if (!recurseReplacement(compositeDB, 0, member)) { + /** + * We want to throw the exception below, but for now, we are only making a warning. + * This is because we have a situation where we still do not accurately map + * definitions with forward references and when this causes a size calculation within + * the {@link ArrayTypeApplier}, we fill in the array with dummy undefined1 types, + * which can cause the replacement issue here. When that gets fixed, the warning + * here should be replaced with the PdbException. + */ + Msg.warn(this, + "PDB: Unable to replace placeholder component of: " + compositeDB.getName()); +// throw new PdbException( +// "Unable to replace placeholder component of: " + compositeDB.getName()); + } + } + + private boolean recurseReplacement(Composite compositeDB, int baseOffset, + DefaultPdbUniversalMember member) throws CancelledException, PdbException { + DataTypeComponent[] components = compositeDB.getDefinedComponents(); + for (DataTypeComponent component : components) { + if (member.getOffset() > baseOffset + component.getEndOffset()) { + continue; + } + if (member.getOffset() < baseOffset + component.getOffset()) { + continue; + } + DataType componentDt = component.getDataType(); + // We would normally just check for a union, expecting any other component to be + // a fully defined datatype, but using DefaultPdbUniveralMember to unflatten + // a union can result in nested structures that are not otherwise resolved. Thus, + // we must check for any composite: union or structure. + if (!applicator.isPlaceholderType(componentDt) && + componentDt instanceof Composite nestedComposite) { + if (recurseReplacement(nestedComposite, baseOffset + component.getOffset(), + member)) { + return true; + } + continue; + } + if (applicator.isPlaceholderType(componentDt) && + component.getFieldName().equals(member.getName()) && + member.getOffset() == baseOffset + component.getOffset()) { + DataType replacementDt = member.getDataType().getDataType(); + int length = replacementDt.getLength(); + if (length != componentDt.getLength()) { + throw new PdbException("Mismatch component type length on replacement: " + + replacementDt.getName()); + } + int ordinal = component.getOrdinal(); + replaceComponent(compositeDB, ordinal, replacementDt); + return true; + } + } + return false; + } + + private static void replaceComponent(Composite composite, int ordinal, DataType newType) + throws PdbException { + if (composite instanceof Structure struct) { + DataTypeComponent dtc = struct.getComponent(ordinal); + struct.replace(ordinal, newType, newType.getLength(), dtc.getFieldName(), + dtc.getComment()); + } + else if (composite instanceof Union union) { + DataTypeComponent dtc = union.getComponent(ordinal); + union.delete(ordinal); + union.insert(ordinal, newType, newType.getLength(), dtc.getFieldName(), + dtc.getComment()); + } + else { + throw new PdbException("Not struct or union: " + composite.getClass().getSimpleName()); + } } -// /** -// * NoType provides ability to hang NoType into a composite type by faking -// * it with a zero-length bitfield. This is a bit of a kludge -// * This will be transformed to a normal BitFieldDataType when cloned. -// */ -// private class NoType extends PdbBitField { -// private NoType(PdbApplicator applicator) throws InvalidDataTypeException { -// super(new CharDataType(applicator.getDataTypeManager()), 0, 0); -// } -// } -// } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java index 0ca281a163..80cf1e081f 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -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) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java index a8b3281166..9dd4d1932e 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -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 dataTypeIdByMsTypeNum; + private Map dataTypeImplByMsTypeNum; + private Map classTypeByMsTypeNum; private ComplexTypeMapper complexTypeMapper; - private ComplexTypeApplierMapper complexApplierMapper; - private JungDirectedGraph> applierDependencyGraph; /** * This namespace map documents as follows: *
@@ -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 getVerticesInPostOrder() {
-		TaskMonitor monitor = getMonitor();
-		monitor.setMessage("PDB: Determining data type dependency order...");
-		return GraphAlgorithms.getVerticesInPostOrder(applierDependencyGraph,
-			GraphNavigator.topDownNavigator());
-	}
-
 	//==============================================================================================
 	//==============================================================================================
-	//==============================================================================================
-	MsTypeApplier getApplierSpec(RecordNumber recordNumber, Class expected)
-			throws PdbException {
-		return typeApplierParser.getApplierSpec(recordNumber, expected);
-	}
-
 	MsTypeApplier getApplierOrNoTypeSpec(RecordNumber recordNumber,
 			Class 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 placeholderPointers;
+	private Set pointerIDs;
+	// Structure used to mock placeholder array.
+	private Map placeholderArrays;
+	private Set 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 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.
+	 * 

+ * 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. + *

+ * 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. + *

+ * 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 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); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbUniversalMember.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbUniversalMember.java index b1aca1826a..980d6d30dc 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbUniversalMember.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbUniversalMember.java @@ -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); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java index 83c9a0e650..60377a9df3 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java @@ -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 memberList = fieldListApplier.getMemberList(); + List 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); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java index 375c1ecac6..6c6ec4aea1 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java @@ -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; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java index c4748c9c99..8399cfd0a7 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java @@ -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 baseClassList = new ArrayList<>(); - private List memberList = new ArrayList<>(); - private List 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 getBaseClassList() { - return baseClassList; - } - - List getMemberList() { - return memberList; - } - - List 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 bases, List members, + List nonstaticMembers, + List vftPtrs, List methods, + List nestedTypes, List 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 bases = new ArrayList<>(); + List members = new ArrayList<>(); + List 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 nonstaticMembers = + new ArrayList<>(fieldListType.getNonStaticMembers()); + List vftPtrs = + new ArrayList<>(fieldListType.getVftPointers()); + List nestedTypes = + new ArrayList<>(fieldListType.getNestedTypes()); + List 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 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 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 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); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FixupContext.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FixupContext.java new file mode 100644 index 0000000000..0cc8373b74 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FixupContext.java @@ -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 stagedRecordFifo = new ArrayDeque<>(); + private Deque inProgressRecordStack = new ArrayDeque<>(); + private Deque fixupRecordFifo = new ArrayDeque<>(); + + private Map> map = new HashMap<>(); + private Map 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 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 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 getFixups() throws PdbException { + Integer record = peekFixupsRecord(); + if (record == null) { + throw new PdbException("Empty fixups retrieval"); + } + List fixups = map.get(record); + if (fixups == null) { + throw new PdbException("Fixups not found on retrieval"); + } + return fixups; + } + + private List getProcessFixups() throws PdbException { + Integer record = peekProcessRecord(); + if (record == null) { + throw new PdbException("Context empty on fixups retrieval"); + } + List fixups = map.get(record); + if (fixups == null) { + throw new PdbException("Fixups not found"); + } + return fixups; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java index 2e92a806fd..a8d6911809 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -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)) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java index 4ee4bdc0a5..a84a4f2a3a 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java @@ -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); -// } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java index c87262cd12..b06b4041e0 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java @@ -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; } - } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java index 63159b22e3..a8aebefdcb 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -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; } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsTypeApplier.java index a177648fcd..2bc89487f1 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsTypeApplier.java @@ -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 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 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; +// } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java index 106068a7af..26cddcf2e2 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java @@ -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; } - } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java index 74d896af2c..6e39a1130d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java @@ -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(""); - } - } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java index 8f6f2f3e65..68666c78eb 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java @@ -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; @@ -28,7 +28,7 @@ import ghidra.util.Msg; /** * Metrics captured during the application of a PDB. This is a Ghidra class separate from the * PDB API that we have crafted to help us quantify and qualify the ability apply the PDB - * to a {@link DataTypeManager} and/or {@link Program}. + * to a {@link DataTypeManager} and/or {@link Program}. */ public class PdbApplicatorMetrics { @@ -68,7 +68,7 @@ public class PdbApplicatorMetrics { LocalThreadStorage3216MsSymbol.PDB_ID, LocalThreadStorage32MsSymbol.PDB_ID, LocalThreadStorage32StMsSymbol.PDB_ID, - + // AbstractUserDefinedTypeMsSymbol CobolUserDefinedType16MsSymbol.PDB_ID, CobolUserDefinedTypeMsSymbol.PDB_ID, @@ -89,7 +89,7 @@ public class PdbApplicatorMetrics { * List of symbols seen (by their ID) as Public symbols. */ //@formatter:off - private static final Set EXPECTED_LINKER_SYMBOLS = Set.of( + private static final Set EXPECTED_LINKER_SYMBOLS = Set.of( PeCoffSectionMsSymbol.PDB_ID, TrampolineMsSymbol.PDB_ID, ObjectNameMsSymbol.PDB_ID, @@ -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()); } //============================================================================================== diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java index 187466df1b..059cf560eb 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -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::__value_type,std::__1::basic_string >,std::__1::less,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); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java index fbf6e4cb8b..28968daed7 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java @@ -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()); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java index 9dd295225c..e663389580 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java @@ -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 //======================================= @@ -211,7 +213,7 @@ public class PrimitiveTypeApplier extends MsTypeApplier { //======================================= // Unsigned Character types //======================================= - // 8-bit unsigned + // 8-bit unsigned case 0x0020: primitiveDataType = primitiveApplicator.getUnsignedCharType(); break; @@ -344,7 +346,7 @@ public class PrimitiveTypeApplier extends MsTypeApplier { case 0x007a: primitiveDataType = primitiveApplicator.getUnicode16Type(); break; - // 16-bit pointer to a 16-bit unicode char + // 16-bit pointer to a 16-bit unicode char case 0x017a: primitiveDataType = primitiveApplicator.get16NearPointerType(type, primitiveApplicator.getUnicode16Type()); @@ -387,7 +389,7 @@ public class PrimitiveTypeApplier extends MsTypeApplier { case 0x007b: primitiveDataType = primitiveApplicator.getUnicode32Type(); break; - // 16-bit pointer to a 32-bit unicode char + // 16-bit pointer to a 32-bit unicode char case 0x017b: primitiveDataType = primitiveApplicator.get16NearPointerType(type, primitiveApplicator.getUnicode32Type()); @@ -2060,6 +2062,9 @@ public class PrimitiveTypeApplier extends MsTypeApplier { } + primitiveDataType = applicator.resolve(primitiveDataType); + applicator.putDataType(indexNumber, primitiveDataType); + return primitiveDataType; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java index dc72477dc8..094506ede4 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java @@ -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(); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java index 449351a41a..abf402b79b 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java @@ -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); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierFactory.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierFactory.java index f6a5624088..f9e80eda7d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierFactory.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierFactory.java @@ -30,11 +30,11 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; public class TypeApplierFactory { private DefaultPdbApplicator applicator; - private Map appliersByRecordNumber; + private Map 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 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; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java index 5cf98b40c6..53ceae90e0 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -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; } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java index 6671dd59bb..882f23fac9 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java @@ -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) diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java index a32a5acec3..2d5bd89be5 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java @@ -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()); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java index 89cb7c2ade..e79ccb913a 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java @@ -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 list = msShape.getDescriptorList(); StructureDataType shape = new StructureDataType(applicator.getAnonymousTypesCategory(), - "vtshape" + index, 0, applicator.getDataTypeManager()); + "vtshape" + msShape.getRecordNumber().getNumber(), 0, applicator.getDataTypeManager()); List 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); } diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/TypesTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/TypesTest.java index 0685a85556..e4466e3f77 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/TypesTest.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/TypesTest.java @@ -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"); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java index dcbfb93053..8c1a76c7f0 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java @@ -106,7 +106,7 @@ class StructureDB extends CompositeDB implements StructureInternal { * NOTE: The offset of the migrated flex array component and structure length may change during * upgrade when packing is enabled when the original packed structure length did not properly * factor the flex-array alignment. Repack does not occur in the read-only case. - * + * * @param oldFlexArrayRecord record which corresponds to an old flex-array component * @throws IOException if a database error occurs */ @@ -564,7 +564,7 @@ class StructureDB extends CompositeDB implements StructureInternal { * offset shift to the remaining components. Removal of other component types will result in * an offset and ordinal shift to the remaining components. In the case of a non-packed * structure, the resulting shift will cause in a timestamp change for this structure. - * + * * @param index defined component index * @param disableOffsetShift if false, and component is not a bit-field, an offset shift and * possible structure length change will be performed for non-packed structure. @@ -778,7 +778,7 @@ class StructureDB extends CompositeDB implements StructureInternal { *

* WARNING! copying non-packed structures which contain bitfields can produce invalid results * when switching endianness due to the differences in packing order. - * + * * @param dtm target data type manager * @return cloned structure */ @@ -796,7 +796,7 @@ class StructureDB extends CompositeDB implements StructureInternal { *

* WARNING! cloning non-packed structures which contain bitfields can produce invalid results * when switching endianness due to the differences in packing order. - * + * * @param dtm target data type manager * @return cloned structure */ @@ -906,7 +906,7 @@ class StructureDB extends CompositeDB implements StructureInternal { /** * Backup from specified defined-component index to the first component which contains the * specified offset. - * + * * @param index any defined component index which contains offset. * @param offset offset within structure. * @return index of first defined component containing specific offset. @@ -929,7 +929,7 @@ class StructureDB extends CompositeDB implements StructureInternal { * Identify defined-component index of the first non-zero-length component which contains the * specified offset. If only zero-length components exist, the last zero-length component which * contains the offset will be returned. - * + * * @param index any defined component index which contains offset. * @param offset offset within structure. * @return index of first defined component containing specific offset. @@ -950,7 +950,7 @@ class StructureDB extends CompositeDB implements StructureInternal { /** * Advance from specified defined-component index to the last component which contains the * specified offset. - * + * * @param index any defined component index which contains offset. * @param offset offset within structure. * @return index of last defined component containing specific offset. @@ -1307,7 +1307,7 @@ class StructureDB extends CompositeDB implements StructureInternal { int length, String componentName, String comment) throws IOException { // Attempt quick update of a single defined component if possible. - // A quick update requires that component characteristics including length, offset, + // A quick update requires that component characteristics including length, offset, // and alignment (if packed) not change. All other situations generally require a // repack. DataTypeComponentDB oldComponent = replacedComponents.get(0); @@ -1557,7 +1557,7 @@ class StructureDB extends CompositeDB implements StructureInternal { /** * Replaces the internal components of this structure with components of the given structure. - * + * * @param dataType the structure to get the component information from. * @throws IllegalArgumentException if any of the component data types are not allowed to * replace a component in this composite data type. For example, suppose dt1 contains dt2. @@ -1593,7 +1593,7 @@ class StructureDB extends CompositeDB implements StructureInternal { /** * Replaces the internal components of this structure with components of the given structure * including packing and alignment settings. - * + * * @param struct structure to be copied * @param notify provide notification if true * @throws DataTypeDependencyException if circular dependency detected @@ -1780,14 +1780,14 @@ class StructureDB extends CompositeDB implements StructureInternal { } /** - * Get the available space for an existing defined component in relation to the next defined + * Get the available space for an existing defined component in relation to the next defined * component or the end of the structure. Method should be used in conjunction with * {@link #consumeBytesAfter(int, int)} and/or {@link #shiftOffsets(int, int, int)} for * non-packed structure use. This method is intended to supplt the maxLength parameter * for the {@link #getPreferredComponentLength(DataType, int, int)} method call. - * + * * @param index defined components index - * @return available space for this component (i.e., maxLength). {@link Integer#MAX_VALUE} + * @return available space for this component (i.e., maxLength). {@link Integer#MAX_VALUE} * is returned if last component in non-packed structure, or -1 if structure is packed. */ private int getAvailableComponentSpace(int index) { @@ -2097,7 +2097,7 @@ class StructureDB extends CompositeDB implements StructureInternal { * Replace the specified components with a new component containing the specified data type. * If {@link DataType#DEFAULT} is specified as the resolvedDataType only a clear operation * is performed. - * + * * @param origComponents the original sequence of data type components in this structure to be * replaced. These components must be adjacent components in sequential order. If an * non-packed undefined component is specified no other component may be included. @@ -2206,7 +2206,7 @@ class StructureDB extends CompositeDB implements StructureInternal { /** * Gets the number of Undefined bytes beginning at the indicated component ordinal. Undefined * bytes that have a field name or comment specified are also included. - * + * * @param ordinal the component ordinal to begin checking at. * @return the number of contiguous undefined bytes */