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 5e959b9009..75858b5b65 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 @@ -19,8 +19,7 @@ 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.*; -import ghidra.app.util.demangler.microsoft.MicrosoftDemangler; -import ghidra.app.util.demangler.microsoft.MicrosoftMangledContext; +import ghidra.app.util.demangler.microsoft.*; import ghidra.docking.settings.SettingsImpl; import ghidra.program.model.address.*; import ghidra.program.model.data.*; @@ -53,6 +52,7 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { private String originalTypeName; private DemangledDataType demangledDataType; + private DemangledDataType originalDemangledDataType; private boolean hasProcessedName = false; private Namespace namespace; @@ -445,7 +445,9 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { if (value instanceof String) { originalTypeName = (String) value; // The returned demangledDataType an be null - demangledDataType = getDemangledDataType(originalTypeName, program, nameAddress); + demangledDataType = getDemangledDataType(originalTypeName, program, nameAddress, false); + originalDemangledDataType = + getDemangledDataType(originalTypeName, program, nameAddress, true); } hasProcessedName = true; return originalTypeName; @@ -502,6 +504,18 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { return hasComplexType() ? demangledDataType.getNamespaceString() : null; } + /** + * Gets the full pathname (includes namespaces) of the original type descriptor. + * This means a namespace that was not modified by the demangler output options. + * Does not currently account or anonymous namespace replacement. + * Will return the modified namespace if the non-modified one cannot be reproduced. + * This may include modifiers. It doesn't contain the refType. + * @return the full pathname or null. + */ + public String getOriginalDescriptorTypeNamespace() { + return hasComplexType() ? originalDemangledDataType.getNamespaceString() : null; + } + /** * Gets the address of where to find the type name, if there is one. * Otherwise, this returns null. @@ -619,14 +633,17 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { * @param mangledString the mangled string to be demangled * @param program the program * @param address address of the mangled string + * @param useOriginalOptions {@code true} to use original underlying demangler output options * @return the DemangledDataType or null if couldn't demangle or is not a class type */ private static DemangledDataType getDemangledDataType(String mangledString, Program program, - Address address) { + Address address, boolean useOriginalOptions) { MicrosoftDemangler demangler = new MicrosoftDemangler(); try { + MicrosoftDemanglerOptions mdo = + useOriginalOptions ? MicrosoftDemanglerOptions.DEFAULT_UNDERLYING_OUTPUT : null; MicrosoftMangledContext mangledContext = - demangler.createMangledContext(mangledString, null, program, address); + demangler.createMangledContext(mangledString, mdo, program, address); DemangledDataType demangledType = demangler.demangleType(mangledContext); if (isPermittedType(demangledType)) { return demangledType; diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateRtti1BackgroundCmd.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateRtti1BackgroundCmd.java index 0b992feb37..11e98a2064 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateRtti1BackgroundCmd.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateRtti1BackgroundCmd.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -26,7 +26,7 @@ import ghidra.program.model.symbol.SymbolUtilities; import ghidra.util.exception.CancelledException; /** - * This command will create an RTTI1 data type. + * This command will create an RTTI1 data type. * If there are any existing instructions in the area to be made into data, the command will fail. * Any data in the area will be replaced with the new dataType. */ @@ -37,10 +37,10 @@ public class CreateRtti1BackgroundCmd extends AbstractCreateDataBackgroundCmd vfTableBlocks, @@ -190,7 +190,7 @@ public class CreateRtti4BackgroundCmd extends AbstractCreateDataBackgroundCmdrttiSuffix, which is in the + * Function that will create a symbol based on the rttiSuffix, which is in the * class or namespace that is indicated by the demangledType string. - * + * * @param program the program where the symbol is being created - * @param rttiAddress Address of the RTTI datatype + * @param rttiAddress Address of the RTTI datatype * @param typeDescriptorModel the model for the type descriptor structure * @param rttiSuffix suffix name indicating which type of RTTI structure * @return true if a symbol was created, false otherwise @@ -131,7 +131,7 @@ public class RttiUtil { try { Symbol symbol = symbolTable.createLabel(rttiAddress, name, classNamespace, SourceType.IMPORTED); - // Set the symbol to be primary so that the demangler + // Set the symbol to be primary so that the demangler // won't demangle again symbol.setPrimary(); if (replaceSymbolWithNoTicks(symbol)) { @@ -174,7 +174,7 @@ public class RttiUtil { symbol.setName(name, symbol.getSource()); //do this in case the mangled name is currently primary which will cause demangler - //to replace the ticks again once demangled since demangler only demangles primary + //to replace the ticks again once demangled since demangler only demangles primary symbol.setPrimary(); return true; } @@ -209,7 +209,7 @@ public class RttiUtil { } /** - * Determines the number of vf addresses in the vf table that begins at the specified base + * Determines the number of vf addresses in the vf table that begins at the specified base * address. * @param program the program whose memory is providing their addresses * @param vfTableBaseAddress the base address in the program for the vf table @@ -226,7 +226,7 @@ public class RttiUtil { PseudoDisassembler pseudoDisassembler = new PseudoDisassembler(program); // Create pointers starting at the address until reaching a 0 pointer. - // Terminate the possible table at any entry containing a cross reference that + // Terminate the possible table at any entry containing a cross reference that // is beyond the first table entry and don't include it. int tableSize = 0; Address currentVfPointerAddress = vfTableBaseAddress; @@ -280,10 +280,10 @@ public class RttiUtil { * indicate the end of a vftable * @param address the address of a possible pointer in a vftable * @return true if there are references to the given address and any of the references are - * types that would indicate the given pointer should not be in the vftable preceding it. In + * types that would indicate the given pointer should not be in the vftable preceding it. In * general most references would fall into this category such as ones created by user, importer, - * disassembler. Returns false if no references or if the only references are ones not - * indicative of the end of a vftable. + * disassembler. Returns false if no references or if the only references are ones not + * indicative of the end of a vftable. */ private static boolean referenceIndicatesEndOfTable(ReferenceManager referenceManager, Address address) { @@ -304,7 +304,7 @@ public class RttiUtil { // if it is analysis source type but reference is data that is not read this indicates // it is not the kind of reference that should end a vftable // For example something could be getting this address to figure out the address pointed - // to so that that address can be referenced. + // to so that that address can be referenced. if (ref.getReferenceType().isData() && !ref.getReferenceType().isRead()) { return true; } @@ -313,7 +313,7 @@ public class RttiUtil { } /** - * Gets the namespace referred to by the type descriptor model if it can determine the + * Gets the namespace referred to by the type descriptor model if it can determine the * namespace. Otherwise it returns the empty string. * @param rtti0Model the model for the type descriptor whose namespace is to be returned. * @return the namespace or the empty string. @@ -330,6 +330,26 @@ public class RttiUtil { return descriptorTypeNamespace; } + /** + * Gets the "original" namespace referred to by the type descriptor model if it can determine + * the namespace. Otherwise it returns the empty string. The "original" namespace is + * the namespace without any changes to the demangler output options. This is suitable + * for applying to a plate comment + * @param rtti0Model the model for the type descriptor whose namespace is to be returned. + * @return the "original" namespace or the empty string. + */ + public static String getOriginalDescriptorTypeNamespace(TypeDescriptorModel rtti0Model) { + String descriptorTypeNamespace = rtti0Model.getOriginalDescriptorTypeNamespace(); + if (descriptorTypeNamespace == null) { + + descriptorTypeNamespace = rtti0Model.getOriginalTypename(); + + Msg.warn(RttiUtil.class, rtti0Model.getAddress().toString() + + ": Could not demangle TypeDescriptor namespace so using the mangled string as the namespace."); + } + return descriptorTypeNamespace; + } + /** * Identify common TypeInfo address through examination of discovered VtTables */ diff --git a/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerOptions.java b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerOptions.java index 9da87596f0..5337b4e125 100644 --- a/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerOptions.java +++ b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerOptions.java @@ -17,12 +17,39 @@ package ghidra.app.util.demangler.microsoft; import generic.json.Json; import ghidra.app.util.demangler.DemanglerOptions; +import mdemangler.MDOutputOptions; /** * Microsoft demangler options */ public class MicrosoftDemanglerOptions extends DemanglerOptions { + /** + * Default Microsoft Demangler option for using the encoded number when outputting an + * anonymous namespace node (this can be different from the default option of the underlying + * demangler) + */ + public static final boolean DEFAULT_MSD_USE_ANON_NS = true; + + /** + * Default Microsoft Demangler option for applying user-defined-type (UDT) tags + * (e.g., "struct") when the UDT is a template or function argument (this can be different + * from the default option of the underlying demangler) + */ + public static final boolean DEFAULT_MSD_APPLY_UDT_TAG = false; + + /** + * MicrosoftDemanglerOptions that match the default underlying options. These can be + * different than the default MicrosoftDemanglerOptions. + */ + public static final MicrosoftDemanglerOptions DEFAULT_UNDERLYING_OUTPUT; + static { + DEFAULT_UNDERLYING_OUTPUT = new MicrosoftDemanglerOptions(); + DEFAULT_UNDERLYING_OUTPUT + .setUseEncodedAnonymousNamespace(MDOutputOptions.DEFAULT_USE_ANON_NS); + DEFAULT_UNDERLYING_OUTPUT.setApplyUdtArgumentTypeTag(MDOutputOptions.DEFAULT_APPLY_UDT_TAG); + } + // Processing options private boolean errorOnRemainingChars; private MsCInterpretation interpretation; @@ -68,8 +95,8 @@ public class MicrosoftDemanglerOptions extends DemanglerOptions { private void defaultInits() { errorOnRemainingChars = true; interpretation = MsCInterpretation.FUNCTION_IF_EXISTS; - useEncodedAnonymousNamespace = true; - applyUdtArgumentTypeTag = false; + useEncodedAnonymousNamespace = DEFAULT_MSD_USE_ANON_NS; + applyUdtArgumentTypeTag = DEFAULT_MSD_APPLY_UDT_TAG; } /** diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDOutputOptions.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDOutputOptions.java index 11acd45c70..2c0806c742 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDOutputOptions.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDOutputOptions.java @@ -21,9 +21,20 @@ package mdemangler; */ public class MDOutputOptions { - // These defaults match standard output - private boolean useEncodedAnonymousNamespaceNumber = false; - private boolean applyUdtArgumentTypeTag = true; + /** + * Default MDMang output option for using the encoded number when outputting an + * anonymous namespace node. This matches the MSFT standard + */ + public static final boolean DEFAULT_USE_ANON_NS = false; + + /** + * Default MDMang output option for applying user-defined-type (UDT) tags (e.g., "struct") + * when the UDT is a template or function argument. This matches the MSFT standard + */ + public static final boolean DEFAULT_APPLY_UDT_TAG = true; + + private boolean useEncodedAnonymousNamespaceNumber = DEFAULT_USE_ANON_NS; + private boolean applyUdtArgumentTypeTag = DEFAULT_APPLY_UDT_TAG; /** * Constructor