diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/ClassUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/ClassUtils.java deleted file mode 100644 index c5be7ce674..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/ClassUtils.java +++ /dev/null @@ -1,35 +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; - -import ghidra.program.model.data.PointerDataType; - -public class ClassUtils { - - // Prototype values for now. Need to come to agreement on what these should be - public static final String VBPTR = "{vbptr}"; - public static final String VFPTR = "{vfptr}"; - - /** - * Type used for {@link #VBPTR} and {@link #VFPTR} fields in a class - */ - public static final PointerDataType VXPTR_TYPE = new PointerDataType(); - - private ClassUtils() { - // no instances - } - -} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/PlaceholderVirtualBaseTable.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/PlaceholderVirtualBaseTable.java new file mode 100644 index 0000000000..add13dc88c --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/PlaceholderVirtualBaseTable.java @@ -0,0 +1,126 @@ +/* ### + * 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.classtype; + +import java.util.*; + +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; + +/** + * Virtual Base Table without a program + */ +public class PlaceholderVirtualBaseTable extends VirtualBaseTable { + + private int entrySize; + + private int maxIndexSeen = -1; + private Map entriesByIndex = new HashMap<>(); + + /** + * Constructor + * @param owner the class that owns the table + * @param parentage the parentage of the base class(es) of the table + * @param entrySize the size of the index field for each table entry as it would be in memory + */ + public PlaceholderVirtualBaseTable(ClassID owner, List parentage, int entrySize) { + super(owner, parentage); + if (entrySize != 4 && entrySize != 8) { + throw new IllegalArgumentException("Invalid size (" + entrySize + "): must be 4 or 8."); + } + this.entrySize = entrySize; + } + + /* + * For the next method below... once we determine the number of virtual bases (virtual and + * indirect virtual) for each class (from PDB or other), we can determine the number of + * entries in each VBT. For a VBT for the main class, the number is equal... if for some + * parentage, then the number can reflect the number of the parent. + * TODO: can VBT overlay/extend one from parent???????????????????????????????????????????? + */ + /** + * TBD: need to determine table size to do this. Might want to place a symbol (diff method?). + */ + void createTableDataType(int numEntries) { + + } + + int getMaxIndex() { + return maxIndexSeen; + } + + public void setBaseClassOffsetAndId(int index, Long offset, ClassID baseId) { + VBTableEntry entry = entriesByIndex.get(index); + if (entry == null) { + entry = new VirtualBaseTableEntry(offset, baseId); + entriesByIndex.put(index, entry); + } + else { + entry.setOffset(offset); + entry.setClassId(baseId); + } + maxIndexSeen = Integer.max(maxIndexSeen, index); + } + + public void setBaseClassId(int index, ClassID baseId) { + VBTableEntry entry = entriesByIndex.get(index); + if (entry == null) { + entry = new VirtualBaseTableEntry(baseId); + entriesByIndex.put(index, entry); + } + else { + entry.setClassId(baseId); + } + maxIndexSeen = Integer.max(maxIndexSeen, index); + } + + public void setBaseOffset(int index, Long offset) { + VBTableEntry entry = entriesByIndex.get(index); + if (entry == null) { + entry = new VirtualBaseTableEntry(offset); + entriesByIndex.put(index, entry); + } + else { + entry.setOffset(offset); + } + maxIndexSeen = Integer.max(maxIndexSeen, index); + } + + @Override + public Long getBaseOffset(int index) throws PdbException { + VBTableEntry entry = entriesByIndex.get(index); + Long offset = (entry == null) ? null : entry.getOffset(); + maxIndexSeen = Integer.max(maxIndexSeen, index); + return offset; + } + + @Override + public ClassID getBaseClassId(int index) { + VBTableEntry entry = entriesByIndex.get(index); + ClassID id = (entry == null) ? null : entry.getClassId(); + maxIndexSeen = Integer.max(maxIndexSeen, index); + return id; + } + + @Override + public VBTableEntry getBase(int index) throws PdbException { + VBTableEntry entry = entriesByIndex.get(index); + if (entry != null) { + maxIndexSeen = Integer.max(maxIndexSeen, index); + } + return entry; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualBaseTable.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualBaseTable.java index cc7d8ec90f..78e4741fce 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualBaseTable.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualBaseTable.java @@ -36,8 +36,6 @@ public class ProgramVirtualBaseTable extends VirtualBaseTable { private Boolean createdFromMemory = null; private Boolean createdFromCompiled = null; - private int numEntries = 0; - private int maxIndexSeen = -1; private Map entriesByIndex = new HashMap<>(); @@ -47,7 +45,7 @@ public class ProgramVirtualBaseTable extends VirtualBaseTable { * @param parentage the parentage of the base class(es) of the table * @param program the program * @param address the address of the table - * @param entrySize the size for each table entry + * @param entrySize the size of the index field for each table entry in memory * @param ctm the class type manager * @param mangledName the mangled name of the table */ @@ -76,7 +74,7 @@ public class ProgramVirtualBaseTable extends VirtualBaseTable { * Returns the mangled name * @return the mangled name */ - String getMangledName() { + public String getMangledName() { return mangledName; } @@ -136,16 +134,16 @@ public class ProgramVirtualBaseTable extends VirtualBaseTable { return entry; } - // Need to decide if we want to allow this to overwrite existing entry. - public void setBaseClassId(int index, ClassID baseId) throws PdbException { + public void setBaseClassId(int index, ClassID baseId) { VBTableEntry entry = entriesByIndex.get(index); - if (entry != null) { - throw new PdbException( - "Entry already exists in Virtual Base Table for index: " + index); + if (entry == null) { + entry = new VirtualBaseTableEntry(baseId); + entriesByIndex.put(index, entry); } - entry = new VirtualBaseTableEntry(baseId); - entriesByIndex.put(index, entry); - maxIndexSeen = Integer.max(maxIndexSeen, index); // do we want this here with a "set" method? + else { + entry.setClassId(baseId); + } + maxIndexSeen = Integer.max(maxIndexSeen, index); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualFunctionTable.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualFunctionTable.java index 282b47c638..ab868668ae 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualFunctionTable.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualFunctionTable.java @@ -68,7 +68,7 @@ public class ProgramVirtualFunctionTable extends VirtualFunctionTable { * Returns the mangled name * @return the mangled name */ - String getMangledName() { + public String getMangledName() { return mangledName; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VBTableEntry.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VBTableEntry.java index 7d5878f535..2dc4ad76c4 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VBTableEntry.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VBTableEntry.java @@ -24,7 +24,7 @@ public interface VBTableEntry { * Sets the entry offset value * @param offset the offset */ - public void setOffset(long offset); + public void setOffset(Long offset); /** * Gets the entry offset value diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VirtualBaseTable.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VirtualBaseTable.java index 6b9666d20e..8169090a09 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VirtualBaseTable.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VirtualBaseTable.java @@ -24,8 +24,18 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; * Abstract class for virtual base tables */ public abstract class VirtualBaseTable implements VBTable { + protected ClassID owner; // Does this belong here in this abstract class? protected List parentage; // Not sure this belongs in this abstract class + /** + * The number of entries in the table + */ + protected Integer numEntries; + /** + * This is the offset within the class where we expect to find the pointer that can point to + * this table + */ + protected Long ptrOffsetInClass; /** * Virtual Base Table for a base (parent) class within an owner class. The owner and parent @@ -83,6 +93,22 @@ public abstract class VirtualBaseTable implements VBTable { return parentage; } + /** + * Returns the number of entries in the table + * @return the number of entries; {@code null} if not initialized + */ + public Integer getNumEntries() { + return numEntries; + } + + /** + * Gets the offset within the class for the pointer that can point to this table + * @return the offset; {@code null} if not initialized + */ + public Long getPtrOffsetInClass() { + return ptrOffsetInClass; + } + /** * Sets the owner of the table * @param ownerArg the class to set as owner @@ -99,6 +125,22 @@ public abstract class VirtualBaseTable implements VBTable { this.parentage = parentage; } + /** + * Sets the number of entries for the table + * @param numEntriesArg the number of entries + */ + public void setNumEntries(Integer numEntriesArg) { + numEntries = numEntriesArg; + } + + /** + * Sets the offset within the class for the pointer that can point to this table + * @param offset the offset + */ + public void setPtrOffsetInClass(Long offset) { + ptrOffsetInClass = offset; + } + void emit(StringBuilder builder) { builder.append("VBT for the following parentage within: " + owner); builder.append("\n"); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VirtualBaseTableEntry.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VirtualBaseTableEntry.java index b92a7e584b..0d7a0df188 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VirtualBaseTableEntry.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VirtualBaseTableEntry.java @@ -24,21 +24,21 @@ public class VirtualBaseTableEntry implements VBTableEntry { // Re-evaluate which constructors and setters we need - VirtualBaseTableEntry(long offset) { + public VirtualBaseTableEntry(Long offset) { this(offset, null); } - VirtualBaseTableEntry(ClassID baseId) { + public VirtualBaseTableEntry(ClassID baseId) { this(null, baseId); } - VirtualBaseTableEntry(Long offset, ClassID baseId) { + public VirtualBaseTableEntry(Long offset, ClassID baseId) { this.offset = offset; this.baseId = baseId; } @Override - public void setOffset(long offset) { + public void setOffset(Long offset) { this.offset = offset; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VirtualFunctionTable.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VirtualFunctionTable.java index a677fe8285..0da715b9d4 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VirtualFunctionTable.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/VirtualFunctionTable.java @@ -26,6 +26,15 @@ public abstract class VirtualFunctionTable implements VFTable { protected ClassID owner; protected List parentage; + /** + * The number of entries in the table + */ + protected int numEntries; + /** + * This is the offset within the class where we expect to find the pointer that can point to + * this table + */ + protected int ptrOffsetInClass; /** * Virtual Function Table for a base (parent) class within an owner class. The owner and parent @@ -37,6 +46,7 @@ public abstract class VirtualFunctionTable implements VFTable { VirtualFunctionTable(ClassID owner, List parentage) { this.owner = owner; this.parentage = new ArrayList<>(parentage); + numEntries = 0; } /** @@ -71,6 +81,22 @@ public abstract class VirtualFunctionTable implements VFTable { return parentage; } + /** + * Returns the number of entries in the table + * @return the number of entries + */ + public int getNumEntries() { + return numEntries; + } + + /** + * Gets the offset within the class for the pointer that can point to this table + * @return the offset + */ + public int getPtrOffsetInClass() { + return ptrOffsetInClass; + } + /** * Sets the owner of the table * @param ownerArg the class to set as owner @@ -87,6 +113,22 @@ public abstract class VirtualFunctionTable implements VFTable { this.parentage = parentage; } + /** + * Sets the number of entries for the table + * @param numEntriesArg the number of entries + */ + public void setNumEntries(int numEntriesArg) { + numEntries = numEntriesArg; + } + + /** + * Sets the offset within the class for the pointer that can point to this table + * @param offset the offset + */ + public void setPtrOffsetInClass(int offset) { + ptrOffsetInClass = offset; + } + void emit(StringBuilder builder) { builder.append("VBT for the following classes within: " + owner); builder.append("\n"); 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 bf67521bee..5f569c1b87 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 @@ -137,6 +137,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } else { applyCpp(combo, type, lists); + applicator.markFilledInForBase(type.getRecordNumber()); } return true; } @@ -182,6 +183,15 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } List myMembers = new ArrayList<>(); addClassTypeBaseClasses(composite, classType, lists.bases(), type); + // Note: I've seen the situation where there is no vftptr for a class where I expected one. + // Situation is where a parent has a vftptr with a vtshape with one entry. The child + // class defines an additional virtual method, and there is an actual table in memory with + // with the appropriate mangled label for this class that has two entries, but the list + // here does not have the vftptr, and I believe it was due to the fact that new new method + // was never called in the code. Thus... do not count on getting a vtshape in this + // situation. Note that a record of a an appropriate two-entry vtshape was found right + // before the class definition, but no pointer to it was created or referred to in the + // field list. addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers); addMembers(composite, classType, lists.nonstaticMembers(), type, myMembers); @@ -262,20 +272,31 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { private void applyDirectBaseClass(AbstractBaseClassMsType base, CppCompositeType myClassType, Access defaultAccess) throws PdbException { - CppCompositeType underlyingClassType = - getUnderlyingClassType(base.getBaseClassRecordNumber()); + RecordNumber recordNumber = base.getBaseClassRecordNumber(); + DataType dt = applicator.getDataType(recordNumber); + if (!(dt instanceof Composite comp)) { + Msg.warn(this, "Composite not found for base class: " + dt); + return; + } + CppCompositeType underlyingClassType = getUnderlyingClassType(recordNumber); if (underlyingClassType == null) { return; } ClassFieldMsAttributes atts = base.getAttributes(); int offset = applicator.bigIntegerToInt(base.getOffset()); - myClassType.addDirectBaseClass(underlyingClassType, + myClassType.addDirectBaseClass(comp, underlyingClassType, ClassFieldAttributes.convert(atts, defaultAccess), offset); } private void applyDirectVirtualBaseClass(AbstractVirtualBaseClassMsType base, CppCompositeType myClassType, Access defaultAccess) throws PdbException { - CppCompositeType underlyingCt = getUnderlyingClassType(base.getBaseClassRecordNumber()); + RecordNumber recordNumber = base.getBaseClassRecordNumber(); + DataType dt = applicator.getDataType(recordNumber); + if (!(dt instanceof Composite comp)) { + Msg.warn(this, "Composite not found for base class: " + dt); + return; + } + CppCompositeType underlyingCt = getUnderlyingClassType(recordNumber); if (underlyingCt == null) { return; } @@ -284,14 +305,20 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { ClassFieldMsAttributes atts = base.getAttributes(); int basePointerOffset = applicator.bigIntegerToInt(base.getBasePointerOffset()); int offsetFromVbt = applicator.bigIntegerToInt(base.getBaseOffsetFromVbt()); - myClassType.addDirectVirtualBaseClass(underlyingCt, + myClassType.addDirectVirtualBaseClass(comp, underlyingCt, ClassFieldAttributes.convert(atts, defaultAccess), basePointerOffset, vbtptr, offsetFromVbt); } private void applyIndirectVirtualBaseClass(AbstractIndirectVirtualBaseClassMsType base, CppCompositeType myClassType, Access defaultAccess) throws PdbException { - CppCompositeType underlyingCt = getUnderlyingClassType(base.getBaseClassRecordNumber()); + RecordNumber recordNumber = base.getBaseClassRecordNumber(); + DataType dt = applicator.getDataType(recordNumber); + if (!(dt instanceof Composite comp)) { + Msg.warn(this, "Composite not found for base class: " + dt); + return; + } + CppCompositeType underlyingCt = getUnderlyingClassType(recordNumber); if (underlyingCt == null) { return; } @@ -300,7 +327,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { ClassFieldMsAttributes atts = base.getAttributes(); int basePointerOffset = applicator.bigIntegerToInt(base.getBasePointerOffset()); int offsetFromVbt = applicator.bigIntegerToInt(base.getBaseOffsetFromVbt()); - myClassType.addIndirectVirtualBaseClass(underlyingCt, + myClassType.addIndirectVirtualBaseClass(comp, underlyingCt, ClassFieldAttributes.convert(atts, defaultAccess), basePointerOffset, vbtptr, offsetFromVbt); } @@ -390,7 +417,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { applicator.checkCancelled(); if (base instanceof AbstractBaseClassMsType bc) { RecordNumber recordNumber = bc.getBaseClassRecordNumber(); - DataType dt = applicator.getDataTypeOrSchedule(recordNumber); + DataType dt = applicator.getBaseClassDataTypeOrSchedule(recordNumber); if (dt == null) { done = false; } @@ -402,7 +429,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { done = false; } recordNumber = vbc.getBaseClassRecordNumber(); - dt = applicator.getDataTypeOrSchedule(recordNumber); + dt = applicator.getBaseClassDataTypeOrSchedule(recordNumber); if (dt == null) { done = false; } @@ -414,7 +441,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { done = false; } recordNumber = ivbc.getBaseClassRecordNumber(); - dt = applicator.getDataTypeOrSchedule(recordNumber); + dt = applicator.getBaseClassDataTypeOrSchedule(recordNumber); if (dt == null) { done = false; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java index d5e50769d3..b7d7432645 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java @@ -16,19 +16,17 @@ package ghidra.app.util.pdb.pdbapplicator; import java.util.*; -import java.util.Map.Entry; import org.apache.commons.lang3.StringUtils; -import ghidra.app.util.ClassUtils; import ghidra.app.util.SymbolPath; import ghidra.app.util.bin.format.pdb.*; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog; import ghidra.app.util.pdb.classtype.*; import ghidra.program.model.data.*; +import ghidra.program.model.gclass.ClassUtils; import ghidra.util.Msg; -import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; @@ -45,37 +43,90 @@ public class CppCompositeType { "Virtual Base - Speculative Placement"; //private static final String INDIRECT_VIRTUAL_BASE_CLASS_COMMENT = "Indirect Virtual Base Class"; - // Order matters for both base classes and members for class layout. Members get offsets, - // which helps for those, but layout algorithms usually utilize order. - private List syntacticBaseClasses; - private List layoutBaseClasses; - private List myMembers; - private List layoutMembers; - private List layoutVftPtrMembers; - private Map vftPtrTypeByOffset; private boolean isFinal; private ClassKey classKey; private String className; // String for now. private String mangledName; private int size; - private CategoryPath baseCategoryPath; private SymbolPath symbolPath; - private Composite composite; private CategoryPath categoryPath; + private DataTypePath selfBaseDataTypePath; + private ProgramClassID myId; + + private CategoryPath baseCategoryPath; private CategoryPath internalsCategoryPath; + private Composite composite; + private Composite selfBaseType; - private List memberData; + private String summarizedClassVxtPtrInfo; - private boolean hasSelfBase; + // Order matters for both base classes and members for class layout. Members get offsets, + // which helps for those, but layout algorithms usually utilize order. + private List directLayoutBaseClasses; + private List virtualLayoutBaseClasses; + private List directVirtualLayoutBaseClasses; + private List indirectVirtualLayoutBaseClasses; - static String createSelfBaseClassName(Composite composite) { - return composite.getName(); - } + private TreeMap vftPtrTypeByOffset; + private List myMembers; + private List layoutMembers; - static CategoryPath createSelfBaseCategoryPath(CppCompositeType cppType) { - return cppType.getSelfBaseCategoryName( - CppCompositeType.createSelfBaseClassName(cppType.getComposite())); - } + private List syntacticBaseClasses; + + //============================================================================================== + //============================================================================================== + // Data used for laying out the class + + /** + * Holds the offset of the VftPtr allocated by this class; is null if it is sharing a VftPtr + * of a base class or if one is not needed + */ + private Long myVftPtrOffset; + /** + * Holds the offset of the VbtPtr allocated by this class; is null if it is sharing a VbtPtr + * of a base class or if one is not needed. + */ + private Long myVbtPtrOffset; + + /** + * Holds the offset of the VftPtr used by this class, whether allocated by this class or + * found in a parent class; null if doesn't use a VftPtr + */ + private Long mainVftPtrOffset; + /** + * Holds the offset of the VbtPtr used by this class, whether allocated by this class or + * found in a parent class; null if doesn't use a VbtPtr + */ + private Long mainVbtPtrOffset; + + /** + * Holds the main Vbt for this class + */ + private VirtualBaseTable mainVbt; + + /** + * Value during processing to indicate whether this class has a zero-sized base + */ + private boolean hasZeroBaseSize; + + /** + * Hold the depth-first traversal occurrence of virtual bases. See more detail in algorithm + * that generates this non-perfect information + */ + private LinkedHashMap> depthFirstVirtualBases; + + private List layoutVftPtrMembers; + private List layoutVbtPtrMembers; + + private Map vftTableIdByOffset; // possibly future use + private Map vftOffsetByTableId; // possibly future use + private Map vbtTableIdByOffset; //we use this one + private Map vbtOffsetByTableId; // possibly future use + + private TreeMap baseOffsetById; + + //============================================================================================== + // Data used for resolving main vftptr /* * Not certain, but think there should only be one Virtual Base Table for a given @@ -86,33 +137,482 @@ public class CppCompositeType { * offset, in case we see more than one. Want to log the fact if more than one value is seen * for a particular hierarchy level. */ - private Map placeholderVirtualBaseTables; + private Map placeholderVirtualBaseTables; - //---------------------------------------------------------------------------------------------- + //============================================================================================== + // Data used for analyzing Vxts and their parentage + + private TreeSet propagatedSelfBaseVfts; + private TreeSet propagatedSelfBaseVbts; + private TreeSet propagatedDirectVirtualBaseVfts; + private TreeSet propagatedDirectVirtualBaseVbts; + private TreeSet propagatededIndirectVirtualBaseVfts; + private TreeSet propagatedIndirectVirtualBaseVbts; + private TreeMap finalLayoutVfts; + private TreeMap finalLayoutVbts; + + //============================================================================================== + //============================================================================================== public CppCompositeType(CategoryPath baseCategoryPath, SymbolPath symbolPath, Composite composite, String mangledName) { Objects.requireNonNull(symbolPath, "symbolPath may not be null"); Objects.requireNonNull(composite, "composite may not be null"); - syntacticBaseClasses = new ArrayList<>(); - layoutBaseClasses = new ArrayList<>(); - myMembers = new ArrayList<>(); - layoutMembers = new ArrayList<>(); - - memberData = new ArrayList<>(); - layoutVftPtrMembers = new ArrayList<>(); - vftPtrTypeByOffset = new HashMap<>(); isFinal = false; classKey = ClassKey.UNKNOWN; this.baseCategoryPath = baseCategoryPath; this.symbolPath = symbolPath; this.composite = composite; - placeholderVirtualBaseTables = new HashMap<>(); - categoryPath = new CategoryPath(composite.getCategoryPath(), composite.getName()); - internalsCategoryPath = new CategoryPath(categoryPath, "!internal"); + this.mangledName = mangledName; + myId = getClassId(this); + internalsCategoryPath = ClassUtils.getClassInternalsPath(composite); // eliminate + selfBaseDataTypePath = ClassUtils.getBaseClassDataTypePath(composite); + + directLayoutBaseClasses = new ArrayList<>(); + virtualLayoutBaseClasses = new ArrayList<>(); + directVirtualLayoutBaseClasses = new ArrayList<>(); + indirectVirtualLayoutBaseClasses = new ArrayList<>(); + + vftPtrTypeByOffset = new TreeMap<>(); + myMembers = new ArrayList<>(); + layoutMembers = new ArrayList<>(); + + syntacticBaseClasses = new ArrayList<>(); + } + + //============================================================================================== + /** + * Method to add a direct base class for this class. Does not include attributes... + * this method is suitable for testing + * @param comp the base composite + * @param baseClassType the base class type + * @param offset the offset + * @throws PdbException upon issue with the base not being suitable + */ + public void addDirectBaseClass(Composite comp, CppCompositeType baseClassType, int offset) + throws PdbException { + addDirectBaseClass(comp, baseClassType, ClassFieldAttributes.UNKNOWN, offset); + } + + /** + * Method to add a direct base class for this class + * @param comp the base composite + * @param baseClassType the base class type + * @param attributes the attributes of the base class + * @param offset the offset + * @throws PdbException upon issue with the base not being suitable + */ + public void addDirectBaseClass(Composite comp, CppCompositeType baseClassType, + ClassFieldAttributes attributes, int offset) throws PdbException { + validateBaseClass(baseClassType); + DirectLayoutBaseClass base = + new DirectLayoutBaseClass(comp, baseClassType, attributes, offset); + directLayoutBaseClasses.add(base); + } + + /** + * Method to add a direct virtual base class for this class. Does not include attributes... + * this method is suitable for testing + * @param comp the base composite + * @param baseClassType the base class type + * @param basePointerOffset the offset of the vbtptr within the class that specifies where this + * base is located within the class + * @param vbptr the vbptr type + * @param offsetFromVbt the offset into the vbt that specifies where this base is located + * within the class + * @throws PdbException upon issue with the base not being suitable + */ + public void addDirectVirtualBaseClass(Composite comp, CppCompositeType baseClassType, + int basePointerOffset, DataType vbptr, int offsetFromVbt) throws PdbException { + addDirectVirtualBaseClass(comp, baseClassType, ClassFieldAttributes.UNKNOWN, + basePointerOffset, vbptr, offsetFromVbt); + } + + /** + * Method to add a direct virtual base class for this class + * @param comp the base composite + * @param baseClassType the base class type + * @param attributes the attributes of the base class + * @param basePointerOffset the offset of the vbtptr within the class that specifies where this + * base is located within the class + * @param vbptr the vbptr type + * @param offsetFromVbt the offset into the vbt that specifies where this base is located + * within the class + * @throws PdbException upon issue with the base not being suitable + */ + public void addDirectVirtualBaseClass(Composite comp, CppCompositeType baseClassType, + ClassFieldAttributes attributes, int basePointerOffset, DataType vbptr, + int offsetFromVbt) throws PdbException { + validateBaseClass(baseClassType); + DirectVirtualLayoutBaseClass base = + new DirectVirtualLayoutBaseClass(comp, baseClassType, attributes, basePointerOffset, + vbptr, offsetFromVbt); + directVirtualLayoutBaseClasses.add(base); + virtualLayoutBaseClasses.add(base); + } + + /** + * Method to add an indirect virtual base class for this class. Does not include attributes... + * this method is suitable for testing + * @param comp the base composite + * @param baseClassType the base class type + * @param basePointerOffset the offset of the vbtptr within the class that specifies where this + * base is located within the class + * @param vbptr the vbptr type + * @param offsetFromVbt the offset into the vbt that specifies where this base is located + * within the class + * @throws PdbException upon issue with the base not being suitable + */ + public void addIndirectVirtualBaseClass(Composite comp, CppCompositeType baseClassType, + int basePointerOffset, DataType vbptr, int offsetFromVbt) throws PdbException { + addIndirectVirtualBaseClass(comp, baseClassType, ClassFieldAttributes.UNKNOWN, + basePointerOffset, vbptr, offsetFromVbt); + } + + /** + * Method to add an indirect virtual base class for this class + * @param comp the base composite + * @param baseClassType the base class type + * @param attributes the attributes of the base class + * @param basePointerOffset the offset of the vbtptr within the class that specifies where this + * base is located within the class + * @param vbptr the vbptr type + * @param offsetFromVbt the offset into the vbt that specifies where this base is located + * within the class + * @throws PdbException upon issue with the base not being suitable + */ + public void addIndirectVirtualBaseClass(Composite comp, CppCompositeType baseClassType, + ClassFieldAttributes attributes, int basePointerOffset, DataType vbptr, + int offsetFromVbt) throws PdbException { + validateBaseClass(baseClassType); + IndirectVirtualLayoutBaseClass base = new IndirectVirtualLayoutBaseClass(comp, + baseClassType, attributes, basePointerOffset, vbptr, offsetFromVbt); + indirectVirtualLayoutBaseClasses.add(base); + virtualLayoutBaseClasses.add(base); + } + + /** + * Method for user to specify a location and type of a virtual function table pointer (from PDB) + * @param ptrType the pointer data type + * @param offset the offset + */ + public void addVirtualFunctionTablePointer(Pointer ptrType, int offset) { + vftPtrTypeByOffset.put((long) offset, ptrType); + } + + /** + * Method for adding a member to this type, to include a comment, but no attributes parameter + * @param memberName member name + * @param dataType data type of member + * @param isFlexibleArray {@code true} if member is a flexible array + * @param offset offset of the member + * @param comment comment for the member + */ + public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, int offset, + String comment) { + addMember(memberName, dataType, isFlexibleArray, ClassFieldAttributes.UNKNOWN, offset, + comment); + } + + /** + * Method for adding a member to this type; no attributes or comment parameters + * @param memberName member name + * @param dataType data type of member + * @param isFlexibleArray {@code true} if member is a flexible array + * @param offset offset of the member + */ + public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, + int offset) { + addMember(memberName, dataType, isFlexibleArray, ClassFieldAttributes.UNKNOWN, offset, + null); + } + + /** + * Method for adding a member to this type; includes attributes, but no comment parameter + * @param memberName member name + * @param dataType data type of member + * @param isFlexibleArray {@code true} if member is a flexible array + * @param attributes the attributes for the member + * @param offset offset of the member + */ + public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, + ClassFieldAttributes attributes, int offset) { + Member newMember = new Member(memberName, dataType, isFlexibleArray, attributes, offset); + myMembers.add(newMember); + addMember(layoutMembers, newMember); + } + + /** + * Method for adding a member to this type, to include a attribtues and comment + * @param memberName member name + * @param dataType data type of member + * @param isFlexibleArray {@code true} if member is a flexible array + * @param attributes the attributes for the member + * @param offset offset of the member + * @param comment comment for the member + */ + public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, + ClassFieldAttributes attributes, int offset, String comment) { + Member newMember = + new Member(memberName, dataType, isFlexibleArray, attributes, offset, comment); + myMembers.add(newMember); + addMember(layoutMembers, newMember); + } + + /** + * Method to perform class layout from the user specified information. Note that all + * dependency classes (parents, etc.) must have had their like-processing performed + * @param layoutOptions the options + * @param vxtManager the VxtManager + * @param monitor the TaskMonitor + * @throws PdbException upon issue performing the layout + * @throws CancelledException upon user cancellation + */ + public void createLayout(ObjectOrientedClassLayout layoutOptions, VxtManager vxtManager, + TaskMonitor monitor) throws PdbException, CancelledException { + switch (layoutOptions) { + case MEMBERS_ONLY: + createMembersOnlyClassLayout(monitor); + break; + case CLASS_HIERARCHY: + createHierarchicalClassLayout(vxtManager, monitor); + // Next line for developer testing cfb432 + //System.out.print(summarizedClassVxtPtrInfo); + break; + } + } + + /** + * Method to set whether the class is specified as "final" (sealed) + * @param isFinal {@code true} if final + */ + public void setFinal(boolean isFinal) { + this.isFinal = isFinal; + } + + /** + * Returns whether the class was marked "final" + * @return {@code true} if final + */ + public boolean isFinal() { + return isFinal; + } + + /** + * Method to specify the composite has a "class" tag + */ + public void setClass() { + classKey = ClassKey.CLASS; + } + + /** + * Method to specify the composite has a "struct" tag + */ + public void setStruct() { + classKey = ClassKey.STRUCT; + } + + /** + * Method to specify the composite has a "union" tag + */ + public void setUnion() { + classKey = ClassKey.UNION; + } + + /** + * Returns the key (i.e., class, struct, union) for this composite + * @return the key + */ + public ClassKey getKey() { + return classKey; + } + + /** + * Method to set the name of the composite + * @param className the name + */ + public void setName(String className) { + this.className = className; + } + + /** + * Returns the name of this composite + * @return the name + */ + public String getName() { + return className; + } + + /** + * Returns the DataTypePath of the composite + * @return the DataTypePath + */ + public DataTypePath getDataTypePath() { + return composite.getDataTypePath(); + } + + /** + * Method to set the mangled name of this composite type + * @param mangledName the mangled name + */ + public void setMangledName(String mangledName) { this.mangledName = mangledName; } + /** + * Returns the mangled name of this composite + * @return the mangled name; can be null if not initialized by the user + */ + public String getMangledName() { + return mangledName; + } + + /** + * Method to set the size of this composite + * @param size the size + */ + public void setSize(int size) { + this.size = size; + } + + /** + * Returns the specified composite size that was set by the user + * @return the size + */ + public int getSize() { + return size; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(classKey); + builder.append(className); + if (isFinal) { + builder.append(" final"); + } + StringBuilder baseBuilder = new StringBuilder(); + for (BaseClass base : syntacticBaseClasses) { + if (baseBuilder.length() == 0) { + baseBuilder.append(" : "); + } + else { + baseBuilder.append(", "); + } + baseBuilder.append(base); + } + builder.append(baseBuilder); + return builder.toString(); + } + + //============================================================================================== + /** + * Returns the SymbolPath name of this class + * @return the SymbolPath + */ + public SymbolPath getSymbolPath() { + return symbolPath; + } + + /** + * Returns the ClassID for this class + * @return the class id + */ + public ProgramClassID getClassId() { + return myId; + } + + /** + * Returns the class composite as a full class layout + * @return the composite + */ + public Composite getComposite() { + return composite; + } + + /** + * Returns the "self-base" composite for this class. When a separate self base is not + * needed for this class, the composite is the same as the layout composite returned by + * {@link #getComposite()} + * @return the self-base composite + */ + public Composite getSelfBaseType() { + return selfBaseType; + } + + // TODO: move to ClassUtils? + /** + * Returns the "internals" CategoryPath of this composite + * @return the CategoryPath + */ + public CategoryPath getInternalsCategoryPath() { + return internalsCategoryPath; + } + + /** + * Return developer VxtPtr summary for this class + * @return the summary + */ + String getSummarizedClassVxtPtrInfo() { + return summarizedClassVxtPtrInfo; + } + + /** + * Create DataTypePath of self base of this class + * @param baseName the + * @return the data type path + */ + public DataTypePath getSelfBaseDataTypePath(String baseName) { + return new DataTypePath(getInternalsCategoryPath(), baseName); + } + + /** + * Create DataTypePath of VBTable. Currently using the offset of the vbptr, but that might + * change if/when we come up with better naming (like inheritance naming) + * @param offset offset of the vbptr + * @return the data type path + */ + public DataTypePath getVBTableDataTypePath(int offset) { + return new DataTypePath(getInternalsCategoryPath(), String.format("Vbtable_%08x", offset)); + } + + /** + * Create DataTypePath of VFTable. Currently using the offset of the vfptr, but that might + * change if/when we come up with better naming (like inheritance naming) + * @param offset offset of the vfptr + * @return the data type path + */ + public DataTypePath getVFTableDataTypePath(int offset) { + return new DataTypePath(getInternalsCategoryPath(), String.format("Vftable_%08x", offset)); + } + + //============================================================================================== + //============================================================================================== + /** + * Method to validate a base class as being suitable as a base + * @param baseClassType the base class type + * @throws PdbException if not suitable + */ + private static void validateBaseClass(CppCompositeType baseClassType) throws PdbException { + if (baseClassType.isFinal) { + throw new PdbException("Cannot inherit base class marked final."); + } + } + + /** + * Underlying method for adding a member to the class + * @param members the members list + * @param newMember the new member to add to the list + */ + private void addMember(List members, Member newMember) { + members.add(newMember); + } + + //============================================================================================== + //============================================================================================== + + // NOTE: Need to investigate the usefulness of the following methods and types from long ago + public static CppClassType createCppClassType(CategoryPath baseCategoryPath, SymbolPath symbolPath, Composite composite, String mangledName) { return new CppClassType(baseCategoryPath, symbolPath, composite, mangledName); @@ -156,8 +656,35 @@ public class CppCompositeType { setStruct(); } } + //============================================================================================== - static boolean validateMangledCompositeName(String mangledCompositeTypeName, ClassKey type) { + /** + * Returns the DataTypePath for the specified CppCompositeType + * @param cppType the type + * @return the data type path + */ + private static DataTypePath createSelfBaseCategoryPath(CppCompositeType cppType) { + return cppType.getSelfBaseDataTypePath(cppType.getComposite().getName()); + } + + /** + * Generates a class id for the CPP type specified + * @param cpp the CPP type + * @return the class id + */ + private static ProgramClassID getClassId(CppCompositeType cpp) { + return new ProgramClassID(cpp.baseCategoryPath, cpp.getSymbolPath()); + } + + //============================================================================================== + //============================================================================================== + /** + * Validates the mangled name against the class key + * @param mangledCompositeTypeName the mangled name + * @param key the key + * @return {@code true} if passed validation + */ + static boolean validateMangledCompositeName(String mangledCompositeTypeName, ClassKey key) { if (mangledCompositeTypeName == null) { return false; } @@ -172,21 +699,21 @@ public class CppCompositeType { } switch (mangledCompositeTypeName.charAt(3)) { case 'T': - if ((type.compareTo(ClassKey.UNION) != 0) && - (type.compareTo(ClassKey.UNKNOWN) != 0)) { - PdbLog.message("Warning: Mismatched complex type 'T' for " + type); + if ((key.compareTo(ClassKey.UNION) != 0) && + (key.compareTo(ClassKey.UNKNOWN) != 0)) { + PdbLog.message("Warning: Mismatched complex type 'T' for " + key); } break; case 'U': - if ((type.compareTo(ClassKey.STRUCT) != 0) && - (type.compareTo(ClassKey.UNKNOWN) != 0)) { - PdbLog.message("Warning: Mismatched complex type 'U' for " + type); + if ((key.compareTo(ClassKey.STRUCT) != 0) && + (key.compareTo(ClassKey.UNKNOWN) != 0)) { + PdbLog.message("Warning: Mismatched complex type 'U' for " + key); } break; case 'V': - if ((type.compareTo(ClassKey.CLASS) != 0) && - (type.compareTo(ClassKey.UNKNOWN) != 0)) { - PdbLog.message("Warning: Mismatched complex type 'V' for " + type); + if ((key.compareTo(ClassKey.CLASS) != 0) && + (key.compareTo(ClassKey.UNKNOWN) != 0)) { + PdbLog.message("Warning: Mismatched complex type 'V' for " + key); } break; default: @@ -197,6 +724,11 @@ public class CppCompositeType { } + /** + * Method to do some validation of the class parameters prior to trying to the user trying + * to construct or use the class + * @return {@code true} if validation passed + */ public boolean validate() { // C++ rules: // If final, can have an empty name. I believe this means "name" can be empty, but @@ -208,193 +740,948 @@ public class CppCompositeType { return true; } - private List getLayoutBaseClasses() { - return layoutBaseClasses; + //============================================================================================== + //============================================================================================== + + private TreeSet getPropagatedSelfBaseVfts() { + return propagatedSelfBaseVfts; } - SymbolPath getSymbolPath() { - return symbolPath; + private TreeSet getPropagatedSelfBaseVbts() { + return propagatedSelfBaseVbts; } - Composite getComposite() { - return composite; + private TreeSet getPropagatedDirectVirtualBaseVfts() { + return propagatedDirectVirtualBaseVfts; } - public CategoryPath getCategoryPath() { - return categoryPath; + private TreeSet getPropagatedDirectVirtualBaseVbts() { + return propagatedDirectVirtualBaseVbts; } - public CategoryPath getInternalsCategoryPath() { - return internalsCategoryPath; + private TreeSet getPropagatedIndirectVirtualBaseVfts() { + return propagatededIndirectVirtualBaseVfts; } - public void setFinal(boolean isFinal) { - this.isFinal = isFinal; + private TreeSet getPropagatedIndirectVirtualBaseVbts() { + return propagatedIndirectVirtualBaseVbts; } - public boolean isFinal() { - return isFinal; + //============================================================================================== + //============================================================================================== + private void createHierarchicalClassLayout(VxtManager vxtManager, TaskMonitor monitor) + throws PdbException, CancelledException { + + initLayoutAlgorithmData(); + + findDirectBaseVxtPtrs(); + + findOrAllocateMainVftPtr(); + findOrAllocateMainVbtPtr(); + + createClassLayout(vxtManager, monitor); + + finalizeAllVxtParentage(); + } - public void setClass() { - classKey = ClassKey.CLASS; + /** + * Initializes data for class layout and vxtptr information + */ + private void initLayoutAlgorithmData() { + + //====== + // Data used for laying out the class + + layoutVftPtrMembers = new ArrayList<>(); + layoutVbtPtrMembers = new ArrayList<>(); + + vftTableIdByOffset = new HashMap<>(); + vftOffsetByTableId = new HashMap<>(); + vbtTableIdByOffset = new HashMap<>(); + vbtOffsetByTableId = new HashMap<>(); + + baseOffsetById = new TreeMap<>(); + + //====== + // Data used for resolving main vftptr + + placeholderVirtualBaseTables = new HashMap<>(); + + //====== + // Data used for analyzing Vxts and their parentage + + propagatedSelfBaseVfts = new TreeSet<>(); + propagatedSelfBaseVbts = new TreeSet<>(); + propagatedDirectVirtualBaseVfts = new TreeSet<>(); + propagatedDirectVirtualBaseVbts = new TreeSet<>(); + propagatededIndirectVirtualBaseVfts = new TreeSet<>(); + propagatedIndirectVirtualBaseVbts = new TreeSet<>(); + finalLayoutVfts = new TreeMap<>(); + finalLayoutVbts = new TreeMap<>(); } - public void setStruct() { - classKey = ClassKey.STRUCT; + /** + * Determines final parentage information for each vxt. This information includes full + * parentage as well as a shortened version similar to the MSFT mangled scheme (results not + * 100%... needs more work) + */ + private void finalizeAllVxtParentage() { + + // Now consolidate virtual indirects (can we use some of what is in MsftVxtManager in the + // future (move the node stuff to VxtManager)? + + PNode vbtChildToParentRoot = new PNode(null); + PNode vbtParentToChildRoot = new PNode(null); + PNode vftChildToParentRoot = new PNode(null); + PNode vftParentToChildRoot = new PNode(null); + PNode childToParentNode; + PNode parentToChildNode; + + for (VxtPtrInfo info : finalLayoutVfts.values()) { + List parentage = info.parentage(); + childToParentNode = vftChildToParentRoot; + parentToChildNode = vftParentToChildRoot; + for (ClassID id : parentage) { + String name = ((ProgramClassID) id).getSymbolPath().toString(); + childToParentNode.incrementPathCount(); + childToParentNode = childToParentNode.getOrAddBranch(name); + } + for (ClassID id : parentage.reversed()) { + String name = ((ProgramClassID) id).getSymbolPath().toString(); + parentToChildNode.incrementPathCount(); + parentToChildNode = parentToChildNode.getOrAddBranch(name); + } + } + for (VxtPtrInfo info : finalLayoutVbts.values()) { + List parentage = info.parentage(); + childToParentNode = vbtChildToParentRoot; + parentToChildNode = vbtParentToChildRoot; + for (ClassID id : parentage) { + String name = ((ProgramClassID) id).getSymbolPath().toString(); + childToParentNode.incrementPathCount(); + childToParentNode = childToParentNode.getOrAddBranch(name); + } + for (ClassID id : parentage.reversed()) { + String name = ((ProgramClassID) id).getSymbolPath().toString(); + parentToChildNode.incrementPathCount(); + parentToChildNode = parentToChildNode.getOrAddBranch(name); + } + } + + StringBuilder builder = new StringBuilder(); + for (VxtPtrInfo info : finalLayoutVfts.values()) { + List altParentage = + finalizeVxtPtrParentage(vftChildToParentRoot, vftParentToChildRoot, info); + builder.append(dumpVxtPtrResult("vft", info, altParentage)); + + } + for (VxtPtrInfo info : finalLayoutVbts.values()) { + List altParentage = + finalizeVxtPtrParentage(vbtChildToParentRoot, vbtParentToChildRoot, info); + builder.append(dumpVxtPtrResult("vbt", info, altParentage)); + } + if (!builder.isEmpty()) { + builder.insert(0, String.format("Class: %s\n", getSymbolPath().toString())); + } + summarizedClassVxtPtrInfo = builder.toString(); } - public void setUnion() { - classKey = ClassKey.UNION; + /** + * Finalizes the simplification of parentage for the vxt using the collected tree data + * @param childToParentNode the child-to-parent tree root node + * @param parentToChildNode the parent-to-child tree root node + * @param info the information for this vxt + * @return the resultant simplified parentage for the vxt + */ + private List finalizeVxtPtrParentage(PNode childToParentNode, PNode parentToChildNode, + VxtPtrInfo info) { + List parentage = info.parentage(); + List altParentage = new ArrayList<>(); + String startNode = null; + + for (ClassID id : parentage) { + String name = ((ProgramClassID) id).getSymbolPath().toString(); + childToParentNode = childToParentNode.getBranch(name); + if (childToParentNode.getPathCount() == 1) { + startNode = name; + break; + } + } + + // If not null, then look for start; otherwise assume start encountered + // (use all nodes) + boolean foundStart = (startNode == null); + for (ClassID id : parentage.reversed()) { + String name = ((ProgramClassID) id).getSymbolPath().toString(); + if (name.equals(startNode)) { + foundStart = true; + } + if (parentToChildNode.getPathCount() > 1) { + if (foundStart) { + altParentage.addFirst(id); + } + } + else { + break; + } + parentToChildNode = parentToChildNode.getBranch(name); + } + return altParentage; } - // not sure if user can see Type when returned. - public ClassKey getType() { - return classKey; + /** + * Creates a String dump presentation of the VxtPtrInfo and alternative parentage + * @param vxt either {@code "vft"} or {@code "vbt"} String for the VxtPtrInfo + * @param info the VxtPtrInfo + * @param altParentage the alternative parentage + * @return the String output + */ + private String dumpVxtPtrResult(String vxt, VxtPtrInfo info, List altParentage) { + List r1 = new ArrayList<>(); + for (ClassID id : altParentage.reversed()) { + String name = ((ProgramClassID) id).getSymbolPath().toString(); + r1.add(name); + } + List r2 = new ArrayList<>(); + for (ClassID id : info.parentage().reversed()) { + String name = ((ProgramClassID) id).getSymbolPath().toString(); + r2.add(name); + } + return String.format(" %4d %s %s\t%s\n", info.finalOffset(), vxt, r1.toString(), + r2.toString()); } - public void setName(String className) { - this.className = className; + /** + * Creates the self-base composite + */ + private void createSelfBase() { + DataTypePath selfBasePath = createSelfBaseCategoryPath(this); + selfBaseType = new StructureDataType(selfBasePath.getCategoryPath(), + selfBasePath.getDataTypeName(), 0, composite.getDataTypeManager()); + selfBaseType.setDescription("Base of " + selfBasePath.getDataTypeName()); } - public String getName() { - return className; + /** + * Creates a members-only layout (the legacy layout)... excludes C++ class hierarchy and vxts + * @param monitor the task monitor + * @throws CancelledException upon user cancellation + */ + private void createMembersOnlyClassLayout(TaskMonitor monitor) throws CancelledException { + TreeMap map = new TreeMap<>(); + for (Member member : layoutMembers) { + ClassPdbMember classPdbMember = + new ClassPdbMember(member.getName(), member.getDataType(), + member.isFlexibleArray(), member.getOffset(), member.getComment()); + map.put((long) member.getOffset(), classPdbMember); + } + List sm = new ArrayList<>(map.values()); + if (!DefaultCompositeMember.applyDataTypeMembers(composite, false, false, size, + sm, msg -> Msg.warn(this, msg), monitor)) { + clearComponents(composite); + } + selfBaseType = composite; } - public DataTypePath getDataTypePath() { - return composite.getDataTypePath(); + /** + * Lays out the composite and possible self-base for this class + * @param vxtManager the vxtManager + * @param monitor the monitor + * @throws CancelledException upon user cancellation + * @throws PdbException up issue with finding the vbt or assigning offsets to virtual bases + */ + private void createClassLayout(VxtManager vxtManager, TaskMonitor monitor) + throws CancelledException, PdbException { + List selfBaseMembers = getSelfBaseClassMembers(); + if (getNumLayoutVirtualBaseClasses() == 0) { + if (!DefaultCompositeMember.applyDataTypeMembers(composite, false, false, size, + selfBaseMembers, msg -> Msg.warn(this, msg), monitor)) { + clearComponents(composite); + } + selfBaseType = composite; + } + else { + createSelfBase(); + if (!DefaultCompositeMember.applyDataTypeMembers(selfBaseType, false, false, 0, + selfBaseMembers, msg -> Msg.warn(this, msg), monitor)) { + clearComponents(composite); + } + ClassPdbMember directClassPdbMember = + new ClassPdbMember("", selfBaseType, false, 0, SELF_BASE_COMMENT); + + mainVbt = getMainVbt(vxtManager); + assignVirtualBaseOffsets(); + + String baseComment = (mainVbt instanceof ProgramVirtualBaseTable) ? VIRTUAL_BASE_COMMENT + : VIRTUAL_BASE_SPECULATIVE_COMMENT; + TreeMap virtualBasePdbMembers = + getVirtualBaseClassMembers(baseComment); + findVirtualBaseVxtPtrs(); + + TreeMap allMembers = new TreeMap<>(); + allMembers.put(0L, directClassPdbMember); + allMembers.putAll(virtualBasePdbMembers); + List am = new ArrayList<>(allMembers.values()); + + if (!DefaultCompositeMember.applyDataTypeMembers(composite, false, false, size, + am, msg -> Msg.warn(this, msg), monitor)) { + clearComponents(composite); + } + } } - public void setMangledName(String mangledName) { - this.mangledName = mangledName; + // Taken from PdbUtil without change. Would have had to change access on class PdbUtil and + // this ensureSize method to public to make it accessible. Can revert to using PdbUtil + // once we move this new module from Contrib to Features/PDB. + private final static void clearComponents(Composite composite) { + if (composite instanceof Structure) { + ((Structure) composite).deleteAll(); + } + else { + while (composite.getNumComponents() > 0) { + composite.delete(0); + } + } } - public String getMangledName() { - return mangledName; + /** + * Reports whether the base of this class has zero size + * @return {@code true} if has zero size + */ + private boolean hasZeroBaseSize() { + return hasZeroBaseSize; } - public void setSize(int size) { - this.size = size; - } + /** + * Returns the self base class members, including possible direct self bases, vxts, and + * regular members + * @return the members + */ + private List getSelfBaseClassMembers() { + // Attempting to use TreeMap to sort with the key being a record of + // ByteBitOffset (Long byteOff, int bitOff, int ordinal) {} + // so that vxtptrs could get injected properly, but this did not work until the "ordinal" + // field was included, but the overall solution still does not work because of the + // ordering of records when flattened (as MSFT does them) unions are in play. In such + // cases we might get members at offsets: 0, 4, 8, 12, 14, 16, 20 24, 12, 16, 24, 28, 32 + // which has a union at offset 12 within this outer type. + // Thus, we just insert the vxts into the members list that is constructed with + // base classes and regular members + hasZeroBaseSize = true; + List members = new ArrayList<>(); + String accumulatedComment = ""; + for (DirectLayoutBaseClass base : directLayoutBaseClasses) { + CppCompositeType baseComposite = base.getBaseClassType(); + // Cannot do baseComposite.getSelfBaseType().isZeroLength() + // or baseComposite.getComposite().isZeroLength() + if (!baseComposite.hasZeroBaseSize()) { + hasZeroBaseSize = false; + String comment = BASE_COMMENT; + if (!accumulatedComment.isEmpty()) { + comment += " and previous " + accumulatedComment; + } + Composite baseDataType = base.getSelfBaseDataType(); + int offset = base.getOffset(); + // This does not have attributes like "Member" does (consider changes?) + ClassPdbMember classPdbMember = + new ClassPdbMember("", baseDataType, false, offset, comment); + members.add(classPdbMember); + accumulatedComment = ""; + } + else { + // Note that if there is only base and it has zero size, this message will not + // get output. Consider where we might notate this case in the structure for + // an improved result + String comment = + "(Empty Base " + base.getDataTypePath().getDataTypeName() + ")"; + accumulatedComment += comment; + } + } + hasZeroBaseSize &= layoutVftPtrMembers.size() == 0; + hasZeroBaseSize &= layoutVbtPtrMembers.size() == 0; + hasZeroBaseSize &= layoutMembers.size() == 0; - public int getSize() { - return size; - } + for (Member member : layoutMembers) { + ClassPdbMember classPdbMember = + new ClassPdbMember(member.getName(), member.getDataType(), + member.isFlexibleArray(), member.getOffset(), member.getComment()); + members.add(classPdbMember); + } - public int getNumMembers() { - return myMembers.size(); - } - - public int getNumLayoutMembers() { - return layoutMembers.size(); - } - - public void addVirtualFunctionTablePointer(Pointer ptrType, int offset) { - // Not using ptrType argument for member... not generic enough - Member newMember = - new Member(ClassUtils.VFPTR, ClassUtils.VXPTR_TYPE, false, ClassFieldAttributes.UNKNOWN, - offset); - layoutVftPtrMembers.add(newMember); - vftPtrTypeByOffset.put(offset, ptrType); - } - - public Pointer getVftPtrType(int offset) { - return vftPtrTypeByOffset.get(offset); - } - - private void insertVirtualFunctionTablePointers(List pdbMembers) { - for (Member vftPtrMember : layoutVftPtrMembers) { - ClassPdbMember vftPtrPdbMember = new ClassPdbMember(vftPtrMember.getName(), - vftPtrMember.getDataType(), vftPtrMember.isFlexibleArray(), - vftPtrMember.getOffset(), vftPtrMember.getComment()); + for (Member vftMember : layoutVftPtrMembers) { // not expecting more than one + ClassPdbMember classPdbMember = + new ClassPdbMember(vftMember.getName(), vftMember.getDataType(), + vftMember.isFlexibleArray(), vftMember.getOffset(), vftMember.getComment()); + int vOff = vftMember.getOffset(); int index = 0; - for (ClassPdbMember member : pdbMembers) { - if (member.getOffset() > vftPtrMember.getOffset()) { + for (ClassPdbMember member : members) { + if (member.getOffset() >= vOff) { break; } index++; } - pdbMembers.add(index, vftPtrPdbMember); + members.add(index, classPdbMember); + } + for (Member vbtMember : layoutVbtPtrMembers) { // not expecting more than one + ClassPdbMember classPdbMember = + new ClassPdbMember(vbtMember.getName(), vbtMember.getDataType(), + vbtMember.isFlexibleArray(), vbtMember.getOffset(), vbtMember.getComment()); + int vOff = vbtMember.getOffset(); + int index = 0; + for (ClassPdbMember member : members) { + if (member.getOffset() >= vOff) { + break; + } + index++; + } + members.add(index, classPdbMember); + } + return members; + } + + /** + * Returns the virtual base class members for our class + * @param baseComment the general virtual base class comment to be used + * @return the members + */ + private TreeMap getVirtualBaseClassMembers(String baseComment) { + TreeMap map = new TreeMap<>(); + String accumulatedComment = ""; + for (VirtualLayoutBaseClass base : virtualLayoutBaseClasses) { + CppCompositeType baseComposite = base.getBaseClassType(); + ClassID id = baseComposite.getClassId(); + Long offset = baseOffsetById.get(id); + // Cannot do baseComposite.getSelfBaseType().isZeroLength() + // or baseComposite.getComposite().isZeroLength() + if (!baseComposite.hasZeroBaseSize()) { + String comment = baseComment; + if (!accumulatedComment.isEmpty()) { + comment += " and previous " + accumulatedComment; + } + Composite baseDataType = base.getSelfBaseDataType(); + // This does not have attributes + ClassPdbMember classPdbMember = + new ClassPdbMember("", baseDataType, false, offset.intValue(), comment); + map.put(offset, classPdbMember); + accumulatedComment = ""; + } + else { + String comment = + "(Empty Virtual Base " + base.getDataTypePath().getDataTypeName() + ")"; + accumulatedComment += comment; + } + } + return map; + } + + /** + * Finds all virtual base and virtual function pointers in the hierarchy of this class's + * self base. + */ + private void findDirectBaseVxtPtrs() { + for (DirectLayoutBaseClass base : directLayoutBaseClasses) { + CppCompositeType cppBaseType = base.getBaseClassType(); + ProgramClassID baseId = cppBaseType.getClassId(); + long baseOffset = base.getOffset(); + // Note that if the parent has already had its layout done, it will not have + // used the vxtManager that we are passing in here; it will have used whatever + // was passed to the layout method for that class + for (VxtPtrInfo info : cppBaseType.getPropagatedSelfBaseVfts()) { + VxtPtrInfo newInfo = createSelfOwnedDirectVxtPtrInfo(info, baseId, baseOffset); + storeVxtInfo(propagatedSelfBaseVfts, finalLayoutVfts, vftTableIdByOffset, + vftOffsetByTableId, newInfo); + } + for (VxtPtrInfo info : cppBaseType.getPropagatedSelfBaseVbts()) { + VxtPtrInfo newInfo = createSelfOwnedDirectVxtPtrInfo(info, baseId, baseOffset); + storeVxtInfo(propagatedSelfBaseVbts, finalLayoutVbts, vbtTableIdByOffset, + vbtOffsetByTableId, newInfo); + } } } - public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, int offset, - String comment) { - addMember(memberName, dataType, isFlexibleArray, ClassFieldAttributes.UNKNOWN, offset, - comment); + /** + * Finds all virtual base and virtual function pointers in the hierarchy of this class's + * virtual bases. Gathers results from the accumulation of all "direct" virtual base classes; + * we are not relying on the "indirect" virtual base class information from the PDB. This + * is done this way so that we can collect parentage information for the pointers. + */ + private void findVirtualBaseVxtPtrs() { + // Walk direct bases to find vxts of virtual bases. TODO: also notate all rolled up + // virtuals for each direct base. + for (DirectLayoutBaseClass base : directLayoutBaseClasses) { + + CppCompositeType cppBaseType = base.getBaseClassType(); + + for (VxtPtrInfo info : cppBaseType.getPropagatedDirectVirtualBaseVfts()) { + VxtPtrInfo newInfo = createSelfOwnedVirtualVxtPtrInfo(info); + storeVxtInfo(propagatedDirectVirtualBaseVfts, finalLayoutVfts, vftTableIdByOffset, + vftOffsetByTableId, newInfo); + } + for (VxtPtrInfo info : cppBaseType.getPropagatedDirectVirtualBaseVbts()) { + VxtPtrInfo newInfo = createSelfOwnedVirtualVxtPtrInfo(info); + storeVxtInfo(propagatedDirectVirtualBaseVbts, finalLayoutVbts, vbtTableIdByOffset, + vbtOffsetByTableId, newInfo); + } + for (VxtPtrInfo info : cppBaseType.getPropagatedIndirectVirtualBaseVfts()) { + VxtPtrInfo newInfo = createSelfOwnedVirtualVxtPtrInfo(info); + storeVxtInfo(propagatededIndirectVirtualBaseVfts, finalLayoutVfts, + vftTableIdByOffset, vftOffsetByTableId, newInfo); + } + for (VxtPtrInfo info : cppBaseType.getPropagatedIndirectVirtualBaseVbts()) { + VxtPtrInfo newInfo = createSelfOwnedVirtualVxtPtrInfo(info); + storeVxtInfo(propagatedIndirectVirtualBaseVbts, finalLayoutVbts, vbtTableIdByOffset, + vbtOffsetByTableId, newInfo); + } + } + + // This loop is currently purposefully separate from the above; we want to determine if + // separate vs. together has bearing on order in the lists that might match layout, etc. + // if we didn't have VBT in memory to consult. + for (DirectVirtualLayoutBaseClass base : directVirtualLayoutBaseClasses) { + + CppCompositeType cppBaseType = base.getBaseClassType(); + ProgramClassID baseId = cppBaseType.getClassId(); + + for (VxtPtrInfo info : cppBaseType.getPropagatedSelfBaseVfts()) { + VxtPtrInfo newInfo = createVirtualOwnedSelfVxtPtrInfo(info, baseId); + storeVxtInfo(propagatedDirectVirtualBaseVfts, finalLayoutVfts, vftTableIdByOffset, + vftOffsetByTableId, newInfo); + } + for (VxtPtrInfo info : cppBaseType.getPropagatedSelfBaseVbts()) { + VxtPtrInfo newInfo = createVirtualOwnedSelfVxtPtrInfo(info, baseId); + storeVxtInfo(propagatedDirectVirtualBaseVbts, finalLayoutVbts, vbtTableIdByOffset, + vbtOffsetByTableId, newInfo); + } + for (VxtPtrInfo info : cppBaseType.getPropagatedDirectVirtualBaseVfts()) { + VxtPtrInfo newInfo = createVirtualOwnedVirtualVxtPtrInfo(info); + storeVxtInfo(propagatededIndirectVirtualBaseVfts, finalLayoutVfts, + vftTableIdByOffset, vftOffsetByTableId, newInfo); + } + for (VxtPtrInfo info : cppBaseType.getPropagatedDirectVirtualBaseVbts()) { + VxtPtrInfo newInfo = createVirtualOwnedVirtualVxtPtrInfo(info); + storeVxtInfo(propagatedIndirectVirtualBaseVbts, finalLayoutVbts, vbtTableIdByOffset, + vbtOffsetByTableId, newInfo); + } + for (VxtPtrInfo info : cppBaseType.getPropagatedIndirectVirtualBaseVfts()) { + VxtPtrInfo newInfo = createVirtualOwnedVirtualVxtPtrInfo(info); + storeVxtInfo(propagatededIndirectVirtualBaseVfts, finalLayoutVfts, + vftTableIdByOffset, vftOffsetByTableId, newInfo); + } + for (VxtPtrInfo info : cppBaseType.getPropagatedIndirectVirtualBaseVbts()) { + VxtPtrInfo newInfo = createVirtualOwnedVirtualVxtPtrInfo(info); + storeVxtInfo(propagatedIndirectVirtualBaseVbts, finalLayoutVbts, vbtTableIdByOffset, + vbtOffsetByTableId, newInfo); + } + + } } - public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, - int offset) { - addMember(memberName, dataType, isFlexibleArray, ClassFieldAttributes.UNKNOWN, offset, - null); + // Note sure what the final information will look like when we are done. For this stopping + // point, this method stores what we currently want to store + /** + * Method to store the propagated and final results of the vxt + * @param propagate the propagate tree + * @param finalInfo the final info tree + * @param tableIdByOffset the table-id-by-offset map + * @param offsetByTableId the offset-by-table-id map + * @param info the vxt ptr info + */ + private void storeVxtInfo(TreeSet propagate, TreeMap finalInfo, + Map tableIdByOffset, Map offsetByTableId, + VxtPtrInfo info) { + propagate.add(info); + Long finalOffset = info.finalOffset(); + finalInfo.putIfAbsent(finalOffset, info); + OwnerParentage op = new OwnerParentage(info.baseId(), info.parentage()); + tableIdByOffset.put(finalOffset, op); + offsetByTableId.put(op, finalOffset); } - public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, - ClassFieldAttributes attributes, int offset) { - Member newMember = new Member(memberName, dataType, isFlexibleArray, attributes, offset); - myMembers.add(newMember); - addMember(layoutMembers, newMember); + /** + * Converts VxtPtrInfo from self-owned direct base for this class + * @param baseInfo the vxt info from the base + * @param baseId the base id of the base + * @param baseOffset the base offset of the base + * @return the new VxtPtrInfo for this class + */ + private VxtPtrInfo createSelfOwnedDirectVxtPtrInfo(VxtPtrInfo baseInfo, ClassID baseId, + long baseOffset) { + Long accumOffset = baseInfo.accumOffset() + baseOffset; + return new VxtPtrInfo(accumOffset, accumOffset, baseId, updateParentage(baseInfo)); } - public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, - ClassFieldAttributes attributes, int offset, String comment) { - Member newMember = - new Member(memberName, dataType, isFlexibleArray, attributes, offset, comment); - myMembers.add(newMember); - addMember(layoutMembers, newMember); + /** + * Converts VxtPtrInfo from self-owned direct or indirect virtual base for this class + * @param baseInfo the vxt info from the base + * @return the new VxtPtrInfo for this class + */ + private VxtPtrInfo createSelfOwnedVirtualVxtPtrInfo(VxtPtrInfo baseInfo) { + Long accumOffset = baseInfo.accumOffset(); + Long finalOffset = accumOffset + baseOffsetById.get(baseInfo.baseId()); + return new VxtPtrInfo(finalOffset, accumOffset, baseInfo.baseId(), + updateParentage(baseInfo)); } - private void addMember(List members, Member newMember) { - members.add(newMember); + /** + * Converts VxtPtrInfo from virtual-based-owned direct base for this class + * @param baseInfo the vxt info from the base + * @param baseId the base id of the base + * @return the new VxtPtrInfo for this class + */ + private VxtPtrInfo createVirtualOwnedSelfVxtPtrInfo(VxtPtrInfo baseInfo, ClassID baseId) { + Long accumOffset = baseInfo.accumOffset(); + Long finalOffset = accumOffset + baseOffsetById.get(baseId); + return new VxtPtrInfo(finalOffset, accumOffset, baseId, updateParentage(baseInfo)); + } + + /** + * Converts VxtPtrInfo from virtual-based-owned direct or indirect virtual base for this class + * @param baseInfo the vxt info from the base + * @return the new VxtPtrInfo for this class + */ + private VxtPtrInfo createVirtualOwnedVirtualVxtPtrInfo(VxtPtrInfo baseInfo) { + Long accumOffset = baseInfo.accumOffset(); + Long finalOffset = accumOffset + baseOffsetById.get(baseInfo.baseId()); + return new VxtPtrInfo(finalOffset, accumOffset, baseInfo.baseId(), + updateParentage(baseInfo)); + } + + private List updateParentage(VxtPtrInfo info) { + List newParentage = new ArrayList<>(info.parentage()); + newParentage.add(myId); + return newParentage; + } + + /** + * Uses the main virtual base table to assign offsets for the virtual bases + * @throws PdbException if a virtual base offset cannot be identified + */ + private void assignVirtualBaseOffsets() throws PdbException { + for (VirtualLayoutBaseClass base : virtualLayoutBaseClasses) { + CppCompositeType cppBaseType = base.getBaseClassType(); + Long baseOffset = mainVbt.getBaseOffset(base.getOffetFromVbt()); + if (baseOffset == null) { + throw new PdbException("Cannot place base class"); + } + baseOffset += base.getBasePointerOffset(); + ProgramClassID baseId = cppBaseType.getClassId(); + baseOffsetById.put(baseId, baseOffset); + } + } + + /** + * Finds or allocates (if needed) the Virtual Function Table "Pointer" within the class + * structure + */ + private void findOrAllocateMainVftPtr() { + if (propagatedSelfBaseVfts.isEmpty()) { + if (!vftPtrTypeByOffset.isEmpty()) { + if (vftPtrTypeByOffset.size() > 1) { + Msg.warn(this, "Unexpected multiple vfts for " + myId); + } + myVftPtrOffset = vftPtrTypeByOffset.firstKey(); + VxtPtrInfo info = + new VxtPtrInfo(myVftPtrOffset, myVftPtrOffset, myId, List.of(myId)); + propagatedSelfBaseVfts.add(info); + finalLayoutVfts.put(info.accumOffset(), info); + OwnerParentage op = new OwnerParentage(info.baseId(), info.parentage()); + vftTableIdByOffset.put(info.accumOffset(), op); + vftOffsetByTableId.put(op, info.accumOffset()); + Member newMember = new Member(ClassUtils.VFPTR, ClassUtils.VXPTR_TYPE, false, + ClassFieldAttributes.UNKNOWN, myVftPtrOffset.intValue()); + layoutVftPtrMembers.add(newMember); + myMembers.add(newMember); + + } + } + mainVftPtrOffset = finalLayoutVfts.isEmpty() ? null : finalLayoutVfts.firstKey(); + } + + /** + * Finds or allocates (if needed) the Virtual Base Table "Pointer" for within the class + * structure + */ + private void findOrAllocateMainVbtPtr() { + if (propagatedSelfBaseVbts.isEmpty()) { + if (!virtualLayoutBaseClasses.isEmpty()) { + TreeSet vbtOffsets = new TreeSet<>(); + for (VirtualLayoutBaseClass base : virtualLayoutBaseClasses) { + vbtOffsets.add((long) base.getBasePointerOffset()); + } + if (vbtOffsets.size() > 1) { + Msg.warn(this, "Unexpected multiple vbts for " + myId); + } + Long vbtPtrOffset = vbtOffsets.first(); + if (myVbtPtrOffset != null && vbtPtrOffset != myVbtPtrOffset) { + Msg.warn(this, "Mismatch vbt location for " + myId); + } + VxtPtrInfo info = new VxtPtrInfo(vbtPtrOffset, vbtPtrOffset, myId, List.of(myId)); + propagatedSelfBaseVbts.add(info); + finalLayoutVbts.put(info.accumOffset(), info); + OwnerParentage op = new OwnerParentage(info.baseId(), info.parentage()); + vbtTableIdByOffset.put(info.accumOffset(), op); + vbtOffsetByTableId.put(op, info.accumOffset()); + myVbtPtrOffset = finalLayoutVbts.firstKey(); + Member newMember = new Member(ClassUtils.VBPTR, ClassUtils.VXPTR_TYPE, false, + ClassFieldAttributes.UNKNOWN, myVbtPtrOffset.intValue()); + layoutVbtPtrMembers.add(newMember); + myMembers.add(newMember); + } + } + mainVbtPtrOffset = finalLayoutVbts.isEmpty() ? null : finalLayoutVbts.firstKey(); + } + + /** + * Provides the Virtual Base Table to be used for placing virtual bases of this class + */ + private VirtualBaseTable getMainVbt(VxtManager vxtManager) throws PdbException { + VirtualBaseTable vbt = null; + if (!finalLayoutVbts.isEmpty()) { + VxtPtrInfo firstVbtPtrInfo = finalLayoutVbts.firstEntry().getValue(); + List reorderedVirtualBases = new ArrayList<>(); + for (ClassID bId : depthFirstVirtualBases().keySet()) { + for (VirtualLayoutBaseClass base : virtualLayoutBaseClasses) { + CppCompositeType baseType = base.getBaseClassType(); + ClassID id = baseType.getClassId(); + if (id.equals(bId)) { + reorderedVirtualBases.add(base); + } + } + } + long offset = selfBaseType.getAlignedLength(); + for (VirtualLayoutBaseClass base : reorderedVirtualBases) { + CppCompositeType baseType = base.getBaseClassType(); + addPlaceholderVirtualBaseTableEntry(vxtManager, base, offset); + offset += baseType.getSelfBaseType().getAlignedLength(); + } + if (vxtManager instanceof MsftVxtManager mvxtManager) { + VBTable table = mvxtManager.findVbt(myId, firstVbtPtrInfo.parentage()); + if (table instanceof ProgramVirtualBaseTable pvbt) { + return pvbt; + } + } + vbt = placeholderVirtualBaseTables.get(mainVbtPtrOffset); + } + return vbt; + } + + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + // used by find main vbt (probably should evaluate for cleanup) + private void addPlaceholderVirtualBaseTableEntry(VxtManager vxtManager, + VirtualLayoutBaseClass base, Long baseOffset) throws PdbException { + + long index = base.getBasePointerOffset(); + OwnerParentage op = vbtTableIdByOffset.get(index); + if (op == null) { + // error + return; + } + if (vxtManager instanceof MsftVxtManager mvxtManager) { + VBTable xtable = mvxtManager.findVbt(op.owner(), op.parentage()); + if (xtable == null) { + int entrySize = + composite.getDataTypeManager().getDataOrganization().getIntegerSize(); + PlaceholderVirtualBaseTable newTable = + new PlaceholderVirtualBaseTable(op.owner(), op.parentage(), entrySize); + xtable = newTable; + placeholderVirtualBaseTables.put(index, newTable); + } + if (xtable instanceof PlaceholderVirtualBaseTable ptable) { + VBTableEntry e = ptable.getBase(base.getOffetFromVbt()); + if (e != null) { + return; + } + ClassID baseId = base.getBaseClassType().getClassId(); + ptable.setBaseClassOffsetAndId(base.getOffetFromVbt(), baseOffset, baseId); + } + } + else { + PlaceholderVirtualBaseTable ptable = placeholderVirtualBaseTables.get(index); + if (ptable == null) { + int entrySize = + composite.getDataTypeManager().getDataOrganization().getIntegerSize(); + ptable = new PlaceholderVirtualBaseTable(op.owner(), op.parentage(), entrySize); + placeholderVirtualBaseTables.put(index, ptable); + } + VBTableEntry e = ptable.getBase(base.getOffetFromVbt()); + if (e != null) { + return; + } + ClassID baseId = base.getBaseClassType().getClassId(); + ptable.setBaseClassOffsetAndId(base.getOffetFromVbt(), baseOffset, baseId); + } + } + + /** + * Returns depth-first occurrences of ClassIDs along with their parentage with the assumption + * that all direct (non-virtual) base classes occur before direct virtual base classes. + * It is also presumed that the list of direct virtual base classes for any class are found + * in their definition correct order (though might be interspersed with direct non-virtual + * bases in the actual definition) + * @return the ClassIDs and corresponding parentages (referred to by their ClassIDs) + */ + private LinkedHashMap> depthFirstVirtualBases() { + + if (depthFirstVirtualBases != null) { + return depthFirstVirtualBases; + } + depthFirstVirtualBases = new LinkedHashMap<>(); + + for (DirectLayoutBaseClass base : directLayoutBaseClasses) { + CppCompositeType bt = base.getBaseClassType(); + LinkedHashMap> baseResults = bt.depthFirstVirtualBases(); + // It is bad to replace an existing entry: we are counting on the parentage of the + // first one that occurs. Thus, we need to inspect and add them one at a time instead + // of using addAll(). + for (Map.Entry> entry : baseResults.entrySet()) { + if (!depthFirstVirtualBases.containsKey(entry.getKey())) { + depthFirstVirtualBases.put(entry.getKey(), entry.getValue()); + } + } + } + // If we have a vbt for this class in memory, we can properly place all virtual (direct + // and indirect) for this class. Problem is if we don't have a vbt in program memory, + // the problem cannot be solved appropriately. + // Problem is that MSFT PDB reports all DirectBases (non-virtual) first, followed by all + // DirectVirtualBases, followed by all IndirectVirtualBases. But by doing so, they + // throw away useful information regarding the order of defined base classes for this + // class. The PDB contents won't distinguish between + // class A : B, virtual C + // and + // class A : virtual C, B + // ... but these classes can lay out differently when B has its own virtual class(es). + // The indirect virtual bases cloud things even further. The direct virtual bases + // and indirect virtual base (we call both of these, collectively, virtual bases) will + // have representation in the main vbt for this class, and depending on the definition + // hierarchy direct virtual bases can intermingled with the indirect virtual bases. + // We essentially walk the hierarchy of direct non-virtual bases and direct virtual bases + // to craft our own list of indirect virtual bases to try to help with this, and it seems + // to help a little. We only use use the PDB-provided indirect virtual bases for when + // finding the offset of the base using the vbt (when we have a real vbt in program + // memory). + // This algorithm is meant to try its best to help when we don't have a vbt in program + // memory. + for (VirtualLayoutBaseClass base : virtualLayoutBaseClasses) { + CppCompositeType bt = base.getBaseClassType(); + LinkedHashMap> baseResults = bt.depthFirstVirtualBases(); + // It is bad to replace an existing entry: we are counting on the parentage of the + // first one that occurs. Thus, we need to inspect and add them one at a time instead + // of using addAll(). + for (Map.Entry> entry : baseResults.entrySet()) { + if (!depthFirstVirtualBases.containsKey(entry.getKey())) { + depthFirstVirtualBases.put(entry.getKey(), entry.getValue()); + } + } + } + for (DirectVirtualLayoutBaseClass base : directVirtualLayoutBaseClasses) { + CppCompositeType bt = base.getBaseClassType(); + ClassID baseId = bt.getClassId(); + ArrayList baseParentage = new ArrayList<>(List.of(baseId)); + depthFirstVirtualBases.put(baseId, baseParentage); + } + // add self to all parentage + for (List parentage : depthFirstVirtualBases.values()) { + parentage.addFirst(myId); + } + return depthFirstVirtualBases; + } + + /** + * Class used for collecting owner and parentage information for vxtptrs (and maybe base + * classes... in the future). Used for creating a tree of information that is used for + * determining shortened MSFT parentage. + */ + private static class PNode { + private String name; + private List branches; + private int pathCount; + + private PNode(String name) { + this.name = name; + branches = new ArrayList<>(); + pathCount = 0; + } + + private void incrementPathCount() { + pathCount++; + } + + private int getPathCount() { + return pathCount; + } + + private PNode getBranch(String branchName) { + for (PNode node : branches) { + if (node.name.equals(branchName)) { + return node; + } + } + return null; + } + + private PNode getOrAddBranch(String branchName) { + PNode node = getBranch(branchName); + if (node != null) { + return node; + } + node = new PNode(branchName); + branches.add(node); + return node; + } + } //============================================================================================== - /* - * These "insert" methods should be used judiciously. You need to know what/why you are doing - * this. Changing the order of "normal" members can mess up the layout algorithms from - * {@link DefaultCompositeMember}. The only place we currently think we can use these is - * when trying to place vbptr members. Not all of these methods are used too. - * @param isFlexibleArray TODO + //============================================================================================== + + /** + * Record holding owner and parentage using ClassIDs. These can be used for vxtptrs and + * (possibly) also for base class info */ - public void insertMember(String memberName, DataType dataType, boolean isFlexibleArray, - int offset, String comment) { - insertMember(memberName, dataType, isFlexibleArray, ClassFieldAttributes.UNKNOWN, offset, - comment); - } + private record OwnerParentage(ClassID owner, List parentage) {} - public void insertMember(String memberName, DataType dataType, boolean isFlexibleArray, - int offset) { - insertMember(memberName, dataType, isFlexibleArray, ClassFieldAttributes.UNKNOWN, offset, - null); - } - - public void insertMember(String memberName, DataType dataType, boolean isFlexibleArray, - ClassFieldAttributes attributes, int offset) { - Member newMember = new Member(memberName, dataType, isFlexibleArray, attributes, offset); - myMembers.add(newMember); - insertMember(layoutMembers, newMember); - } - - public void insertMember(String memberName, DataType dataType, boolean isFlexibleArray, - ClassFieldAttributes attributes, int offset, String comment) { - Member newMember = - new Member(memberName, dataType, isFlexibleArray, attributes, offset, comment); - myMembers.add(newMember); - insertMember(layoutMembers, newMember); - } - - private void insertMember(List members, Member newMember) { - int index = 0; - for (Member member : members) { - if (member.getOffset() > newMember.getOffset()) { - break; + /** + * We understand the shallow immutability of records and that the contents of the List are + * not used in comparison. Should we convert from record to class? + */ + private record VxtPtrInfo(Long finalOffset, Long accumOffset, ClassID baseId, + List parentage) + implements Comparable { + @Override + public int compareTo(VxtPtrInfo other) { + int val = Long.compare(finalOffset, other.finalOffset); + if (val != 0) { + return val; } - index++; + val = Long.compare(accumOffset, other.accumOffset); + if (val != 0) { + return val; + } + val = baseId.compareTo(other.baseId); + if (val != 0) { + return val; + } + int sizeComp = parentage.size() - other.parentage.size(); + Iterator iter = parentage.iterator(); + Iterator oiter = other.parentage.iterator(); + while (iter.hasNext() && oiter.hasNext()) { + ClassID id = iter.next(); + ClassID oid = oiter.next(); + val = id.compareTo(oid); + if (val != 0) { + return val; + } + } + return sizeComp; } - members.add(index, newMember); } + //============================================================================================== + //============================================================================================== + + // NOTE: Methods from long ago that possibly will have some future use + public void addStaticMember(String memberName, DataType dataType) { addStaticMember(memberName, dataType, ClassFieldAttributes.UNKNOWN); } @@ -404,222 +1691,92 @@ public class CppCompositeType { myMembers.add(new StaticMember(memberName, dataType, attributes)); } - public int getNumLayoutBaseClasses() { - return layoutBaseClasses.size(); - } - public int getNumLayoutVirtualBaseClasses() { - int num = 0; - for (LayoutBaseClass base : layoutBaseClasses) { - if (base instanceof DirectLayoutBaseClass) { - num++; - } - } - return layoutBaseClasses.size() - num; + return virtualLayoutBaseClasses.size(); } public int getNumSyntacticBaseClasses() { return syntacticBaseClasses.size(); } - public void addSyntacticBaseClass(CppCompositeType baseClassType) throws PdbException { - addSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN); - } - - public void addSyntacticBaseClass(CppCompositeType baseClassType, - ClassFieldAttributes attributes) throws PdbException { - validateBaseClass(baseClassType); - syntacticBaseClasses.add(new SyntacticBaseClass(baseClassType, attributes)); - } - - public void addDirectSyntacticBaseClass(CppCompositeType baseClassType) throws PdbException { - addDirectSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN); - } - - public void addDirectSyntacticBaseClass(CppCompositeType baseClassType, - ClassFieldAttributes attributes) throws PdbException { - validateBaseClass(baseClassType); - syntacticBaseClasses.add(new DirectSyntacticBaseClass(baseClassType, attributes)); - } - - public void addVirtualSyntacticBaseClass(CppCompositeType baseClassType) throws PdbException { - addVirtualSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN); - } - - public void addVirtualSyntacticBaseClass(CppCompositeType baseClassType, - ClassFieldAttributes attributes) throws PdbException { - validateBaseClass(baseClassType); - syntacticBaseClasses.add(new VirtualSyntacticBaseClass(baseClassType, attributes)); - } - - public void insertSyntacticBaseClass(CppCompositeType baseClassType, int ordinal) + public void addSyntacticBaseClass(Composite comp, CppCompositeType baseClassType) throws PdbException { - insertSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, ordinal); + addSyntacticBaseClass(comp, baseClassType, ClassFieldAttributes.UNKNOWN); } - public void insertSyntacticBaseClass(CppCompositeType baseClassType, + public void addSyntacticBaseClass(Composite comp, CppCompositeType baseClassType, + ClassFieldAttributes attributes) throws PdbException { + validateBaseClass(baseClassType); + syntacticBaseClasses.add(new SyntacticBaseClass(comp, baseClassType, attributes)); + } + + public void addDirectSyntacticBaseClass(Composite comp, CppCompositeType baseClassType) + throws PdbException { + addDirectSyntacticBaseClass(comp, baseClassType, ClassFieldAttributes.UNKNOWN); + } + + public void addDirectSyntacticBaseClass(Composite comp, CppCompositeType baseClassType, + ClassFieldAttributes attributes) throws PdbException { + validateBaseClass(baseClassType); + syntacticBaseClasses.add(new DirectSyntacticBaseClass(comp, baseClassType, attributes)); + } + + public void addVirtualSyntacticBaseClass(Composite comp, CppCompositeType baseClassType) + throws PdbException { + addVirtualSyntacticBaseClass(comp, baseClassType, ClassFieldAttributes.UNKNOWN); + } + + public void addVirtualSyntacticBaseClass(Composite comp, CppCompositeType baseClassType, + ClassFieldAttributes attributes) throws PdbException { + validateBaseClass(baseClassType); + syntacticBaseClasses.add(new VirtualSyntacticBaseClass(comp, baseClassType, attributes)); + } + + public void insertSyntacticBaseClass(Composite comp, CppCompositeType baseClassType, + int ordinal) throws PdbException { + insertSyntacticBaseClass(comp, baseClassType, ClassFieldAttributes.UNKNOWN, ordinal); + } + + public void insertSyntacticBaseClass(Composite comp, CppCompositeType baseClassType, ClassFieldAttributes attributes, int ordinal) throws PdbException { validateBaseClass(baseClassType); if (ordinal < 0 || ordinal > getNumSyntacticBaseClasses()) { // TODO: Change this to some new Exception type; e.g., ClassTypeException. throw new PdbException("Invalid base class insertion index."); } - syntacticBaseClasses.add(ordinal, new SyntacticBaseClass(baseClassType, attributes)); + syntacticBaseClasses.add(ordinal, new SyntacticBaseClass(comp, baseClassType, attributes)); } - public void insertDirectSyntacticBaseClass(CppCompositeType baseClassType, int ordinal) - throws PdbException { - insertDirectSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, ordinal); + public void insertDirectSyntacticBaseClass(Composite comp, CppCompositeType baseClassType, + int ordinal) throws PdbException { + insertDirectSyntacticBaseClass(comp, baseClassType, ClassFieldAttributes.UNKNOWN, ordinal); } - public void insertDirectSyntacticBaseClass(CppCompositeType baseClassType, + public void insertDirectSyntacticBaseClass(Composite comp, CppCompositeType baseClassType, ClassFieldAttributes attributes, int ordinal) throws PdbException { validateBaseClass(baseClassType); if (ordinal < 0 || ordinal > getNumSyntacticBaseClasses()) { // TODO: Change this to some new Exception type; e.g., ClassTypeException. throw new PdbException("Invalid base class insertion index."); } - syntacticBaseClasses.add(ordinal, new DirectSyntacticBaseClass(baseClassType, attributes)); + syntacticBaseClasses.add(ordinal, + new DirectSyntacticBaseClass(comp, baseClassType, attributes)); } - public void insertVirtualSyntacticBaseClass(CppCompositeType baseClassType, int ordinal) - throws PdbException { - insertVirtualSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, ordinal); + public void insertVirtualSyntacticBaseClass(Composite comp, CppCompositeType baseClassType, + int ordinal) throws PdbException { + insertVirtualSyntacticBaseClass(comp, baseClassType, ClassFieldAttributes.UNKNOWN, ordinal); } - public void insertVirtualSyntacticBaseClass(CppCompositeType baseClassType, + public void insertVirtualSyntacticBaseClass(Composite comp, CppCompositeType baseClassType, ClassFieldAttributes attributes, int ordinal) throws PdbException { validateBaseClass(baseClassType); if (ordinal < 0 || ordinal > getNumSyntacticBaseClasses()) { // TODO: Change this to some new Exception type; e.g., ClassTypeException. throw new PdbException("Invalid base class insertion index."); } - syntacticBaseClasses.add(ordinal, new VirtualSyntacticBaseClass(baseClassType, attributes)); - } - - //============================================================================================== - public void addDirectBaseClass(CppCompositeType baseClassType, int offset) throws PdbException { - addDirectBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, offset); - } - - public void addDirectBaseClass(CppCompositeType baseClassType, ClassFieldAttributes attributes, - int offset) throws PdbException { - validateBaseClass(baseClassType); - layoutBaseClasses.add(new DirectLayoutBaseClass(baseClassType, attributes, offset)); - } - -// // Index is order in list, not physical offset of class elements. -// public void insertDirectBaseClass(CppCompositeType baseClassType, int index) -// throws PdbException { -// insertDirectBaseClass(baseClassType, -// new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), index); -// } -// -// // Index is order in list, not physical offset of class elements. -// public void insertDirectBaseClass(CppCompositeType baseClassType, -// ClassFieldAttributes attributes, int index) throws PdbException { -// validateBaseClass(baseClassType); -// if (index < 0 || index > getNumBaseClasses()) { -// // TODO: Change this to some new Exception type; e.g., ClassTypeException. -// throw new PdbException("Invalid base class insertion index."); -// } -// layoutBaseClasses.add(index, new DirectBaseClass(baseClassType, attributes)); -// } -// - public void addDirectVirtualBaseClass(CppCompositeType baseClassType, int basePointerOffset, - DataType vbptr, int offsetFromVbt) throws PdbException { - addDirectVirtualBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, basePointerOffset, - vbptr, offsetFromVbt); - } - - public void addDirectVirtualBaseClass(CppCompositeType baseClassType, - ClassFieldAttributes attributes, int basePointerOffset, DataType vbptr, - int offsetFromVbt) throws PdbException { - validateBaseClass(baseClassType); - layoutBaseClasses.add(new DirectVirtualLayoutBaseClass(baseClassType, attributes, - basePointerOffset, vbptr, offsetFromVbt)); - } - -// // Index is order in list, not physical offset of class elements. -// public void insertDirectVirtualBaseClass(CppCompositeType baseClassType, int index) -// throws PdbException { -// insertDirectVirtualBaseClass(baseClassType, -// new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), index); -// } -// -// // Index is order in list, not physical offset of class elements. -// public void insertDirectVirtualBaseClass(CppCompositeType baseClassType, -// ClassFieldAttributes attributes, int index) throws PdbException { -// validateBaseClass(baseClassType); -// if (index < 0 || index > getNumBaseClasses()) { -// // TODO: Change this to some new Exception type; e.g., ClassTypeException. -// throw new PdbException("Invalid base class insertion index."); -// } -// layoutBaseClasses.add(index, new DirectVirtualBaseClass(baseClassType, attributes)); -// } -// - public void addIndirectVirtualBaseClass(CppCompositeType baseClassType, int basePointerOffset, - DataType vbptr, int offsetFromVbt) throws PdbException { - addIndirectVirtualBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, basePointerOffset, - vbptr, offsetFromVbt); - } - - public void addIndirectVirtualBaseClass(CppCompositeType baseClassType, - ClassFieldAttributes attributes, int basePointerOffset, DataType vbptr, - int offsetFromVbt) throws PdbException { - validateBaseClass(baseClassType); - layoutBaseClasses.add(new IndirectVirtualLayoutBaseClass(baseClassType, attributes, - basePointerOffset, vbptr, offsetFromVbt)); - } - -// // Index is order in list, not physical offset of class elements. -// public void insertIndirectVirtualBaseClass(CppCompositeType baseClassType, int index) -// throws PdbException { -// insertIndirectVirtualBaseClass(baseClassType, -// new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), index); -// } -// -// // Index is order in list, not physical offset of class elements. -// public void insertIndirectVirtualBaseClass(CppCompositeType baseClassType, -// ClassFieldAttributes attributes, int index) throws PdbException { -// validateBaseClass(baseClassType); -// if (index < 0 || index > getNumBaseClasses()) { -// // TODO: Change this to some new Exception type; e.g., ClassTypeException. -// throw new PdbException("Invalid base class insertion index."); -// } -// layoutBaseClasses.add(index, new IndirectVirtualBaseClass(baseClassType, attributes)); -// } -// - private static void validateBaseClass(CppCompositeType baseClassType) throws PdbException { - if (baseClassType.isFinal) { - throw new PdbException("Cannot inherit base class marked final."); - } - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(classKey); - builder.append(className); - if (isFinal) { - builder.append(" final"); - } - StringBuilder baseBuilder = new StringBuilder(); - for (BaseClass base : syntacticBaseClasses) { - if (baseBuilder.length() == 0) { - baseBuilder.append(" : "); - } - else { - baseBuilder.append(", "); - } - baseBuilder.append(base); - } - builder.append(baseBuilder); - return builder.toString(); - } - - boolean isZeroSize() { - return memberData.size() == 0; + syntacticBaseClasses.add(ordinal, + new VirtualSyntacticBaseClass(comp, baseClassType, attributes)); } //---------------------------------------------------------------------------------------------- @@ -635,660 +1792,6 @@ public class CppCompositeType { } } - //---------------------------------------------------------------------------------------------- - //---------------------------------------------------------------------------------------------- - public void createLayout(ObjectOrientedClassLayout layoutOptions, VxtManager vxtManager, - TaskMonitor monitor) throws PdbException, CancelledException { - if (vxtManager instanceof MsftVxtManager) { // Information from PDB/program symbols - // TODO: both same for now - //doSpeculativeLayout(vxtManager, monitor); - createVbtBasedLayout(layoutOptions, vxtManager, monitor); - } - else { - createSpeculativeLayout(layoutOptions, vxtManager, monitor); - } - } - - //---------------------------------------------------------------------------------------------- - //---------------------------------------------------------------------------------------------- - public void createVbtBasedLayout(ObjectOrientedClassLayout layoutOptions, VxtManager vxtManager, - TaskMonitor monitor) throws PdbException, CancelledException { - CategoryPath cn; - hasSelfBase = false; - switch (layoutOptions) { - case MEMBERS_ONLY: - addLayoutPdbMembers(memberData, layoutMembers); - break; - case CLASS_HIERARCHY: - cn = createSelfBaseCategoryPath(this); - Composite selfBaseType = new StructureDataType(cn.getParent(), cn.getName(), 0, - composite.getDataTypeManager()); - selfBaseType.setDescription("Base of " + cn.getName()); - - List selfBasePdbMembers = getSelfBaseClassMembers(monitor); - List myVirtualLayoutBases = preprocessVirtualBases(monitor); - - // TODO: consider moving down below next line. - boolean allVbtFound = - reconcileVirtualBaseTables(composite.getDataTypeManager(), vxtManager); - - addLayoutPdbMembers(selfBasePdbMembers, layoutMembers); - insertVirtualFunctionTablePointers(selfBasePdbMembers); - - if (!DefaultCompositeMember.applyDataTypeMembers(selfBaseType, false, false, 0, - selfBasePdbMembers, msg -> Msg.warn(this, msg), monitor)) { - clearComponents(selfBaseType); - } - int selfBaseLength = getCompositeLength(selfBaseType); - - if (selfBaseLength == 0) { - // Not using the direct type (only used it to get the selfBaseLength), so - // remove it and add the members to the main type instead. - selfBaseType.getDataTypeManager().remove(selfBaseType, monitor); - } - else { - // this does not deal with the case where more members from memberData get - // added below and must still fit in "size." - if (selfBaseLength > size) { - // Redo it with the size of the overall structure/class - selfBaseType.getDataTypeManager().remove(selfBaseType, monitor); - selfBaseType = new StructureDataType(cn.getParent(), cn.getName(), 0, - composite.getDataTypeManager()); - if (!DefaultCompositeMember.applyDataTypeMembers(selfBaseType, false, - false, size, selfBasePdbMembers, msg -> Msg.warn(this, msg), - monitor)) { - clearComponents(selfBaseType); - } - selfBaseLength = getCompositeLength(selfBaseType); - } - if (getNumLayoutVirtualBaseClasses() == 0) { - // Not using the dummy/direct type (only used it to get the - // selfBaseLength), so remove it and add the members to the main - // type instead. - selfBaseType.getDataTypeManager().remove(selfBaseType, monitor); - memberData.addAll(selfBasePdbMembers); - //addLayoutPdbMembers(memberData, layoutMembers, monitor); - } - else { - ClassPdbMember directClassPdbMember = - new ClassPdbMember("", selfBaseType, false, 0, SELF_BASE_COMMENT); - memberData.add(directClassPdbMember); - hasSelfBase = true; - } - } - - addVirtualBases(selfBaseLength, memberData, myVirtualLayoutBases, allVbtFound, - monitor); - - break; - default: - throw new PdbException("Unhandled layout mode"); - } - - if (!DefaultCompositeMember.applyDataTypeMembers(composite, false, false, size, memberData, - msg -> Msg.warn(this, msg), monitor)) { - clearComponents(composite); - } - } - - //---------------------------------------------------------------------------------------------- - //---------------------------------------------------------------------------------------------- - private List getSelfBaseClassMembers(TaskMonitor monitor) - throws CancelledException { - List mySelfClassPdbMembers = new ArrayList<>(); - TreeMap orderedBaseMembers = new TreeMap<>(); - for (LayoutBaseClass base : getLayoutBaseClasses()) { - monitor.checkCancelled(); - CppCompositeType baseComposite = base.getBaseClassType(); - if (base instanceof DirectLayoutBaseClass) { - if (!baseComposite.isZeroSize()) { - Composite baseDataType = base.getDirectDataType(); - int offset = ((DirectLayoutBaseClass) base).getOffset(); - Member baseMember = - new Member("", baseDataType, false, null, offset, BASE_COMMENT); - orderedBaseMembers.put(offset, baseMember); - } - } - } - for (Member baseMember : orderedBaseMembers.values()) { - addPdbMember(mySelfClassPdbMembers, baseMember); - } - return mySelfClassPdbMembers; - } - - //---------------------------------------------------------------------------------------------- - //---------------------------------------------------------------------------------------------- - private List preprocessVirtualBases(TaskMonitor monitor) - throws CancelledException, PdbException { - List myVirtualLayoutBases = new ArrayList<>(); - for (LayoutBaseClass base : getLayoutBaseClasses()) { - monitor.checkCancelled(); - if (base instanceof VirtualLayoutBaseClass) { - addPlaceholderVirtualBaseTableEntry(((VirtualLayoutBaseClass) base)); - myVirtualLayoutBases.add((VirtualLayoutBaseClass) base); - } - } - return myVirtualLayoutBases; - } - - //---------------------------------------------------------------------------------------------- - //---------------------------------------------------------------------------------------------- - public void createSpeculativeLayout(ObjectOrientedClassLayout layoutOptions, - VxtManager vxtManager, TaskMonitor monitor) throws PdbException, CancelledException { - // Speculative Layout uses recursion to try to know the order of members. However, MSFT - // rearranges the order of the Base Class records such that they are not necessarily in - // the order that the class was declared, and it seems that the member order follows the - // order of the class hierarchy declaration. - // We use recursion and also also reordering so Base Classes always follow their children, - // so with multiple virtual inheritance, a parent from multiple family lines will likely - // get moved. - CategoryPath cn; - hasSelfBase = false; - switch (layoutOptions) { - case MEMBERS_ONLY: - addLayoutPdbMembers(memberData, layoutMembers); - break; - case CLASS_HIERARCHY: - cn = createSelfBaseCategoryPath(this); - Composite selfBaseType = new StructureDataType(cn.getParent(), cn.getName(), 0, - composite.getDataTypeManager()); - selfBaseType.setDescription("Base of " + cn.getName()); - - List myAccumulatedDirectBases = new ArrayList<>(); - List myAccumulatedVirtualBases = new ArrayList<>(); - List selfBasePdbMembers = new ArrayList<>(); - processBaseClassesRecursive(this, true, selfBasePdbMembers, - myAccumulatedDirectBases, myAccumulatedVirtualBases, 0, monitor); - - // TODO: consider moving down below next line. - boolean allVbtFound = - reconcileVirtualBaseTables(composite.getDataTypeManager(), vxtManager); - - addLayoutPdbMembers(selfBasePdbMembers, layoutMembers); - insertVirtualFunctionTablePointers(selfBasePdbMembers); - - if (!DefaultCompositeMember.applyDataTypeMembers(selfBaseType, false, false, 0, - selfBasePdbMembers, msg -> Msg.warn(this, msg), monitor)) { - clearComponents(selfBaseType); - } - int selfBaseLength = getCompositeLength(selfBaseType); - - if (selfBaseLength == 0) { - // Not using the direct type (only used it to get the selfBaseLength), so - // remove it and add the members to the main type instead. - selfBaseType.getDataTypeManager().remove(selfBaseType, monitor); - } - else { - // this does not deal with the case where more members from memberData get - // added below and must still fit in "size." - if (selfBaseLength > size) { - // Redo it with the size of the overall structure/class - selfBaseType.getDataTypeManager().remove(selfBaseType, monitor); - selfBaseType = new StructureDataType(cn.getParent(), cn.getName(), 0, - composite.getDataTypeManager()); - if (!DefaultCompositeMember.applyDataTypeMembers(selfBaseType, false, - false, size, selfBasePdbMembers, msg -> Msg.warn(this, msg), - monitor)) { - clearComponents(selfBaseType); - } - selfBaseLength = getCompositeLength(selfBaseType); - } - if (getNumLayoutVirtualBaseClasses() == 0) { - // Not using the dummy/direct type (only used it to get the - // selfBaseLength), so remove it and add the members to the main - // type instead. - selfBaseType.getDataTypeManager().remove(selfBaseType, monitor); - memberData.addAll(selfBasePdbMembers); - //addLayoutPdbMembers(memberData, layoutMembers, monitor); - } - else { - ClassPdbMember directClassPdbMember = - new ClassPdbMember("", selfBaseType, false, 0, SELF_BASE_COMMENT); - memberData.add(directClassPdbMember); - hasSelfBase = true; - } - } - - addVirtualBasesSpeculatively(selfBaseLength, memberData, - myAccumulatedVirtualBases, monitor); - - break; - default: - throw new PdbException("Unhandled layout mode"); - } - - if (!DefaultCompositeMember.applyDataTypeMembers(composite, false, false, size, memberData, - msg -> Msg.warn(this, msg), monitor)) { - clearComponents(composite); - } - } - - //---------------------------------------------------------------------------------------------- - //---------------------------------------------------------------------------------------------- - private void processBaseClassesRecursive(CppCompositeType cppType, boolean isDirect, - List myPdbMembers, List myAccumulatedDirectBases, - List myAccumulatedVirtualBases, int depth, TaskMonitor monitor) - throws PdbException, CancelledException { - depth++; - for (LayoutBaseClass base : cppType.getLayoutBaseClasses()) { - monitor.checkCancelled(); - CppCompositeType baseComposite = base.getBaseClassType(); - if (base instanceof DirectLayoutBaseClass) { - if (isDirect) { - if (alreadyAccumulatedByName(myAccumulatedDirectBases, base)) { - throw new PdbException( - "Direct base already seen: " + base.getBaseClassType().getName()); - } - if (!baseComposite.isZeroSize()) { - Composite baseDataType = base.getDirectDataType(); - int offset = ((DirectLayoutBaseClass) base).getOffset(); - Member baseMember = - new Member("", baseDataType, false, null, offset, BASE_COMMENT); - addPdbMember(myPdbMembers, baseMember); - } - myAccumulatedDirectBases.add(base); - } - processBaseClassesRecursive(baseComposite, false, myPdbMembers, - myAccumulatedDirectBases, myAccumulatedVirtualBases, depth, monitor); - } - else if (base instanceof VirtualLayoutBaseClass) { - if (depth == 1) { - addPlaceholderVirtualBaseTableEntry(((VirtualLayoutBaseClass) base)); - } - if (alreadyAccumulatedByName(myAccumulatedVirtualBases, base)) { - continue; - } - if (!baseComposite.isZeroSize()) { - processBaseClassesRecursive(baseComposite, false, myPdbMembers, - myAccumulatedDirectBases, myAccumulatedVirtualBases, depth, monitor); - } - myAccumulatedVirtualBases.add((VirtualLayoutBaseClass) base); - } - else { - throw new PdbException("Unknown base class type"); - } - } - } - - //---------------------------------------------------------------------------------------------- - //---------------------------------------------------------------------------------------------- - void addPlaceholderVirtualBaseTableEntry(VirtualLayoutBaseClass base) throws PdbException { - PlaceholderVirtualBaseTable table = - placeholderVirtualBaseTables.get(base.getBasePointerOffset()); - if (table == null) { - table = new PlaceholderVirtualBaseTable(); - placeholderVirtualBaseTables.put(base.getBasePointerOffset(), table); - } - PlaceholderVirtualBaseTableEntry entry = - table.getEntryByIndexInTable(base.getOffetFromVbt()); - if (entry != null) { - throw new PdbException( - "Entry already exists at offset (" + base.getOffetFromVbt() + "): " + entry); - } - entry = new PlaceholderVirtualBaseTableEntry(base); - table.addEntry(base.getOffetFromVbt(), entry); - } - - PlaceholderVirtualBaseTable getPlaceholderVirtualBaseTable(int basePointerOffset) { - return placeholderVirtualBaseTables.get(basePointerOffset); - } - - Map getPlaceholderVirtualBaseTables() { - return placeholderVirtualBaseTables; - } - - private boolean reconcileVirtualBaseTables(DataTypeManager dtm, VxtManager vxtManager) - throws PdbException { - if (placeholderVirtualBaseTables.size() > 1) { - // study this. - } - - boolean allVbtFound = true; - for (Entry tableEntry : placeholderVirtualBaseTables - .entrySet()) { - int vbtptrOffset = tableEntry.getKey(); - PlaceholderVirtualBaseTable table = tableEntry.getValue(); - if (!table.validateOffset()) { - // TODO study this. - } - DataType vbptr = getVbptrDataType(dtm, vxtManager, table); - allVbtFound &= - addOrUpdateVbtAndVbtptrMember(vxtManager, table, vbptr, vbtptrOffset, getName()); - } - return allVbtFound; - } - - private DataType getVbptrDataType(DataTypeManager dtm, VxtManager vxtManager, - PlaceholderVirtualBaseTable table) { - DataType vbptr = null; - for (int index = 1; index < table.getMaxOffset(); index++) { - PlaceholderVirtualBaseTableEntry entry = table.getEntryByIndexInTable(index); - vbptr = entry.getVirtualBaseClass().getVbptr(); - if (vbptr != null) { // take first type... assuming all are the same - break; - } - } - if (vbptr == null) { - vbptr = vxtManager.getDefaultVbtPtr(); - } - return vbptr; - } - - private record CppParentageAndMember(List parentage, Member member) {} - - private boolean addOrUpdateVbtAndVbtptrMember(VxtManager vxtManager, - PlaceholderVirtualBaseTable table, DataType vbptr, int vbtptrOffset, String myClass) - throws PdbException { - - // TODO: if we want to match vbtables with the pointers in *virtual* base classes, we are - // not currently doing the work... we are only looking for direct bases, as they are - // what dictate the placement for our current class (though cross-checks could be done - // with all vbtables (at some point)) - - List parentage = new ArrayList<>(); - - CppParentageAndMember cAndP = findDirectBaseParentageAndMember(this, 0, vbtptrOffset); - - if (cAndP == null) { - insertMember(ClassUtils.VBPTR, ClassUtils.VXPTR_TYPE, false, vbtptrOffset, null); - } - else if (!ClassUtils.VBPTR.equals(cAndP.member().getName())) { - String message = "PDB: Collision of non-" + ClassUtils.VBPTR; - PdbLog.message(message); - Msg.info(this, message); - return false; - } - else { - parentage = cAndP.parentage(); - } - if (!(vxtManager instanceof MsftVxtManager mvxtManager)) { - return false; - } - int entrySize = 4; // Default to something (could be wrong) - if (vbptr instanceof Pointer ptr) { - entrySize = ptr.getDataType().getLength(); - } - return findVbt(table, mvxtManager, entrySize, symbolPath, parentage); - } - - private boolean findVbt(PlaceholderVirtualBaseTable table, MsftVxtManager mvbtm, int entrySize, - SymbolPath ownerSp, List parentage) { - - ClassID mId = new ProgramClassID(baseCategoryPath, ownerSp); - List cIdParentage = new ArrayList<>(); - for (CppCompositeType t : parentage) { - ClassID id = new ProgramClassID(t.baseCategoryPath, t.getSymbolPath()); - cIdParentage.add(id); - } - ProgramVirtualBaseTable vbt = (ProgramVirtualBaseTable) mvbtm.findVbt(mId, cIdParentage); - - table.setVirtualBaseTable(vbt); - - return vbt != null; - } - - private CppParentageAndMember findDirectBaseParentageAndMember(CppCompositeType cppType, - int offsetCppType, int offset) throws PdbException { - for (LayoutBaseClass base : cppType.layoutBaseClasses) { - if (!(base instanceof DirectLayoutBaseClass)) { - continue; - } - DirectLayoutBaseClass directBase = (DirectLayoutBaseClass) base; - int directBaseOffset = directBase.getOffset() + offsetCppType; - int directBaseLength = directBase.getDirectDataType().getLength(); - if (offset >= directBaseOffset && - offset < directBaseOffset + directBaseLength) { - CppCompositeType childCppType = directBase.getBaseClassType(); - CppParentageAndMember cAndP = - findDirectBaseParentageAndMember(childCppType, directBaseOffset, offset); - if (cAndP == null) { - Member member = childCppType.findLayoutMember(offset); - if (member == null) { - return null; - } - cAndP = new CppParentageAndMember(new ArrayList<>(), member); - } - List parentage = cAndP.parentage(); - parentage.add(childCppType); - return cAndP; - } - } - return null; - } - - private Member findLayoutMember(int offset) { - // the following will report the basic, such as int * - for (Member member : layoutMembers) { - if (member.getOffset() == offset) { - return member; - } - } - // the following will report the more info, such as shape1234 *, but this code will not - // hit here, as we should not have an entry for the offset if it did not find it above -// for (Member member : layoutVftPtrMembers) { -// if (member.getOffset() == offset) { -// return member; -// } -// } - return null; - } - - //---------------------------------------------------------------------------------------------- - //---------------------------------------------------------------------------------------------- -// private void addVirtualBases(int startOffset, List pdbMembers, -// List virtualBases, boolean allVbtFound, TaskMonitor monitor) -// throws PdbException, CancelledException { -// String accumulatedComment = ""; -// int memberOffset = startOffset; -// for (VirtualLayoutBaseClass virtualBase : virtualBases) { -// monitor.checkCancelled(); -// Composite baseDataType = virtualBase.getDirectDataType(); -// int virtualBaseLength = getCompositeLength(baseDataType); -// PlaceholderVirtualBaseTable pvbt = -// getPlaceholderVirtualBaseTable(virtualBase.getBasePointerOffset()); -// if (pvbt != null && pvbt.canLookupOffset()) { -// long offset = pvbt.getOffset(virtualBase.getOffetFromVbt()); -// memberOffset = (int) (offset & 0xffffffffL); -// } -// if (virtualBaseLength != 0) { -// String comment = -// "(Virtual Base " + virtualBase.getDataTypePath().getDataTypeName() + ")"; -// accumulatedComment += comment; -// ClassPdbMember virtualClassPdbMember = -// new ClassPdbMember("", baseDataType, false, memberOffset, accumulatedComment); -// pdbMembers.add(virtualClassPdbMember); -// memberOffset += virtualBaseLength; -// accumulatedComment = ""; -// } -// else { -// String comment = "((empty) Virtual Base " + -// virtualBase.getDataTypePath().getDataTypeName() + ")"; -// accumulatedComment += comment; -// } -// // If last base is empty, then its comment and any accumulated to this point -// // will not be seen (not applied to a PdbMember). TODO: Consider options, -// // though we know we have left it in this state and are OK with it for now. -// // We have not considered fall-out from this. -// } -// } - - private void addVirtualBases(int startOffset, List pdbMembers, - List virtualBases, boolean allVbtFound, TaskMonitor monitor) - throws PdbException, CancelledException { - // We accumulate the comment because if there are any empty base classes, they take - // no space and will be at the same offset as a non-empty base class - String accumulatedComment = ""; - int memberOffset = startOffset; - List orderedBases = new ArrayList<>(); - List offsets = new ArrayList<>(); - if (!orderVirtualBases(orderedBases, offsets, virtualBases, monitor)) { - addVirtualBasesSpeculatively(startOffset, pdbMembers, virtualBases, monitor); - return; - } - - for (int index = 0; index < offsets.size(); index++) { - monitor.checkCancelled(); - VirtualLayoutBaseClass virtualBase = orderedBases.get(index); - memberOffset = offsets.get(index); - Composite baseDataType = virtualBase.getDirectDataType(); - int virtualBaseLength = getCompositeLength(baseDataType); - int basePointerOffset = virtualBase.getBasePointerOffset(); -// PlaceholderVirtualBaseTable pvbt = -// getPlaceholderVirtualBaseTable(virtualBase.getBasePointerOffset()); -// if (pvbt != null && pvbt.canLookupOffset()) { -// long offset = pvbt.getOffset(virtualBase.getOffetFromVbt()); -// memberOffset = (int) (offset & 0xffffffffL); -// } - memberOffset += basePointerOffset; - if (virtualBaseLength != 0) { - String comment = VIRTUAL_BASE_COMMENT; - if (!accumulatedComment.isEmpty()) { - comment += " and previous " + accumulatedComment; - } - //accumulatedComment += "Virtual Base"; - ClassPdbMember virtualClassPdbMember = - new ClassPdbMember("", baseDataType, false, memberOffset, comment); - pdbMembers.add(virtualClassPdbMember); - memberOffset += virtualBaseLength; - accumulatedComment = ""; - } - else { - String comment = - "(Empty Virtual Base " + virtualBase.getDataTypePath().getDataTypeName() + ")"; - accumulatedComment += comment; - } - // If last base is empty, then its comment and any accumulated to this point - // will not be seen (not applied to a PdbMember). TODO: Consider options, - // though we know we have left it in this state and are OK with it for now. - // We have not considered fall-out from this. - } - } - - private boolean orderVirtualBases(List ordered, List offsets, - List unordered, TaskMonitor monitor) - throws PdbException, CancelledException { - for (VirtualLayoutBaseClass insertBase : unordered) { - monitor.checkCancelled(); - PlaceholderVirtualBaseTable pvbt = - getPlaceholderVirtualBaseTable(insertBase.getBasePointerOffset()); - if (pvbt == null || !pvbt.canLookupOffset()) { - return false; - } - long offset = pvbt.getOffset(insertBase.getOffetFromVbt()); - int memberOffset = (int) (offset & 0xffffffffL); - int index; - for (index = 0; index < offsets.size(); index++) { - int existingOffset = offsets.get(index); - if (existingOffset > memberOffset) { - break; - } - } - ordered.add(index, insertBase); - offsets.add(index, memberOffset); - } - return true; - } - - //---------------------------------------------------------------------------------------------- - //---------------------------------------------------------------------------------------------- - private void addVirtualBasesSpeculatively(int startOffset, List pdbMembers, - List virtualBases, TaskMonitor monitor) - throws CancelledException { - // We accumulate the comment because if there are any empty base classes, they take - // no space and will be at the same offset as a non-empty base class - String accumulatedComment = ""; - int memberOffset = startOffset; - for (VirtualLayoutBaseClass virtualBase : virtualBases) { - monitor.checkCancelled(); - Composite baseDataType = virtualBase.getDirectDataType(); - int virtualBaseLength = getCompositeLength(baseDataType); - - if (virtualBaseLength != 0) { - String comment = VIRTUAL_BASE_SPECULATIVE_COMMENT; - accumulatedComment += comment; - ClassPdbMember virtualClassPdbMember = - new ClassPdbMember("", baseDataType, false, memberOffset, accumulatedComment); - pdbMembers.add(virtualClassPdbMember); - memberOffset += virtualBaseLength; - accumulatedComment = ""; - } - else { - String comment = "((empty) (Speculative Placement) Virtual Base " + - virtualBase.getDataTypePath().getDataTypeName() + ")"; - accumulatedComment += comment; - } - // If last base is empty, then its comment and any accumulated to this point - // will not be seen (not applied to a PdbMember). TODO: Consider options, - // though we know we have left it in this state and are OK with it for now. - // We have not considered fall-out from this. - } - } - - //---------------------------------------------------------------------------------------------- - //---------------------------------------------------------------------------------------------- - private void addLayoutPdbMembers(List pdbMembers, List members) { - for (Member member : members) { - addPdbMember(pdbMembers, member); - } - } - - void addPdbMember(List pdbMembers, Member member) { - ClassPdbMember classPdbMember = new ClassPdbMember(member.getName(), member.getDataType(), - member.isFlexibleArray(), member.getOffset(), member.getComment()); - pdbMembers.add(classPdbMember); - } - - void insertPdbMember(List pdbMembers, Member member) { - ClassPdbMember classPdbMember = new ClassPdbMember(member.getName(), member.getDataType(), - member.isFlexibleArray(), member.getOffset(), null); - int index = 0; - for (ClassPdbMember existingMember : pdbMembers) { - if (existingMember.getOffset() > member.getOffset()) { - break; - } - index++; - } - pdbMembers.add(index, classPdbMember); - } - - private int getCompositeLength(Composite myComposite) { - if (!myComposite.isZeroLength()) { - return myComposite.getLength(); - } - return 0; - } - - private static boolean alreadyAccumulatedByName(List list, - LayoutBaseClass item) { - DataTypePath dtp = item.getDataTypePath(); - for (LayoutBaseClass iterated : list) { - if (dtp.equals(iterated.getDataTypePath())) { - return true; - } - } - return false; - } - - CategoryPath getSelfBaseCategoryName(String baseName) { - CategoryPath cn = getInternalsCategoryPath(); - return new CategoryPath(cn, baseName); - } - - // TODO: - // Taken from PdbUtil without change. Would have had to change access on class PdbUtil and - // this ensureSize method to public to make it accessible. Can revert to using PdbUtil - // once we move this new module from Contrib to Features/PDB. - final static void clearComponents(Composite composite) { - if (composite instanceof Structure) { - ((Structure) composite).deleteAll(); - } - else { - while (composite.getNumComponents() > 0) { - composite.delete(0); - } - } - } - //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- @@ -1296,14 +1799,23 @@ public class CppCompositeType { // In the future, if CppClassType is a formal DataType, then we want to be able to get // an already-formed unique class from the DTM. There is no reason to have a base // class duplicated as individually created components of DirectBaseClasses. + private Composite comp; + // Added comp above with hopes of eliminating baseClassType (CppCompositeType) in the + // future private CppCompositeType baseClassType; private ClassFieldAttributes attributes; - private BaseClass(CppCompositeType baseClassType, ClassFieldAttributes attributes) { + private BaseClass(Composite comp, CppCompositeType baseClassType, + ClassFieldAttributes attributes) { + this.comp = comp; this.baseClassType = baseClassType; this.attributes = attributes; } + Composite getBaseClassComposite() { + return comp; + } + CppCompositeType getBaseClassType() { return baseClassType; } @@ -1313,8 +1825,7 @@ public class CppCompositeType { } DataTypePath getDataTypePath() { - return new DataTypePath(baseClassType.getCategoryPath().getParent(), - baseClassType.getCategoryPath().getName()); + return baseClassType.getDataTypePath(); } @Override @@ -1325,20 +1836,9 @@ public class CppCompositeType { return builder.toString(); } - Composite getDirectDataType() { + Composite getSelfBaseDataType() { CppCompositeType cct = getBaseClassType(); - CategoryPath selfBasePath = createSelfBaseCategoryPath(cct); - DataTypeManager dtm = cct.getComposite().getDataTypeManager(); - DataType base = dtm.getDataType(selfBasePath.getParent(), selfBasePath.getName()); - if (base == null) { - // There is no self base meaning that the layout class is simple and no self - // base was needed. So return the layout class - base = cct.getComposite(); - } - if (base instanceof Structure s) { - return s; - } - throw new AssertException("Cannot find Base type"); + return ClassUtils.getSelfBaseType(comp); } } @@ -1347,34 +1847,39 @@ public class CppCompositeType { // Syntactic description of base classes. //---------------------------------------------------------------------------------------------- private class SyntacticBaseClass extends BaseClass { - private SyntacticBaseClass(CppCompositeType baseClassType, + private SyntacticBaseClass(Composite comp, CppCompositeType baseClassType, ClassFieldAttributes attributes) { - super(baseClassType, attributes); + super(comp, baseClassType, attributes); } } private class DirectSyntacticBaseClass extends SyntacticBaseClass { - private DirectSyntacticBaseClass(CppCompositeType baseClassType, + private DirectSyntacticBaseClass(Composite comp, CppCompositeType baseClassType, ClassFieldAttributes attributes) { - super(baseClassType, attributes); + super(comp, baseClassType, attributes); } } private class VirtualSyntacticBaseClass extends SyntacticBaseClass { - private VirtualSyntacticBaseClass(CppCompositeType baseClassType, + private VirtualSyntacticBaseClass(Composite comp, CppCompositeType baseClassType, ClassFieldAttributes attributes) { - super(baseClassType, attributes); + super(comp, baseClassType, attributes); } } //---------------------------------------------------------------------------------------------- // Layout description of base classes follow //---------------------------------------------------------------------------------------------- + + // NOTE: The following types are currently used and need to be evaluated for changes and + // possibly moved to their own java files + private abstract class LayoutBaseClass extends BaseClass { Structure layout = null; - LayoutBaseClass(CppCompositeType baseClassType, ClassFieldAttributes attributes) { - super(baseClassType, attributes); + LayoutBaseClass(Composite comp, CppCompositeType baseClassType, + ClassFieldAttributes attributes) { + super(comp, baseClassType, attributes); } void setLayout(Structure layout) { @@ -1392,9 +1897,9 @@ public class CppCompositeType { private class DirectLayoutBaseClass extends LayoutBaseClass { private int offset; - private DirectLayoutBaseClass(CppCompositeType baseClassType, + private DirectLayoutBaseClass(Composite comp, CppCompositeType baseClassType, ClassFieldAttributes attributes, int offset) { - super(baseClassType, attributes); + super(comp, baseClassType, attributes); this.offset = offset; } @@ -1408,9 +1913,10 @@ public class CppCompositeType { private DataType vbptr; private int offsetFromVbt; - private VirtualLayoutBaseClass(CppCompositeType baseClass, ClassFieldAttributes attributes, + private VirtualLayoutBaseClass(Composite comp, CppCompositeType baseClass, + ClassFieldAttributes attributes, int basePointerOffset, DataType vbptr, int offsetFromVbt) { - super(baseClass, attributes); + super(comp, baseClass, attributes); this.basePointerOffset = basePointerOffset; this.vbptr = vbptr; this.offsetFromVbt = offsetFromVbt; @@ -1430,10 +1936,10 @@ public class CppCompositeType { } private class DirectVirtualLayoutBaseClass extends VirtualLayoutBaseClass { - private DirectVirtualLayoutBaseClass(CppCompositeType baseClass, + private DirectVirtualLayoutBaseClass(Composite comp, CppCompositeType baseClass, ClassFieldAttributes attributes, int basePointerOffset, DataType vbptr, int offsetFromVbt) { - super(baseClass, attributes, basePointerOffset, vbptr, offsetFromVbt); + super(comp, baseClass, attributes, basePointerOffset, vbptr, offsetFromVbt); } @Override @@ -1449,10 +1955,10 @@ public class CppCompositeType { } private class IndirectVirtualLayoutBaseClass extends VirtualLayoutBaseClass { - private IndirectVirtualLayoutBaseClass(CppCompositeType baseClass, + private IndirectVirtualLayoutBaseClass(Composite comp, CppCompositeType baseClass, ClassFieldAttributes attributes, int basePointerOffset, DataType vbptr, int offsetFromVbt) { - super(baseClass, attributes, basePointerOffset, vbptr, offsetFromVbt); + super(comp, baseClass, attributes, basePointerOffset, vbptr, offsetFromVbt); } @Override @@ -1601,111 +2107,5 @@ public class CppCompositeType { } //---------------------------------------------------------------------------------------------- - //---------------------------------------------------------------------------------------------- - //---------------------------------------------------------------------------------------------- - static class PlaceholderVirtualBaseTableEntry { - VirtualLayoutBaseClass virtualBaseClass; - int offsetInClass; - - PlaceholderVirtualBaseTableEntry(VirtualLayoutBaseClass virtualBaseClass) { - this.virtualBaseClass = virtualBaseClass; - } - - void setOffsetInClass(int offsetInClass) { - this.offsetInClass = offsetInClass; - } - - int getOffsetInClass() { - return offsetInClass; - } - - String getName() { - return virtualBaseClass.getBaseClassType().getName(); - } - - VirtualLayoutBaseClass getVirtualBaseClass() { - return virtualBaseClass; - } - } - - //---------------------------------------------------------------------------------------------- - static class PlaceholderVirtualBaseTable { - private String name; - private ProgramVirtualBaseTable vbt = null; - - // We do not know if every index will be given. We can check after the fact, and once - // the set of sequential integers is assured, we could create a list. - private Map entriesByIndex; - - PlaceholderVirtualBaseTable() { - this(""); - } - - PlaceholderVirtualBaseTable(String name) { - this.name = name; - entriesByIndex = new HashMap<>(); - } - - String getName() { - return name; - } - - void setName(String name) { - this.name = name; - } - - void setVirtualBaseTable(ProgramVirtualBaseTable vbt) { - this.vbt = vbt; - } - - boolean canLookupOffset() { - return vbt != null; - } - - long getOffset(int ordinal) throws PdbException { - if (vbt != null) { - return vbt.getBaseOffset(ordinal); - } - throw new PdbException("pdbVirtualBaseTable not initialized"); - } - - Map getEntries() { - return entriesByIndex; - } - - int getMaxOffset() { - return entriesByIndex.size() + 1; - } - - // TODO: maybe this should be called validateTableIndicies() - boolean validateOffset() { - int num = entriesByIndex.size() + 1; // assuming 0, plus 1-N) - for (int index : entriesByIndex.keySet()) { - if (index > num || index < 0) { - return false; - } - } - return true; - } - - void addEntry(int indexInTable, PlaceholderVirtualBaseTableEntry entry) { - entriesByIndex.put(indexInTable, entry); - } - - PlaceholderVirtualBaseTableEntry getEntryByIndexInTable(int indexInTable) { - return entriesByIndex.get(indexInTable); - } - - PlaceholderVirtualBaseTableEntry getEntryByName(String nameParam) { - for (Entry entry : entriesByIndex - .entrySet()) { - if (nameParam.equals( - entry.getValue().getVirtualBaseClass().getBaseClassType().getName())) { - return entry.getValue(); - } - } - return null; - } - } } 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 131d876982..8936f3b569 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 @@ -220,6 +220,7 @@ public class DefaultPdbApplicator implements PdbApplicator { // a second PDB analyzer to do the "deferred" processing of functions. Then a mandatory // second PDB analyzer would, at a minimum, remove the map from the analysis state. private Map dataTypeByMsTypeNum; + private Set filledInStructure; private Map classTypeByMsTypeNum; private ComplexTypeMapper complexTypeMapper; /** @@ -267,7 +268,7 @@ public class DefaultPdbApplicator implements PdbApplicator { Objects.requireNonNull(pdb, "pdb cannot be null"); this.pdb = pdb; - this.monitor = (monitor != null) ? monitor : TaskMonitor.DUMMY; + this.monitor = TaskMonitor.dummyIfNull(monitor); // FIXME: should not support use of DataTypeManager-only since it will not have the correct // data organization if it corresponds to a data type archive. Need to evaluate archive @@ -592,6 +593,10 @@ public class DefaultPdbApplicator implements PdbApplicator { multiphaseResolver = new MultiphaseDataTypeResolver(this); + // Following should not need to be part of analysis state because types are filled in + // during first round of processing + filledInStructure = new HashSet<>(); + classTypeManager = new ClassTypeManager(dataTypeManager); pdbPrimitiveTypeApplicator = new PdbPrimitiveTypeApplicator(dataTypeManager); @@ -1054,6 +1059,17 @@ public class DefaultPdbApplicator implements PdbApplicator { dataTypeByMsTypeNum.put(mappedNumber, dataType); } + /** + * Stores whether the structure referenced by the record number has been filled in such that + * it can be used as a base class + * @param recordNumber record number of type record + * @param dataType the data type to store + */ + void markFilledInForBase(RecordNumber recordNumber) { + RecordNumber mappedNumber = getMappedRecordNumber(recordNumber); + filledInStructure.add(mappedNumber); + } + /** * 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 @@ -1097,6 +1113,26 @@ public class DefaultPdbApplicator implements PdbApplicator { return null; } + /** + * Returns the Ghidra data type associated with the PDB record number for the base class + * of another class. In this case, we require the base class structure to be completed + * in order for the child class to be constructed + * 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 PDB type record number + * @return the Ghidra DB data type of the base class + */ + DataType getBaseClassDataTypeOrSchedule(RecordNumber recordNumber) { + RecordNumber mappedNumber = getMappedRecordNumber(recordNumber); + boolean filledIn = filledInStructure.contains(mappedNumber); + DataType dt = dataTypeByMsTypeNum.get(mappedNumber); + if (dt != null && filledIn) { + return dt; + } + multiphaseResolver.scheduleTodo(mappedNumber); + return null; + } + //============================================================================================== /** * Stores the Ghidra class type associated with the PDB data type. diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java index 355af05408..f04e7fef1d 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java @@ -1064,7 +1064,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { static CppCompositeType createD_struct32(VxtManager vxtManager, CppCompositeType C_struct) { try { CppCompositeType D_struct = createStruct32("D", 8); - D_struct.addDirectBaseClass(C_struct, 0); + D_struct.addDirectBaseClass(C_struct.getComposite(), C_struct, 0); D_struct.addMember("d1", u4, false, 4); return D_struct; } @@ -1078,7 +1078,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { static CppCompositeType createD_struct64(VxtManager vxtManager, CppCompositeType C_struct) { try { CppCompositeType D_struct = createStruct64("D", 8); - D_struct.addDirectBaseClass(C_struct, 0); + D_struct.addDirectBaseClass(C_struct.getComposite(), C_struct, 0); D_struct.addMember("d1", u4, false, 4); return D_struct; } @@ -1279,8 +1279,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType E_struct) { try { CppCompositeType F_struct = createStruct32("F", 12); - F_struct.addDirectBaseClass(C_struct, 0); - F_struct.addDirectBaseClass(E_struct, 4); + F_struct.addDirectBaseClass(C_struct.getComposite(), C_struct, 0); + F_struct.addDirectBaseClass(E_struct.getComposite(), E_struct, 4); F_struct.addMember("f1", u4, false, 8); return F_struct; } @@ -1295,8 +1295,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType E_struct) { try { CppCompositeType F_struct = createStruct64("F", 12); - F_struct.addDirectBaseClass(C_struct, 0); - F_struct.addDirectBaseClass(E_struct, 4); + F_struct.addDirectBaseClass(C_struct.getComposite(), C_struct, 0); + F_struct.addDirectBaseClass(E_struct.getComposite(), E_struct, 4); F_struct.addMember("f1", u4, false, 8); return F_struct; } @@ -1427,7 +1427,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { if (C_struct == null) { C_struct = createC_struct32(vxtManager); } - G_struct.addVirtualSyntacticBaseClass(C_struct); + G_struct.addVirtualSyntacticBaseClass(C_struct.getComposite(), C_struct); G_struct.addMember("g1", u4, false, 0); } catch (Exception e) { @@ -1447,7 +1447,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { static CppCompositeType createG_struct32(VxtManager vxtManager, CppCompositeType C_struct) { try { CppCompositeType G_struct = createStruct32("G", 12); - G_struct.addDirectVirtualBaseClass(C_struct, 0, vbtptr32, 1); + G_struct.addDirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, 1); G_struct.addMember("g1", u4, false, 4); return G_struct; } @@ -1461,7 +1461,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { static CppCompositeType createG_struct64(VxtManager vxtManager, CppCompositeType C_struct) { try { CppCompositeType G_struct = createStruct64("G", 20); - G_struct.addDirectVirtualBaseClass(C_struct, 0, vbtptr64, 1); + G_struct.addDirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr64, 1); G_struct.addMember("g1", u4, false, 8); return G_struct; } @@ -1601,7 +1601,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { if (C_struct == null) { C_struct = createC_struct32(vxtManager); } - H_struct.addVirtualSyntacticBaseClass(C_struct); + H_struct.addVirtualSyntacticBaseClass(C_struct.getComposite(), C_struct); H_struct.addMember("h1", u4, false, 0); } catch (Exception e) { @@ -1621,7 +1621,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { static CppCompositeType createH_struct32(VxtManager vxtManager, CppCompositeType C_struct) { try { CppCompositeType H_struct = createStruct32("H", 12); - H_struct.addDirectVirtualBaseClass(C_struct, 0, vbtptr32, 1); + H_struct.addDirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, 1); H_struct.addMember("h1", u4, false, 4); return H_struct; } @@ -1635,7 +1635,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { static CppCompositeType createH_struct64(VxtManager vxtManager, CppCompositeType C_struct) { try { CppCompositeType H_struct = createStruct64("H", 20); - H_struct.addDirectVirtualBaseClass(C_struct, 0, vbtptr64, 1); + H_struct.addDirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr64, 1); H_struct.addMember("h1", u4, false, 8); return H_struct; } @@ -1778,8 +1778,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { if (E_struct == null) { E_struct = createE_struct32(vxtManager); } - G1_struct.addVirtualSyntacticBaseClass(C_struct); - G1_struct.addVirtualSyntacticBaseClass(E_struct); + G1_struct.addVirtualSyntacticBaseClass(C_struct.getComposite(), C_struct); + G1_struct.addVirtualSyntacticBaseClass(E_struct.getComposite(), E_struct); G1_struct.addMember("g11", u4, false, 0); } catch (Exception e) { @@ -1800,8 +1800,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType E_struct) { try { CppCompositeType G1_struct = createStruct32("G1", 16); - G1_struct.addDirectVirtualBaseClass(C_struct, 0, vbtptr32, 1); - G1_struct.addDirectVirtualBaseClass(E_struct, 0, vbtptr32, 2); + G1_struct.addDirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, 1); + G1_struct.addDirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr32, 2); G1_struct.addMember("g11", u4, false, 4); return G1_struct; } @@ -1816,8 +1816,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType E_struct) { try { CppCompositeType G1_struct = createStruct64("G1", 24); - G1_struct.addDirectVirtualBaseClass(C_struct, 0, vbtptr64, 1); - G1_struct.addDirectVirtualBaseClass(E_struct, 0, vbtptr64, 2); + G1_struct.addDirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr64, 1); + G1_struct.addDirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr64, 2); G1_struct.addMember("g11", u4, false, 8); return G1_struct; } @@ -1984,8 +1984,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { if (C_struct == null) { C_struct = createC_struct32(vxtManager); } - H1_struct.addVirtualSyntacticBaseClass(E_struct); - H1_struct.addVirtualSyntacticBaseClass(C_struct); + H1_struct.addVirtualSyntacticBaseClass(E_struct.getComposite(), E_struct); + H1_struct.addVirtualSyntacticBaseClass(C_struct.getComposite(), C_struct); H1_struct.addMember("h11", u4, false, 0); } catch (Exception e) { @@ -2006,8 +2006,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType C_struct) { try { CppCompositeType H1_struct = createStruct32("H1", 16); - H1_struct.addDirectVirtualBaseClass(E_struct, 0, vbtptr32, 1); - H1_struct.addDirectVirtualBaseClass(C_struct, 0, vbtptr32, 2); + H1_struct.addDirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr32, 1); + H1_struct.addDirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, 2); H1_struct.addMember("h11", u4, false, 4); return H1_struct; } @@ -2022,8 +2022,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType C_struct) { try { CppCompositeType H1_struct = createStruct64("H1", 24); - H1_struct.addDirectVirtualBaseClass(E_struct, 0, vbtptr64, 1); - H1_struct.addDirectVirtualBaseClass(C_struct, 0, vbtptr64, 2); + H1_struct.addDirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr64, 1); + H1_struct.addDirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr64, 2); H1_struct.addMember("h11", u4, false, 8); return H1_struct; } @@ -2187,7 +2187,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { if (CC1_struct == null) { CC1_struct = createCC1_struct32(vxtManager); } - GG1_struct.addVirtualSyntacticBaseClass(CC1_struct); + GG1_struct.addVirtualSyntacticBaseClass(CC1_struct.getComposite(), CC1_struct); GG1_struct.addMember("gg11", u4, false, 0); } catch (Exception e) { @@ -2207,7 +2207,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { static CppCompositeType createGG1_struct32(VxtManager vxtManager, CppCompositeType CC1_struct) { try { CppCompositeType GG1_struct = createStruct32("GG1", 12); - GG1_struct.addDirectVirtualBaseClass(CC1_struct, 0, vbtptr32, 1); + GG1_struct.addDirectVirtualBaseClass(CC1_struct.getComposite(), CC1_struct, 0, vbtptr32, + 1); GG1_struct.addMember("gg11", u4, false, 4); return GG1_struct; } @@ -2221,7 +2222,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { static CppCompositeType createGG1_struct64(VxtManager vxtManager, CppCompositeType CC1_struct) { try { CppCompositeType GG1_struct = createStruct64("GG1", 20); - GG1_struct.addDirectVirtualBaseClass(CC1_struct, 0, vbtptr64, 1); + GG1_struct.addDirectVirtualBaseClass(CC1_struct.getComposite(), CC1_struct, 0, vbtptr64, + 1); GG1_struct.addMember("gg11", u4, false, 8); return GG1_struct; } @@ -2361,7 +2363,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { if (CC2_struct == null) { CC2_struct = createCC2_struct32(vxtManager); } - GG2_struct.addVirtualSyntacticBaseClass(CC2_struct); + GG2_struct.addVirtualSyntacticBaseClass(CC2_struct.getComposite(), CC2_struct); GG2_struct.addMember("gg21", u4, false, 0); } catch (Exception e) { @@ -2381,7 +2383,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { static CppCompositeType createGG2_struct32(VxtManager vxtManager, CppCompositeType CC2_struct) { try { CppCompositeType GG2_struct = createStruct32("GG2", 12); - GG2_struct.addDirectVirtualBaseClass(CC2_struct, 0, vbtptr32, 1); + GG2_struct.addDirectVirtualBaseClass(CC2_struct.getComposite(), CC2_struct, 0, vbtptr32, + 1); GG2_struct.addMember("gg21", u4, false, 4); return GG2_struct; } @@ -2395,7 +2398,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { static CppCompositeType createGG2_struct64(VxtManager vxtManager, CppCompositeType CC2_struct) { try { CppCompositeType GG2_struct = createStruct64("GG2", 20); - GG2_struct.addDirectVirtualBaseClass(CC2_struct, 0, vbtptr64, 1); + GG2_struct.addDirectVirtualBaseClass(CC2_struct.getComposite(), CC2_struct, 0, vbtptr64, + 1); GG2_struct.addMember("gg21", u4, false, 8); return GG2_struct; } @@ -2535,7 +2539,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { if (CC2_struct == null) { CC2_struct = createCC2_struct32(vxtManager); } - GG3_struct.addVirtualSyntacticBaseClass(CC2_struct); + GG3_struct.addVirtualSyntacticBaseClass(CC2_struct.getComposite(), CC2_struct); GG3_struct.addMember("gg31", u4, false, 0); } catch (Exception e) { @@ -2555,7 +2559,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { static CppCompositeType createGG3_struct32(VxtManager vxtManager, CppCompositeType CC2_struct) { try { CppCompositeType GG3_struct = createStruct32("GG3", 12); - GG3_struct.addDirectVirtualBaseClass(CC2_struct, 0, vbtptr32, 1); + GG3_struct.addDirectVirtualBaseClass(CC2_struct.getComposite(), CC2_struct, 0, vbtptr32, + 1); GG3_struct.addMember("gg31", u4, false, 4); return GG3_struct; } @@ -2569,7 +2574,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { static CppCompositeType createGG3_struct64(VxtManager vxtManager, CppCompositeType CC2_struct) { try { CppCompositeType GG3_struct = createStruct64("GG3", 20); - GG3_struct.addDirectVirtualBaseClass(CC2_struct, 0, vbtptr64, 1); + GG3_struct.addDirectVirtualBaseClass(CC2_struct.getComposite(), CC2_struct, 0, vbtptr64, + 1); GG3_struct.addMember("gg31", u4, false, 8); return GG3_struct; } @@ -2707,7 +2713,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { static CppCompositeType createGG4_struct32(VxtManager vxtManager, CppCompositeType CC3_struct) { try { CppCompositeType GG4_struct = createStruct32("GG4", 8); - GG4_struct.addDirectVirtualBaseClass(CC3_struct, 0, vbtptr32, 1); + GG4_struct.addDirectVirtualBaseClass(CC3_struct.getComposite(), CC3_struct, 0, vbtptr32, + 1); GG4_struct.addMember("gg41", u4, false, 4); return GG4_struct; } @@ -2721,7 +2728,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { static CppCompositeType createGG4_struct64(VxtManager vxtManager, CppCompositeType CC3_struct) { try { CppCompositeType GG4_struct = createStruct64("GG4", 16); - GG4_struct.addDirectVirtualBaseClass(CC3_struct, 0, vbtptr64, 1); + GG4_struct.addDirectVirtualBaseClass(CC3_struct.getComposite(), CC3_struct, 0, vbtptr64, + 1); GG4_struct.addMember("gg41", u4, false, 8); return GG4_struct; } @@ -2860,8 +2868,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { if (H_struct == null) { H_struct = createH_struct32(vxtManager, C_struct); } - I_struct.addDirectSyntacticBaseClass(G_struct); - I_struct.addDirectSyntacticBaseClass(H_struct); + I_struct.addDirectSyntacticBaseClass(G_struct.getComposite(), G_struct); + I_struct.addDirectSyntacticBaseClass(H_struct.getComposite(), H_struct); I_struct.addMember("i1", u4, false, 0); } catch (Exception e) { @@ -2882,9 +2890,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType H_struct, CppCompositeType C_struct) { try { CppCompositeType I_struct = createStruct32("I", 24); - I_struct.addDirectBaseClass(G_struct, 0); - I_struct.addDirectBaseClass(H_struct, 8); - I_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr32, 1); + I_struct.addDirectBaseClass(G_struct.getComposite(), G_struct, 0); + I_struct.addDirectBaseClass(H_struct.getComposite(), H_struct, 8); + I_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, 1); I_struct.addMember("i1", u4, false, 16); return I_struct; } @@ -2899,9 +2907,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType H_struct, CppCompositeType C_struct) { try { CppCompositeType I_struct = createStruct64("I", 44); - I_struct.addDirectBaseClass(G_struct, 0); - I_struct.addDirectBaseClass(H_struct, 16); - I_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr64, 1); + I_struct.addDirectBaseClass(G_struct.getComposite(), G_struct, 0); + I_struct.addDirectBaseClass(H_struct.getComposite(), H_struct, 16); + I_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr64, 1); I_struct.addMember("i1", u4, false, 32); return I_struct; } @@ -3097,10 +3105,12 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType H_struct, CppCompositeType C_struct, CppCompositeType E_struct) { try { CppCompositeType I1_struct = createStruct32("I1", 28); - I1_struct.addDirectBaseClass(G1_struct, 0); - I1_struct.addDirectBaseClass(H_struct, 8); - I1_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr32, 1); - I1_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr32, 2); + I1_struct.addDirectBaseClass(G1_struct.getComposite(), G1_struct, 0); + I1_struct.addDirectBaseClass(H_struct.getComposite(), H_struct, 8); + I1_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, + 1); + I1_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr32, + 2); I1_struct.addMember("i11", u4, false, 16); return I1_struct; } @@ -3115,10 +3125,12 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType H_struct, CppCompositeType C_struct, CppCompositeType E_struct) { try { CppCompositeType I1_struct = createStruct64("I1", 48); - I1_struct.addDirectBaseClass(G1_struct, 0); - I1_struct.addDirectBaseClass(H_struct, 16); - I1_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr64, 1); - I1_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr64, 2); + I1_struct.addDirectBaseClass(G1_struct.getComposite(), G1_struct, 0); + I1_struct.addDirectBaseClass(H_struct.getComposite(), H_struct, 16); + I1_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr64, + 1); + I1_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr64, + 2); I1_struct.addMember("i11", u4, false, 32); return I1_struct; } @@ -3337,10 +3349,12 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType H1_struct, CppCompositeType C_struct, CppCompositeType E_struct) { try { CppCompositeType I2_struct = createStruct32("I2", 28); - I2_struct.addDirectBaseClass(G_struct, 0); - I2_struct.addDirectBaseClass(H1_struct, 8); - I2_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr32, 1); - I2_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr32, 2); + I2_struct.addDirectBaseClass(G_struct.getComposite(), G_struct, 0); + I2_struct.addDirectBaseClass(H1_struct.getComposite(), H1_struct, 8); + I2_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, + 1); + I2_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr32, + 2); I2_struct.addMember("i21", u4, false, 16); return I2_struct; } @@ -3355,10 +3369,12 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType H1_struct, CppCompositeType C_struct, CppCompositeType E_struct) { try { CppCompositeType I2_struct = createStruct64("I2", 48); - I2_struct.addDirectBaseClass(G_struct, 0); - I2_struct.addDirectBaseClass(H1_struct, 16); - I2_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr64, 1); - I2_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr64, 2); + I2_struct.addDirectBaseClass(G_struct.getComposite(), G_struct, 0); + I2_struct.addDirectBaseClass(H1_struct.getComposite(), H1_struct, 16); + I2_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr64, + 1); + I2_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr64, + 2); I2_struct.addMember("i21", u4, false, 32); return I2_struct; } @@ -3589,8 +3605,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { if (H1_struct == null) { H1_struct = createH1_struct32(vxtManager, E_struct, C_struct); } - I3_struct.addDirectSyntacticBaseClass(G1_struct); - I3_struct.addDirectSyntacticBaseClass(H1_struct); + I3_struct.addDirectSyntacticBaseClass(G1_struct.getComposite(), G1_struct); + I3_struct.addDirectSyntacticBaseClass(H1_struct.getComposite(), H1_struct); I3_struct.addMember("i31", u4, false, 0); } catch (Exception e) { @@ -3612,10 +3628,12 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType H1_struct, CppCompositeType E_struct, CppCompositeType C_struct) { try { CppCompositeType I3_struct = createStruct32("I3", 28); - I3_struct.addDirectBaseClass(G1_struct, 0); - I3_struct.addDirectBaseClass(H1_struct, 8); - I3_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr32, 1); - I3_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr32, 2); + I3_struct.addDirectBaseClass(G1_struct.getComposite(), G1_struct, 0); + I3_struct.addDirectBaseClass(H1_struct.getComposite(), H1_struct, 8); + I3_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, + 1); + I3_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr32, + 2); I3_struct.addMember("i31", u4, false, 16); return I3_struct; } @@ -3630,10 +3648,12 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType H1_struct, CppCompositeType E_struct, CppCompositeType C_struct) { try { CppCompositeType I3_struct = createStruct64("I3", 48); - I3_struct.addDirectBaseClass(G1_struct, 0); - I3_struct.addDirectBaseClass(H1_struct, 16); - I3_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr64, 1); - I3_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr64, 2); + I3_struct.addDirectBaseClass(G1_struct.getComposite(), G1_struct, 0); + I3_struct.addDirectBaseClass(H1_struct.getComposite(), H1_struct, 16); + I3_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr64, + 1); + I3_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr64, + 2); I3_struct.addMember("i31", u4, false, 32); return I3_struct; } @@ -3852,9 +3872,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType E_struct, CppCompositeType C_struct) { try { CppCompositeType I4_struct = createStruct32("I4", 20); - I4_struct.addDirectBaseClass(G1_struct, 0); - I4_struct.addDirectVirtualBaseClass(E_struct, 0, vbtptr32, 2); - I4_struct.addDirectVirtualBaseClass(C_struct, 0, vbtptr32, 1); + I4_struct.addDirectBaseClass(G1_struct.getComposite(), G1_struct, 0); + I4_struct.addDirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr32, 2); + I4_struct.addDirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, 1); I4_struct.addMember("i41", u4, false, 8); return I4_struct; } @@ -3869,9 +3889,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType E_struct, CppCompositeType C_struct) { CppCompositeType I4_struct = createStruct64("I4", 32); try { - I4_struct.addDirectBaseClass(G1_struct, 0); - I4_struct.addDirectVirtualBaseClass(E_struct, 0, vbtptr64, 2); - I4_struct.addDirectVirtualBaseClass(C_struct, 0, vbtptr64, 1); + I4_struct.addDirectBaseClass(G1_struct.getComposite(), G1_struct, 0); + I4_struct.addDirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr64, 2); + I4_struct.addDirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr64, 1); I4_struct.addMember("i41", u4, false, 16); } catch (Exception e) { @@ -4054,9 +4074,11 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType E_struct, CppCompositeType C_struct) { try { CppCompositeType I5_struct = createStruct32("I5", 20); - I5_struct.addDirectBaseClass(G1_struct, 0); - I5_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr32, 2); // check this and I4...TODO - I5_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr32, 1); + I5_struct.addDirectBaseClass(G1_struct.getComposite(), G1_struct, 0); + I5_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr32, + 2); // check this and I4...TODO + I5_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, + 1); I5_struct.addMember("i51", u4, false, 8); return I5_struct; } @@ -4071,9 +4093,11 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType E_struct, CppCompositeType C_struct) { try { CppCompositeType I5_struct = createStruct64("I5", 32); - I5_struct.addDirectBaseClass(G1_struct, 0); - I5_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr64, 2); // check this and I4...TODO - I5_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr64, 1); + I5_struct.addDirectBaseClass(G1_struct.getComposite(), G1_struct, 0); + I5_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr64, + 2); // check this and I4...TODO + I5_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr64, + 1); I5_struct.addMember("i51", u4, false, 16); return I5_struct; } @@ -4358,10 +4382,12 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType I2_struct, CppCompositeType E_struct, CppCompositeType C_struct) { try { CppCompositeType J1_struct = createStruct32("J1", 52); - J1_struct.addDirectBaseClass(I1_struct, 0); - J1_struct.addDirectBaseClass(I2_struct, 20); - J1_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr32, 1); - J1_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr32, 2); + J1_struct.addDirectBaseClass(I1_struct.getComposite(), I1_struct, 0); + J1_struct.addDirectBaseClass(I2_struct.getComposite(), I2_struct, 20); + J1_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, + 1); + J1_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr32, + 2); J1_struct.addMember("j11", u4, false, 40); return J1_struct; } @@ -4376,10 +4402,12 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType I2_struct, CppCompositeType E_struct, CppCompositeType C_struct) { try { CppCompositeType J1_struct = createStruct64("J1", 96); - J1_struct.addDirectBaseClass(I1_struct, 0); - J1_struct.addDirectBaseClass(I2_struct, 40); - J1_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr64, 1); - J1_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr64, 2); + J1_struct.addDirectBaseClass(I1_struct.getComposite(), I1_struct, 0); + J1_struct.addDirectBaseClass(I2_struct.getComposite(), I2_struct, 40); + J1_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr64, + 1); + J1_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr64, + 2); J1_struct.addMember("j11", u4, false, 80); return J1_struct; } @@ -4711,10 +4739,12 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType I1_struct, CppCompositeType C_struct, CppCompositeType E_struct) { try { CppCompositeType J2_struct = createStruct32("J2", 52); - J2_struct.addDirectBaseClass(I2_struct, 0); - J2_struct.addDirectBaseClass(I1_struct, 20); - J2_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr32, 1); - J2_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr32, 2); + J2_struct.addDirectBaseClass(I2_struct.getComposite(), I2_struct, 0); + J2_struct.addDirectBaseClass(I1_struct.getComposite(), I1_struct, 20); + J2_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, + 1); + J2_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr32, + 2); J2_struct.addMember("j21", u4, false, 40); return J2_struct; } @@ -4729,10 +4759,12 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType I1_struct, CppCompositeType C_struct, CppCompositeType E_struct) { try { CppCompositeType J2_struct = createStruct64("J2", 96); - J2_struct.addDirectBaseClass(I2_struct, 0); - J2_struct.addDirectBaseClass(I1_struct, 40); - J2_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr64, 1); - J2_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr64, 2); + J2_struct.addDirectBaseClass(I2_struct.getComposite(), I2_struct, 0); + J2_struct.addDirectBaseClass(I1_struct.getComposite(), I1_struct, 40); + J2_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr64, + 1); + J2_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr64, + 2); J2_struct.addMember("j21", u4, false, 80); return J2_struct; } @@ -5066,11 +5098,13 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType E_struct) { try { CppCompositeType J3_struct = createStruct32("J3", 60); - J3_struct.addDirectBaseClass(I2_struct, 0); - J3_struct.addDirectBaseClass(I1_struct, 20); - J3_struct.addDirectBaseClass(A_struct, 40); - J3_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr32, 1); - J3_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr32, 2); + J3_struct.addDirectBaseClass(I2_struct.getComposite(), I2_struct, 0); + J3_struct.addDirectBaseClass(I1_struct.getComposite(), I1_struct, 20); + J3_struct.addDirectBaseClass(A_struct.getComposite(), A_struct, 40); + J3_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, + 1); + J3_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr32, + 2); J3_struct.addMember("j31", u4, false, 48); return J3_struct; } @@ -5086,11 +5120,13 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType E_struct) { try { CppCompositeType J3_struct = createStruct64("J3", 104); - J3_struct.addDirectBaseClass(I2_struct, 0); - J3_struct.addDirectBaseClass(I1_struct, 40); - J3_struct.addDirectBaseClass(A_struct, 80); - J3_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr64, 1); - J3_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr64, 2); + J3_struct.addDirectBaseClass(I2_struct.getComposite(), I2_struct, 0); + J3_struct.addDirectBaseClass(I1_struct.getComposite(), I1_struct, 40); + J3_struct.addDirectBaseClass(A_struct.getComposite(), A_struct, 80); + J3_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr64, + 1); + J3_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr64, + 2); J3_struct.addMember("j31", u4, false, 88); return J3_struct; } @@ -5455,16 +5491,22 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType E_struct, CppCompositeType CC1_struct, CppCompositeType CC2_struct) { try { CppCompositeType J4_struct = createStruct32("J4", 92); - J4_struct.addDirectBaseClass(I3_struct, 0); - J4_struct.addDirectBaseClass(GG1_struct, 20); - J4_struct.addDirectBaseClass(I_struct, 28); - J4_struct.addDirectBaseClass(A_struct, 48); - J4_struct.addDirectVirtualBaseClass(GG2_struct, 0, vbtptr32, 5); - J4_struct.addDirectVirtualBaseClass(GG3_struct, 0, vbtptr32, 6); - J4_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr32, 1); - J4_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr32, 2); - J4_struct.addIndirectVirtualBaseClass(CC1_struct, 0, vbtptr32, 3); - J4_struct.addIndirectVirtualBaseClass(CC2_struct, 0, vbtptr32, 4); + J4_struct.addDirectBaseClass(I3_struct.getComposite(), I3_struct, 0); + J4_struct.addDirectBaseClass(GG1_struct.getComposite(), GG1_struct, 20); + J4_struct.addDirectBaseClass(I_struct.getComposite(), I_struct, 28); + J4_struct.addDirectBaseClass(A_struct.getComposite(), A_struct, 48); + J4_struct.addDirectVirtualBaseClass(GG2_struct.getComposite(), GG2_struct, 0, vbtptr32, + 5); + J4_struct.addDirectVirtualBaseClass(GG3_struct.getComposite(), GG3_struct, 0, vbtptr32, + 6); + J4_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, + 1); + J4_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr32, + 2); + J4_struct.addIndirectVirtualBaseClass(CC1_struct.getComposite(), CC1_struct, 0, + vbtptr32, 3); + J4_struct.addIndirectVirtualBaseClass(CC2_struct.getComposite(), CC2_struct, 0, + vbtptr32, 4); J4_struct.addMember("j41", u4, false, 56); return J4_struct; } @@ -5481,16 +5523,22 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType E_struct, CppCompositeType CC1_struct, CppCompositeType CC2_struct) { try { CppCompositeType J4_struct = createStruct64("J4", 160); - J4_struct.addDirectBaseClass(I3_struct, 0); - J4_struct.addDirectBaseClass(GG1_struct, 40); - J4_struct.addDirectBaseClass(I_struct, 56); - J4_struct.addDirectBaseClass(A_struct, 96); - J4_struct.addDirectVirtualBaseClass(GG2_struct, 0, vbtptr64, 5); - J4_struct.addDirectVirtualBaseClass(GG3_struct, 0, vbtptr64, 6); - J4_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr64, 1); - J4_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr64, 2); - J4_struct.addIndirectVirtualBaseClass(CC1_struct, 0, vbtptr64, 3); - J4_struct.addIndirectVirtualBaseClass(CC2_struct, 0, vbtptr64, 4); + J4_struct.addDirectBaseClass(I3_struct.getComposite(), I3_struct, 0); + J4_struct.addDirectBaseClass(GG1_struct.getComposite(), GG1_struct, 40); + J4_struct.addDirectBaseClass(I_struct.getComposite(), I_struct, 56); + J4_struct.addDirectBaseClass(A_struct.getComposite(), A_struct, 96); + J4_struct.addDirectVirtualBaseClass(GG2_struct.getComposite(), GG2_struct, 0, vbtptr64, + 5); + J4_struct.addDirectVirtualBaseClass(GG3_struct.getComposite(), GG3_struct, 0, vbtptr64, + 6); + J4_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr64, + 1); + J4_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr64, + 2); + J4_struct.addIndirectVirtualBaseClass(CC1_struct.getComposite(), CC1_struct, 0, + vbtptr64, 3); + J4_struct.addIndirectVirtualBaseClass(CC2_struct.getComposite(), CC2_struct, 0, + vbtptr64, 4); J4_struct.addMember("j41", u4, false, 104); return J4_struct; } @@ -6043,12 +6091,12 @@ public class CppCompositeTypeTest extends AbstractGenericTest { if (GG3_struct == null) { GG3_struct = createGG3_syntactic_struct32(vxtManager, CC2_struct); } - J5_struct.addVirtualSyntacticBaseClass(GG2_struct); - J5_struct.addVirtualSyntacticBaseClass(GG3_struct); - J5_struct.addDirectSyntacticBaseClass(I3_struct); - J5_struct.addDirectSyntacticBaseClass(GG1_struct); - J5_struct.addDirectSyntacticBaseClass(I_struct); - J5_struct.addDirectSyntacticBaseClass(A_struct); + J5_struct.addVirtualSyntacticBaseClass(GG2_struct.getComposite(), GG2_struct); + J5_struct.addVirtualSyntacticBaseClass(GG3_struct.getComposite(), GG3_struct); + J5_struct.addDirectSyntacticBaseClass(I3_struct.getComposite(), I3_struct); + J5_struct.addDirectSyntacticBaseClass(GG1_struct.getComposite(), GG1_struct); + J5_struct.addDirectSyntacticBaseClass(I_struct.getComposite(), I_struct); + J5_struct.addDirectSyntacticBaseClass(A_struct.getComposite(), A_struct); J5_struct.addMember("j51", u4, false, 0); // TODO nned syntactic without index } catch (Exception e) { @@ -6077,16 +6125,22 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType E_struct, CppCompositeType CC1_struct, CppCompositeType CC2_struct) { try { CppCompositeType J5_struct = createStruct32("J5", 92); - J5_struct.addDirectBaseClass(I3_struct, 0); - J5_struct.addDirectBaseClass(GG1_struct, 20); - J5_struct.addDirectBaseClass(I_struct, 28); - J5_struct.addDirectBaseClass(A_struct, 48); - J5_struct.addDirectVirtualBaseClass(GG2_struct, 0, vbtptr32, 4); - J5_struct.addDirectVirtualBaseClass(GG3_struct, 0, vbtptr32, 5); - J5_struct.addIndirectVirtualBaseClass(CC2_struct, 0, vbtptr32, 3); - J5_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr32, 1); - J5_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr32, 2); - J5_struct.addIndirectVirtualBaseClass(CC1_struct, 0, vbtptr32, 6); + J5_struct.addDirectBaseClass(I3_struct.getComposite(), I3_struct, 0); + J5_struct.addDirectBaseClass(GG1_struct.getComposite(), GG1_struct, 20); + J5_struct.addDirectBaseClass(I_struct.getComposite(), I_struct, 28); + J5_struct.addDirectBaseClass(A_struct.getComposite(), A_struct, 48); + J5_struct.addDirectVirtualBaseClass(GG2_struct.getComposite(), GG2_struct, 0, vbtptr32, + 4); + J5_struct.addDirectVirtualBaseClass(GG3_struct.getComposite(), GG3_struct, 0, vbtptr32, + 5); + J5_struct.addIndirectVirtualBaseClass(CC2_struct.getComposite(), CC2_struct, 0, + vbtptr32, 3); + J5_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, + 1); + J5_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr32, + 2); + J5_struct.addIndirectVirtualBaseClass(CC1_struct.getComposite(), CC1_struct, 0, + vbtptr32, 6); J5_struct.addMember("j51", u4, false, 56); return J5_struct; } @@ -6103,16 +6157,22 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType E_struct, CppCompositeType CC1_struct, CppCompositeType CC2_struct) { try { CppCompositeType J5_struct = createStruct64("J5", 164); - J5_struct.addDirectBaseClass(I3_struct, 0); - J5_struct.addDirectBaseClass(GG1_struct, 40); - J5_struct.addDirectBaseClass(I_struct, 56); - J5_struct.addDirectBaseClass(A_struct, 96); - J5_struct.addDirectVirtualBaseClass(GG2_struct, 0, vbtptr32, 4); - J5_struct.addDirectVirtualBaseClass(GG3_struct, 0, vbtptr32, 5); - J5_struct.addIndirectVirtualBaseClass(CC2_struct, 0, vbtptr32, 3); - J5_struct.addIndirectVirtualBaseClass(C_struct, 0, vbtptr32, 1); - J5_struct.addIndirectVirtualBaseClass(E_struct, 0, vbtptr32, 2); - J5_struct.addIndirectVirtualBaseClass(CC1_struct, 0, vbtptr32, 6); + J5_struct.addDirectBaseClass(I3_struct.getComposite(), I3_struct, 0); + J5_struct.addDirectBaseClass(GG1_struct.getComposite(), GG1_struct, 40); + J5_struct.addDirectBaseClass(I_struct.getComposite(), I_struct, 56); + J5_struct.addDirectBaseClass(A_struct.getComposite(), A_struct, 96); + J5_struct.addDirectVirtualBaseClass(GG2_struct.getComposite(), GG2_struct, 0, vbtptr32, + 4); + J5_struct.addDirectVirtualBaseClass(GG3_struct.getComposite(), GG3_struct, 0, vbtptr32, + 5); + J5_struct.addIndirectVirtualBaseClass(CC2_struct.getComposite(), CC2_struct, 0, + vbtptr32, 3); + J5_struct.addIndirectVirtualBaseClass(C_struct.getComposite(), C_struct, 0, vbtptr32, + 1); + J5_struct.addIndirectVirtualBaseClass(E_struct.getComposite(), E_struct, 0, vbtptr32, + 2); + J5_struct.addIndirectVirtualBaseClass(CC1_struct.getComposite(), CC1_struct, 0, + vbtptr32, 6); J5_struct.addMember("j51", u4, false, 104); return J5_struct; } @@ -6645,11 +6705,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType CC3_struct) { try { CppCompositeType J6_struct = createStruct32("J6", 36); - J6_struct.addDirectBaseClass(A_struct, 0); - J6_struct.addDirectVirtualBaseClass(GG4_struct, 8, vbtptr32, 2); - J6_struct.addDirectVirtualBaseClass(GG3_struct, 8, vbtptr32, 4); - J6_struct.addIndirectVirtualBaseClass(CC3_struct, 8, vbtptr32, 1); - J6_struct.addIndirectVirtualBaseClass(CC2_struct, 8, vbtptr32, 3); + J6_struct.addDirectBaseClass(A_struct.getComposite(), A_struct, 0); + J6_struct.addDirectVirtualBaseClass(GG4_struct.getComposite(), GG4_struct, 8, vbtptr32, + 2); + J6_struct.addDirectVirtualBaseClass(GG3_struct.getComposite(), GG3_struct, 8, vbtptr32, + 4); + J6_struct.addIndirectVirtualBaseClass(CC3_struct.getComposite(), CC3_struct, 8, + vbtptr32, 1); + J6_struct.addIndirectVirtualBaseClass(CC2_struct.getComposite(), CC2_struct, 8, + vbtptr32, 3); J6_struct.addMember("j61", u4, false, 12); return J6_struct; } @@ -6665,11 +6729,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { CppCompositeType CC3_struct) { try { CppCompositeType J6_struct = createStruct64("J6", 64); - J6_struct.addDirectBaseClass(A_struct, 0); - J6_struct.addDirectVirtualBaseClass(GG4_struct, 8, vbtptr64, 2); - J6_struct.addDirectVirtualBaseClass(GG3_struct, 8, vbtptr64, 4); - J6_struct.addIndirectVirtualBaseClass(CC3_struct, 8, vbtptr64, 1); - J6_struct.addIndirectVirtualBaseClass(CC2_struct, 8, vbtptr64, 3); + J6_struct.addDirectBaseClass(A_struct.getComposite(), A_struct, 0); + J6_struct.addDirectVirtualBaseClass(GG4_struct.getComposite(), GG4_struct, 8, vbtptr64, + 2); + J6_struct.addDirectVirtualBaseClass(GG3_struct.getComposite(), GG3_struct, 8, vbtptr64, + 4); + J6_struct.addIndirectVirtualBaseClass(CC3_struct.getComposite(), CC3_struct, 8, + vbtptr64, 1); + J6_struct.addIndirectVirtualBaseClass(CC2_struct.getComposite(), CC2_struct, 8, + vbtptr64, 3); J6_struct.addMember("j61", u4, false, 16); return J6_struct; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/gclass/ClassUtils.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/gclass/ClassUtils.java new file mode 100644 index 0000000000..af95c80ec5 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/gclass/ClassUtils.java @@ -0,0 +1,95 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.program.model.gclass; + +import ghidra.program.model.data.*; + +/** + * Utility class for Class-related software modeling. + */ +public class ClassUtils { + + // Prototype values for now. Need to come to agreement on what these should be. Might want + // a separate one for a generic virtual table (not "base" or "function") for gcc/Itanium + // standard + /** + * Standard field name for a virtual base table pointer found within a class + */ + public static final String VBPTR = "{vbptr}"; + + /** + * Standard field name for a virtual function table pointer found within a class + */ + public static final String VFPTR = "{vfptr}"; + + /** + * Type used for {@link #VBPTR} and {@link #VFPTR} fields in a class + */ + public static final PointerDataType VXPTR_TYPE = new PointerDataType(); + + /** + * private constructor -- no instances + */ + private ClassUtils() { + // no instances + } + + /** + * Returns the category for class internals + * @param composite the class composite + * @return the category path + */ + public static CategoryPath getClassInternalsPath(Composite composite) { + DataTypePath dtp = composite.getDataTypePath(); + return new CategoryPath(new CategoryPath(dtp.getCategoryPath(), dtp.getDataTypeName()), + "!internal"); + } + + /** + * Returns the data type path for a suitable base class + * @param composite the class composite + * @return the base class data type path + */ + public static DataTypePath getBaseClassDataTypePath(Composite composite) { + return new DataTypePath(getClassInternalsPath(composite), composite.getName()); + } + + /** + * Returns the "self-base" composite for the specified class composite. This could be + * the composite argument itself of could be a component of it + * @param composite the main class type + * @return the self-base composite + */ + public static Composite getSelfBaseType(Composite composite) { + DataTypeManager dtm = composite.getDataTypeManager(); + DataTypePath dtp = ClassUtils.getBaseClassDataTypePath(composite); + DataType dt = dtm.getDataType(dtp); + if (dt instanceof Composite base) { + return base; + } + if (composite.getNumComponents() > 0) { + DataTypeComponent component = composite.getComponent(0); + DataType componentType = component.getDataType(); + if (componentType instanceof Structure struct) { + if (struct.getDataTypePath().equals(dtp)) { + return struct; + } + } + } + return composite; + } + +}