diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java index 780fd18993..c4748c9c99 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java @@ -35,26 +35,24 @@ public class FieldListTypeApplier extends MsTypeApplier { private List methodList = new ArrayList<>(); private boolean isEmpty; - // return can be null static FieldListTypeApplier getFieldListApplierSpecial(DefaultPdbApplicator applicator, RecordNumber recordNumber) throws PdbException { MsTypeApplier applier = applicator.getApplierOrNoTypeSpec(recordNumber, FieldListTypeApplier.class); - FieldListTypeApplier fieldListApplier = null; - if (applier instanceof FieldListTypeApplier) { - return (FieldListTypeApplier) applicator.getApplierOrNoTypeSpec(recordNumber, - FieldListTypeApplier.class); + if (applier instanceof FieldListTypeApplier fieldListApplier) { + return fieldListApplier; } - try { - if (recordNumber.getCategory() == RecordCategory.TYPE) { - fieldListApplier = new FieldListTypeApplier(applicator, + // Only the NoType spec should fall through to here + if (recordNumber.getCategory() == RecordCategory.TYPE) { + try { + return new FieldListTypeApplier(applicator, applicator.getPdb().getTypeRecord(recordNumber), true); } + catch (IllegalArgumentException e) { + applicator.appendLogMsg(e.getMessage()); + } } - catch (IllegalArgumentException e) { - applicator.appendLogMsg(e.getMessage()); - } - return fieldListApplier; + throw new PdbException("Problem creating field list"); } /** @@ -105,7 +103,9 @@ public class FieldListTypeApplier extends MsTypeApplier { @Override void apply() throws PdbException, CancelledException { - dataType = applyFieldListMsType((AbstractFieldListMsType) msType); + if (!isEmpty()) { + dataType = applyFieldListMsType((AbstractFieldListMsType) msType); + } } List getBaseClassList() { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java index e4d777783d..fbf6e4cb8b 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java @@ -89,16 +89,7 @@ public class PointerTypeApplier extends MsTypeApplier { private DataType getUnderlyingType(AbstractPointerMsType type) { MsTypeApplier underlyingApplier = applicator.getTypeApplier(type.getUnderlyingRecordNumber()); - DataType underlyingType = underlyingApplier.getCycleBreakType(); - if (underlyingType == null) { - // TODO: we have seen underlyingTypeApplier is for NoTypeApplier for VtShapeMsType - // Figure it out, and perhaps create an applier that creates a structure or something? - underlyingType = applicator.getPdbPrimitiveTypeApplicator().getVoidType(); - applicator.appendLogMsg( - "PDB Warning: No type conversion for " + underlyingApplier.getMsType().toString() + - " as underlying type for pointer. Using void."); - } return underlyingType; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierFactory.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierFactory.java index e9a3ad40d4..f6a5624088 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierFactory.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierFactory.java @@ -112,9 +112,9 @@ public class TypeApplierFactory { applier = new MemberFunctionTypeApplier(applicator, (MemberFunction16MsType) type); break; -// case VtShapeMsType.PDB_ID: -// applier = new VtShapeTypeApplier(applicator, (VtShapeMsType) type); -// break; + case VtShapeMsType.PDB_ID: + applier = new VtShapeTypeApplier(applicator, (VtShapeMsType) type); + break; // case Cobol016MsType.PDB_ID: // // Not evaluated/implemented yet. // break; @@ -381,7 +381,7 @@ public class TypeApplierFactory { // // Not evaluated/implemented yet. // break; - // 0x1500 block + // 0x1500 block // case TypeServerMsType.PDB_ID: // // Not evaluated/implemented yet. // break; @@ -472,7 +472,7 @@ public class TypeApplierFactory { // // Not evaluated/implemented yet. // break; - // 0x1600 block + // 0x1600 block // case FunctionIdMsType.PDB_ID: // // Not evaluated/implemented yet. // break; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java index e4b851e67a..a32a5acec3 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java @@ -21,6 +21,7 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; import ghidra.program.model.data.DataType; +import ghidra.program.model.data.VoidDataType; import ghidra.util.exception.CancelledException; /** @@ -68,20 +69,24 @@ public class VirtualFunctionTablePointerTypeApplier extends MsTypeApplier { @Override void apply() throws PdbException, CancelledException { - if (msType instanceof AbstractVirtualFunctionTablePointerMsType) { + if (msType instanceof AbstractVirtualFunctionTablePointerWithOffsetMsType vftPtrWOffset) { dataType = applyPointer( - ((AbstractVirtualFunctionTablePointerMsType) msType).getPointerTypeRecordNumber()); + vftPtrWOffset.getPointerTypeRecordNumber()); + } + else if (msType instanceof AbstractVirtualFunctionTablePointerMsType vftPtr) { + dataType = applyPointer(vftPtr.getPointerTypeRecordNumber()); } else { - dataType = applyPointer( - ((AbstractVirtualFunctionTablePointerWithOffsetMsType) msType).getPointerTypeRecordNumber()); + dataType = VoidDataType.dataType; + applicator.appendLogMsg( + "PDB Warning: Type not handled: " + msType.getClass().getSimpleName()); } } private DataType applyPointer(RecordNumber pointerTypeRecordNumber) { MsTypeApplier rawApplier = applicator.getTypeApplier(pointerTypeRecordNumber); - if (rawApplier instanceof PointerTypeApplier) { - return rawApplier.getDataType(); + if (rawApplier instanceof PointerTypeApplier pointerApplier) { + return pointerApplier.getDataType(); } applicator.appendLogMsg("cannot process " + rawApplier.getClass().getSimpleName() + "for " + getClass().getSimpleName()); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java index 4ae42c1a87..89cb7c2ade 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java @@ -57,40 +57,83 @@ public class VtShapeTypeApplier extends MsTypeApplier { @Override void apply() throws PdbException, CancelledException { + // Note that focused investigation as shown that both the VTShape as well as the pointer + // to the particular VTShapes are not specific to one class; they can be shared by + // totally unrelated classes; moreover, no duplicates of any VTShape or pointer to a + // particular VTShape were found either. Because of this, for now, the VTShape is going + // into an anonymous types category. dataType = createVtShape((VtShapeMsType) msType); } - // TODO: We are creating a structure for the vtshape. Is there anything different we would - // like to do instead? - private DataType createVtShape(VtShapeMsType msShape) throws CancelledException { + // We are creating a structure for the vtshape. + private DataType createVtShape(VtShapeMsType msShape) + throws CancelledException { List list = msShape.getDescriptorList(); - // TODO: what are correct/appropriate CategoryPath and name StructureDataType shape = new StructureDataType(applicator.getAnonymousTypesCategory(), "vtshape" + index, 0, applicator.getDataTypeManager()); List members = new ArrayList<>(); int offset = 0; + int defaultSize = applicator.getDataTypeManager().getDataOrganization().getPointerSize(); + // Since each element has its own property, we have to assume there can be mixed + // properties in the table, thus each element must be set separately. + // However, note that the data types referenced by the symbols (e.g., GDATAx) at the + // vftable locations in memory seem to have these as an array of constant pointers to + // functions with no argument and void return; to me, this does not quite agree with what + // we have here where each element having its own pointer property. For now, + // using a structure here. Moreover, we might want to eventually fix-up the arrays put + // down with the GDATAx symbols with structures that contain pointers to func specs that + // match the real function signatures at each element. for (VtShapeDescriptorMsProperty descriptor : list) { + DataType elementType; switch (descriptor) { case NEAR: + // near16: + // 16-bit offset + elementType = Undefined2DataType.dataType; + break; case FAR: + // far16: + // 16-bit segment + // 16-bit offset + elementType = Undefined4DataType.dataType; + break; + case NEAR32: + // near32: + // 32-bit offset + elementType = Undefined4DataType.dataType; + break; + case FAR32: + // far32: + // 16-bit segment + // 32-bit offset + elementType = Undefined6DataType.dataType; + break; + // lump remaining together; we do not know about thin, outer, or meta + case UNUSED: + // Special message for unused, followed by fall through case + applicator.appendLogMsg("PDB Warning: UNUSED propery found in VTShape."); case THIN: case OUTER: case META: - case NEAR32: - case FAR32: - Pointer pointer = new PointerDataType(applicator.getDataTypeManager()); - DefaultPdbUniversalMember member = - new DefaultPdbUniversalMember(applicator, "", pointer, offset); - offset += pointer.getLength(); - members.add(member); - break; - case UNUSED: - offset += applicator.getDataOrganization().getPointerSize(); - break; + default: + // If any element type is not know, we will not return a full shape structure + // Instead, we return void type. + applicator.appendLogMsg( + "PDB Warning: No type conversion for " + msShape.toString() + + " as underlying type for pointer. Using void."); + return VoidDataType.dataType; } + int size = elementType.getLength(); + if (size == defaultSize) { + elementType = PointerDataType.dataType; + } + DefaultPdbUniversalMember member = + new DefaultPdbUniversalMember(applicator, "", elementType, offset); + offset += size; + members.add(member); } - int size = applicator.getDataOrganization().getPointerSize() * msShape.getCount(); - if (!DefaultCompositeMember.applyDataTypeMembers(shape, false, size, members, + // offset has the total size at this point + if (!DefaultCompositeMember.applyDataTypeMembers(shape, false, offset, members, msg -> Msg.warn(this, msg), applicator.getCancelOnlyWrappingMonitor())) { CompositeTypeApplier.clearComponents(shape); }