mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-24 21:21:56 +00:00
Merge remote-tracking branch 'origin/GP-4246_ghizard_PDB_delay_resolve_and_more_types_processing_cleanup--SQUASHED'
This commit is contained in:
commit
fd88575adf
@ -50,7 +50,7 @@ public class FindDataTypeConflictCauseScript extends GhidraScript {
|
||||
}
|
||||
|
||||
List<DataType> 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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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<CategoryPath> 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.
|
||||
|
@ -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 extends AbstractComplexMsType> T getDefinitionType(AbstractComplexMsType mType,
|
||||
Class<T> type) {
|
||||
Integer num = applicator.getNumber(mType);
|
||||
Integer mappedIndex = applicator.getMappedComplexType(num);
|
||||
if (mappedIndex != null) {
|
||||
mType =
|
||||
applicator.getPdb().getTypeRecord(RecordNumber.typeRecordNumber(mappedIndex), type);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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<RecordNumber> args = getArgsRecordNumbers(type);
|
||||
|
||||
boolean hasPlaceholder = false;
|
||||
|
||||
List<RecordNumber> args = argsList.getArgRecordNumbers();
|
||||
List<ParameterDefinition> parameterDefinitionList = new ArrayList<>();
|
||||
int parameterCount = 0;
|
||||
for (RecordNumber arg : args) {
|
||||
applicator.checkCancelled();
|
||||
|
||||
AbstractMsType argMsType = applicator.getPdb().getTypeRecord(arg);
|
||||
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<RecordNumber> 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<RecordNumber> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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) &&
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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<Integer, Integer> map;
|
||||
private Map<RecordNumber, RecordNumber> 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<NumFwdRef> 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",
|
||||
|
@ -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<DefaultPdbUniversalMember> 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<DefaultPdbUniversalMember> 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<AbstractMsType> msBases, AbstractMsType type, FixupContext fixupContext,
|
||||
boolean breakCycle) throws PdbException, CancelledException {
|
||||
private void addClassTypeBaseClasses(Composite composite, CppCompositeType myClassType,
|
||||
List<AbstractMsType> 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<AbstractMemberMsType> msMembers, AbstractCompositeMsType type,
|
||||
List<DefaultPdbUniversalMember> myMembers, FixupContext fixupContext,
|
||||
boolean breakCycle) throws CancelledException, PdbException {
|
||||
|
||||
List<DefaultPdbUniversalMember> 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<AbstractVirtualFunctionTablePointerMsType> msVftPtrs, AbstractCompositeMsType type,
|
||||
List<DefaultPdbUniversalMember> myMembers, FixupContext fixupContext,
|
||||
boolean breakCycle) throws CancelledException, PdbException {
|
||||
List<DefaultPdbUniversalMember> 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<AbstractMsType> msMembers, AbstractCompositeMsType type,
|
||||
List<DefaultPdbUniversalMember> 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<AbstractMethodRecordMs> 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<Integer, DataType> 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<AbstractMemberMsType> msMembers = lists.nonstaticMembers();
|
||||
|
||||
List<Integer> 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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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<Integer, Long> dataTypeIdByMsTypeNum;
|
||||
private Map<Integer, DataTypeImpl> dataTypeImplByMsTypeNum;
|
||||
private Map<Integer, CppCompositeType> classTypeByMsTypeNum;
|
||||
// second PDB analyzer would, at a minimum, remove the map from the analysis state.
|
||||
private Map<RecordNumber, DataType> dataTypeByMsTypeNum;
|
||||
private Map<RecordNumber, CppCompositeType> 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<SymbolGroup> createSymbolGroups() throws CancelledException, PdbException {
|
||||
private List<SymbolGroup> createSymbolGroups() throws CancelledException {
|
||||
List<SymbolGroup> 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<Integer, Pointer> placeholderPointers;
|
||||
private Set<Long> pointerIDs;
|
||||
// Structure used to mock placeholder array.
|
||||
private Map<PlaceholderArrayKey, Structure> placeholderArrays;
|
||||
private Set<Long> arrayIDs;
|
||||
|
||||
private void initializePlaceholders() {
|
||||
placeholderPointers = new HashMap<>();
|
||||
pointerIDs = new HashSet<>();
|
||||
placeholderArrays = new HashMap<>();
|
||||
arrayIDs = new HashSet<>();
|
||||
}
|
||||
|
||||
private void cleanUpPlaceholders() throws CancelledException {
|
||||
|
||||
TaskMonitor monitor = getMonitor();
|
||||
DataTypeManager dtm = getDataTypeManager();
|
||||
|
||||
// Remove placeholder arrays from DTM and from the Set
|
||||
for (long id : arrayIDs) {
|
||||
checkCancelled();
|
||||
DataType dt = dtm.getDataType(id);
|
||||
Collection<DataType> parents = dt.getParents();
|
||||
if (parents.size() == 0) {
|
||||
dtm.remove(dt, monitor);
|
||||
}
|
||||
else {
|
||||
Msg.warn(this,
|
||||
"PDB: Could not eliminate parented placeholder array: " + dt.getName());
|
||||
}
|
||||
}
|
||||
arrayIDs.clear();
|
||||
arrayIDs = null;
|
||||
|
||||
// Eliminate array placeholder map
|
||||
placeholderArrays.clear();
|
||||
placeholderArrays = null;
|
||||
|
||||
// Not removing placeholder pointers from DTM, but we are eliminating them from the Set
|
||||
pointerIDs.clear();
|
||||
pointerIDs = null;
|
||||
|
||||
// Eliminate pointer placeholder map
|
||||
placeholderPointers.clear();
|
||||
placeholderPointers = null;
|
||||
}
|
||||
|
||||
Pointer getPlaceholderPointer(int size) throws PdbException {
|
||||
Pointer pointer = placeholderPointers.get(size);
|
||||
if (pointer != null) {
|
||||
return pointer;
|
||||
}
|
||||
DataTypeManager dtm = getDataTypeManager();
|
||||
pointer = new PointerDataType(null, size, dtm);
|
||||
pointer = (Pointer) resolve(pointer);
|
||||
long id = dtm.getID(pointer);
|
||||
if (id == -1) {
|
||||
throw new PdbException("Could not create placeholder pointer.");
|
||||
}
|
||||
placeholderPointers.put(size, pointer);
|
||||
pointerIDs.add(id);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
boolean isPlaceholderPointer(DataType pointer) {
|
||||
// need this check for unresolved member types (such as primitives or bit-fields)
|
||||
if (pointer instanceof DataTypeImpl || pointer instanceof BitFieldDataType) {
|
||||
return false;
|
||||
}
|
||||
long id = getDataTypeManager().getID(pointer);
|
||||
return pointerIDs.contains(id);
|
||||
}
|
||||
|
||||
private record PlaceholderArrayKey(int arraySize, int alignment) {}
|
||||
|
||||
// Using a structure as a mock array because we can set both size and alignment, which
|
||||
// is what needs to be consistent with the final real array when used in a containing
|
||||
// composite.
|
||||
DataType getPlaceholderArray(int arraySize, int alignment) throws PdbException {
|
||||
PlaceholderArrayKey key = new PlaceholderArrayKey(arraySize, alignment);
|
||||
Structure placeholderArray = placeholderArrays.get(key);
|
||||
if (placeholderArray != null) {
|
||||
return placeholderArray;
|
||||
}
|
||||
|
||||
DataTypeManager dtm = getDataTypeManager();
|
||||
String name = String.format("placeholder_array_%08x_%02x", arraySize, alignment);
|
||||
placeholderArray =
|
||||
new StructureDataType(getPlaceholderTypesCategory(), name, arraySize, dtm);
|
||||
placeholderArray.align(alignment);
|
||||
if (arraySize == 0) {
|
||||
// For the zero-length, we need to enable packing to prevent the placeholder array
|
||||
// (actual structure) from reporting itself as "not yet defined."
|
||||
placeholderArray.setPackingEnabled(true);
|
||||
}
|
||||
placeholderArray = (Structure) resolve(placeholderArray);
|
||||
|
||||
long id = dtm.getID(placeholderArray);
|
||||
if (id == -1) {
|
||||
throw new PdbException("Could not create array placeholder.");
|
||||
}
|
||||
placeholderArrays.put(key, placeholderArray);
|
||||
arrayIDs.add(id);
|
||||
return placeholderArray;
|
||||
}
|
||||
|
||||
boolean isPlaceholderArray(DataType array) {
|
||||
return array.getCategoryPath().equals(getPlaceholderTypesCategory());
|
||||
}
|
||||
|
||||
boolean isPlaceholderType(DataType type) {
|
||||
return isPlaceholderPointer(type) || isPlaceholderArray(type);
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
//==============================================================================================
|
||||
//==============================================================================================
|
||||
|
||||
/**
|
||||
* Returns the processed Ghidra class type associated with the PDB type record number. Causes
|
||||
* the type to be processed if it already has not been.
|
||||
* <p>
|
||||
* This method is intended to be used by "Consumers" that need the type after all type
|
||||
* creation is complete.
|
||||
* 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.
|
||||
* <p>
|
||||
* 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 <T> class return type
|
||||
* @param recordNumber record number
|
||||
* @param typeClass desired class type for return
|
||||
* @return the record
|
||||
*/
|
||||
public <T extends AbstractMsType> T getTypeRecord(RecordNumber recordNumber,
|
||||
Class<T> typeClass) {
|
||||
return pdb.getTypeRecord(recordNumber, typeClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record for the mapped associated record number, which is expected to match the
|
||||
* desired class
|
||||
* @param <T> class return type
|
||||
* @param recordNumber record number
|
||||
* @param typeClass desired class type for return
|
||||
* @return the record
|
||||
*/
|
||||
public <T extends AbstractMsType> T getMappedTypeRecord(RecordNumber recordNumber,
|
||||
Class<T> 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<RecordNumber, DataType> 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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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<AbstractMsType> bases, List<AbstractMsType> members,
|
||||
List<AbstractMemberMsType> nonstaticMembers,
|
||||
List<AbstractStaticMemberMsType> staticMembers,
|
||||
List<AbstractVirtualFunctionTablePointerMsType> vftPtrs, List<AbstractMsType> methods,
|
||||
List<AbstractNestedTypeMsType> nestedTypes, List<AbstractEnumerateMsType> 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<AbstractMemberMsType> nonstaticMembers =
|
||||
new ArrayList<>(fieldListType.getNonStaticMembers());
|
||||
List<AbstractStaticMemberMsType> staticMembers =
|
||||
new ArrayList<>(fieldListType.getStaticMembers());
|
||||
List<AbstractVirtualFunctionTablePointerMsType> vftPtrs =
|
||||
new ArrayList<>(fieldListType.getVftPointers());
|
||||
List<AbstractNestedTypeMsType> 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);
|
||||
}
|
||||
|
||||
|
@ -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<Integer> stagedRecordFifo = new ArrayDeque<>();
|
||||
private Deque<Integer> inProgressRecordStack = new ArrayDeque<>();
|
||||
private Deque<Integer> fixupRecordFifo = new ArrayDeque<>();
|
||||
|
||||
private Map<Integer, List<Integer>> map = new HashMap<>();
|
||||
private Map<Integer, DataType> fixupTypes = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Checks that record is already being processed and, if not, adds it to the Staged state
|
||||
* @param record the number of the record
|
||||
* @throws PdbException upon the record already in the process or fixup state
|
||||
*/
|
||||
void ensureInContext(int record) throws PdbException {
|
||||
if (inProgressRecordStack.contains(record)) {
|
||||
return;
|
||||
}
|
||||
if (fixupRecordFifo.contains(record)) {
|
||||
return;
|
||||
}
|
||||
addStagedRecord(record);
|
||||
}
|
||||
|
||||
DataType getFixupDataType(int record) {
|
||||
return fixupTypes.get(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds record to the Staged state if not already there
|
||||
* @param recordNumber the number of the record
|
||||
* @throws PdbException upon the record already in the process or fixup state
|
||||
*/
|
||||
void addStagedRecord(int recordNumber) throws PdbException {
|
||||
if (stagedRecordFifo.contains(recordNumber)) {
|
||||
return;
|
||||
}
|
||||
if (inProgressRecordStack.contains(recordNumber)) {
|
||||
throw new PdbException("Record Number in process state: " + recordNumber);
|
||||
}
|
||||
if (fixupRecordFifo.contains(recordNumber)) {
|
||||
throw new PdbException("Record Number in fixup state: " + recordNumber);
|
||||
}
|
||||
if (map.containsKey(recordNumber)) {
|
||||
throw new PdbException("Record Number already exists: " + recordNumber);
|
||||
}
|
||||
map.put(recordNumber, new ArrayList<>());
|
||||
putStagedRecord(recordNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the next record in the Staged state to the process state and returns its number
|
||||
* @return the number of the record moved
|
||||
* @throws PdbException if the record happens to be in another state (should not happen if
|
||||
* in the Staged state)
|
||||
*/
|
||||
Integer moveFromStagedToProcessRecord() throws PdbException {
|
||||
Integer record = getStagedRecord();
|
||||
if (record != null) {
|
||||
putProcessRecord(record);
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the specified record number from the Staged state to the Process state
|
||||
* @param number the number of the record
|
||||
* @throws PdbException if the record is not in the Staged state
|
||||
*/
|
||||
void moveFromStagedToProcessRecord(int number) throws PdbException {
|
||||
if (!stagedRecordFifo.remove(number)) {
|
||||
throw new PdbException("Number not in Staged state: " + number);
|
||||
}
|
||||
putProcessRecord(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the specified record to the head of the Process state. If the record had been
|
||||
* in the Staged state or anywhere else in the Process state, it is moved to the head of the
|
||||
* Process state
|
||||
* @param number the number of the record
|
||||
* @throws PdbException if the records is not in the Staged state
|
||||
*/
|
||||
void moveToHeadProcessRecord(int number) throws PdbException {
|
||||
if (stagedRecordFifo.contains(number)) {
|
||||
stagedRecordFifo.remove(number);
|
||||
}
|
||||
else if (inProgressRecordStack.contains(number)) {
|
||||
inProgressRecordStack.remove(number);
|
||||
inProgressRecordStack.offerFirst(number);
|
||||
}
|
||||
else {
|
||||
map.put(number, new ArrayList<>());
|
||||
}
|
||||
putProcessRecord(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the specified record from the Process state to the Fixup state
|
||||
* @param number the number of the record
|
||||
* @param dataType the type that has been created for this in-progress type
|
||||
* @throws PdbException if the record is not in the Process state
|
||||
*/
|
||||
void moveProcessToFixupsRecord(int number, DataType dataType) throws PdbException {
|
||||
if (!inProgressRecordStack.remove(number)) {
|
||||
throw new PdbException("Number not in process state: " + number);
|
||||
}
|
||||
if (fixupTypes.containsKey(number)) {
|
||||
throw new PdbException("Number already in progress: " + number);
|
||||
}
|
||||
putFixupsRecord(number);
|
||||
fixupTypes.put(number, dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the next record from the Fixup state and returns the number
|
||||
* @return the number
|
||||
*/
|
||||
Integer popFixupsRecord() {
|
||||
Integer record = getFixupsRecord();
|
||||
if (record != null) {
|
||||
if (map.containsKey(record)) {
|
||||
map.remove(record);
|
||||
}
|
||||
if (fixupTypes.containsKey(record)) {
|
||||
fixupTypes.remove(record);
|
||||
}
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
||||
// Not sure we will use this method
|
||||
/**
|
||||
* Removes the head of the Process state and returns the number. The number is not moved
|
||||
* to the Fixup state
|
||||
* @return the number
|
||||
*/
|
||||
Integer popProcessRecord() {
|
||||
Integer record = getProcessRecord();
|
||||
if (record != null) {
|
||||
if (map.containsKey(record)) {
|
||||
map.remove(record);
|
||||
}
|
||||
// Since pop from current, not adding to fixups
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
||||
private void putStagedRecord(int record) throws PdbException {
|
||||
if (stagedRecordFifo.contains(record)) {
|
||||
return;
|
||||
}
|
||||
if (inProgressRecordStack.contains(record)) {
|
||||
throw new PdbException("Record exists in another state: " + record);
|
||||
}
|
||||
if (fixupRecordFifo.contains(record)) {
|
||||
throw new PdbException("Record exists in another state: " + record);
|
||||
}
|
||||
stagedRecordFifo.addFirst(record);
|
||||
}
|
||||
|
||||
private Integer getStagedRecord() {
|
||||
return stagedRecordFifo.pollLast();
|
||||
}
|
||||
|
||||
/**
|
||||
* Peeks at and returns the record number of the head of the Staged state
|
||||
* @return the record number
|
||||
*/
|
||||
Integer peekStagedRecord() {
|
||||
return stagedRecordFifo.peekLast();
|
||||
}
|
||||
|
||||
private void putProcessRecord(int record) throws PdbException {
|
||||
if (inProgressRecordStack.contains(record)) {
|
||||
return;
|
||||
}
|
||||
if (stagedRecordFifo.contains(record)) {
|
||||
throw new PdbException("Record exists in another state: " + record);
|
||||
}
|
||||
if (fixupRecordFifo.contains(record)) {
|
||||
throw new PdbException("Record exists in another state: " + record);
|
||||
}
|
||||
inProgressRecordStack.addFirst(record);
|
||||
}
|
||||
|
||||
private Integer getProcessRecord() {
|
||||
return inProgressRecordStack.pollFirst();
|
||||
}
|
||||
|
||||
private void putFixupsRecord(int record) throws PdbException {
|
||||
if (fixupRecordFifo.contains(record)) {
|
||||
return;
|
||||
}
|
||||
if (stagedRecordFifo.contains(record)) {
|
||||
throw new PdbException("Record exists in another state: " + record);
|
||||
}
|
||||
if (inProgressRecordStack.contains(record)) {
|
||||
throw new PdbException("Record exists in another state: " + record);
|
||||
}
|
||||
fixupRecordFifo.addFirst(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Peeks at and returns the record number of the head of the Process state
|
||||
* @return the record number
|
||||
*/
|
||||
Integer peekProcessRecord() {
|
||||
return inProgressRecordStack.peekFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and returns the record number of the head of the Fixup state
|
||||
* @return the record number
|
||||
*/
|
||||
Integer getFixupsRecord() {
|
||||
return fixupRecordFifo.pollLast();
|
||||
}
|
||||
|
||||
/**
|
||||
* Peeks at and returns the record number of the head of the Fixup state
|
||||
* @return the record number
|
||||
*/
|
||||
Integer peekFixupsRecord() {
|
||||
return fixupRecordFifo.peekLast();
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
|
||||
/**
|
||||
* Puts the fixup index into the fixups for the current head of the Process state
|
||||
* @param fixupIndex the fixup index
|
||||
* @throws PdbException if the head of the Process state is empty or is fixups cannot be found
|
||||
*/
|
||||
void putFixup(int fixupIndex) throws PdbException {
|
||||
List<Integer> fixups = getProcessFixups();
|
||||
fixups.add(fixupIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the fixups for the current head of the Process state is empty
|
||||
* @return {@code true} if empty
|
||||
* @throws PdbException if there is no head of the Process state or its fixups cannot be found
|
||||
*/
|
||||
boolean processFixupsIsEmpty() throws PdbException {
|
||||
List<Integer> fixups = getProcessFixups();
|
||||
return fixups.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Peeks at and returns head of the Fixup state
|
||||
* @return the number of the record
|
||||
*/
|
||||
Integer peekFixupRecord() {
|
||||
return peekFixupsRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fixups for the head of the Fixups state
|
||||
* @return the fixup indices
|
||||
* @throws PdbException if the head of the Fixups state does not exist or its fixups cannot be
|
||||
* found
|
||||
*/
|
||||
List<Integer> getFixups() throws PdbException {
|
||||
Integer record = peekFixupsRecord();
|
||||
if (record == null) {
|
||||
throw new PdbException("Empty fixups retrieval");
|
||||
}
|
||||
List<Integer> fixups = map.get(record);
|
||||
if (fixups == null) {
|
||||
throw new PdbException("Fixups not found on retrieval");
|
||||
}
|
||||
return fixups;
|
||||
}
|
||||
|
||||
private List<Integer> getProcessFixups() throws PdbException {
|
||||
Integer record = peekProcessRecord();
|
||||
if (record == null) {
|
||||
throw new PdbException("Context empty on fixups retrieval");
|
||||
}
|
||||
List<Integer> fixups = map.get(record);
|
||||
if (fixups == null) {
|
||||
throw new PdbException("Fixups not found");
|
||||
}
|
||||
return fixups;
|
||||
}
|
||||
|
||||
}
|
@ -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 " +
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -19,7 +19,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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
// }
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
// }
|
||||
}
|
||||
|
@ -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<RecordNumber, RecordNode> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -18,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<Integer, MsTypeApplier> 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<? extends MsTypeApplier> 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));
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user