diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/CreateTypeDescriptorBackgroundCmd.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/CreateTypeDescriptorBackgroundCmd.java index a3c02a388f..6408326574 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/CreateTypeDescriptorBackgroundCmd.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/CreateTypeDescriptorBackgroundCmd.java @@ -37,7 +37,7 @@ public class CreateTypeDescriptorBackgroundCmd private static final String RTTI_0_NAME = "RTTI Type Descriptor"; /** - * Constructs a command for applying a TypeDescriptor data type at an address using the + * Constructs a command for applying a TypeDescriptor data type at an address using the * default validation and apply options. * @param address the address where the data should be created using the data type. */ @@ -46,13 +46,13 @@ public class CreateTypeDescriptorBackgroundCmd } /** - * Constructs a command for applying a TypeDescriptor data type at an address using the + * Constructs a command for applying a TypeDescriptor data type at an address using the * indicated options. * @param address the address where the data should be created using the data type. - * @param validationOptions the options for controlling how validation is performed when + * @param validationOptions the options for controlling how validation is performed when * determining whether or not to create the data structure at the indicated address. * @param applyOptions the options for creating the new data structure and its associated - * markup in the program as well as whether to follow other data references and create their + * markup in the program as well as whether to follow other data references and create their * data too. */ public CreateTypeDescriptorBackgroundCmd(Address address, @@ -65,7 +65,7 @@ public class CreateTypeDescriptorBackgroundCmd * by the model and using the indicated options. * @param model the model indicating the TypeDescriptor data to be created by this command. * @param applyOptions the options for creating the new data structure and its associated - * markup in the program as well as whether to follow other data references and create their + * markup in the program as well as whether to follow other data references and create their * data too. */ public CreateTypeDescriptorBackgroundCmd(TypeDescriptorModel model, @@ -152,13 +152,14 @@ public class CreateTypeDescriptorBackgroundCmd return false; } + // If PDB had been run, then the namespace here might already have been promoted to + // a class type. At this point in processing, we know that the model only has a type + // with a "class" or "struct" tag (see TypeDescriptorModel). //
Note: For now this assumes all classes and structs with RTTI data must // actually be classes. In the future this might need additional checking before // promoting some "struct" ref types to being a class, if we can better determine - // whether or not they are actually classes. - String refType = model.getRefType(); // Can be null. - boolean makeClass = "class".equals(refType) || "struct".equals(refType); - if (makeClass) { + // whether or not they are actually classes. + if (!(classNamespace instanceof GhidraClass)) { classNamespace = RttiUtil.promoteToClassNamespace(program, classNamespace); } diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java index 8b145ca3ac..7815cfcfa3 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java @@ -18,8 +18,7 @@ package ghidra.app.cmd.data; import ghidra.app.cmd.data.rtti.RttiUtil; import ghidra.app.util.datatype.microsoft.DataValidationOptions; import ghidra.app.util.datatype.microsoft.MSDataTypeUtils; -import ghidra.app.util.demangler.DemangledObject; -import ghidra.app.util.demangler.DemangledType; +import ghidra.app.util.demangler.*; import ghidra.docking.settings.SettingsImpl; import ghidra.program.model.address.*; import ghidra.program.model.data.*; @@ -30,14 +29,12 @@ import ghidra.program.model.mem.Memory; import ghidra.program.model.scalar.Scalar; import ghidra.program.model.symbol.Namespace; import ghidra.program.model.symbol.Symbol; +import ghidra.util.Msg; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import mdemangler.*; -import mdemangler.datatype.MDDataType; -import mdemangler.datatype.complex.MDComplexType; -import mdemangler.datatype.modifier.MDModifierType; -import mdemangler.naming.MDQualifiedName; +import mdemangler.MDException; +import mdemangler.MDMangGhidra; /** * Model for the TypeDescriptor data type. @@ -57,7 +54,7 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { private boolean hasVFPointer; private String originalTypeName; - private MDComplexType mdComplexType; + private DemangledDataType demangledDataType; private boolean hasProcessedName = false; private Namespace namespace; @@ -65,6 +62,8 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { * Creates the model for the exception handling TypeDescriptor data type. * @param program the program * @param address the address in the program for the TypeDescriptor data type. + * @param validationOptions options indicating how to validate the data type at the indicated + * address */ public TypeDescriptorModel(Program program, Address address, DataValidationOptions validationOptions) { @@ -204,8 +203,9 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { } /** - * Gets the TypeDescriptor structure for the indicated program. - * @return the TypeDescriptor structure. + * Gets the TypeDescriptor structure for the indicated program + * @param program the program which will contain this model's data type + * @return the TypeDescriptor structure */ public static DataType getDataType(Program program) { @@ -247,9 +247,10 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { } /** - * Determine if this model's data type has a vf table pointer. - * @param program the program which will contain this model's data type. - * @return true if the data type has a vf table pointer. Otherwise, it has a hash value. + * Determines if this model's data type program-wide TypeInfo Vftable pointer. This is used + * as an indication as to whether the particular data type has a Vftable pointer + * @param program the program which will contain this model's data type + * @return true if the data type has a vf table pointer. Otherwise, it has a hash value */ private static boolean hasVFPointer(Program program) { @@ -374,7 +375,7 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { */ public Scalar getHashValue() throws InvalidDataTypeException, UndefinedValueException { checkValidity(); - if (hasVFPointer) { + if (!hasVFPointer) { throw new UndefinedValueException( "No hash value is defined for this TypeDescriptor model."); } @@ -429,6 +430,9 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { * model's address. */ private String doGetTypeName() throws InvalidDataTypeException { + if (hasProcessedName) { + return originalTypeName; + } // last component is the type descriptor name. Address nameAddress = getComponentAddressOfTypeName(); // Could be null. if (nameAddress == null) { @@ -442,9 +446,7 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { Object value = terminatedStringDt.getValue(nameMemBuffer, SettingsImpl.NO_SETTINGS, 1); if (value instanceof String) { originalTypeName = (String) value; - if (originalTypeName != null) { - mdComplexType = getMDComplexType(program, originalTypeName); // Can be null. - } + demangledDataType = getDemangledDataType(originalTypeName); // Can be null } hasProcessedName = true; return originalTypeName; @@ -453,13 +455,13 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { private boolean hasComplexType() { if (!hasProcessedName) { try { - getTypeName(); // Initialize originalTypeName & mdComplexType if possible. + getTypeName(); // Initialize originalTypeName & demangledDataType if possible. } catch (InvalidDataTypeException e) { return false; } } - return (mdComplexType != null); + return (demangledDataType != null); } /** @@ -468,16 +470,7 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { * @return the full demangled type name or null. */ public String getDemangledTypeDescriptor() { - return hasComplexType() ? mdComplexType.toString() : null; - } - - /** - * Gets the reference type of the type descriptor. (i.e. class, struct, union, enum) - * @return the type of thing referred to by this descriptor, or null if it couldn't be - * determined. - */ - public String getRefType() { - return hasComplexType() ? mdComplexType.getTypeName() : null; + return hasComplexType() ? demangledDataType.getOriginalDemangled() : null; } /** @@ -486,24 +479,15 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { * be determined. */ public String getDescriptorName() { - if (!hasComplexType()) { - return null; - } - MDQualifiedName qualifiedName = mdComplexType.getNamespace(); - return qualifiedName.getName(); + return hasComplexType() ? demangledDataType.getName() : null; } /** * Gets the parent namespace of the type descriptor. * @return the parent namespace as a DemangledType or null. */ - public DemangledType getParentNamespace() { - if (!hasComplexType()) { - return null; - } - MDQualifiedName qualifiedName = mdComplexType.getNamespace(); - MDMangGhidra demangler = new MDMangGhidra(); - return demangler.processNamespace(qualifiedName); + public Demangled getParentNamespace() { + return hasComplexType() ? demangledDataType.getNamespace() : null; } /** @@ -512,7 +496,7 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { * @return the full pathname or null. */ public String getDescriptorTypeNamespace() { - return hasComplexType() ? mdComplexType.getTypeNamespace() : null; + return hasComplexType() ? demangledDataType.getNamespaceString() : null; } /** @@ -585,27 +569,20 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { } /** - * Gets the namespace for this descriptor. It will create the namespace if it doesn't already exist. - * @return the descriptor's namespace, or null if it couldn't be determined. + * Gets the namespace for this descriptor. It will create the namespace if it doesn't already + * exist + * @return the descriptor's namespace or null if it couldn't be determined */ public Namespace getDescriptorAsNamespace() { - if (namespace == null || isNamespaceDeleted(namespace)) { - String descriptorName = getDescriptorName(); // Can be null. - if (descriptorName == null) { - return null; - } - - String demangledSource = mdComplexType.toString(); - DemangledType typeNamespace = - new DemangledType(originalTypeName, demangledSource, descriptorName); - DemangledType parentNamespace = getParentNamespace(); // Can be null; - if (parentNamespace != null) { - typeNamespace.setNamespace(parentNamespace); - } - Program program = getProgram(); - namespace = DemangledObject.createNamespace(program, typeNamespace, - program.getGlobalNamespace(), false); + if (namespace != null && !isNamespaceDeleted(namespace)) { + return namespace; } + if (hasComplexType() && demangledDataType == null) { + return null; + } + Program program = getProgram(); + namespace = DemangledObject.createNamespace(program, demangledDataType, + program.getGlobalNamespace(), false); return namespace; } @@ -618,27 +595,37 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { } /** - * Gets a demangler complex type for the indicated mangled string. - * @param program the program containing the mangled string - * @param mangledString the mangled string to be decoded - * @return the associated complex type or null if the string couldn't be demangled. + * Gets a DemangledDataType for the indicated mangled string + * @param mangledString the mangled string to be demangled + * @return the DemangledDataType or null if couldn't demangle or is not a class type */ - private static MDComplexType getMDComplexType(Program program, String mangledString) { + private static DemangledDataType getDemangledDataType(String mangledString) { MDMangGhidra demangler = new MDMangGhidra(); try { - MDDataType mangledDt = demangler.demangleType(mangledString, true); - if (mangledDt instanceof MDModifierType modifierType) { - MDType refType = modifierType.getReferencedType(); - if (refType instanceof MDComplexType complexType) { - return complexType; - } + // Note that we could play with the return value, but it is not needed; instead, we + // get the DemangledDataType by calling the appropriate method + demangler.demangleType(mangledString, true); + DemangledDataType demangledType = demangler.getDataType(); + if (isPermittedType(demangledType)) { + return demangledType; } - return null; // Not an MDComplexType } catch (MDException e) { // Couldn't demangle. - return null; } + return null; + } + + private static boolean isPermittedType(DemangledDataType demangledDataType) { + if (demangledDataType == null) { + return false; + } + if (demangledDataType.isClass() || demangledDataType.isStruct()) { + return true; + } + Msg.info(TypeDescriptorModel.class, + "Unprocessed TypeDescriptor: " + demangledDataType.getSignature()); + return false; } } diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/RttiAnalyzer.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/RttiAnalyzer.java index 9a6ec6f351..fb0779a73a 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/RttiAnalyzer.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/plugin/prototype/MicrosoftCodeAnalyzerPlugin/RttiAnalyzer.java @@ -18,7 +18,6 @@ package ghidra.app.plugin.prototype.MicrosoftCodeAnalyzerPlugin; import java.util.*; import ghidra.app.cmd.data.CreateTypeDescriptorBackgroundCmd; -import ghidra.app.cmd.data.TypeDescriptorModel; import ghidra.app.cmd.data.rtti.*; import ghidra.app.services.*; import ghidra.app.util.datatype.microsoft.*; @@ -30,7 +29,7 @@ import ghidra.program.model.listing.Program; import ghidra.program.model.mem.MemoryBlock; import ghidra.program.util.ProgramMemoryUtil; import ghidra.util.bytesearch.*; -import ghidra.util.exception.*; +import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; /** @@ -58,12 +57,12 @@ public class RttiAnalyzer extends AbstractAnalyzer { public RttiAnalyzer() { super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER); setSupportsOneTimeAnalysis(); - // Set priority of RTTI analyzer to run after Demangler so can see if better + // Set priority of RTTI analyzer to run after Demangler so can see if better // plate comment or label already exists from Demangler. setPriority(AnalysisPriority.REFERENCE_ANALYSIS.before()); setDefaultEnablement(true); validationOptions = new DataValidationOptions(); - applyOptions = new DataApplyOptions(); + applyOptions = new DataApplyOptions(); } @Override @@ -74,21 +73,21 @@ public class RttiAnalyzer extends AbstractAnalyzer { @Override public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) throws CancelledException { - + // "rttiFound" option added in 10.3 so if analyzed with previous version analyzer will rerun - if(hasRun(program)) { + if (hasRun(program)) { return true; } - + Address commonVfTableAddress = RttiUtil.findTypeInfoVftableAddress(program, monitor); - if (commonVfTableAddress == null) { + if (commonVfTableAddress == null) { setRttiFound(program, false); return true; } - - RttiUtil.createTypeInfoVftableSymbol(program,commonVfTableAddress); - + + RttiUtil.createTypeInfoVftableSymbol(program, commonVfTableAddress); + Set
possibleTypeAddresses = locatePotentialRTTI0Entries(program, set, monitor); if (possibleTypeAddresses == null) { setRttiFound(program, false); @@ -98,10 +97,10 @@ public class RttiAnalyzer extends AbstractAnalyzer { // We now have a list of potential rtti0 addresses. processRtti0(possibleTypeAddresses, program, monitor); setRttiFound(program, true); - + return true; } - + /** * Has this analyzer been run on the given program. NOTE: option new as of 10.3 so this will * not be accurate for older programs. @@ -111,13 +110,13 @@ public class RttiAnalyzer extends AbstractAnalyzer { private boolean hasRun(Program program) { Options programOptions = program.getOptions(Program.PROGRAM_INFO); Boolean hasRun = (Boolean) programOptions.getObject(RTTI_FOUND_OPTION, null); - if(hasRun == null) { + if (hasRun == null) { return false; } return true; - + } - + /** * Method to set the RTTI Found option for the given program * @param program the given program @@ -146,9 +145,9 @@ public class RttiAnalyzer extends AbstractAnalyzer { // use the type_info vftable address to find a list of potential RTTI0 addresses int alignment = program.getDefaultPointerSize(); List dataBlocks = ProgramMemoryUtil.getMemoryBlocksStartingWithName( - program, program.getMemory(), ".data", TaskMonitor.DUMMY); + program, program.getMemory(), ".data", TaskMonitor.DUMMY); Set
possibleTypeAddresses = ProgramMemoryUtil.findDirectReferences(program, - dataBlocks, alignment, commonVfTableAddress, monitor); + dataBlocks, alignment, commonVfTableAddress, monitor); return possibleTypeAddresses; } @@ -164,26 +163,13 @@ public class RttiAnalyzer extends AbstractAnalyzer { monitor.checkCancelled(); monitor.setProgress(count++); - // Validate - TypeDescriptorModel typeModel = - new TypeDescriptorModel(program, rtti0Address, validationOptions); - try { - // Check that name matches the expected format. - String typeName = typeModel.getTypeName(); // can be null. - if (typeName == null || !typeName.startsWith(CLASS_PREFIX_CHARS)) { - continue; // Invalid so don't create. - } - } - catch (InvalidDataTypeException e) { - continue; // Invalid so don't create. - } - // Create the TypeDescriptor (RTTI 0) regardless of the other RTTI structures. CreateTypeDescriptorBackgroundCmd typeDescCmd = new CreateTypeDescriptorBackgroundCmd( rtti0Address, validationOptions, applyOptions); - typeDescCmd.applyTo(program, monitor); - - rtti0Locations.add(rtti0Address); + // Could call typeDescCmd.getStatusMsg() on failure + if (typeDescCmd.applyTo(program, monitor)) { + rtti0Locations.add(rtti0Address); + } } // Create any valid RTTI4s for this TypeDescriptor @@ -237,7 +223,7 @@ public class RttiAnalyzer extends AbstractAnalyzer { } /** For each of the RTTI0 locations found locate the associated RTTI4 structure referring to it. - * + * * @param program program to be searched * @param dataBlocks dataBlocks to search * @param rtti0Locations list of known rtti0 locations @@ -286,7 +272,7 @@ public class RttiAnalyzer extends AbstractAnalyzer { /** * Add a search pattern, to the searcher, for the set of bytes representing an address - * + * * @param searcher pattern searcher * @param validationOptions RTTI4 validation options * @param addresses list of found valid RTTI4 locations accumulated during actual search @@ -324,7 +310,7 @@ public class RttiAnalyzer extends AbstractAnalyzer { return; // Only process valid RTTI 4 data. } - // Check that the RTTI 0 is referred to both directly from the RTTI 4 and indirectly + // Check that the RTTI 0 is referred to both directly from the RTTI 4 and indirectly // through the RTTI 3. boolean refersToRtti0 = rtti4Model.refersToRtti0(getMatchValue()); if (!refersToRtti0) {