From f1495cb6a1ba3db8e6bd6fbcc74408a7bfd45e65 Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:17:35 -0500 Subject: [PATCH] GP-4246 - PDB improve types processing - better queuing mechanism, remove placeholder types, delay resolve --- .../FindDataTypeConflictCauseScript.java | 2 +- .../ghidra/app/util/DataTypeNamingUtil.java | 4 +- .../ghidra/app/util/pdb/PdbCategories.java | 15 +- .../AbstractComplexTypeApplier.java | 20 +- .../AbstractFunctionTypeApplier.java | 159 +++--- .../ArgumentsListTypeApplier.java | 22 +- .../pdb/pdbapplicator/ArrayTypeApplier.java | 76 ++- .../pdbapplicator/BaseClassTypeApplier.java | 18 +- .../pdbapplicator/BitfieldTypeApplier.java | 28 +- .../pdb/pdbapplicator/ComplexTypeMapper.java | 36 +- .../pdbapplicator/CompositeTypeApplier.java | 495 ++++++++---------- .../pdb/pdbapplicator/DataSymbolApplier.java | 47 +- .../pdbapplicator/DefaultPdbApplicator.java | 453 +++++----------- .../pdb/pdbapplicator/EnumTypeApplier.java | 72 +-- .../pdbapplicator/EnumerateTypeApplier.java | 19 +- .../pdbapplicator/FieldListTypeApplier.java | 29 +- .../util/pdb/pdbapplicator/FixupContext.java | 313 ----------- .../pdbapplicator/FunctionSymbolApplier.java | 2 +- .../pdb/pdbapplicator/LabelSymbolApplier.java | 4 +- .../MemberFunctionTypeApplier.java | 54 +- .../pdb/pdbapplicator/MemberTypeApplier.java | 16 +- .../pdbapplicator/ModifierTypeApplier.java | 54 +- .../pdb/pdbapplicator/MsDataTypeApplier.java | 84 +++ .../MsDataTypeComponentApplier.java | 32 ++ .../util/pdb/pdbapplicator/MsTypeApplier.java | 52 -- .../MultiphaseDataTypeResolver.java | 254 +++++++++ .../pdb/pdbapplicator/NestedTypeApplier.java | 26 +- .../util/pdb/pdbapplicator/NoTypeApplier.java | 11 - .../util/pdb/pdbapplicator/PdbResearch.java | 12 +- .../pdb/pdbapplicator/PointerTypeApplier.java | 125 ++--- .../pdbapplicator/PrimitiveTypeApplier.java | 22 +- .../pdbapplicator/ProcedureTypeApplier.java | 20 +- .../pdbapplicator/PublicSymbolApplier.java | 4 +- .../pdb/pdbapplicator/TypeApplierFactory.java | 9 +- .../pdbapplicator/TypedefSymbolApplier.java | 2 +- .../UdtSourceLineTypeApplier.java | 36 +- ...irtualFunctionTablePointerTypeApplier.java | 40 +- .../pdb/pdbapplicator/VtShapeTypeApplier.java | 15 +- 38 files changed, 1141 insertions(+), 1541 deletions(-) delete mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FixupContext.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsDataTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsDataTypeComponentApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MultiphaseDataTypeResolver.java diff --git a/Ghidra/Features/Base/ghidra_scripts/FindDataTypeConflictCauseScript.java b/Ghidra/Features/Base/ghidra_scripts/FindDataTypeConflictCauseScript.java index 2c89843903..a2f69dcb81 100644 --- a/Ghidra/Features/Base/ghidra_scripts/FindDataTypeConflictCauseScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/FindDataTypeConflictCauseScript.java @@ -50,7 +50,7 @@ public class FindDataTypeConflictCauseScript extends GhidraScript { } List selectedDatatypes = dtmService.getSelectedDatatypes(); - if (selectedDatatypes.size() != 1 || !(selectedDatatypes.get(0) instanceof Composite)) { + if (selectedDatatypes.size() != 1) { popup("Select a single conflict datatype before running script"); return; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/DataTypeNamingUtil.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/DataTypeNamingUtil.java index f3d52b5cde..6c5101152f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/DataTypeNamingUtil.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/DataTypeNamingUtil.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategories.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategories.java index 3fc8d79e9d..7381555414 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategories.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategories.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -35,7 +35,6 @@ public class PdbCategories { private CategoryPath pdbUncategorizedCategory; private CategoryPath anonymousFunctionsCategory; private CategoryPath anonymousTypesCategory; - private CategoryPath placeholderTypesCategory; private CategoryPath baseModuleTypedefsCategory; private List typedefCategories = new ArrayList<>(); @@ -63,8 +62,6 @@ public class PdbCategories { // anonymousFunctionCount = 0; anonymousTypesCategory = new CategoryPath(pdbRootCategory, "!_anon_types_"); - - placeholderTypesCategory = new CategoryPath(pdbRootCategory, "!_placeholder_types_"); } /** @@ -193,14 +190,6 @@ public class PdbCategories { return anonymousTypesCategory; } - /** - * Returns the {@link CategoryPath} for Anonymous Types Category for the PDB. - * @return the {@link CategoryPath} - */ - public CategoryPath getPlaceholderTypesCategory() { - return placeholderTypesCategory; - } - // /** // * Returns the name of what should be the next Anonymous Function (based on the count of // * the number of anonymous functions) so that there is a unique name for the function. diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java index dd8cbd8cae..cf5dd8eee7 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java @@ -24,12 +24,12 @@ import ghidra.app.util.pdb.PdbNamespaceUtils; /** * Applier for {@link AbstractComplexMsType} types. */ -public abstract class AbstractComplexTypeApplier extends MsTypeApplier { +public abstract class AbstractComplexTypeApplier extends MsDataTypeApplier { // Intended for: AbstractComplexMsType /** - * Constructor for complex type applier. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. + * Constructor for complex type applier + * @param applicator {@link DefaultPdbApplicator} for which this class is working */ public AbstractComplexTypeApplier(DefaultPdbApplicator applicator) { super(applicator); @@ -56,12 +56,7 @@ public abstract class AbstractComplexTypeApplier extends MsTypeApplier { */ public T getDefinitionType(AbstractComplexMsType mType, Class type) { - Integer num = applicator.getNumber(mType); - Integer mappedIndex = applicator.getMappedComplexType(num); - if (mappedIndex != null) { - mType = - applicator.getPdb().getTypeRecord(RecordNumber.typeRecordNumber(mappedIndex), type); - } + mType = applicator.getMappedTypeRecord(mType.getRecordNumber(), type); return type.cast(mType); } @@ -75,11 +70,8 @@ public abstract class AbstractComplexTypeApplier extends MsTypeApplier { //return mine or my def's (and set mine) SymbolPath getFixedSymbolPath(AbstractComplexMsType type) { SymbolPath path = getSymbolPath(type); - Integer num = applicator.getNumber(type); - Integer mappedIndex = applicator.getMappedComplexType(num); - if (mappedIndex != null) { - return PdbNamespaceUtils.convertToGhidraPathName(path, mappedIndex); - } + RecordNumber mappedNumber = applicator.getMappedRecordNumber(type.getRecordNumber()); + Integer num = mappedNumber.getNumber(); return PdbNamespaceUtils.convertToGhidraPathName(path, num); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java index 109914cb05..40ca480083 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java @@ -30,13 +30,13 @@ import ghidra.util.exception.InvalidInputException; /** * Applier for certain function types. */ -public abstract class AbstractFunctionTypeApplier extends MsTypeApplier { +public abstract class AbstractFunctionTypeApplier extends MsDataTypeApplier { // Intended for: see children /** * Constructor for the applicator that applies a "function" type, transforming it into a - * Ghidra DataType. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. + * Ghidra DataType + * @param applicator {@link DefaultPdbApplicator} for which this class is working */ public AbstractFunctionTypeApplier(DefaultPdbApplicator applicator) { super(applicator); @@ -52,28 +52,29 @@ public abstract class AbstractFunctionTypeApplier extends MsTypeApplier { /** * Returns the function "this" pointer * @param type the PDB type being inspected - * @param fixupContext the fixup context to use; or pass in null during fixup process - * @param breakCycle specify {@code true} when employing break-cycle logic (pointers to * Composites within composites) * @return the "this" pointer or null if does not have or is not a recognized type * @throws CancelledException upon user cancellation * @throws PdbException upon processing error */ - protected abstract Pointer getThisPointer(AbstractMsType type, FixupContext fixupContext, - boolean breakCycle) throws CancelledException, PdbException; + protected abstract Pointer getThisPointer(AbstractMsType type) + throws CancelledException, PdbException; /** - * Returns the containing class if function member of class + * Returns the RecordNumber of the function "this" pointer; {@code null} if not this pointer * @param type the PDB type being inspected - * @param fixupContext the fixup context to use; or pass in null during fixup process - * @param breakCycle specify {@code true} when employing break-cycle logic (pointers to - * Composites within composites) - * @return the containing class composite type - * @throws CancelledException upon user cancellation - * @throws PdbException upon processing error + * @return the record number of the "this" pointer or null if does not have or is not a + * recognized type */ - protected abstract Composite getContainingComplexApplier(AbstractMsType type, - FixupContext fixupContext, boolean breakCycle) throws CancelledException, PdbException; + protected abstract RecordNumber getThisPointerRecordNumber(AbstractMsType type); + + /** + * Returns the RecordNumber of the containing class if function member of class; {@code null} + * if no containing class + * @param type the PDB type being inspected + * @return the record number of the containing class composite type or {@code null} if none + */ + protected abstract RecordNumber getContainingComplexRecordNumber(AbstractMsType type); /** * Processes containing class if one exists @@ -105,23 +106,15 @@ public abstract class AbstractFunctionTypeApplier extends MsTypeApplier { protected abstract RecordNumber getArgListRecordNumber(AbstractMsType type); private boolean setReturnType(FunctionDefinitionDataType functionDefinition, - AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws CancelledException, PdbException { + AbstractMsType type) { if (isConstructor(type)) { return true; } RecordNumber returnRecord = getReturnRecordNumber(type); - if (returnRecord == null) { - return false; - } - DataType returnType = - applicator.getProcessedDataType(returnRecord, fixupContext, breakCycle); + DataType returnType = applicator.getDataType(returnRecord); if (returnType == null) { return false; } - if (applicator.isPlaceholderPointer(returnType)) { - return false; - } functionDefinition.setReturnType(returnType); return true; } @@ -160,43 +153,30 @@ public abstract class AbstractFunctionTypeApplier extends MsTypeApplier { } } - private boolean setArguments(FunctionDefinitionDataType functionDefinition, AbstractMsType type, - FixupContext fixupContext, boolean breakCycle) throws CancelledException, PdbException { + private boolean setArguments(FunctionDefinitionDataType functionDefinition, AbstractMsType type) + throws CancelledException, PdbException { - RecordNumber argsRecord = getArgListRecordNumber(type); - AbstractMsType aType = applicator.getPdb().getTypeRecord(argsRecord); - if (!(aType instanceof AbstractArgumentsListMsType argsList)) { - applicator.appendLogMsg( - "PDB Warning: expecting args list but found " + aType.getClass().getSimpleName() + - " for parameter list of " + functionDefinition.getName()); - return false; - } + List args = getArgsRecordNumbers(type); - boolean hasPlaceholder = false; - - List args = argsList.getArgRecordNumbers(); List parameterDefinitionList = new ArrayList<>(); int parameterCount = 0; for (RecordNumber arg : args) { applicator.checkCancelled(); - AbstractMsType argMsType = applicator.getPdb().getTypeRecord(arg); + AbstractMsType argMsType = applicator.getTypeRecord(arg); if (argMsType instanceof PrimitiveMsType primitive && primitive.isNoType()) { // Arguments list is empty. (There better not have been any arguments up until // now.) break; } - DataType argDataType = applicator.getProcessedDataType(arg, fixupContext, breakCycle); + DataType argDataType = applicator.getDataType(arg); if (argDataType == null) { applicator.appendLogMsg( "PDB Warning: No type conversion for " + argMsType.toString() + " for parameter " + parameterCount + " of " + functionDefinition.getName()); } else { - if (applicator.isPlaceholderPointer(argDataType)) { - hasPlaceholder = true; - } try { ParameterDefinition parameterDefinition = new ParameterDefinitionImpl(null, argDataType, ""); @@ -225,49 +205,90 @@ public abstract class AbstractFunctionTypeApplier extends MsTypeApplier { } } } - if (hasPlaceholder) { - return false; - } functionDefinition.setArguments(parameterDefinitionList .toArray(new ParameterDefinition[parameterDefinitionList.size()])); return true; } @Override - public DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) + boolean apply(AbstractMsType type) throws CancelledException, PdbException { - DataType existing = applicator.getDataType(type); - if (existing != null) { - return existing; + + if (!precheckOrScheduleDependencies(type)) { + return false; } + FunctionDefinitionDataType functionDefinition = new FunctionDefinitionDataType( applicator.getAnonymousFunctionsCategory(), "_func", applicator.getDataTypeManager()); - boolean hasPlaceholder = false; - processContainingType(type); + setReturnType(functionDefinition, type); + setArguments(functionDefinition, type); + Pointer thisPointer = getThisPointer(type); - if (!setReturnType(functionDefinition, type, fixupContext, breakCycle)) { - hasPlaceholder = true; - } - - if (!setArguments(functionDefinition, type, fixupContext, breakCycle)) { - hasPlaceholder = true; - } - - if (hasPlaceholder) { - return null; - } - - Pointer thisPointer = getThisPointer(type, fixupContext, breakCycle); CallingConvention convention = getCallingConvention(type); setCallingConvention(functionDefinition, convention, thisPointer); DataTypeNamingUtil.setMangledAnonymousFunctionName(functionDefinition); + DataType dataType = functionDefinition; - DataType resolvedType = applicator.resolve(functionDefinition); - applicator.putDataType(type, resolvedType); - return resolvedType; + applicator.putDataType(type, dataType); + return true; + } + + /** + * Uses {@link DefaultPdbApplicator#getDataTypeOrSchedule(Integer)}) on all underlying types + * to ensure that the types get scheduled... and detects whether any types were not yet + * available so that this composite type is denoted as not done. + * @param type the MS type of the function + * @return {@code true} if all underlying types are already available + * @throws PdbException upon processing issue + */ + private boolean precheckOrScheduleDependencies(AbstractMsType type) + throws PdbException { + boolean done = true; + + RecordNumber returnRecordNumber = getReturnRecordNumber(type); + DataType dt = applicator.getDataTypeOrSchedule(returnRecordNumber); + if (dt == null) { + done = false; + } + + List args = getArgsRecordNumbers(type); + for (RecordNumber argRecordNumber : args) { + dt = applicator.getDataTypeOrSchedule(argRecordNumber); + if (dt == null) { + done = false; + } + } + + RecordNumber thisRecordNumber = getThisPointerRecordNumber(type); + if (thisRecordNumber != null) { + dt = applicator.getDataTypeOrSchedule(thisRecordNumber); + if (dt == null) { + done = false; + } + } + + RecordNumber containerRecordNumber = getContainingComplexRecordNumber(type); + if (containerRecordNumber != null) { + dt = applicator.getDataTypeOrSchedule(containerRecordNumber); + if (dt == null) { + done = false; + } + } + + return done; + } + + private List getArgsRecordNumbers(AbstractMsType type) throws PdbException { + RecordNumber argsRecord = getArgListRecordNumber(type); + AbstractMsType aType = applicator.getTypeRecord(argsRecord); + if (!(aType instanceof AbstractArgumentsListMsType argsList)) { + throw new PdbException( + "Expecting arguments list but got: " + aType.getClass().getSimpleName()); + } + return argsList.getArgRecordNumbers(); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java index 15f1fdea3e..948bed1e67 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java @@ -15,32 +15,22 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractArgumentsListMsType; -import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; -import ghidra.program.model.data.DataType; -import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractArgumentsListMsType} types. */ -public class ArgumentsListTypeApplier extends MsTypeApplier { +public class ArgumentsListTypeApplier extends MsDataTypeComponentApplier { // Intended for: AbstractArgumentsListMsType /** - * Constructor for the applicator that applies a arguments list. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. - * @throws IllegalArgumentException Upon invalid arguments. + * Constructor for the applicator that applies a arguments list + * @param applicator {@link DefaultPdbApplicator} for which this class is working + * @throws IllegalArgumentException Upon invalid arguments */ - public ArgumentsListTypeApplier(DefaultPdbApplicator applicator) throws IllegalArgumentException { + public ArgumentsListTypeApplier(DefaultPdbApplicator applicator) + throws IllegalArgumentException { super(applicator); } - @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { - // do nothing - return null; - } - } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java index c59765fb96..00aa37fa43 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -28,66 +28,50 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractArrayMsType} types. */ -public class ArrayTypeApplier extends MsTypeApplier { +public class ArrayTypeApplier extends MsDataTypeApplier { // Intended for: AbstractArrayMsType /** * Constructor for the applicator that applies a "array" type, transforming it into a - * Ghidra DataType. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. + * Ghidra DataType + * @param applicator {@link DefaultPdbApplicator} for which this class is working */ public ArrayTypeApplier(DefaultPdbApplicator applicator) { super(applicator); } @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { - return applyType((AbstractArrayMsType) type, fixupContext); + boolean apply(AbstractMsType type) throws PdbException, CancelledException { + + AbstractArrayMsType arrayType = (AbstractArrayMsType) type; + // Doing pre-check on type first using the getDataTypeOrSchedule method. The logic is + // simpler here for Composites or Functions because we only have one dependency type, + // so we are not doing a separate call to a pre-check method as there is in those appliers. + // If type is not available, return false. + RecordNumber underlyingRecordNumber = arrayType.getElementTypeRecordNumber(); + DataType underlyingDataType = applicator.getDataTypeOrSchedule(underlyingRecordNumber); + if (underlyingDataType == null) { + return false; + } + + int numElements = calculateNumElements(arrayType, underlyingDataType); + if (numElements == -1) { + // There was a math calculation problem (probably have the wrong underlying type, + // which we still need to figure out; i.e., better composite mapper) so we + // will change the underlying type for now... + underlyingDataType = Undefined1DataType.dataType; + numElements = getSizeInt(arrayType); // array size (but divided by 1) is array size + } + DataType dataType = new ArrayDataType(underlyingDataType, numElements, -1, + applicator.getDataTypeManager()); + applicator.putDataType(arrayType, dataType); + return true; } boolean isFlexibleArray(AbstractMsType type) { return BigInteger.ZERO.equals(type.getSize()); } - private DataType applyType(AbstractArrayMsType type, FixupContext fixupContext) - throws CancelledException, PdbException { - if (fixupContext != null) { - DataType existingDt = applicator.getDataType(type); - if (existingDt != null) { - return existingDt; - } - } - - RecordNumber underlyingRecord = type.getElementTypeRecordNumber(); - DataType underlyingDataType = - applicator.getProcessedDataType(underlyingRecord, fixupContext, false); - - DataType dataType; - if (applicator.isPlaceholderType(underlyingDataType)) { - Long longArraySize = getSizeLong(type); - int intArraySize = longArraySize.intValue(); - dataType = - applicator.getPlaceholderArray(intArraySize, underlyingDataType.getAlignment()); - } - else { - int numElements = calculateNumElements(type, underlyingDataType); - if (numElements == -1) { - // There was a math calculation problem (probably have the wrong underlying type, - // which we still need to figure out; i.e., better composite mapper) so we - // will change the underlying type for now... - underlyingDataType = Undefined1DataType.dataType; - numElements = getSizeInt(type); // array size (but divided by 1) is array size - } - dataType = new ArrayDataType(underlyingDataType, numElements, -1, - applicator.getDataTypeManager()); - } - - DataType resolvedType = applicator.resolve(dataType); - applicator.putDataType(type, resolvedType); - return resolvedType; - } - private int calculateNumElements(AbstractArrayMsType type, DataType underlyingDataType) { if (underlyingDataType == null) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java index b0f188bf81..ab0d2290c0 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java @@ -15,24 +15,21 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; -import ghidra.program.model.data.DataType; -import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractBaseClassMsType}, {@link AbstractVirtualBaseClassMsType}, and * {@link AbstractIndirectVirtualBaseClassMsType} types. */ -public class BaseClassTypeApplier extends MsTypeApplier { +public class BaseClassTypeApplier extends MsDataTypeComponentApplier { // Intended for: AbstractBaseClassMsType, AbstractVirtualBaseClassMsType, or // AbstractIndirectVirtualBaseClassMsType /** - * Constructor for base class applier. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. - * @throws IllegalArgumentException Upon invalid arguments. + * Constructor for base class applier + * @param applicator {@link DefaultPdbApplicator} for which this class is working + * @throws IllegalArgumentException Upon invalid arguments */ public BaseClassTypeApplier(DefaultPdbApplicator applicator) throws IllegalArgumentException { @@ -54,13 +51,6 @@ public class BaseClassTypeApplier extends MsTypeApplier { return ((AbstractIndirectVirtualBaseClassMsType) type).getBaseClassRecordNumber(); } - @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { - // do nothing - return null; - } - private static AbstractMsType validateType(AbstractMsType type) throws IllegalArgumentException { if (!(type instanceof AbstractBaseClassMsType) && diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java index 1f6d36a830..c45c349585 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java @@ -27,36 +27,42 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractBitfieldMsType} types. */ -public class BitfieldTypeApplier extends MsTypeApplier { +public class BitfieldTypeApplier extends MsDataTypeApplier { // Intended for: AbstractBitfieldMsType /** - * Constructor for bitfield applier. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. + * Constructor for bitfield applier + * @param applicator {@link DefaultPdbApplicator} for which this class is working */ public BitfieldTypeApplier(DefaultPdbApplicator applicator) { super(applicator); } @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { + boolean apply(AbstractMsType type) throws PdbException, CancelledException { + AbstractBitfieldMsType mType = (AbstractBitfieldMsType) type; + // Doing pre-check on type first using the getDataTypeOrSchedule method. The logic is + // simpler here for Composites or Functions because we only have one dependency type, + // so we are not doing a separate call to a pre-check method as there is in those appliers. + // If type is not available, return false. RecordNumber elementRecordNumber = mType.getElementRecordNumber(); - DataType baseDataType = - applicator.getProcessedDataType(elementRecordNumber, fixupContext, breakCycle); + DataType baseDataType = applicator.getDataTypeOrSchedule(elementRecordNumber); + if (baseDataType == null) { + return false; + } + DataType bitFieldDataType; try { bitFieldDataType = new Pdb2BitField(baseDataType.clone(applicator.getDataTypeManager()), mType.getBitLength(), mType.getBitPosition()); } catch (InvalidDataTypeException e) { - applicator.appendLogMsg( + throw new PdbException( "Problem creating PdbBitField for " + type.getName() + ", error: " + e.toString()); - return null; } - // do not resolve bit-fields! - return bitFieldDataType; + applicator.putDataType(mType, bitFieldDataType); + return true; } /** diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeMapper.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeMapper.java index 6672cead48..c76849e815 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeMapper.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeMapper.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,6 +19,7 @@ import java.util.*; import ghidra.app.util.SymbolPath; import ghidra.app.util.SymbolPathParser; +import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber; import ghidra.app.util.bin.format.pdb2.pdbreader.TypeProgramInterface; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; import ghidra.util.exception.CancelledException; @@ -26,7 +27,7 @@ import ghidra.util.task.TaskMonitor; /** * Maps forward references with corresponding definitions for composites and enums. Map is of - * record number (index) to record number (index)--always of TYPE RecordCategory, as we are not + * RecordNumber to RecordNumber--always of TYPE RecordCategory, as we are not * expecting Complex type records numbers to be mapped from ITEM RecordCategory lists. We are * always creating a map of higher number to lower number, as we are assuming that processing * will be done in an increasing-record-number order. @@ -40,35 +41,27 @@ import ghidra.util.task.TaskMonitor; // tried. public class ComplexTypeMapper { - private Map map; + private Map map; //============================================================================================== public ComplexTypeMapper() { map = new HashMap<>(); } -// /** -// * Returns map to alternate record number or argument record number if no map. Result is -// * record number of alternative record for the complex type. It should be the lower of the -// * two numbers for the set of fwdref and def records, with the fwdref generally, but not -// * always, the lower-numbered record. -// * @param recordNumber the record number for which to do the lookup -// * @return the mapped number -// */ /** * Returns map to alternate record number or argument record number if no map. Result is - * record number of alternative record for the complex type. Map is of fwdref to definition - * numbers. The fwdref number is generally, but not always, the lower number + * RecordNumber of alternative record for the complex type. Map is of fwdref to definition + * RecordNumbers. The fwdref number is generally, but not always, the lower number * @param recordNumber the record number for which to do the lookup - * @return the mapped number + * @return the mapped record number or the original record number if no mapped entry */ - public Integer getMapped(int recordNumber) { + public RecordNumber getMapped(RecordNumber recordNumber) { return map.getOrDefault(recordNumber, recordNumber); } // Storing type (isFwd or isDef) so that if we decide to parse Types on demand, we will not // have to parse it again to see if it is a fwdref or def. - private record NumFwdRef(int number, boolean isFwd) {} + private record NumFwdRef(RecordNumber number, boolean isFwd) {} //============================================================================================== //============================================================================================== @@ -131,6 +124,7 @@ public class ComplexTypeMapper { SymbolPath symbolPath = new SymbolPath(SymbolPathParser.parse(complexType.getName())); boolean isFwdRef = complexType.getMsProperty().isForwardReference(); + RecordNumber recordNumber = complexType.getRecordNumber(); Deque numTypeFIFO = typeFIFOsByPath.get(symbolPath); if (numTypeFIFO == null) { @@ -138,7 +132,7 @@ public class ComplexTypeMapper { typeFIFOsByPath.put(symbolPath, numTypeFIFO); // Putting forward reference or definition (doesn't matter which it is) - if (!numTypeFIFO.add(new NumFwdRef(indexNumber, isFwdRef))) { + if (!numTypeFIFO.add(new NumFwdRef(recordNumber, isFwdRef))) { // Error } } @@ -148,7 +142,7 @@ public class ComplexTypeMapper { // If same in FIFO, then add to bottom of the FIFO, as all records on this FIFO // will be the same per this algorithm. if (firstNumFwdRef.isFwd() == isFwdRef) { - if (!numTypeFIFO.add(new NumFwdRef(indexNumber, isFwdRef))) { + if (!numTypeFIFO.add(new NumFwdRef(recordNumber, isFwdRef))) { // Error } } @@ -167,7 +161,7 @@ public class ComplexTypeMapper { // symbol path and we need the fwdref symbol path to be the same. Thus we // want to be able to have ready access to the def record. if (isFwdRef) { - map.put(indexNumber, firstNumFwdRef.number()); + map.put(recordNumber, firstNumFwdRef.number()); // // Following is just temporary during development to compare with // // previous mapping capability. TODO remove // System.out.println(String.format("%d %s %d -> %d", @@ -175,7 +169,7 @@ public class ComplexTypeMapper { // indexNumber, firstNumFwdRef.number())); } else { - map.put(firstNumFwdRef.number(), indexNumber); + map.put(firstNumFwdRef.number(), recordNumber); // // Following is just temporary during development to compare with // // previous mapping capability. TODO remove // System.out.println(String.format("%d %s %d <- %d", 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 1bb6ce1351..d2dca25ef3 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,7 +16,8 @@ package ghidra.app.util.pdb.pdbapplicator; import java.math.BigInteger; -import java.util.*; +import java.util.ArrayList; +import java.util.List; import ghidra.app.util.SymbolPath; import ghidra.app.util.bin.format.pdb.DefaultCompositeMember; @@ -43,8 +44,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { // Intended for: AbstractCompositeMsType /** - * Constructor for composite type applier, for transforming a composite into a - * Ghidra DataType + * Constructor for composite type applier, for transforming a composite into a Ghidra DataType * @param applicator {@link DefaultPdbApplicator} for which this class is working */ public CompositeTypeApplier(DefaultPdbApplicator applicator) { @@ -75,15 +75,17 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { String mangledName = compositeMsType.getMangledName(); + int size = myApplicator.bigIntegerToInt(compositeMsType.getSize()); + if (compositeMsType instanceof AbstractClassMsType) { myApplicator.predefineClass(fixedSymbolPath); - myComposite = new StructureDataType(categoryPath, fixedSymbolPath.getName(), 0, + myComposite = new StructureDataType(categoryPath, fixedSymbolPath.getName(), size, myApplicator.getDataTypeManager()); myClassType = new CppCompositeType(myComposite, mangledName); myClassType.setClass(); } else if (compositeMsType instanceof AbstractStructureMsType) { - myComposite = new StructureDataType(categoryPath, fixedSymbolPath.getName(), 0, + myComposite = new StructureDataType(categoryPath, fixedSymbolPath.getName(), size, myApplicator.getDataTypeManager()); myClassType = new CppCompositeType(myComposite, mangledName); myClassType.setStruct(); @@ -101,35 +103,39 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { return null; } myClassType.setName(name); - myClassType.setSize(myApplicator.bigIntegerToInt(compositeMsType.getSize())); + myClassType.setSize(size); myClassType.setFinal(compositeMsType.getMsProperty().isSealed()); return new ComboType(myComposite, myClassType); } @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { - return apply((AbstractCompositeMsType) type, fixupContext, breakCycle); + boolean apply(AbstractMsType type) throws PdbException, CancelledException { + return apply((AbstractCompositeMsType) type); } - private void applyInternal(ComboType combo, AbstractCompositeMsType type, - FixupContext fixupContext, boolean breakCycle) throws CancelledException, PdbException { + private boolean applyInternal(ComboType combo, AbstractCompositeMsType type) + throws CancelledException, PdbException { FieldListTypeApplier fieldListApplier = FieldListTypeApplier .getFieldListApplierSpecial(applicator, type.getFieldDescriptorListRecordNumber()); FieldListTypeApplier.FieldLists lists = fieldListApplier.getFieldLists(type.getFieldDescriptorListRecordNumber()); + if (!precheckOrScheduleDependencies(lists)) { + return false; + } + if (type instanceof AbstractUnionMsType) { - applyBasic(combo, type, lists, fixupContext, breakCycle); + applyBasic(combo, type, lists); } else { - applyCpp(combo, type, lists, fixupContext, breakCycle); + applyCpp(combo, type, lists); } + return true; } //============================================================================================== private void applyBasic(ComboType combo, AbstractCompositeMsType type, - FieldListTypeApplier.FieldLists lists, FixupContext fixupContext, boolean breakCycle) + FieldListTypeApplier.FieldLists lists) throws CancelledException, PdbException { Composite composite = combo.dt(); CppCompositeType classType = combo.ct(); @@ -137,10 +143,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { int size = getSizeInt(type); clearComponents(composite); List myMembers = new ArrayList<>(); - addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers, fixupContext, - breakCycle); - addMembers(composite, classType, lists.nonstaticMembers(), type, myMembers, fixupContext, - breakCycle); + addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers); + addMembers(composite, classType, lists.nonstaticMembers(), type, myMembers); if (!DefaultCompositeMember.applyDataTypeMembers(composite, isClass, size, myMembers, msg -> reconstructionWarn(msg, hasHiddenComponents(lists)), @@ -151,18 +155,15 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { //============================================================================================== private void applyCpp(ComboType combo, AbstractCompositeMsType type, - FieldListTypeApplier.FieldLists lists, FixupContext fixupContext, boolean breakCycle) + FieldListTypeApplier.FieldLists lists) throws PdbException, CancelledException { Composite composite = combo.dt(); CppCompositeType classType = combo.ct(); clearComponents(composite); List myMembers = new ArrayList<>(); - addClassTypeBaseClassesNew(composite, classType, lists.bases(), type, fixupContext, - breakCycle); - addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers, fixupContext, - breakCycle); - addMembers(composite, classType, lists.nonstaticMembers(), type, myMembers, fixupContext, - breakCycle); + addClassTypeBaseClasses(composite, classType, lists.bases(), type); + addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers); + addMembers(composite, classType, lists.nonstaticMembers(), type, myMembers); if (!classType.validate()) { // TODO: Investigate. We should do this check for some classes somewhere. Should @@ -205,14 +206,14 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { return (lists.methods().size() != 0 || lists.bases().size() != 0); } - private void addClassTypeBaseClassesNew(Composite composite, CppCompositeType myClassType, - List msBases, AbstractMsType type, FixupContext fixupContext, - boolean breakCycle) throws PdbException, CancelledException { + private void addClassTypeBaseClasses(Composite composite, CppCompositeType myClassType, + List msBases, AbstractMsType type) + throws PdbException, CancelledException { AbstractCompositeMsType cType = (AbstractCompositeMsType) type; for (AbstractMsType baseType : msBases) { - + applicator.checkCancelled(); MsTypeApplier baseApplier = applicator.getTypeApplier(baseType); if (!(baseApplier instanceof BaseClassTypeApplier baseTypeApplier)) { applicator.appendLogMsg(baseApplier.getClass().getSimpleName() + @@ -221,15 +222,13 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } if (baseType instanceof AbstractBaseClassMsType baseClassType) { - applyDirectBaseClass(baseClassType, myClassType, fixupContext); + applyDirectBaseClass(baseClassType, myClassType); } else if (baseType instanceof AbstractVirtualBaseClassMsType virtualBaseClassType) { - applyDirectVirtualBaseClass(virtualBaseClassType, myClassType, fixupContext, - breakCycle); + applyDirectVirtualBaseClass(virtualBaseClassType, myClassType); } else if (baseType instanceof AbstractIndirectVirtualBaseClassMsType indirectVirtualBaseClassType) { - applyIndirectVirtualBaseClass(indirectVirtualBaseClassType, myClassType, - fixupContext, breakCycle); + applyIndirectVirtualBaseClass(indirectVirtualBaseClassType, myClassType); } else { throw new AssertException( @@ -238,10 +237,10 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } } - private void applyDirectBaseClass(AbstractBaseClassMsType base, CppCompositeType myClassType, - FixupContext fixupContext) throws PdbException, CancelledException { + private void applyDirectBaseClass(AbstractBaseClassMsType base, CppCompositeType myClassType) + throws PdbException { CppCompositeType underlyingClassType = - getUnderlyingClassType(base.getBaseClassRecordNumber(), fixupContext); + getUnderlyingClassType(base.getBaseClassRecordNumber()); if (underlyingClassType == null) { return; } @@ -251,15 +250,14 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } private void applyDirectVirtualBaseClass(AbstractVirtualBaseClassMsType base, - CppCompositeType myClassType, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { + CppCompositeType myClassType) throws PdbException { CppCompositeType underlyingCt = - getUnderlyingClassType(base.getBaseClassRecordNumber(), fixupContext); + getUnderlyingClassType(base.getBaseClassRecordNumber()); if (underlyingCt == null) { return; } DataType vbtptr = getVirtualBaseTablePointerDataType( - base.getVirtualBasePointerRecordNumber(), fixupContext, breakCycle); + base.getVirtualBasePointerRecordNumber()); ClassFieldMsAttributes atts = base.getAttributes(); int basePointerOffset = applicator.bigIntegerToInt(base.getBasePointerOffset()); int offsetFromVbt = applicator.bigIntegerToInt(base.getBaseOffsetFromVbt()); @@ -268,15 +266,14 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } private void applyIndirectVirtualBaseClass(AbstractIndirectVirtualBaseClassMsType base, - CppCompositeType myClassType, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { + CppCompositeType myClassType) throws PdbException { CppCompositeType underlyingCt = - getUnderlyingClassType(base.getBaseClassRecordNumber(), fixupContext); + getUnderlyingClassType(base.getBaseClassRecordNumber()); if (underlyingCt == null) { return; } - DataType vbtptr = getVirtualBaseTablePointerDataType( - base.getVirtualBasePointerRecordNumber(), fixupContext, breakCycle); + DataType vbtptr = + getVirtualBaseTablePointerDataType(base.getVirtualBasePointerRecordNumber()); ClassFieldMsAttributes atts = base.getAttributes(); int basePointerOffset = applicator.bigIntegerToInt(base.getBasePointerOffset()); int offsetFromVbt = applicator.bigIntegerToInt(base.getBaseOffsetFromVbt()); @@ -284,17 +281,14 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { basePointerOffset, vbtptr, offsetFromVbt); } - private CppCompositeType getUnderlyingClassType(RecordNumber recordNumber, - FixupContext fixupContext) throws CancelledException, PdbException { + private CppCompositeType getUnderlyingClassType(RecordNumber recordNumber) { - AbstractMsType type = applicator.getPdb().getTypeRecord(recordNumber); + AbstractMsType type = applicator.getTypeRecord(recordNumber); if (!(type instanceof AbstractCompositeMsType comp)) { applicator.appendLogMsg(type.getClass().getSimpleName() + " seen where Composite Type expected for base class."); return null; } - // not sure if need to do this. TODO: evaluate - applicator.getProcessedDataType(recordNumber, fixupContext, false); MsTypeApplier baseUnderlyingApplier = applicator.getTypeApplier(recordNumber); if (!(baseUnderlyingApplier instanceof CompositeTypeApplier)) { @@ -310,14 +304,13 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { return underlyingClassType; } - private DataType getVirtualBaseTablePointerDataType(RecordNumber recordNumber, - FixupContext fixupContext, boolean breakCycle) throws CancelledException, PdbException { - DataType dt = applicator.getProcessedDataType(recordNumber, fixupContext, breakCycle); - if (dt != null) { - return dt; + private DataType getVirtualBaseTablePointerDataType(RecordNumber recordNumber) + throws PdbException { + DataType dataType = applicator.getDataType(recordNumber); + if (dataType == null) { + throw new PdbException("Type not processed for record: " + recordNumber); } - applicator.appendLogMsg("Generating a generic Virtual Base Table Pointer."); - return new PointerDataType(); + return dataType; } private static CppCompositeType.ClassFieldAttributes convertAttributes( @@ -357,77 +350,167 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { private void addMembers(Composite composite, CppCompositeType myClassType, List msMembers, AbstractCompositeMsType type, - List myMembers, FixupContext fixupContext, - boolean breakCycle) throws CancelledException, PdbException { - + List myMembers) + throws CancelledException, PdbException { for (int index = 0; index < msMembers.size(); index++) { applicator.checkCancelled(); AbstractMemberMsType memberType = msMembers.get(index); - DefaultPdbUniversalMember member = - getNonStaticMember(composite, memberType, index, fixupContext, breakCycle); + DefaultPdbUniversalMember member = getNonStaticMember(composite, memberType, index); DataType dt = member.getDataType().getDataType(); - if (applicator.isPlaceholderType(dt)) { - fixupContext.putFixup(index); - } myMembers.add(member); myClassType.addMember(member.getName(), dt, member.isZeroLengthArray(), member.getAttributes(), member.getOffset(), member.getComment()); } } + // Does not use applier... goes straight to vftptr type private void addVftPtrs(Composite composite, CppCompositeType myClassType, List msVftPtrs, AbstractCompositeMsType type, - List myMembers, FixupContext fixupContext, - boolean breakCycle) throws CancelledException, PdbException { + List myMembers) + throws CancelledException, PdbException { for (AbstractVirtualFunctionTablePointerMsType vftPtr : msVftPtrs) { - MsTypeApplier applierIterated = applicator.getTypeApplier(vftPtr); - if (applierIterated instanceof VirtualFunctionTablePointerTypeApplier vtPtrApplier) { - DefaultPdbUniversalMember member = - getVftPtrMember(vftPtr, vtPtrApplier, fixupContext, breakCycle); - myMembers.add(member); - myClassType.addVirtualFunctionTablePointer(member.getName(), - member.getDataType().getDataType(), member.getOffset()); + applicator.checkCancelled(); + RecordNumber recordNumber = vftPtr.getPointerTypeRecordNumber(); + DataType dataType = applicator.getDataType(recordNumber); + if (dataType == null) { + throw new PdbException("Type not processed for record: " + recordNumber); } + int offset = vftPtr.getOffset(); + String vftPtrMemberName = vftPtr.getName(); + DefaultPdbUniversalMember member = + new DefaultPdbUniversalMember(vftPtrMemberName, dataType, offset); + myMembers.add(member); + myClassType.addVirtualFunctionTablePointer(member.getName(), + member.getDataType().getDataType(), member.getOffset()); } } - // We broke up the big addMembers() method that had static and non-static members, along with - // vftptrs, and the items in this method. These were not really processed in the older - // method, but we wanted to capture the types that still possible - private void addOthers(Composite composite, CppCompositeType myClassType, - List msMembers, AbstractCompositeMsType type, - List myMembers, FixupContext fixupContext) - throws CancelledException, PdbException { - - for (AbstractMsType typeIterated : msMembers) { - MsTypeApplier applierIterated = applicator.getTypeApplier(typeIterated); - if (applierIterated instanceof EnumerateTypeApplier enumerateApplier && - typeIterated instanceof AbstractEnumerateMsType enumerateType) { - processEnumerate(type, enumerateApplier, enumerateType); - } - else if (applierIterated instanceof NestedTypeApplier nestedTypeApplier) { - processNestedType(type, nestedTypeApplier, typeIterated); - } - else if (applierIterated instanceof NoTypeApplier) { - if (typeIterated instanceof AbstractStaticMemberMsType) { - // TODO: Investigate anything that hits here (set break point), see if we - // see dot apply the information. If so, probably should create an applier - // for the contained MS type. + /** + * Uses {@link DefaultPdbApplicator#getDataTypeOrSchedule(Integer)}) on all underlying types + * to ensure that the types get scheduled... and detects whether any types were not yet + * available so that this composite type is denoted as not done. + * @param lists the lists of all underlying types + * @return {@code true} if all underlying types are already available + * @throws PdbException upon processing issue + * @throws CancelledException upon user cancellation + */ + private boolean precheckOrScheduleDependencies(FieldListTypeApplier.FieldLists lists) + throws PdbException, CancelledException { + boolean done = true; + for (AbstractMsType base : lists.bases()) { + applicator.checkCancelled(); + if (base instanceof AbstractBaseClassMsType bc) { + RecordNumber recordNumber = bc.getBaseClassRecordNumber(); + DataType dt = applicator.getDataTypeOrSchedule(recordNumber); + if (dt == null) { + done = false; } - else { - processNotHandled(composite, applierIterated, typeIterated); + } + else if (base instanceof AbstractVirtualBaseClassMsType vbc) { + RecordNumber recordNumber = vbc.getVirtualBasePointerRecordNumber(); + DataType dt = applicator.getDataTypeOrSchedule(recordNumber); + if (dt == null) { + done = false; + } + recordNumber = vbc.getBaseClassRecordNumber(); + dt = applicator.getDataTypeOrSchedule(recordNumber); + if (dt == null) { + done = false; + } + } + else if (base instanceof AbstractIndirectVirtualBaseClassMsType ivbc) { + RecordNumber recordNumber = ivbc.getVirtualBasePointerRecordNumber(); + DataType dt = applicator.getDataTypeOrSchedule(recordNumber); + if (dt == null) { + done = false; + } + recordNumber = ivbc.getBaseClassRecordNumber(); + dt = applicator.getDataTypeOrSchedule(recordNumber); + if (dt == null) { + done = false; } } else { - processNotHandled(composite, applierIterated, typeIterated); + throw new PdbException("Unhandled type: " + base.getClass().getSimpleName()); + } + } + for (AbstractMsType method : lists.methods()) { + applicator.checkCancelled(); + if (method instanceof AbstractOneMethodMsType oneMethod) { + RecordNumber recordNumber = oneMethod.getProcedureTypeRecordNumber(); + DataType dt = applicator.getDataTypeOrSchedule(recordNumber); + if (dt == null) { + done = false; + } + } + else if (method instanceof AbstractOverloadedMethodMsType overloadedMethod) { + RecordNumber recordNumber = overloadedMethod.getTypeMethodListRecordNumber(); + AbstractMsType msType = applicator.getTypeRecord(recordNumber); + if (msType instanceof AbstractMethodListMsType methodList) { + List methodRecords = methodList.getList(); + for (AbstractMethodRecordMs methodRecord : methodRecords) { + recordNumber = methodRecord.getProcedureTypeRecordNumber(); + DataType dt = applicator.getDataTypeOrSchedule(recordNumber); + if (dt == null) { + done = false; + } + } + } + } + else { + throw new PdbException("Unhandled type: " + method.getClass().getSimpleName()); + } + } + for (AbstractNestedTypeMsType nested : lists.nestedTypes()) { + applicator.checkCancelled(); + RecordNumber recordNumber = nested.getNestedTypeDefinitionRecordNumber(); + DataType dt = applicator.getDataTypeOrSchedule(recordNumber); + if (dt == null) { + done = false; + } + } + for (AbstractMemberMsType nonstaticMember : lists.nonstaticMembers()) { + applicator.checkCancelled(); + RecordNumber recordNumber = nonstaticMember.getFieldTypeRecordNumber(); + DataType dt = applicator.getDataTypeOrSchedule(recordNumber); + if (dt == null) { + done = false; + } + } + for (AbstractStaticMemberMsType staticMember : lists.staticMembers()) { + applicator.checkCancelled(); + RecordNumber recordNumber = staticMember.getFieldTypeRecordNumber(); + DataType dt = applicator.getDataTypeOrSchedule(recordNumber); + if (dt == null) { + done = false; } } + // Not doing enumerates for now... look at EnumTypeApplier, too, regarding how to deal + // with not storing a type with applicator.putDataType and yet getting removed from or + // not being added to the "todo" schedule. +// for (AbstractEnumerateMsType enumerate : lists.enumerates()) { +// applicator.checkCancelled(); +// RecordNumber recordNumber = enumerate.getRecordNumber(); +// DataType dt = applicator.getDataTypeOrSchedule(recordNumber); +// if (dt == null) { +// done = false; +// } +// } + for (AbstractVirtualFunctionTablePointerMsType msVftPtr : lists.vftPtrs()) { + applicator.checkCancelled(); + RecordNumber recordNumber = msVftPtr.getPointerTypeRecordNumber(); + DataType dt = applicator.getDataTypeOrSchedule(recordNumber); + if (dt == null) { + done = false; + } + } + return done; } private DefaultPdbUniversalMember getNonStaticMember(Composite container, - AbstractMemberMsType memberMsType, int ordinal, FixupContext fixupContext, - boolean breakCycle) throws CancelledException, PdbException { + AbstractMemberMsType memberMsType, int ordinal) + throws CancelledException, PdbException { MsTypeApplier applier = applicator.getTypeApplier(memberMsType); if (!(applier instanceof MemberTypeApplier memberApplier)) { @@ -440,16 +523,22 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { ClassFieldMsAttributes memberAttributes = memberMsType.getAttribute(); memberAttributes.getAccess(); // TODO: do something with this and other attributes - AbstractMsType fieldType = - applicator.getPdb().getTypeRecord(memberMsType.getFieldTypeRecordNumber()); + RecordNumber typeRecordNumber = memberMsType.getFieldTypeRecordNumber(); + AbstractMsType fieldType = applicator.getTypeRecord(typeRecordNumber); MsTypeApplier fieldApplier = applicator.getTypeApplier(fieldType); String memberComment = null; - DataType fieldDataType = applicator.getProcessedDataType( - memberMsType.getFieldTypeRecordNumber(), fixupContext, breakCycle); - if (fieldApplier instanceof PointerTypeApplier ptrApplier) { + RecordNumber fieldRecordNumber = memberMsType.getFieldTypeRecordNumber(); + DataType fieldDataType = applicator.getDataType(fieldRecordNumber); + if (fieldDataType == null) { + throw new PdbException("Type not processed for record: " + fieldRecordNumber); + } + else if (fieldApplier instanceof PointerTypeApplier ptrApplier) { + // The above placeholder could be a pointer, but then we wouldn't be getting + // a comment here anyways, so the "else" is perfect... we don't want to overwrite + // the placeholder comment AbstractPointerMsType pointerType = (AbstractPointerMsType) fieldType; - memberComment = ptrApplier.getPointerCommentField(pointerType, fixupContext); + memberComment = ptrApplier.getPointerCommentField(pointerType); } boolean isZeroLengthArray = (fieldDataType instanceof Array && @@ -461,16 +550,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { return member; } - private DefaultPdbUniversalMember getVftPtrMember( - AbstractVirtualFunctionTablePointerMsType type, - VirtualFunctionTablePointerTypeApplier vtPtrApplier, FixupContext fixupContext, - boolean breakCycle) throws CancelledException, PdbException { - String vftPtrMemberName = vtPtrApplier.getMemberName(type); - int offset = vtPtrApplier.getOffset(type); - DataType dt = vtPtrApplier.apply(type, fixupContext, breakCycle); - return new DefaultPdbUniversalMember(vftPtrMemberName, dt, offset); - } - + // Not yet working: not sure of the work we will do private void processEnumerate(AbstractCompositeMsType type, EnumerateTypeApplier applier, AbstractEnumerateMsType enumerateType) { String fieldName = enumerateType.getName(); @@ -480,6 +560,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { fieldName + " and value " + numeric + "."); } + // Not yet working: not sure of the work we will do private void processNestedType(AbstractCompositeMsType type, NestedTypeApplier nestedTypeApplier, AbstractMsType enumerateType) { // Need to make sure that "this" class id dependent on all elements composing the @@ -512,35 +593,12 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } - private void processNotHandled(Composite composite, MsTypeApplier applier, - AbstractMsType memberType) { - applicator.appendLogMsg(applier.getClass().getSimpleName() + " with contained " + - memberType.getClass().getSimpleName() + " unexpected for " + composite.getName()); - } - //============================================================================================== - DataType fixup(AbstractCompositeMsType type, Map contextMap) - throws CancelledException, PdbException { - DataType dt = applicator.getDataType(type); - if (dt instanceof DataTypeImpl || !(dt instanceof Composite)) { - throw new PdbException("Can only fixup Composite DB "); - } - return null; - } + boolean apply(AbstractCompositeMsType type) throws CancelledException, PdbException { - //============================================================================================== - DataType apply(AbstractCompositeMsType type, FixupContext fixupContext, boolean breakCycle) - throws CancelledException, PdbException { + RecordNumber recordNumber = type.getRecordNumber(); - int typeNumber = type.getRecordNumber().getNumber(); - int mappedNumber = applicator.getMappedComplexType(typeNumber); - DataType existingDt = applicator.getDataType(mappedNumber); - if (existingDt != null) { - return existingDt; - } - - AbstractMsType msType = - applicator.getPdb().getTypeRecord(RecordNumber.typeRecordNumber(mappedNumber)); + AbstractMsType msType = applicator.getMappedTypeRecord(recordNumber); if (!(msType instanceof AbstractCompositeMsType)) { throw new PdbException("PDB processing error"); } @@ -554,147 +612,30 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { composite = combo.dt(); myClassType = combo.ct(); applicator.putClassType(type, myClassType); + // Since we are delaying resolve, we should be able to store this data type earlier... + // which is what I'm now doing before applyInternal(). This should save doing some + // fixups (e.g., where my ball of types wants a pointer to this particular type). + // Composite is only type that we store before it is finished... this does cycle-break + // in two ways... + // 1) from the data type perspective, a pointer can always find the underlying type + // if it is a composite, thus whatever cycles can be created from composites are + // taken care of + // 2) from a processing perspective, we allow dependencies to get trickled up on the + // processing todo stack if they are not found in the applicator map. This could + // cause processing oscillation because of dependencies, but since we push the + // type here, it will always be found in the map and never trickled upward + applicator.putDataType(msType, composite); } else { composite = myClassType.getComposite(); combo = new ComboType(composite, myClassType); } - applyInternal(combo, type, fixupContext, breakCycle); - - composite = (Composite) applicator.resolve(composite); - applicator.putDataType(mappedNumber, composite); - return composite; + return applyInternal(combo, type); } private AbstractCompositeMsType getDefinitionType(AbstractComplexMsType type) { return getDefinitionType(type, AbstractCompositeMsType.class); } - public void fixUp(FixupContext fixupContext) throws PdbException, CancelledException { - - Integer indexNumber = fixupContext.peekFixupRecord(); - if (indexNumber == null) { - return; - } - - AbstractMsType t = - applicator.getPdb().getTypeRecord(RecordNumber.typeRecordNumber(indexNumber)); - if (!(t instanceof AbstractComplexMsType type)) { - throw new PdbException("error"); - } - AbstractCompositeMsType defType = getDefinitionType(type); - - DataType dataType = applicator.getDataType(indexNumber); - if (dataType == null) { - applicator.appendLogMsg("Null type for index: " + indexNumber); - return; - } - if (dataType instanceof DataTypeImpl) { - applicator.appendLogMsg("Impl type for index: " + indexNumber); - return; - } - if (!(dataType instanceof Composite compositeDB)) { - applicator.appendLogMsg("Composite expected type for index: " + indexNumber); - return; - } - - FieldListTypeApplier fieldListApplier = FieldListTypeApplier.getFieldListApplierSpecial( - applicator, defType.getFieldDescriptorListRecordNumber()); - FieldListTypeApplier.FieldLists lists = - fieldListApplier.getFieldLists(defType.getFieldDescriptorListRecordNumber()); - - List msMembers = lists.nonstaticMembers(); - - List fixupIndices = fixupContext.getFixups(); - for (int index : fixupIndices) { - applicator.checkCancelled(); - AbstractMemberMsType memberType = msMembers.get(index); - // Using a null FixupContext signifies "doing" vs. creating fixups. - DefaultPdbUniversalMember member = - getNonStaticMember(compositeDB, memberType, index, null, false); - replaceComponentDataType(compositeDB, member); - } - } - - private void replaceComponentDataType(Composite compositeDB, DefaultPdbUniversalMember member) - throws CancelledException, PdbException { - DataType dt = member.getDataType().getDataType(); - if (applicator.isPlaceholderPointer(dt)) { - throw new PdbException("Placeholder pointer not expected"); - } - if (!recurseReplacement(compositeDB, 0, member)) { - /** - * We want to throw the exception below, but for now, we are only making a warning. - * This is because we have a situation where we still do not accurately map - * definitions with forward references and when this causes a size calculation within - * the {@link ArrayTypeApplier}, we fill in the array with dummy undefined1 types, - * which can cause the replacement issue here. When that gets fixed, the warning - * here should be replaced with the PdbException. - */ - Msg.warn(this, - "PDB: Unable to replace placeholder component of: " + compositeDB.getName()); -// throw new PdbException( -// "Unable to replace placeholder component of: " + compositeDB.getName()); - } - } - - private boolean recurseReplacement(Composite compositeDB, int baseOffset, - DefaultPdbUniversalMember member) throws CancelledException, PdbException { - DataTypeComponent[] components = compositeDB.getDefinedComponents(); - for (DataTypeComponent component : components) { - if (member.getOffset() > baseOffset + component.getEndOffset()) { - continue; - } - if (member.getOffset() < baseOffset + component.getOffset()) { - continue; - } - DataType componentDt = component.getDataType(); - // We would normally just check for a union, expecting any other component to be - // a fully defined datatype, but using DefaultPdbUniveralMember to unflatten - // a union can result in nested structures that are not otherwise resolved. Thus, - // we must check for any composite: union or structure. - if (!applicator.isPlaceholderType(componentDt) && - componentDt instanceof Composite nestedComposite) { - if (recurseReplacement(nestedComposite, baseOffset + component.getOffset(), - member)) { - return true; - } - continue; - } - if (applicator.isPlaceholderType(componentDt) && - component.getFieldName().equals(member.getName()) && - member.getOffset() == baseOffset + component.getOffset()) { - DataType replacementDt = member.getDataType().getDataType(); - int length = replacementDt.getLength(); - if (length != componentDt.getLength()) { - throw new PdbException("Mismatch component type length on replacement: " + - replacementDt.getName()); - } - int ordinal = component.getOrdinal(); - replaceComponent(compositeDB, ordinal, replacementDt); - return true; - } - } - return false; - } - - private static void replaceComponent(Composite composite, int ordinal, DataType newType) - throws PdbException { - if (composite instanceof Structure struct) { - DataTypeComponent dtc = struct.getComponent(ordinal); - struct.replace(ordinal, newType, newType.getLength(), dtc.getFieldName(), - dtc.getComment()); - } - else if (composite instanceof Union union) { - DataTypeComponent dtc = union.getComponent(ordinal); - union.delete(ordinal); - union.insert(ordinal, newType, newType.getLength(), dtc.getFieldName(), - dtc.getComment()); - } - else { - throw new PdbException("Not struct or union: " + composite.getClass().getSimpleName()); - } - } - } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java index 9389c902ae..0098f52f78 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java @@ -15,7 +15,8 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import ghidra.app.util.bin.format.pdb2.pdbreader.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.MsSymbolIterator; +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractDataMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.program.model.address.Address; @@ -47,14 +48,13 @@ public class DataSymbolApplier extends MsSymbolApplier @Override public void apply(MsSymbolIterator iter) throws PdbException, CancelledException { getValidatedSymbol(iter, true); + Address address = applicator.getAddress(symbol); + if (applicator.isInvalidAddress(address, symbol.getName())) { + return; + } + // createData() can return false on failure, but we want to put the symbol down regardless + createData(address); Address symbolAddress = applicator.getAddress(symbol); - if (applicator.isInvalidAddress(symbolAddress, symbol.getName())) { - return; - } - RecordNumber typeRecordNumber = symbol.getTypeRecordNumber(); - if (!createData(symbol, symbolAddress, typeRecordNumber)) { - return; - } applicator.createSymbol(symbolAddress, symbol.getName(), false); } @@ -62,36 +62,29 @@ public class DataSymbolApplier extends MsSymbolApplier public void applyTo(NestingSymbolApplier applyToApplier, MsSymbolIterator iter) throws PdbException, CancelledException { getValidatedSymbol(iter, true); - if (applyToApplier instanceof FunctionSymbolApplier) { - FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applyToApplier; - DataType dataType = applicator.getCompletedDataType(symbol.getTypeRecordNumber()); - if (dataType == null) { // TODO: check that we can have null here. - return; // silently return. - } + if (applyToApplier instanceof FunctionSymbolApplier functionSymbolApplier) { Address address = applicator.getAddress(symbol); - if (!createData(symbol, address, dataType)) { - return; + if (applicator.isInvalidAddress(address, symbol.getName())) { + return; // silently return } + // createData() can return false on failure, but we want to put the symbol down regardless + createData(address); + DataType dataType = applicator.getCompletedDataType(symbol.getTypeRecordNumber()); functionSymbolApplier.setLocalVariable(address, symbol.getName(), dataType); } } MsTypeApplier getTypeApplier(AbstractMsSymbol abstractSymbol) { - if (!(abstractSymbol instanceof AbstractDataMsSymbol symbol)) { + if (!(abstractSymbol instanceof AbstractDataMsSymbol dataSymbol)) { throw new AssertException( "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); } - return applicator.getTypeApplier(symbol.getTypeRecordNumber()); + return applicator.getTypeApplier(dataSymbol.getTypeRecordNumber()); } - boolean createData(AbstractDataMsSymbol symbol, Address address, RecordNumber typeRecordNumber) - throws CancelledException, PdbException { - DataType dataType = applicator.getCompletedDataType(typeRecordNumber); - return createData(symbol, address, dataType); - } - - boolean createData(AbstractDataMsSymbol symbol, Address address, DataType dataType) { - if (applicator.isInvalidAddress(address, symbol.getName())) { + boolean createData(Address address) throws CancelledException, PdbException { + DataType dataType = applicator.getCompletedDataType(symbol.getTypeRecordNumber()); + if (dataType == null) { // TODO: check that we can have null here. return false; } if (applicator.getImageBase().equals(address) && @@ -121,7 +114,7 @@ public class DataSymbolApplier extends MsSymbolApplier if (cu != null) { if ((cu instanceof Instruction) || !address.equals(cu.getAddress())) { applicator.appendLogMsg("Warning: Did not create data type \"" + - dataType.getDisplayName() + "\" at address " + address + " due to conflict"); + dataType.getName() + "\" at address " + address + " due to conflict"); return; } Data d = (Data) cu; 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 cdf13c4c60..3f7452fa9e 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 @@ -35,6 +35,7 @@ import ghidra.app.util.bin.format.pe.cli.tables.CliAbstractTableRow; import ghidra.app.util.importer.MessageLog; import ghidra.app.util.pdb.PdbCategories; import ghidra.framework.options.Options; +import ghidra.program.database.data.DataTypeUtilities; import ghidra.program.disassemble.DisassemblerContextImpl; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSet; @@ -137,16 +138,17 @@ public class DefaultPdbApplicator implements PdbApplicator { PdbRegisterNameToProgramRegisterMapper registerNameToRegisterMapper; //============================================================================================== + private MultiphaseDataTypeResolver multiphaseResolver; private int resolveCount; + private int conflictCount; private PdbCategories categoryUtils; private PdbPrimitiveTypeApplicator pdbPrimitiveTypeApplicator; private TypeApplierFactory typeApplierParser; - // We may need to put one or more of the following maps into the "analysis state" for access by + // We may need to put the following map into the "analysis state" for access by // a second PDB analyzer to do the "deferred" processing of functions. Then a mandatory - // second PDB analyzer would, at a minimum, remove the maps from the analysis state. - private Map dataTypeIdByMsTypeNum; - private Map dataTypeImplByMsTypeNum; - private Map classTypeByMsTypeNum; + // second PDB analyzer would, at a minimum, remove the map from the analysis state. + private Map dataTypeByMsTypeNum; + private Map classTypeByMsTypeNum; private ComplexTypeMapper complexTypeMapper; /** * This namespace map documents as follows: @@ -316,6 +318,7 @@ public class DefaultPdbApplicator implements PdbApplicator { PdbResearch.initBreakPointRecordNumbers(); // for developmental debug resolveCount = 0; + conflictCount = 0; // PdbResearch.childWalk(this, monitor); @@ -332,6 +335,7 @@ public class DefaultPdbApplicator implements PdbApplicator { // PdbResearch.developerDebugOrder(this, monitor); Msg.info(this, "resolveCount: " + resolveCount); + Msg.info(this, "conflictCount: " + conflictCount); // Currently, defining classes needs to have a program. When this is no longer true, // then this call can be performed with the data types only work. @@ -437,10 +441,9 @@ public class DefaultPdbApplicator implements PdbApplicator { pdbAddressManager = new PdbAddressManager(this, imageBase); categoryUtils = setPdbCatogoryUtils(pdb.getFilename()); - initializePlaceholders(); + multiphaseResolver = new MultiphaseDataTypeResolver(this); pdbPrimitiveTypeApplicator = new PdbPrimitiveTypeApplicator(dataTypeManager); - dataTypeIdByMsTypeNum = new HashMap<>(); - dataTypeImplByMsTypeNum = new HashMap<>(); + dataTypeByMsTypeNum = new HashMap<>(); classTypeByMsTypeNum = new HashMap<>(); complexTypeMapper = new ComplexTypeMapper(); typeApplierParser = new TypeApplierFactory(this); @@ -495,7 +498,7 @@ public class DefaultPdbApplicator implements PdbApplicator { imageBase = (imageBaseParam != null) ? imageBaseParam : program.getImageBase(); } - private List createSymbolGroups() throws CancelledException, PdbException { + private List createSymbolGroups() throws CancelledException { List mySymbolGroups = new ArrayList<>(); PdbDebugInfo debugInfo = pdb.getDebugInfo(); if (debugInfo == null) { @@ -684,14 +687,6 @@ public class DefaultPdbApplicator implements PdbApplicator { return categoryUtils.getAnonymousTypesCategory(); } - /** - * Returns the {@link CategoryPath} for Placeholder Types Category for the PDB - * @return the {@link CategoryPath} - */ - CategoryPath getPlaceholderTypesCategory() { - return categoryUtils.getPlaceholderTypesCategory(); - } - // /** // * Returns the name of what should be the next Anonymous Function (based on the count of // * the number of anonymous functions) so that there is a unique name for the function. @@ -754,130 +749,16 @@ public class DefaultPdbApplicator implements PdbApplicator { //============================================================================================== //============================================================================================== - private Map placeholderPointers; - private Set pointerIDs; - // Structure used to mock placeholder array. - private Map placeholderArrays; - private Set arrayIDs; - - private void initializePlaceholders() { - placeholderPointers = new HashMap<>(); - pointerIDs = new HashSet<>(); - placeholderArrays = new HashMap<>(); - arrayIDs = new HashSet<>(); - } - - private void cleanUpPlaceholders() throws CancelledException { - - TaskMonitor monitor = getMonitor(); - DataTypeManager dtm = getDataTypeManager(); - - // Remove placeholder arrays from DTM and from the Set - for (long id : arrayIDs) { - checkCancelled(); - DataType dt = dtm.getDataType(id); - Collection parents = dt.getParents(); - if (parents.size() == 0) { - dtm.remove(dt, monitor); - } - else { - Msg.warn(this, - "PDB: Could not eliminate parented placeholder array: " + dt.getName()); - } - } - arrayIDs.clear(); - arrayIDs = null; - - // Eliminate array placeholder map - placeholderArrays.clear(); - placeholderArrays = null; - - // Not removing placeholder pointers from DTM, but we are eliminating them from the Set - pointerIDs.clear(); - pointerIDs = null; - - // Eliminate pointer placeholder map - placeholderPointers.clear(); - placeholderPointers = null; - } - - Pointer getPlaceholderPointer(int size) throws PdbException { - Pointer pointer = placeholderPointers.get(size); - if (pointer != null) { - return pointer; - } - DataTypeManager dtm = getDataTypeManager(); - pointer = new PointerDataType(null, size, dtm); - pointer = (Pointer) resolve(pointer); - long id = dtm.getID(pointer); - if (id == -1) { - throw new PdbException("Could not create placeholder pointer."); - } - placeholderPointers.put(size, pointer); - pointerIDs.add(id); - return pointer; - } - - boolean isPlaceholderPointer(DataType pointer) { - // need this check for unresolved member types (such as primitives or bit-fields) - if (pointer instanceof DataTypeImpl || pointer instanceof BitFieldDataType) { - return false; - } - long id = getDataTypeManager().getID(pointer); - return pointerIDs.contains(id); - } - - private record PlaceholderArrayKey(int arraySize, int alignment) {} - - // Using a structure as a mock array because we can set both size and alignment, which - // is what needs to be consistent with the final real array when used in a containing - // composite. - DataType getPlaceholderArray(int arraySize, int alignment) throws PdbException { - PlaceholderArrayKey key = new PlaceholderArrayKey(arraySize, alignment); - Structure placeholderArray = placeholderArrays.get(key); - if (placeholderArray != null) { - return placeholderArray; - } - - DataTypeManager dtm = getDataTypeManager(); - String name = String.format("placeholder_array_%08x_%02x", arraySize, alignment); - placeholderArray = - new StructureDataType(getPlaceholderTypesCategory(), name, arraySize, dtm); - placeholderArray.align(alignment); - if (arraySize == 0) { - // For the zero-length, we need to enable packing to prevent the placeholder array - // (actual structure) from reporting itself as "not yet defined." - placeholderArray.setPackingEnabled(true); - } - placeholderArray = (Structure) resolve(placeholderArray); - - long id = dtm.getID(placeholderArray); - if (id == -1) { - throw new PdbException("Could not create array placeholder."); - } - placeholderArrays.put(key, placeholderArray); - arrayIDs.add(id); - return placeholderArray; - } - - boolean isPlaceholderArray(DataType array) { - return array.getCategoryPath().equals(getPlaceholderTypesCategory()); - } - - boolean isPlaceholderType(DataType type) { - return isPlaceholderPointer(type) || isPlaceholderArray(type); - } - - //============================================================================================== - //============================================================================================== - //============================================================================================== - /** * Returns the processed Ghidra class type associated with the PDB type record number. Causes * the type to be processed if it already has not been. *

* This method is intended to be used by "Consumers" that need the type after all type - * creation is complete. + * creation is complete (i.e., symbol appliers). Thus, an additional resolve step is added + * here because the internal processing of PDB data types does not resolve pointers and + * structures used to stub certain pointers (member pointers and other larger-than-64-bit + * pointers) and we assume that a consumer is going to lay down this type in a program, so + * we make sure that it is resolved. * @param recordNumber the record number of the type needed * @return the Ghidra data type * @throws CancelledException upon user cancellation @@ -885,23 +766,19 @@ public class DefaultPdbApplicator implements PdbApplicator { * @see #getDataType(AbstractMsType) * @see #getDataType(RecordNumber) */ - DataType getCompletedDataType(RecordNumber recordNumber) //************************************************ 5 REFS + DataType getCompletedDataType(RecordNumber recordNumber) throws CancelledException, PdbException { DataType dataType = getDataType(recordNumber); if (dataType instanceof DataTypeImpl) { if (!(dataType instanceof BuiltInDataType)) { - AbstractMsType type = getPdb().getTypeRecord(recordNumber); - Msg.info(this, "Type not resolved for record: " + recordNumber + "; " + - type.getClass().getSimpleName()); + dataType = resolve(dataType); + putDataType(recordNumber, dataType); } } else if (dataType == null) { - AbstractMsType type = getPdb().getTypeRecord(recordNumber); - Msg.info(this, "Type not completed for record: " + recordNumber + "; " + + AbstractMsType type = getTypeRecord(recordNumber); + throw new PdbException("Type not completed for record: " + recordNumber + "; " + type.getClass().getSimpleName()); - FixupContext fixupContext = new FixupContext(); - fixupContext.addStagedRecord(recordNumber.getNumber()); - dataType = getProcessedDataType(recordNumber, fixupContext, false); } return dataType; } @@ -914,40 +791,20 @@ public class DefaultPdbApplicator implements PdbApplicator { * @param dataType the data type to store */ void putDataType(AbstractMsType msType, DataType dataType) { - Integer number = getNumber(msType); - putDataType(number, dataType); + RecordNumber recordNumber = msType.getRecordNumber(); + putDataType(recordNumber, dataType); } /** - * Stores the Ghidra data type associated with the PDB data type. + * Stores the Ghidra data type associated with the PDB record number. * This method is intended to be used by appliers that work on this specific type, not by * appliers that need the data type - * @param number number of type record + * @param recordNumber record number of type record * @param dataType the data type to store */ - void putDataType(Integer number, DataType dataType) { - DataType existing = getDataType(number); // could be null - if (existing == dataType) { - return; - } - if (existing != null) { - if (dataType.isEquivalent(existing)) { - if (!(existing instanceof DataTypeImpl) || dataType instanceof DataTypeImpl) { - return; - } - } - else if (isDefinedComposite(existing)) { - //TODO: Need to investigate how to deal with this.... we are only storing one, so - // how do we know we have the correct one... we should know by what the fwdref was... - // record-number-wise. - if (isDefinedComposite(dataType)) { - appendLogMsg("Existing and Replacement datatypes are both keepers:\n" + - existing + "\n" + dataType + "\n"); - } - return; - } - } - putDataTypeInternal(number, dataType); + void putDataType(RecordNumber recordNumber, DataType dataType) { + RecordNumber mappedNumber = getMappedRecordNumber(recordNumber); + dataTypeByMsTypeNum.put(mappedNumber, dataType); } /** @@ -958,15 +815,12 @@ public class DefaultPdbApplicator implements PdbApplicator { * @return the Ghidra data type */ DataType getDataType(AbstractMsType msType) { - Integer number = getNumber(msType); - if (number == null) { - return null; - } - return getDataType(number); + RecordNumber recordNumber = msType.getRecordNumber(); + return getDataType(recordNumber); } /** - * Returns the Ghidra data type associated with the PDB type record number. + * Returns the Ghidra data type associated with the PDB record number. *

* This method is intended to be used by appliers that work on this specific type, not by * appliers that need the data type @@ -975,48 +829,25 @@ public class DefaultPdbApplicator implements PdbApplicator { * @see #getDataType(AbstractMsType) */ DataType getDataType(RecordNumber recordNumber) { - if (recordNumber.getCategory() != RecordCategory.TYPE) { - return null; - } - return getDataType(recordNumber.getNumber()); + RecordNumber mappedNumber = getMappedRecordNumber(recordNumber); + return dataTypeByMsTypeNum.get(mappedNumber); } /** - * Returns the Ghidra data type associated with the PDB data type number. + * Returns the Ghidra data type associated with the PDB record number. * This method is intended to be used by appliers that work on this specific type, not by * appliers that need the data type - * @param number the PDB type record number + * @param recordNumber the PDB type record number * @return the Ghidra data type */ - DataType getDataType(Integer number) { - Integer mappedNumber = getMappedComplexType(number); - Long ID = dataTypeIdByMsTypeNum.get(mappedNumber); - if (ID == null) { - return dataTypeImplByMsTypeNum.get(mappedNumber); - } - return dataTypeManager.getDataType(ID); - } - - private boolean isDefinedComposite(DataType dt) { - return (dt instanceof Composite comp && comp.getNumDefinedComponents() > 0); - } - - private void putDataTypeInternal(Integer number, DataType dataType) { - Integer mappedNumber = getMappedComplexType(number); - if (dataType instanceof DataTypeImpl impl) { - if (!(dataType instanceof BuiltInDataType)) { - Msg.warn(this, "PDB: Unexpected Impl storage: " + impl.getClass().getSimpleName()); - } - dataTypeImplByMsTypeNum.put(mappedNumber, impl); - } - else { - long dataTypeID = dataTypeManager.getID(dataType); - if (dataTypeID == -1) { - // Error, such as DataType is not DB version - return; - } - dataTypeIdByMsTypeNum.put(mappedNumber, dataTypeID); + DataType getDataTypeOrSchedule(RecordNumber recordNumber) { + RecordNumber mappedNumber = getMappedRecordNumber(recordNumber); + DataType dt = dataTypeByMsTypeNum.get(mappedNumber); + if (dt != null) { + return dt; } + multiphaseResolver.scheduleTodo(recordNumber); + return null; } //============================================================================================== @@ -1028,8 +859,8 @@ public class DefaultPdbApplicator implements PdbApplicator { * @param classType the class to store */ void putClassType(AbstractMsType msType, CppCompositeType classType) { - Integer number = getNumber(msType); - CppCompositeType existing = getClassType(number); + RecordNumber recordNumber = msType.getRecordNumber(); + CppCompositeType existing = getClassType(recordNumber); if (existing == classType) { return; } @@ -1038,7 +869,7 @@ public class DefaultPdbApplicator implements PdbApplicator { "Existing class type; not replacing:\n" + existing + "\n" + classType + "\n"); return; } - putClassType(number, classType); + putClassType(recordNumber, classType); } /** @@ -1051,35 +882,78 @@ public class DefaultPdbApplicator implements PdbApplicator { * @see #getDataType(RecordNumber) */ CppCompositeType getClassType(AbstractMsType msType) { - Integer number = getNumber(msType); - return getClassType(number); + return getClassType(msType.getRecordNumber()); } - private CppCompositeType getClassType(Integer number) { - return classTypeByMsTypeNum.get(getMappedComplexType(number)); + private CppCompositeType getClassType(RecordNumber recordNumber) { + return classTypeByMsTypeNum.get(getMappedRecordNumber(recordNumber)); } - private void putClassType(Integer number, CppCompositeType classType) { - Integer mappedNumber = getMappedComplexType(number); + private void putClassType(RecordNumber recordNumber, CppCompositeType classType) { + RecordNumber mappedNumber = getMappedRecordNumber(recordNumber); classTypeByMsTypeNum.put(mappedNumber, classType); } //============================================================================================== - // Might change this to private if removed use from CompositeTypeApplier - Integer getNumber(AbstractMsType msType) { - if (msType == null) { - return null; - } - RecordNumber recordNumber = msType.getRecordNumber(); - if (recordNumber == null || recordNumber.getCategory() != RecordCategory.TYPE) { - return null; - } - return recordNumber.getNumber(); + /** + * Returns the record for the associated record number, which is expected to match the + * desired class + * @param recordNumber the record number + * @return the record + */ + public AbstractMsType getTypeRecord(RecordNumber recordNumber) { + return pdb.getTypeRecord(recordNumber, AbstractMsType.class); } + /** + * Returns the record for the mapped associated record number, which is expected to match the + * desired class + * @param recordNumber the record number + * @return the record + */ + public AbstractMsType getMappedTypeRecord(RecordNumber recordNumber) { + RecordNumber mappedNumber = getMappedRecordNumber(recordNumber); + return pdb.getTypeRecord(mappedNumber, AbstractMsType.class); + } + + /** + * Returns the record for the associated record number, which is expected to match the + * desired class + * @param class return type + * @param recordNumber record number + * @param typeClass desired class type for return + * @return the record + */ + public T getTypeRecord(RecordNumber recordNumber, + Class typeClass) { + return pdb.getTypeRecord(recordNumber, typeClass); + } + + /** + * Returns the record for the mapped associated record number, which is expected to match the + * desired class + * @param class return type + * @param recordNumber record number + * @param typeClass desired class type for return + * @return the record + */ + public T getMappedTypeRecord(RecordNumber recordNumber, + Class typeClass) { + RecordNumber mappedNumber = getMappedRecordNumber(recordNumber); + return pdb.getTypeRecord(mappedNumber, typeClass); + } + + //============================================================================================== // Might change this to private if removed use from CompositeTypeApplier - Integer getMappedComplexType(Integer input) { - return complexTypeMapper.getMapped(input); + /** + * Returns map to alternate record number or argument record number if no map. Result is + * RecordNumber of alternative record for the complex type. Map is of fwdref to definition + * RecordNumbers. The fwdref number is generally, but not always, the lower number + * @param recordNumber the record number for which to do the lookup + * @return the mapped record number or the original record number if no mapped entry + */ + RecordNumber getMappedRecordNumber(RecordNumber recordNumber) { + return complexTypeMapper.getMapped(recordNumber); } //============================================================================================== @@ -1115,98 +989,24 @@ public class DefaultPdbApplicator implements PdbApplicator { for (int indexNumber = tpi.getTypeIndexMin(); indexNumber < tpi .getTypeIndexMaxExclusive(); indexNumber++) { monitor.checkCancelled(); - processAndResolve(indexNumber); + RecordNumber recordNumber = RecordNumber.typeRecordNumber(indexNumber); + RecordNumber mappedNumber = getMappedRecordNumber(recordNumber); + multiphaseResolver.process(mappedNumber); monitor.incrementProgress(1); } - // Might need to do this later (after typedefs and symbols)... TODO: figure this out - cleanUpPlaceholders(); + doCheck(); } - private void processAndResolve(int indexNumber) throws CancelledException, PdbException { - DataType dt = getDataType(indexNumber); - if (dt != null && !(dt instanceof DataTypeImpl)) { - return; - } - RecordNumber recordNumber = RecordNumber.typeRecordNumber(indexNumber); - AbstractMsType msType = pdb.getTypeRecord(recordNumber); - MsTypeApplier applier = getTypeApplier(recordNumber); - if (applier instanceof CompositeTypeApplier) { - FixupContext fixupContext = new FixupContext(); - int mappedNumber = getMappedComplexType(indexNumber); - fixupContext.moveToHeadProcessRecord(mappedNumber); - DataType dataType = applier.apply(msType, fixupContext, false); - fixupContext.moveProcessToFixupsRecord(mappedNumber, dataType); - fixUpTypes(fixupContext); - } - else { - DataType dataType = applier.apply(msType, null, true); - } - } - - DataType getProcessedDataType(RecordNumber recordNumber, FixupContext fixupContext, - boolean breakCycle) throws CancelledException, PdbException { - int mappedNumber = getMappedComplexType(recordNumber.getNumber()); - AbstractMsType type = pdb.getTypeRecord(RecordNumber.typeRecordNumber(mappedNumber)); - MsTypeApplier applier = getTypeApplier(recordNumber); - - if (fixupContext == null) { - return applier.apply(type, fixupContext, breakCycle); - } - - if (!(applier instanceof CompositeTypeApplier) && - !(applier instanceof ModifierTypeApplier)) { - return applier.apply(type, fixupContext, breakCycle); - } - - DataType dataType = getDataType(mappedNumber); - if (dataType != null) { - return dataType; - } - dataType = fixupContext.getFixupDataType(mappedNumber); - if (dataType != null) { - return dataType; - } - - fixupContext.ensureInContext(mappedNumber); - if (breakCycle) { - return null; - } - - fixupContext.moveToHeadProcessRecord(mappedNumber); - dataType = applier.apply(type, fixupContext, breakCycle); - fixupContext.moveProcessToFixupsRecord(mappedNumber, dataType); - - return dataType; - } - - private void fixUpTypes(FixupContext fixupContext) throws PdbException, CancelledException { - - Integer recordToProcess; - while ((recordToProcess = fixupContext.peekStagedRecord()) != null) { - checkCancelled(); - RecordNumber recordNumber = RecordNumber.typeRecordNumber(recordToProcess); - AbstractMsType msType = pdb.getTypeRecord(recordNumber); - MsTypeApplier applier = getTypeApplier(recordNumber); - fixupContext.moveFromStagedToProcessRecord(); - DataType dataType = applier.apply(msType, fixupContext, false); - fixupContext.moveProcessToFixupsRecord(recordToProcess, dataType); - } - - while ((recordToProcess = fixupContext.peekFixupsRecord()) != null) { - checkCancelled(); - RecordNumber recordNumber = RecordNumber.typeRecordNumber(recordToProcess); - AbstractMsType msType = pdb.getTypeRecord(recordNumber); - MsTypeApplier applier = getTypeApplier(recordNumber); - if (applier instanceof CompositeTypeApplier fixupApplier) { - DataType dataType = applier.apply(msType, fixupContext, false); - if (dataType instanceof DataTypeImpl) { - appendLogMsg("Unexpected resolve for: " + dataType.getClass().getSimpleName()); - dataType = resolve(dataType); + private void doCheck() throws PdbException { + for (Map.Entry entry : dataTypeByMsTypeNum.entrySet()) { + DataType dt = entry.getValue(); + if (dt instanceof DataTypeImpl) { + if (!(dt instanceof Pointer) && !(dt instanceof BitFieldDataType) && + !(dt instanceof BuiltInDataType)) { + throw new PdbException("Type not fully processed: " + entry.getKey()); } - fixupApplier.fixUp(fixupContext); } - fixupContext.popFixupsRecord(); } } @@ -1240,7 +1040,7 @@ public class DefaultPdbApplicator implements PdbApplicator { String filename = entry.getKey(); PdbLog.message("FileName: " + filename); for (RecordNumber recordNumber : entry.getValue()) { - AbstractMsType msType = pdb.getTypeRecord(recordNumber); + AbstractMsType msType = getTypeRecord(recordNumber); PdbLog.message(recordNumber.toString() + "\n" + msType); } } @@ -1249,7 +1049,7 @@ public class DefaultPdbApplicator implements PdbApplicator { int moduleNumber = entry.getKey(); PdbLog.message("ModuleNumber: " + moduleNumber); for (RecordNumber recordNumber : entry.getValue()) { - AbstractMsType msType = pdb.getTypeRecord(recordNumber); + AbstractMsType msType = getTypeRecord(recordNumber); PdbLog.message(recordNumber.toString() + "\n" + msType); } } @@ -1271,11 +1071,13 @@ public class DefaultPdbApplicator implements PdbApplicator { .getTypeIndexMaxExclusive(); indexNumber++) { monitor.checkCancelled(); RecordNumber recordNumber = RecordNumber.itemRecordNumber(indexNumber); - AbstractMsType msType = pdb.getTypeRecord(recordNumber); + AbstractMsType msType = getTypeRecord(recordNumber); MsTypeApplier applier = getTypeApplier(recordNumber); - FixupContext fixupContext = new FixupContext(); - fixupContext.addStagedRecord(indexNumber); - applier.apply(msType, fixupContext, false); // fixupContext and breakCycle meaningless here? + // TODO: Need to decide what work gets done for ITEM types and craft interface for + // calling methods for doing work. Perhaps something like the following: +// if (applier instanceof MsItemTypeApplier itemApplier) { +// itemApplier.apply(msType); +// } monitor.incrementProgress(1); } } @@ -1296,6 +1098,9 @@ public class DefaultPdbApplicator implements PdbApplicator { DataType resolved = getDataTypeManager().resolve(dataType, DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER); resolveCount++; + if (DataTypeUtilities.isConflictDataType(resolved)) { + conflictCount++; + } return resolved; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java index 60377a9df3..942bbdf9f7 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java @@ -21,7 +21,6 @@ import ghidra.app.util.SymbolPath; import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; import ghidra.program.model.data.*; -import ghidra.program.model.data.Enum; import ghidra.util.Msg; import ghidra.util.exception.CancelledException; @@ -32,17 +31,15 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { // Intended for: AbstractEnumMsType /** - * Constructor for enum type applier, for transforming a enum into a - * Ghidra DataType. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. + * Constructor for enum type applier, for transforming a enum into a Ghidra DataType + * @param applicator {@link DefaultPdbApplicator} for which this class is working */ public EnumTypeApplier(DefaultPdbApplicator applicator) { super(applicator); } - private long getMask(AbstractEnumMsType type, FixupContext fixupContext, boolean breakCycle) - throws CancelledException, PdbException { - switch (getLength(type, fixupContext, breakCycle)) { + private long getMask(AbstractEnumMsType type) { + switch (getLength(type)) { case 1: return 0xffL; case 2: @@ -54,24 +51,21 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { } } - private int getLength(AbstractEnumMsType type, FixupContext fixupContext, boolean breakCycle) - throws CancelledException, PdbException { - DataType underlyingDataType = getUnderlyingDataType(type, fixupContext, breakCycle); + private int getLength(AbstractEnumMsType type) { + DataType underlyingDataType = getUnderlyingDataType(type); if (underlyingDataType == null) { return 1; } return Integer.max(underlyingDataType.getLength(), 1); } - private DataType getUnderlyingDataType(AbstractEnumMsType type, FixupContext fixupContext, - boolean breakCycle) throws CancelledException, PdbException { + private DataType getUnderlyingDataType(AbstractEnumMsType type) { RecordNumber underlyingRecordNumber = type.getUnderlyingRecordNumber(); - return applicator.getProcessedDataType(underlyingRecordNumber, fixupContext, breakCycle); + return applicator.getDataType(underlyingRecordNumber); } - boolean isSigned(AbstractEnumMsType type, FixupContext fixupContext, boolean breakCycle) - throws CancelledException, PdbException { - DataType underlyingType = getUnderlyingDataType(type, fixupContext, breakCycle); + boolean isSigned(AbstractEnumMsType type) { + DataType underlyingType = getUnderlyingDataType(type); if (underlyingType == null) { return false; } @@ -81,8 +75,7 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { return false; } - private EnumDataType createEmptyEnum(AbstractEnumMsType type, FixupContext fixupContext, - boolean breakCycle) throws CancelledException, PdbException { + private EnumDataType createEmptyEnum(AbstractEnumMsType type) { AbstractEnumMsType defType = getDefinitionType(type); @@ -90,39 +83,31 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { CategoryPath categoryPath = applicator.getCategory(fixedPath.getParent()); EnumDataType enumDataType = new EnumDataType(categoryPath, fixedPath.getName(), - getLength(defType, fixupContext, breakCycle), applicator.getDataTypeManager()); + getLength(defType), applicator.getDataTypeManager()); return enumDataType; } @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) + boolean apply(AbstractMsType type) throws PdbException, CancelledException { //Ghidra cannot handle fwdrefs and separate definitions for enumerates as it can for // composites. Thus, we will just try to provide the defined version now. - Integer number = applicator.getNumber(type); - Integer mapped = applicator.getMappedComplexType(number); - AbstractEnumMsType definedEnum = (AbstractEnumMsType) applicator.getPdb() - .getTypeRecord(RecordNumber.typeRecordNumber(mapped)); + AbstractEnumMsType definedEnum = + (AbstractEnumMsType) applicator.getMappedTypeRecord(type.getRecordNumber()); - DataType existingDt = applicator.getDataType(mapped); - if (existingDt != null) { - if (!(existingDt instanceof Enum)) { - throw new PdbException("PDB error retrieving Enum type"); - } - return existingDt; - } + // Note that we do not need to check on underlying data types, as there are none. - EnumDataType enumDataType = createEmptyEnum(definedEnum, fixupContext, breakCycle); - applyEnumMsType(enumDataType, definedEnum, fixupContext, breakCycle); + EnumDataType enumDataType = createEmptyEnum(definedEnum); + applyEnumMsType(enumDataType, definedEnum); - DataType dataType = applicator.resolve(enumDataType); - applicator.putDataType(mapped, dataType); - return dataType; + DataType dataType = enumDataType; + applicator.putDataType(definedEnum, dataType); + return true; } - private EnumDataType applyEnumMsType(EnumDataType enumDataType, AbstractEnumMsType type, - FixupContext fixupContext, boolean breakCycle) throws PdbException, CancelledException { + private EnumDataType applyEnumMsType(EnumDataType enumDataType, AbstractEnumMsType type) + throws PdbException { if (enumDataType.getCount() != 0) { //already applied @@ -147,19 +132,18 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { enumerates.size() + " available for " + fullPathName); } - int length = getLength(type, fixupContext, breakCycle); - boolean isSigned = isSigned(type, fixupContext, breakCycle); + int length = getLength(type); + boolean isSigned = isSigned(type); for (AbstractEnumerateMsType enumerateType : enumerates) { SymbolPath memberSymbolPath = new SymbolPath(enumerateType.getName()); enumDataType.add(memberSymbolPath.getName(), narrowingConversion(type, length, isSigned, - enumerateType.getNumeric(), fixupContext, breakCycle)); + enumerateType.getNumeric())); } return enumDataType; } private long narrowingConversion(AbstractEnumMsType type, int outputSize, boolean outputSigned, - Numeric numeric, FixupContext fixupContext, boolean breakCycle) - throws CancelledException, PdbException { + Numeric numeric) { if (!numeric.isIntegral()) { Msg.info(this, "Non-integral numeric found: " + numeric); return 0; @@ -168,7 +152,7 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { pdbLogAndInfoMessage(this, "Using zero in place of non-integral enumerate: " + numeric); return 0L; // } - return numeric.getIntegral().longValue() & getMask(type, fixupContext, breakCycle); + return numeric.getIntegral().longValue() & getMask(type); } private AbstractEnumMsType getDefinitionType(AbstractComplexMsType type) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java index 6c6ec4aea1..cffb65b98c 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java @@ -16,37 +16,24 @@ package ghidra.app.util.pdb.pdbapplicator; import ghidra.app.util.bin.format.pdb2.pdbreader.Numeric; -import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractEnumerateMsType; -import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.app.util.pdb.PdbNamespaceUtils; import ghidra.program.model.data.DataType; -import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractEnumerateMsType} types. */ -public class EnumerateTypeApplier extends MsTypeApplier { +public class EnumerateTypeApplier extends MsDataTypeComponentApplier { // Intended for: AbstractEnumerateMsType /** - * Constructor for enumerate type applier, for transforming a enumerate into a - * Ghidra DataType. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. + * Constructor for enumerate type applier, for transforming a enumerate into a Ghidra DataType + * @param applicator {@link DefaultPdbApplicator} for which this class is working */ public EnumerateTypeApplier(DefaultPdbApplicator applicator) { super(applicator); } - @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { - DataType dataType = applyEnumerateMsType((AbstractEnumerateMsType) type); - //dataType is null for now... so no resolve - //return applicator.resolve(dataType); - return null; - } - String getName(AbstractEnumerateMsType type) { return PdbNamespaceUtils.fixUnnamed(type.getName(), type.getRecordNumber().getNumber()); } 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 8399cfd0a7..08b90eaee7 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 @@ -21,14 +21,12 @@ import java.util.List; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; -import ghidra.program.model.data.DataType; -import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractFieldListMsType} types and {@code NO_TYPE} when in place of the * former type. */ -public class FieldListTypeApplier extends MsTypeApplier { +public class FieldListTypeApplier extends MsDataTypeComponentApplier { //TODO: evaluate the static method and multiple constructors... what can be cleaned up with // regard to these and the possible NoType record??? @@ -46,35 +44,30 @@ public class FieldListTypeApplier extends MsTypeApplier { } /** - * Constructor. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. - * @throws IllegalArgumentException Upon invalid arguments. + * Constructor + * @param applicator {@link DefaultPdbApplicator} for which this class is working + * @throws IllegalArgumentException Upon invalid arguments */ public FieldListTypeApplier(DefaultPdbApplicator applicator) throws IllegalArgumentException { super(applicator); } - @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { - // do nothing - return null; - } - //============================================================================================== record FieldLists(List bases, List members, List nonstaticMembers, + List staticMembers, List vftPtrs, List methods, List nestedTypes, List enumerates) {} //============================================================================================== FieldLists getFieldLists(RecordNumber recordNumber) throws PdbException { - AbstractMsType type = applicator.getPdb().getTypeRecord(recordNumber); + AbstractMsType type = applicator.getTypeRecord(recordNumber); if (type instanceof PrimitiveMsType primitive && primitive.isNoType()) { return new FieldLists(new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), - new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); + new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), + new ArrayList<>()); } else if (type instanceof AbstractFieldListMsType fieldListType) { return getFieldLists(fieldListType); @@ -98,6 +91,8 @@ public class FieldListTypeApplier extends MsTypeApplier { } List nonstaticMembers = new ArrayList<>(fieldListType.getNonStaticMembers()); + List staticMembers = + new ArrayList<>(fieldListType.getStaticMembers()); List vftPtrs = new ArrayList<>(fieldListType.getVftPointers()); List nestedTypes = @@ -115,6 +110,7 @@ public class FieldListTypeApplier extends MsTypeApplier { members.addAll(lists.members()); methods.addAll(lists.methods()); nonstaticMembers.addAll(lists.nonstaticMembers()); + staticMembers.addAll(lists.staticMembers()); vftPtrs.addAll(lists.vftPtrs()); nestedTypes.addAll(lists.nestedTypes()); enumerates.addAll(lists.enumerates()); @@ -124,7 +120,8 @@ public class FieldListTypeApplier extends MsTypeApplier { } } - return new FieldLists(bases, members, nonstaticMembers, vftPtrs, methods, nestedTypes, + return new FieldLists(bases, members, nonstaticMembers, staticMembers, vftPtrs, methods, + nestedTypes, enumerates); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FixupContext.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FixupContext.java deleted file mode 100644 index 0cc8373b74..0000000000 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FixupContext.java +++ /dev/null @@ -1,313 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.app.util.pdb.pdbapplicator; - -import java.util.*; - -import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; -import ghidra.program.model.data.DataType; - -/** - * Applier context used for fixups of data types - */ -public class FixupContext { - - private Deque stagedRecordFifo = new ArrayDeque<>(); - private Deque inProgressRecordStack = new ArrayDeque<>(); - private Deque fixupRecordFifo = new ArrayDeque<>(); - - private Map> map = new HashMap<>(); - private Map fixupTypes = new HashMap<>(); - - /** - * Checks that record is already being processed and, if not, adds it to the Staged state - * @param record the number of the record - * @throws PdbException upon the record already in the process or fixup state - */ - void ensureInContext(int record) throws PdbException { - if (inProgressRecordStack.contains(record)) { - return; - } - if (fixupRecordFifo.contains(record)) { - return; - } - addStagedRecord(record); - } - - DataType getFixupDataType(int record) { - return fixupTypes.get(record); - } - - /** - * Adds record to the Staged state if not already there - * @param recordNumber the number of the record - * @throws PdbException upon the record already in the process or fixup state - */ - void addStagedRecord(int recordNumber) throws PdbException { - if (stagedRecordFifo.contains(recordNumber)) { - return; - } - if (inProgressRecordStack.contains(recordNumber)) { - throw new PdbException("Record Number in process state: " + recordNumber); - } - if (fixupRecordFifo.contains(recordNumber)) { - throw new PdbException("Record Number in fixup state: " + recordNumber); - } - if (map.containsKey(recordNumber)) { - throw new PdbException("Record Number already exists: " + recordNumber); - } - map.put(recordNumber, new ArrayList<>()); - putStagedRecord(recordNumber); - } - - /** - * Moves the next record in the Staged state to the process state and returns its number - * @return the number of the record moved - * @throws PdbException if the record happens to be in another state (should not happen if - * in the Staged state) - */ - Integer moveFromStagedToProcessRecord() throws PdbException { - Integer record = getStagedRecord(); - if (record != null) { - putProcessRecord(record); - } - return record; - } - - /** - * Puts the specified record number from the Staged state to the Process state - * @param number the number of the record - * @throws PdbException if the record is not in the Staged state - */ - void moveFromStagedToProcessRecord(int number) throws PdbException { - if (!stagedRecordFifo.remove(number)) { - throw new PdbException("Number not in Staged state: " + number); - } - putProcessRecord(number); - } - - /** - * Puts the specified record to the head of the Process state. If the record had been - * in the Staged state or anywhere else in the Process state, it is moved to the head of the - * Process state - * @param number the number of the record - * @throws PdbException if the records is not in the Staged state - */ - void moveToHeadProcessRecord(int number) throws PdbException { - if (stagedRecordFifo.contains(number)) { - stagedRecordFifo.remove(number); - } - else if (inProgressRecordStack.contains(number)) { - inProgressRecordStack.remove(number); - inProgressRecordStack.offerFirst(number); - } - else { - map.put(number, new ArrayList<>()); - } - putProcessRecord(number); - } - - /** - * Moves the specified record from the Process state to the Fixup state - * @param number the number of the record - * @param dataType the type that has been created for this in-progress type - * @throws PdbException if the record is not in the Process state - */ - void moveProcessToFixupsRecord(int number, DataType dataType) throws PdbException { - if (!inProgressRecordStack.remove(number)) { - throw new PdbException("Number not in process state: " + number); - } - if (fixupTypes.containsKey(number)) { - throw new PdbException("Number already in progress: " + number); - } - putFixupsRecord(number); - fixupTypes.put(number, dataType); - } - - /** - * Removes the next record from the Fixup state and returns the number - * @return the number - */ - Integer popFixupsRecord() { - Integer record = getFixupsRecord(); - if (record != null) { - if (map.containsKey(record)) { - map.remove(record); - } - if (fixupTypes.containsKey(record)) { - fixupTypes.remove(record); - } - } - return record; - } - - // Not sure we will use this method - /** - * Removes the head of the Process state and returns the number. The number is not moved - * to the Fixup state - * @return the number - */ - Integer popProcessRecord() { - Integer record = getProcessRecord(); - if (record != null) { - if (map.containsKey(record)) { - map.remove(record); - } - // Since pop from current, not adding to fixups - } - return record; - } - - private void putStagedRecord(int record) throws PdbException { - if (stagedRecordFifo.contains(record)) { - return; - } - if (inProgressRecordStack.contains(record)) { - throw new PdbException("Record exists in another state: " + record); - } - if (fixupRecordFifo.contains(record)) { - throw new PdbException("Record exists in another state: " + record); - } - stagedRecordFifo.addFirst(record); - } - - private Integer getStagedRecord() { - return stagedRecordFifo.pollLast(); - } - - /** - * Peeks at and returns the record number of the head of the Staged state - * @return the record number - */ - Integer peekStagedRecord() { - return stagedRecordFifo.peekLast(); - } - - private void putProcessRecord(int record) throws PdbException { - if (inProgressRecordStack.contains(record)) { - return; - } - if (stagedRecordFifo.contains(record)) { - throw new PdbException("Record exists in another state: " + record); - } - if (fixupRecordFifo.contains(record)) { - throw new PdbException("Record exists in another state: " + record); - } - inProgressRecordStack.addFirst(record); - } - - private Integer getProcessRecord() { - return inProgressRecordStack.pollFirst(); - } - - private void putFixupsRecord(int record) throws PdbException { - if (fixupRecordFifo.contains(record)) { - return; - } - if (stagedRecordFifo.contains(record)) { - throw new PdbException("Record exists in another state: " + record); - } - if (inProgressRecordStack.contains(record)) { - throw new PdbException("Record exists in another state: " + record); - } - fixupRecordFifo.addFirst(record); - } - - /** - * Peeks at and returns the record number of the head of the Process state - * @return the record number - */ - Integer peekProcessRecord() { - return inProgressRecordStack.peekFirst(); - } - - /** - * Removes and returns the record number of the head of the Fixup state - * @return the record number - */ - Integer getFixupsRecord() { - return fixupRecordFifo.pollLast(); - } - - /** - * Peeks at and returns the record number of the head of the Fixup state - * @return the record number - */ - Integer peekFixupsRecord() { - return fixupRecordFifo.peekLast(); - } - - //============================================================================================== - - /** - * Puts the fixup index into the fixups for the current head of the Process state - * @param fixupIndex the fixup index - * @throws PdbException if the head of the Process state is empty or is fixups cannot be found - */ - void putFixup(int fixupIndex) throws PdbException { - List fixups = getProcessFixups(); - fixups.add(fixupIndex); - } - - /** - * Returns true if the fixups for the current head of the Process state is empty - * @return {@code true} if empty - * @throws PdbException if there is no head of the Process state or its fixups cannot be found - */ - boolean processFixupsIsEmpty() throws PdbException { - List fixups = getProcessFixups(); - return fixups.isEmpty(); - } - - /** - * Peeks at and returns head of the Fixup state - * @return the number of the record - */ - Integer peekFixupRecord() { - return peekFixupsRecord(); - } - - /** - * Returns the fixups for the head of the Fixups state - * @return the fixup indices - * @throws PdbException if the head of the Fixups state does not exist or its fixups cannot be - * found - */ - List getFixups() throws PdbException { - Integer record = peekFixupsRecord(); - if (record == null) { - throw new PdbException("Empty fixups retrieval"); - } - List fixups = map.get(record); - if (fixups == null) { - throw new PdbException("Fixups not found on retrieval"); - } - return fixups; - } - - private List getProcessFixups() throws PdbException { - Integer record = peekProcessRecord(); - if (record == null) { - throw new PdbException("Context empty on fixups retrieval"); - } - List fixups = map.get(record); - if (fixups == null) { - throw new PdbException("Fixups not found"); - } - return fixups; - } - -} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java index 577ca44196..525914795f 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java @@ -132,7 +132,7 @@ public class FunctionSymbolApplier extends AbstractBlockContextApplier function.setNoReturn(isNonReturning()); - AbstractMsType fType = applicator.getPdb().getTypeRecord(typeRecordNumber); + AbstractMsType fType = applicator.getTypeRecord(typeRecordNumber); MsTypeApplier applier = applicator.getTypeApplier(fType); if (!(applier instanceof AbstractFunctionTypeApplier)) { applicator.appendLogMsg("Error: Failed to resolve datatype RecordNumber " + diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java index 6b972b937f..f91280744b 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java index a84a4f2a3a..c5ea7aaed5 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java @@ -19,7 +19,8 @@ import ghidra.app.util.SymbolPath; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; -import ghidra.program.model.data.*; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.Pointer; import ghidra.util.exception.CancelledException; /** @@ -30,33 +31,38 @@ public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier { // Intended for: AbstractMemberFunctionMsType /** * Constructor for the applicator that applies {@link AbstractMemberFunctionMsType}, - * transforming it into a Ghidra {@link DataType}. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. - * @throws IllegalArgumentException Upon type mismatch. + * transforming it into a Ghidra {@link DataType} + * @param applicator {@link DefaultPdbApplicator} for which this class is working + * @throws IllegalArgumentException Upon type mismatch */ public MemberFunctionTypeApplier(DefaultPdbApplicator applicator) throws IllegalArgumentException { super(applicator); } - private MsTypeApplier getThisPointerApplier(AbstractMemberFunctionMsType procType) { - MsTypeApplier applier = applicator.getTypeApplier(procType.getThisPointerRecordNumber()); - return applier; - } - @Override protected CallingConvention getCallingConvention(AbstractMsType type) { return ((AbstractMemberFunctionMsType) type).getCallingConvention(); } @Override - protected Pointer getThisPointer(AbstractMsType type, FixupContext fixupContext, - boolean breakCycle) throws CancelledException, PdbException { + protected RecordNumber getThisPointerRecordNumber(AbstractMsType type) { + return ((AbstractMemberFunctionMsType) type).getThisPointerRecordNumber(); + } + + @Override + protected RecordNumber getContainingComplexRecordNumber(AbstractMsType type) { + return ((AbstractMemberFunctionMsType) type).getContainingClassRecordNumber(); + } + + @Override + protected Pointer getThisPointer(AbstractMsType type) + throws CancelledException, PdbException { RecordNumber ptrRecord = ((AbstractMemberFunctionMsType) type).getThisPointerRecordNumber(); if (ptrRecord == null) { return null; } - AbstractMsType mType = applicator.getPdb().getTypeRecord(ptrRecord); + AbstractMsType mType = applicator.getTypeRecord(ptrRecord); if (mType instanceof PrimitiveMsType primitive && primitive.isNoType()) { return null; } @@ -64,44 +70,28 @@ public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier { predefineClass(msPtr.getUnderlyingRecordNumber()); } applicator.getPdbApplicatorMetrics().witnessMemberFunctionThisPointer(mType); - DataType dt = applicator.getProcessedDataType(ptrRecord, fixupContext, breakCycle); + DataType dt = applicator.getDataType(ptrRecord); if (dt instanceof Pointer ptr) { return ptr; } return null; } - @Override - protected Composite getContainingComplexApplier(AbstractMsType type, FixupContext fixupContext, - boolean breakCycle) throws CancelledException, PdbException { - RecordNumber containerRecord = - ((AbstractMemberFunctionMsType) type).getContainingClassRecordNumber(); - if (containerRecord == null) { - return null; - } - AbstractMsType mType = applicator.getPdb().getTypeRecord(containerRecord); - applicator.getPdbApplicatorMetrics().witnessMemberFunctionContainingType(mType); - DataType dt = applicator.getProcessedDataType(containerRecord, fixupContext, breakCycle); - if (dt instanceof Composite composite) { - return composite; - } - return null; - } - @Override protected void processContainingType(AbstractMsType type) { + // TODO: evaluate whether we need to schedule this container type... guessing not RecordNumber containerRecord = ((AbstractMemberFunctionMsType) type).getContainingClassRecordNumber(); if (containerRecord == null) { return; } predefineClass(containerRecord); - AbstractMsType mType = applicator.getPdb().getTypeRecord(containerRecord); + AbstractMsType mType = applicator.getTypeRecord(containerRecord); applicator.getPdbApplicatorMetrics().witnessMemberFunctionContainingType(mType); } private void predefineClass(RecordNumber recordNumber) { - AbstractMsType type = applicator.getPdb().getTypeRecord(recordNumber); + AbstractMsType type = applicator.getTypeRecord(recordNumber); if (!(type instanceof AbstractCompositeMsType msComposite)) { return; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java index b06b4041e0..ad1c7193eb 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java @@ -15,30 +15,20 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMemberMsType; -import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; -import ghidra.program.model.data.DataType; -import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractMemberMsType} types. */ -public class MemberTypeApplier extends MsTypeApplier { +public class MemberTypeApplier extends MsDataTypeComponentApplier { // Intended for: AbstractMemberMsType /** - * Constructor for member type applier. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. + * Constructor for member type applier + * @param applicator {@link DefaultPdbApplicator} for which this class is working */ public MemberTypeApplier(DefaultPdbApplicator applicator) { super(applicator); } - @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { - // do nothing - return null; - } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java index a8aebefdcb..8c26c90079 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -25,39 +25,30 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractModifierMsType} types. */ -public class ModifierTypeApplier extends MsTypeApplier { +public class ModifierTypeApplier extends MsDataTypeApplier { // Intended for: AbstractModifierMsType /** - * Constructor for modifier type applier. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. + * Constructor for modifier type applier + * @param applicator {@link DefaultPdbApplicator} for which this class is working */ public ModifierTypeApplier(DefaultPdbApplicator applicator) { super(applicator); } - RecordNumber getUnderlyingNonModifierRecordNumber(RecordNumber underlyingRecord) { - return getUnderlyingNonModifierRecordNumber(applicator, underlyingRecord); - } - - static RecordNumber getUnderlyingNonModifierRecordNumber(DefaultPdbApplicator applicator, - RecordNumber underlyingRecord) { - AbstractMsType underlyingType = applicator.getPdb().getTypeRecord(underlyingRecord); - while (underlyingType instanceof AbstractModifierMsType modifierType) { - RecordNumber modifiedRecord = modifierType.getModifiedRecordNumber(); - underlyingType = applicator.getPdb().getTypeRecord(modifiedRecord); - } - return underlyingType.getRecordNumber(); - } - @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { - AbstractModifierMsType modifierType = (AbstractModifierMsType) type; - RecordNumber modifiedRecord = modifierType.getModifiedRecordNumber(); + boolean apply(AbstractMsType type) throws PdbException, CancelledException { - DataType modifiedType = - applicator.getProcessedDataType(modifiedRecord, fixupContext, false); + AbstractModifierMsType modifierMsType = (AbstractModifierMsType) type; + // Doing pre-check on type first using the getDataTypeOrSchedule method. The logic is + // simpler here for Composites or Functions because we only have one dependency type, + // so we are not doing a separate call to a pre-check method as there is in those appliers. + // If type is not available, return false. + RecordNumber modifiedRecordNumber = modifierMsType.getModifiedRecordNumber(); + DataType modifiedType = applicator.getDataTypeOrSchedule(modifiedRecordNumber); + if (modifiedType == null) { + return false; + } // If Ghidra eventually has a modified type (const, volatile) in its model, then we can // perform the applicator.getDataType(modifierType) here, and the @@ -75,11 +66,14 @@ public class ModifierTypeApplier extends MsTypeApplier { // the underlying type of a Modifier to be a pointer. However, MSFT primitives include // pointers to primitives, so in these cases we could see a const pointer to primitive // where the const comes from the Modifier type. + DataType modifierType = modifiedType; -// if (modifiedType != null && !applicator.isPlaceholderType(modifiedType)) { - if (modifiedType != null) { - applicator.putDataType(modifierType, modifiedType); - } - return modifiedType; + // Store modified type as modifier type + applicator.putDataType(modifierMsType, modifierType); + // I'm hesitant to schedule resolve... what if I'm a pointer. Should I resolve + // modified pointers, modified other types, both, or neither? TODO; investigate + + return true; } + } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsDataTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsDataTypeApplier.java new file mode 100644 index 0000000000..27f3939109 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsDataTypeApplier.java @@ -0,0 +1,84 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; +import ghidra.util.exception.CancelledException; + +/** + * Abstract class representing the applier for a specific PDB_ID type, distinguished as + * representing an actual data type... not a component of a data type for which there is + * no associated type. + */ +public abstract class MsDataTypeApplier extends MsTypeApplier { + + /** + * Constructor. + * @param applicator {@link DefaultPdbApplicator} for which this class is working. + */ + public MsDataTypeApplier(DefaultPdbApplicator applicator) { + super(applicator); + } + + /** + * Apply the {@link AbstractMsType} in an attempt to create a Ghidra type + * @param type the PDB type to work on + * @return the {@code true} if type is done and can be removed from the {@code todoStack} + * @throws PdbException if there was a problem processing the data. + * @throws CancelledException upon user cancellation + */ + abstract boolean apply(AbstractMsType type) throws PdbException, CancelledException; + + /** + * Returns the (long) size of the type or 0 if unknown. Or Long.MAX_VALUE if too large. + * @param type the PDB type being inspected + * @return the size; zero if unknown. + */ + long getSizeLong(AbstractMsType type) { + return applicator.bigIntegerToLong(type.getSize()); + } + + /** + * Returns the (int) size of the type or 0 if unknown. Or Integer.MAX_VALUE if too large. + * @param type the PDB type being inspected + * @return the size; zero if unknown. + */ + int getSizeInt(AbstractMsType type) { + return applicator.bigIntegerToInt(type.getSize()); + } + + //============================================================================================== + // TODO: Need to investigate if we adopt the following... if so, should use them consistently. + +// /** +// * Convenience method for getting the {@link DataType} from the applicator pertaining +// * to this PDB type +// * @param type the PDB type +// * @return the ghidra data type +// */ +// DataType getDataType(AbstractMsType type) { +// return applicator.getDataType(type); +// } +// +// protected int getIndex(AbstractMsType type) { +// RecordNumber recordNumber = type.getRecordNumber(); +// if (recordNumber != null) { +// return recordNumber.getNumber(); +// } +// return -1; +// } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsDataTypeComponentApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsDataTypeComponentApplier.java new file mode 100644 index 0000000000..9ebb379081 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsDataTypeComponentApplier.java @@ -0,0 +1,32 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +/** + * Abstract class representing the applier for a specific PDB_ID type, distinguished as having + * components for an actual data type but not representing a data type in and of itself. + */ +public abstract class MsDataTypeComponentApplier extends MsTypeApplier { + + /** + * Constructor. + * @param applicator {@link DefaultPdbApplicator} for which this class is working. + */ + public MsDataTypeComponentApplier(DefaultPdbApplicator applicator) { + super(applicator); + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsTypeApplier.java index 2bc89487f1..14d9b668ba 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsTypeApplier.java @@ -15,11 +15,9 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.program.model.data.DataType; -import ghidra.util.exception.CancelledException; /** * Abstract class representing the applier for a specific PDB_ID type. The @@ -54,54 +52,4 @@ public abstract class MsTypeApplier { applicator.pdbLogAndInfoMessage(originator, message); } - /** - * Apply the {@link AbstractMsType} in an attempt to create a Ghidra type. - * @param type the PDB type to work on - * @param fixupContext the fixup context to use; or pass in null during fixup process - * @param breakCycle TODO - * @return the resultant DataType - * @throws PdbException if there was a problem processing the data. - * @throws CancelledException upon user cancellation - */ - abstract DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException; - - /** - * Returns the (long) size of the type or 0 if unknown. Or Long.MAX_VALUE if too large. - * @param type the PDB type being inspected - * @return the size; zero if unknown. - */ - long getSizeLong(AbstractMsType type) { - return applicator.bigIntegerToLong(type.getSize()); - } - - /** - * Returns the (int) size of the type or 0 if unknown. Or Integer.MAX_VALUE if too large. - * @param type the PDB type being inspected - * @return the size; zero if unknown. - */ - int getSizeInt(AbstractMsType type) { - return applicator.bigIntegerToInt(type.getSize()); - } - - //============================================================================================== - // TODO: Need to investigate if we adopt the following... if so, should use them consistently. - -// /** -// * Convenience method for getting the {@link DataType} from the applicator pertaining -// * to this PDB type -// * @param type the PDB type -// * @return the ghidra data type -// */ -// DataType getDataType(AbstractMsType type) { -// return applicator.getDataType(type); -// } -// -// protected int getIndex(AbstractMsType type) { -// RecordNumber recordNumber = type.getRecordNumber(); -// if (recordNumber != null) { -// return recordNumber.getNumber(); -// } -// return -1; -// } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MultiphaseDataTypeResolver.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MultiphaseDataTypeResolver.java new file mode 100644 index 0000000000..0d25925244 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MultiphaseDataTypeResolver.java @@ -0,0 +1,254 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.HashMap; +import java.util.Map; + +import ghidra.app.util.bin.format.pdb2.pdbreader.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; +import ghidra.program.model.data.*; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +/** + * Performs appropriated multiple passes on data types to get theme filled in and resolved + */ +public class MultiphaseDataTypeResolver { + + private DefaultPdbApplicator applicator; + private AbstractPdb pdb; + private TaskMonitor monitor; + + private RecordStack todoStack; + private RecordStack resolveStack; + + public MultiphaseDataTypeResolver(DefaultPdbApplicator applicator) { + this.applicator = applicator; + this.pdb = applicator.getPdb(); + this.monitor = applicator.getMonitor(); + todoStack = new RecordStack(); + resolveStack = new RecordStack(); + } + + /** + * Processes the data type associated with the record number and all dependencies of that + * type. Deals with cyclic dependencies and ultimately stores resolved (in most cases) + * types in the DefaultPdbApplicator types map + * @param recordNumber the record number + * @throws PdbException upon processing error + * @throws CancelledException upon user cancellation + */ + void process(RecordNumber recordNumber) throws PdbException, CancelledException { + + // If found in the applicator map then the type is completed. + if (applicator.getDataType(recordNumber) != null) { + return; + } + // If not in the map, it will also not be in the todo or resolve stacks, as both + // should be empty at this point. + scheduleTodo(recordNumber); + + RecordNumber recordToProcess; + // Peek at top of stack. If can be removed, it will be; otherwise other records can be + // pushed on top of this one for next loop cycle. + while ((recordToProcess = todoStack.peek()) != null) { + monitor.checkCancelled(); + MsDataTypeApplier dataTypeApplier = + (MsDataTypeApplier) applicator.getTypeApplier(recordToProcess); + AbstractMsType msType = pdb.getTypeRecord(recordToProcess); + // If processing is done, then pop from todoStack and put onto resolveStack. + // If not completed, the do not remove from todoStack. + if (dataTypeApplier.apply(msType)) { + if (todoStack.peek() != recordToProcess) { + throw new AssertException("Top of stack violation"); + } + todoStack.pop(); + resolveStack.push(recordToProcess); + } + } + + // Pop top of stack and work on it. + while ((recordToProcess = resolveStack.pop()) != null) { + monitor.checkCancelled(); + DataType dataType = applicator.getDataType(recordToProcess); + // Resolve and re-store most data types + if (!(dataType instanceof PointerDataType || dataType instanceof BitFieldDataType)) { + dataType = applicator.resolve(dataType); + applicator.putDataType(recordToProcess, dataType); + } + } + } + + /** + * Method used to schedule another type (indicated by the record number). This scheduled + * type is put on top of a stack of types to process, pushing what was the current type + * being processed down. If the type indicated by the record number is already on the stack, + * it is lifted to the top of the stack. Note that composite types (by virtue of the fact + * that impls for these are created and stored in the applicator map, but not filled in) will + * not be lifted to the top of the stack. This prevents oscillation on the stack and also + * is the mechanism by which dependency cycles are broken + * @param recordNumber the record number to be scheduled + */ + void scheduleTodo(RecordNumber recordNumber) { + MsTypeApplier applier = applicator.getTypeApplier(recordNumber); + if (!(applier instanceof MsDataTypeApplier dataTypeApplier)) { + // Return without scheduling... only want to schedule that that have a legitimate + // data type to store + return; + } + todoStack.push(recordNumber); + } + + /** + * Stack of record numbers with O(1) push/pop, O(1) contains, O(1) removal from + * anywhere, and thus O(1) move from anywhere to top. These nodes hold the RecordNumbers + * that are being scheduled + */ + static class RecordStack { + + static class RecordNode { + RecordNode next; + RecordNode prev; + RecordNumber recordNumber; + + /** + * Create new node for the record number. Note that the {@code next} and {@code prev} + * values are not set. They must be set by the RecordStack. + * @param recordNumber the record number + */ + private RecordNode(RecordNumber recordNumber) { + this.recordNumber = recordNumber; + } + } + + static final RecordNumber HEAD = RecordNumber.typeRecordNumber(-1); + static final RecordNumber TAIL = RecordNumber.typeRecordNumber(-2); + Map map; + RecordNode head; + RecordNode tail; + + /** + * Constructor for new record stack + */ + RecordStack() { + // head and tail are not put into the map + map = new HashMap<>(); + head = new RecordNode(HEAD); + tail = new RecordNode(TAIL); + head.next = null; + head.prev = tail; + tail.next = head; + tail.prev = null; + } + + /** + * Indicates if number number exists on stack + * @param recordNumber the record number to check + * @return {@code true} if exists + */ + boolean contains(RecordNumber recordNumber) { + return map.containsKey(recordNumber); + } + + /** + * Pushes the record number onto the top of the stack. If the record number was already + * on the stack, it is moved to the top + * @param recordNumber the record number to push + */ + void push(RecordNumber recordNumber) { + RecordNode node = getNode(recordNumber); + if (node == head.prev) { + return; // already on top of stack + } + if (node == null) { + node = new RecordNode(recordNumber); + map.put(recordNumber, node); + } + else { // already exists in non-top-of-stack position + removeNodeLinkage(node); + } + insertNodeLinkage(head, node); + } + + /** + * Peek at top node + * @return the node's record number or {@code null} if if no nodes left + */ + RecordNumber peek() { + RecordNode node = getTop(); + if (node == tail) { + return null; + } + return node.recordNumber; + } + + /** + * Pop top node + * @return the popped node's record number or {@code null} if if no nodes left + */ + RecordNumber pop() { + RecordNode node = getTop(); + if (node == tail) { + return null; + } + removeNodeLinkage(node); + map.remove(node.recordNumber); + return node.recordNumber; + } + + /** + * Get node for the record number + * @return the node + */ + private RecordNode getNode(RecordNumber recordNumber) { + return map.get(recordNumber); + } + + /** + * Get top node + * @return the node + */ + private RecordNode getTop() { + return head.prev; + } + + /** + * Add node to the stack. Gets placed below locationNode, which can be head for pushing + * onto the stack + */ + private void insertNodeLinkage(RecordNode locationNode, RecordNode newNode) { + newNode.next = locationNode; + newNode.prev = locationNode.prev; + locationNode.prev.next = newNode; + locationNode.prev = newNode; + } + + /** + * Remove node from bidirectional linkage + * @param node the node to remove; must not be {@code head}, {@code tail}, or {@code null} + */ + private void removeNodeLinkage(RecordNode node) { + node.prev.next = node.next; + node.next.prev = node.prev; + node.prev = null; + node.next = null; + } + + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java index 26cddcf2e2..46291a1059 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java @@ -15,16 +15,12 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; -import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; -import ghidra.program.model.data.DataType; -import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractNestedTypeMsType} and {@link AbstractNestedTypeExtMsType} types. */ -public class NestedTypeApplier extends MsTypeApplier { +public class NestedTypeApplier extends MsDataTypeComponentApplier { // Intended for: AbstractNestedTypeMsType or AbstractNestedTypeExtMsType /** @@ -53,25 +49,6 @@ public class NestedTypeApplier extends MsTypeApplier { return ""; } - @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { - RecordNumber typeRecordNumber; - if (type instanceof AbstractNestedTypeMsType nestedType) { - typeRecordNumber = nestedType.getNestedTypeDefinitionRecordNumber(); - } - else if (type instanceof AbstractNestedTypeExtMsType extNestedType) { - typeRecordNumber = extNestedType.getNestedTypeDefinitionRecordNumber(); - } - else { - throw new PdbException( - "Unexpected nested type in field list: " + type.getClass().getSimpleName()); - } - AbstractMsType mType = applicator.getPdb().getTypeRecord(typeRecordNumber); - MsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber); - return applier.apply(mType, fixupContext, breakCycle); - } - private static AbstractMsType validateType(AbstractMsType type) throws IllegalArgumentException { if (!(type instanceof AbstractNestedTypeMsType) && @@ -81,4 +58,5 @@ public class NestedTypeApplier extends MsTypeApplier { } return type; } + } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java index 6e39a1130d..19c3951f96 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java @@ -15,11 +15,6 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; -import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; -import ghidra.program.model.data.DataType; -import ghidra.util.exception.CancelledException; - /** * Used for creating a wrapper for when there is not associated type to the PDB type (or if we * have not yet created the association). @@ -37,10 +32,4 @@ public class NoTypeApplier extends MsTypeApplier { super(applicator); } - @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { - // do nothing - return null; - } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java index 225ed75ea7..d619b9b627 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java @@ -378,10 +378,12 @@ public class PdbResearch { for (int indexNumber : developerDebugOrderIndexNumbers) { monitor.checkCancelled(); PdbResearch.checkBreak(indexNumber); - FixupContext fixupContext = new FixupContext(); - fixupContext.addStagedRecord(indexNumber); - applicator.getProcessedDataType(RecordNumber.typeRecordNumber(indexNumber), - fixupContext, true); + //20240214: neutered internals... containing method not being used at the moment... + // consider what needs to be done below +// FixupContext fixupContext = new FixupContext(); +// fixupContext.addStagedRecord(indexNumber); +// applicator.getProcessedDataType(RecordNumber.typeRecordNumber(indexNumber), +// fixupContext, true); } } @@ -426,7 +428,7 @@ public class PdbResearch { MsSymbolApplier applier = applicator.getSymbolApplier(iter); if (applier instanceof TypedefSymbolApplier typedefApplier) { RecordNumber typeNumber = typedefApplier.getTypeRecordNumber(); - AbstractMsType type = applicator.getPdb().getTypeRecord(typeNumber); + AbstractMsType type = applicator.getTypeRecord(typeNumber); System.out .println( "UDT " + typedefApplier.getName() + " depends on " + type.toString()); 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 d49a494c40..26e792a723 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 @@ -21,22 +21,21 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractPointerMsType.MsPointerMode; import ghidra.program.model.data.*; +import ghidra.util.Msg; import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractPointerMsType} types. */ -public class PointerTypeApplier extends MsTypeApplier { +public class PointerTypeApplier extends MsDataTypeApplier { // Intended for: AbstractPointerMsType /** - * Constructor for pointer type applier, for transforming a enum into a - * Ghidra DataType. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. - * @throws IllegalArgumentException Upon invalid arguments. + * Constructor for pointer type applier, for transforming a enum into a Ghidra DataType + * @param applicator {@link DefaultPdbApplicator} for which this class is working + * @throws IllegalArgumentException Upon invalid arguments */ - public PointerTypeApplier(DefaultPdbApplicator applicator) - throws IllegalArgumentException { + public PointerTypeApplier(DefaultPdbApplicator applicator) throws IllegalArgumentException { super(applicator); } @@ -45,15 +44,14 @@ public class PointerTypeApplier extends MsTypeApplier { * if we develop member pointers into the Ghidra framework; this method exists to pass some * pertinent information along to the user * @param type the PDB type being inspected - * @param fixupContext the fixup context to use; or pass in null during fixup process * @return comment string or null * @throws CancelledException upon user cancellation * @throws PdbException upon processing error */ - String getPointerCommentField(AbstractPointerMsType type, FixupContext fixupContext) + String getPointerCommentField(AbstractPointerMsType type) throws CancelledException, PdbException { - AbstractPointerMsType.MsPointerMode pointerMode = type.getPointerMode(); - if (pointerMode == AbstractPointerMsType.MsPointerMode.MEMBER_FUNCTION_POINTER) { + AbstractPointerMsType.MsPointerMode msPointerMode = type.getPointerMode(); + if (msPointerMode == AbstractPointerMsType.MsPointerMode.MEMBER_FUNCTION_POINTER) { // We are no longer able to get underlying type in time due to cycle breaks unless // we start doing fixups on pmf/pdm pointers. // TODO: consider fixups on these later... maybe after we understand contents of @@ -63,7 +61,7 @@ public class PointerTypeApplier extends MsTypeApplier { //return "\"::*\" (pmf) to type: " + underlyingType; return "\"::*\" (pmf)"; } - else if (pointerMode == AbstractPointerMsType.MsPointerMode.MEMBER_DATA_POINTER) { + else if (msPointerMode == AbstractPointerMsType.MsPointerMode.MEMBER_DATA_POINTER) { // We are no longer able to get underlying type in time due to cycle breaks unless // we start doing fixups on pmf/pdm pointers. // TODO: consider fixups on these later... maybe after we understand contents of @@ -77,56 +75,57 @@ public class PointerTypeApplier extends MsTypeApplier { } @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { + boolean apply(AbstractMsType type) throws PdbException, CancelledException { + + AbstractPointerMsType pointerMsType = (AbstractPointerMsType) type; + // Doing pre-check on type first using the getDataTypeOrSchedule method. The logic is + // simpler here for Composites or Functions because we only have one dependency type, + // so we are not doing a separate call to a pre-check method as there is in those appliers. + // If type is not available, return false. + RecordNumber underlyingRecordNumber = pointerMsType.getUnderlyingRecordNumber(); + DataType underlyingType = applicator.getDataTypeOrSchedule(underlyingRecordNumber); + if (underlyingType == null) { + return false; + } DataType dataType; - if (fixupContext != null) { - // The next line will only return null until we start putting in a DB version of the - // pointer, below. Need to work that out. TODO: take care of this - dataType = applicator.getDataType(type); - if (dataType != null) { - return dataType; - } - } + if (type instanceof DummyMsType) { dataType = new PointerDataType(applicator.getDataTypeManager()); } else { - dataType = applyAbstractPointerMsType((AbstractPointerMsType) type, fixupContext); + AbstractPointerMsType.MsPointerMode msPointerMode = pointerMsType.getPointerMode(); + switch (msPointerMode) { + case POINTER: + dataType = processPointer(pointerMsType, underlyingType); + case LVALUE_REFERENCE: + dataType = processReference(pointerMsType, underlyingType); + case RVALUE_REFERENCE: + dataType = processReference(pointerMsType, underlyingType); + case MEMBER_DATA_POINTER: + case MEMBER_FUNCTION_POINTER: + dataType = processMemberPointer(pointerMsType, underlyingType); + case INVALID: + case RESERVED: + Msg.warn(this, "Unable to process PointerMode: " + msPointerMode + + ". Using default Pointer."); + dataType = PointerDataType.dataType; + default: + throw new PdbException("PDB Error: unhandled PointerMode in " + getClass()); + } } - dataType = applicator.resolve(dataType); + applicator.putDataType(type, dataType); - return dataType; + return true; } - private DataType getUnderlyingType(AbstractPointerMsType type, FixupContext fixupContext) - throws CancelledException, PdbException { - RecordNumber underlyingRecord = type.getUnderlyingRecordNumber(); - return applicator.getProcessedDataType(underlyingRecord, fixupContext, true); - } + private DataType processMemberPointer(AbstractPointerMsType type, DataType underlyingType) { - private DataType applyAbstractPointerMsType(AbstractPointerMsType type, - FixupContext fixupContext) throws CancelledException, PdbException { - - AbstractPointerMsType.MsPointerMode pointerMode = type.getPointerMode(); - if (pointerMode == AbstractPointerMsType.MsPointerMode.MEMBER_DATA_POINTER || - pointerMode == AbstractPointerMsType.MsPointerMode.MEMBER_FUNCTION_POINTER) { - return processMemberPointer(type, fixupContext); - } - return processPointer(type, fixupContext); - } - - private DataType processMemberPointer(AbstractPointerMsType type, FixupContext fixupContext) - throws CancelledException, PdbException { - - // future use - DataType underlyingType = getUnderlyingType(type, fixupContext); int size = type.getSize().intValueExact(); String name; - AbstractPointerMsType.MsPointerMode pointerMode = type.getPointerMode(); - if (pointerMode == AbstractPointerMsType.MsPointerMode.MEMBER_FUNCTION_POINTER) { + AbstractPointerMsType.MsPointerMode msPointerMode = type.getPointerMode(); + if (msPointerMode == AbstractPointerMsType.MsPointerMode.MEMBER_FUNCTION_POINTER) { name = String.format("pmf_%08x", type.toString().hashCode()); } else { @@ -139,12 +138,11 @@ public class PointerTypeApplier extends MsTypeApplier { DataType dt = new StructureDataType(storagePath, name, size); dt.setDescription(type.toString()); - return applicator.resolve(dt); + return dt; } private CategoryPath getCategoryPathForMemberPointer(RecordNumber containingClassRecordNumber) { - AbstractMsType containingType = - applicator.getPdb().getTypeRecord(containingClassRecordNumber); + AbstractMsType containingType = applicator.getTypeRecord(containingClassRecordNumber); MsTypeApplier applier = applicator.getTypeApplier(containingClassRecordNumber); if (containingType instanceof AbstractCompositeMsType compositeMsType && applier instanceof CompositeTypeApplier compositeApplier) { @@ -155,9 +153,7 @@ public class PointerTypeApplier extends MsTypeApplier { return applicator.getAnonymousTypesCategory(); } - private DataType processPointer(AbstractPointerMsType type, FixupContext fixupContext) - throws CancelledException, PdbException { - DataType underlyingType = getUnderlyingType(type, fixupContext); + private DataType processPointer(AbstractPointerMsType type, DataType underlyingType) { int size = type.getSize().intValueExact(); if (size > PointerDataType.MAX_POINTER_SIZE_BYTES) { return getStubPointer(type); @@ -165,21 +161,28 @@ public class PointerTypeApplier extends MsTypeApplier { if (size == applicator.getDataOrganization().getPointerSize()) { size = -1; // Use default } - if (underlyingType == null || applicator.isPlaceholderType(underlyingType)) { - return applicator.getPlaceholderPointer(size); + return new PointerDataType(underlyingType, size, applicator.getDataTypeManager()); + } + + private DataType processReference(AbstractPointerMsType type, DataType underlyingType) { + int size = type.getSize().intValueExact(); + if (size > PointerDataType.MAX_POINTER_SIZE_BYTES) { + return getStubPointer(type); + } + if (size == applicator.getDataOrganization().getPointerSize()) { + size = -1; // Use default } return new PointerDataType(underlyingType, size, applicator.getDataTypeManager()); } private DataType getStubPointer(AbstractPointerMsType type) { int size = type.getSize().intValueExact(); - AbstractMsType under = applicator.getPdb().getTypeRecord(type.getUnderlyingRecordNumber()); + AbstractMsType under = applicator.getTypeRecord(type.getUnderlyingRecordNumber()); CategoryPath categoryPath = applicator.getAnonymousTypesCategory(); - MsPointerMode mode = type.getPointerMode(); + MsPointerMode msPointerMode = type.getPointerMode(); AbstractPointerMsType.PointerType pt = type.getPointerType(); - String name = - String.format("StubPtr%d_%s%s_To_%s", 8 * size, pt.toString(), mode.toString(), - under.getName()); + String name = String.format("StubPtr%d_%s%s_To_%s", 8 * size, pt.toString(), + msPointerMode.toString(), under.getName()); DataType stubPtr = new StructureDataType(categoryPath, name, size); return stubPtr; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java index e663389580..4b6abbd9cf 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java @@ -16,6 +16,7 @@ package ghidra.app.util.pdb.pdbapplicator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.app.util.bin.format.pdb2.pdbreader.type.PrimitiveMsType; import ghidra.program.model.data.DataType; @@ -24,22 +25,20 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link PrimitiveMsType} types. */ -public class PrimitiveTypeApplier extends MsTypeApplier { +public class PrimitiveTypeApplier extends MsDataTypeApplier { // Intended for: PrimitiveMsType /** - * Constructor for primitive type applier, for transforming a primitive into a - * Ghidra DataType. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. + * Constructor for primitive type applier, for transforming a primitive into a Ghidra DataType + * @param applicator {@link DefaultPdbApplicator} for which this class is working */ public PrimitiveTypeApplier(DefaultPdbApplicator applicator) { super(applicator); } @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { - return applyPrimitiveMsType((PrimitiveMsType) type); + boolean apply(AbstractMsType type) throws PdbException, CancelledException { + return (applyPrimitiveMsType((PrimitiveMsType) type) != null); } boolean isNoType(AbstractMsType type) { @@ -59,7 +58,9 @@ public class PrimitiveTypeApplier extends MsTypeApplier { // } int indexNumber = type.getNumber(); - DataType existingDt = applicator.getDataType(indexNumber); + RecordNumber recordNumber = RecordNumber.typeRecordNumber(indexNumber); + DataType existingDt = applicator.getDataType(recordNumber); + if (existingDt != null) { return existingDt; } @@ -2062,8 +2063,11 @@ public class PrimitiveTypeApplier extends MsTypeApplier { } + // Doing a direct and immediate resolve (not scheduling... the type would never get into + // the processing queue because primitive type numbers are not found in the sequential + // set of record numbers, but they are referred to by non-primitive types). primitiveDataType = applicator.resolve(primitiveDataType); - applicator.putDataType(indexNumber, primitiveDataType); + applicator.putDataType(recordNumber, primitiveDataType); return primitiveDataType; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java index 094506ede4..6ca2c351e3 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java @@ -18,7 +18,8 @@ package ghidra.app.util.pdb.pdbapplicator; 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.*; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.Pointer; import ghidra.util.exception.CancelledException; /** @@ -29,9 +30,9 @@ public class ProcedureTypeApplier extends AbstractFunctionTypeApplier { // Intended for: AbstractProcedureMsType /** * Constructor for the applicator that applies {@link AbstractProcedureMsType}, - * transforming it into a Ghidra {@link DataType}. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. - * @throws IllegalArgumentException Upon invalid arguments. + * transforming it into a Ghidra {@link DataType} + * @param applicator {@link DefaultPdbApplicator} for which this class is working + * @throws IllegalArgumentException Upon invalid arguments */ public ProcedureTypeApplier(DefaultPdbApplicator applicator) throws IllegalArgumentException { super(applicator); @@ -43,14 +44,17 @@ public class ProcedureTypeApplier extends AbstractFunctionTypeApplier { } @Override - protected Pointer getThisPointer(AbstractMsType type, FixupContext fixupContext, - boolean breakCycle) throws CancelledException, PdbException { + protected RecordNumber getThisPointerRecordNumber(AbstractMsType type) { return null; } @Override - protected Composite getContainingComplexApplier(AbstractMsType type, FixupContext fixupContext, - boolean breakCycle) throws CancelledException, PdbException { + protected RecordNumber getContainingComplexRecordNumber(AbstractMsType type) { + return null; + } + + @Override + protected Pointer getThisPointer(AbstractMsType type) throws CancelledException, PdbException { return null; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java index 63622fdbfb..40e49663ba 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 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 f9e80eda7d..742528e004 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 @@ -18,8 +18,7 @@ package ghidra.app.util.pdb.pdbapplicator; import java.util.HashMap; import java.util.Map; -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.*; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; /** @@ -30,10 +29,12 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; public class TypeApplierFactory { private DefaultPdbApplicator applicator; + private AbstractPdb pdb; private Map appliersByPdbId; TypeApplierFactory(DefaultPdbApplicator applicator) { this.applicator = applicator; + this.pdb = applicator.getPdb(); appliersByPdbId = new HashMap<>(); } @@ -51,7 +52,7 @@ public class TypeApplierFactory { MsTypeApplier getApplierOrNoTypeSpec(RecordNumber recordNumber, Class expected) throws PdbException { MsTypeApplier applier = getTypeApplier(recordNumber); - AbstractMsType type = applicator.getPdb().getTypeRecord(recordNumber); + AbstractMsType type = pdb.getTypeRecord(recordNumber); if (!expected.isInstance(applier)) { if (!(applier instanceof PrimitiveTypeApplier && ((PrimitiveTypeApplier) applier).isNoType(type))) { @@ -63,7 +64,7 @@ public class TypeApplierFactory { } MsTypeApplier getTypeApplier(RecordNumber recordNumber) { - return getTypeApplier(applicator.getPdb().getTypeRecord(recordNumber)); + return getTypeApplier(pdb.getTypeRecord(recordNumber)); } //============================================================================================== diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java index 6bbb492fde..fc7236ab41 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java @@ -91,7 +91,7 @@ public class TypedefSymbolApplier extends MsSymbolApplier String name = symbol.getName(); RecordNumber typeRecordNumber = symbol.getTypeRecordNumber(); - AbstractMsType mType = applicator.getPdb().getTypeRecord(typeRecordNumber); + AbstractMsType mType = applicator.getTypeRecord(typeRecordNumber); MsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber); // TODO:... NOT SURE IF WILL ALWAYS BE A DATATYPE OR WILL BE A VARIABLE OR ???? if (applier == null) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java index 882f23fac9..499be68dc5 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java @@ -15,11 +15,8 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; -import ghidra.program.model.data.DataType; -import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractBaseClassMsType}, {@link AbstractVirtualBaseClassMsType}, and @@ -83,22 +80,23 @@ public class UdtSourceLineTypeApplier extends MsTypeApplier { return null; } - @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { - String filename = getSourceFileName(type); - int lineNumber = getLineNumber(type); - RecordNumber udtRecordNumber = getUdtRecordNumber(type); - MsTypeApplier typeApplier = applicator.getTypeApplier(udtRecordNumber); - - // do nothing at the moment. - applicator.putRecordNumberByFileName(udtRecordNumber, filename); - if (type instanceof UserDefinedTypeModuleSourceAndLineMsType) { - int moduleNumber = ((UserDefinedTypeModuleSourceAndLineMsType) type).getModuleNumber(); - applicator.putRecordNumberByModuleNumber(udtRecordNumber, moduleNumber); - } - return null; - } + // Keeping as commented out for now so to have something to start with for this ITEM type +// @Override +// DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) +// throws PdbException, CancelledException { +// String filename = getSourceFileName(type); +// int lineNumber = getLineNumber(type); +// RecordNumber udtRecordNumber = getUdtRecordNumber(type); +// MsTypeApplier typeApplier = applicator.getTypeApplier(udtRecordNumber); +// +// // do nothing at the moment. +// applicator.putRecordNumberByFileName(udtRecordNumber, filename); +// if (type instanceof UserDefinedTypeModuleSourceAndLineMsType) { +// int moduleNumber = ((UserDefinedTypeModuleSourceAndLineMsType) type).getModuleNumber(); +// applicator.putRecordNumberByModuleNumber(udtRecordNumber, moduleNumber); +// } +// return null; +// } private static AbstractMsType validateType(AbstractMsType type) throws IllegalArgumentException { 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 2c3379a691..52c9e4de1d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java @@ -15,24 +15,19 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; -import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; -import ghidra.program.model.data.DataType; -import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractVirtualFunctionTablePointerMsType} and * {@link AbstractVirtualFunctionTablePointerWithOffsetMsType} types. */ -public class VirtualFunctionTablePointerTypeApplier extends MsTypeApplier { +public class VirtualFunctionTablePointerTypeApplier extends MsDataTypeComponentApplier { // Intended for: AbstractVirtualFunctionTablePointerMsType or // AbstractVirtualFunctionTablePointerWithOffsetMsType /** - * Constructor for enum type applier, for transforming a enum into a - * Ghidra DataType. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. + * Constructor for enum type applier, for transforming a enum into a Ghidra DataType + * @param applicator {@link DefaultPdbApplicator} for which this class is working * @throws IllegalArgumentException Upon invalid arguments. */ public VirtualFunctionTablePointerTypeApplier(DefaultPdbApplicator applicator) @@ -56,34 +51,7 @@ public class VirtualFunctionTablePointerTypeApplier extends MsTypeApplier { return "VFTablePtr" + getOffset(type); } - @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { - - // usually no record number, so cannot retrieve or store from/to applicator - - AbstractVirtualFunctionTablePointerMsType vftPtrType = validateType(type); - RecordNumber recordNumber = vftPtrType.getPointerTypeRecordNumber(); - DataType dataType = applyPointer(recordNumber, fixupContext, breakCycle); - - // unlike regular pointer, we are resolving vft pointer - dataType = applicator.resolve(dataType); - return dataType; - } - - private DataType applyPointer(RecordNumber pointerTypeRecordNumber, FixupContext fixupContext, - boolean breakCycle) throws CancelledException, PdbException { - MsTypeApplier rawApplier = applicator.getTypeApplier(pointerTypeRecordNumber); - if (rawApplier instanceof PointerTypeApplier pointerApplier) { - AbstractMsType type = applicator.getPdb().getTypeRecord(pointerTypeRecordNumber); - return pointerApplier.apply(type, fixupContext, breakCycle); - } - applicator.appendLogMsg("cannot process " + rawApplier.getClass().getSimpleName() + "for " + - getClass().getSimpleName()); - return null; - } - - private static AbstractVirtualFunctionTablePointerMsType validateType(AbstractMsType type) + private static AbstractMsType validateType(AbstractMsType type) throws IllegalArgumentException { if (!(type instanceof AbstractVirtualFunctionTablePointerMsType vftPtrType)) { throw new IllegalArgumentException( 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 e79ccb913a..817ae84cb5 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 @@ -28,12 +28,12 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link VtShapeMsType} types. */ -public class VtShapeTypeApplier extends MsTypeApplier { +public class VtShapeTypeApplier extends MsDataTypeApplier { // Intended for: VtShapeMsType /** - * Constructor for vtshape type applier. - * @param applicator {@link DefaultPdbApplicator} for which this class is working. + * Constructor for vtshape type applier + * @param applicator {@link DefaultPdbApplicator} for which this class is working */ public VtShapeTypeApplier(DefaultPdbApplicator applicator) { super(applicator); @@ -49,16 +49,16 @@ public class VtShapeTypeApplier extends MsTypeApplier { } @Override - DataType apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle) - throws PdbException, CancelledException { + boolean apply(AbstractMsType type) 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 dataType = createVtShape((VtShapeMsType) type); -// return applicator.resolve(dataType); - return dataType; + applicator.putDataType(type, dataType); + return true; } // We are creating a structure for the vtshape. @@ -133,4 +133,5 @@ public class VtShapeTypeApplier extends MsTypeApplier { } return shape; // not resolved } + }