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 89eb5b74a1..2e158eb1bc 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 @@ -15,12 +15,15 @@ */ package ghidra.app.cmd.data; +import ghidra.app.cmd.data.rtti.RttiUtil; import ghidra.app.util.datatype.microsoft.DataApplyOptions; import ghidra.app.util.datatype.microsoft.DataValidationOptions; import ghidra.program.model.address.Address; import ghidra.program.model.data.*; import ghidra.program.model.listing.*; +import ghidra.program.model.symbol.Namespace; import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.Msg; import ghidra.util.exception.CancelledException; import ghidra.util.exception.InvalidInputException; @@ -90,8 +93,8 @@ public class CreateTypeDescriptorBackgroundCmd * be applied as a sized character array immediately following the structure whose size does not include * the char array bytes. * @return false if the data type was not created because it already exists, true otherwise - * @throws CodeUnitInsertionException - * @throws CancelledException + * @throws CodeUnitInsertionException if creating data throws exception + * @throws CancelledException if cancelled */ @Override protected boolean createData() throws CodeUnitInsertionException, CancelledException { @@ -142,7 +145,26 @@ public class CreateTypeDescriptorBackgroundCmd monitor.checkCanceled(); // Label - EHDataTypeUtilities.createSymbolIfNeeded(program, prefix, RTTI_0_NAME, null, + Namespace classNamespace = model.getDescriptorAsNamespace(); + + if (classNamespace == null) { + Msg.error(RttiUtil.class, "Cannot get namespace from model " + model.getAddress()); + return false; + } + + //
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) { + classNamespace = RttiUtil.promoteToClassNamespace(program, classNamespace); + } + + // Make the symbol even if the namespace couldn't be promoted + // the method to promote spits out debug error if it cannot be promoted + EHDataTypeUtilities.createSymbolIfNeeded(program, classNamespace, RTTI_0_NAME, getDataAddress(), applyOptions); return true; diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/EHDataTypeUtilities.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/EHDataTypeUtilities.java index 83301b446d..a50c366637 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/EHDataTypeUtilities.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/EHDataTypeUtilities.java @@ -256,9 +256,8 @@ public class EHDataTypeUtilities { * the specified address in the program. * * @param program the program. - * @param prefix the symbol prefix to be used in the symbol name. + * @param classNamespace the class Namespace to create the symbol in * @param dataTypeName the dataTypeName to be used in the symbol name. - * @param suffix the symbol suffix to be used in the symbol name. * @param address the address where the symbol should be created in the program. * @param applyOptions options indicating whether or not to apply comments. * @@ -266,8 +265,8 @@ public class EHDataTypeUtilities { * * @throws InvalidInputException thrown if symbol can't be created as specified. */ - public static Symbol createSymbolIfNeeded(Program program, String prefix, String dataTypeName, - String suffix, Address address, DataApplyOptions applyOptions) + public static Symbol createSymbolIfNeeded(Program program, Namespace classNamespace, + String dataTypeName, Address address, DataApplyOptions applyOptions) throws InvalidInputException { if (dataTypeName == null || !applyOptions.shouldCreateLabel()) { @@ -277,20 +276,21 @@ public class EHDataTypeUtilities { // Make sure we have underscores in name dataTypeName = SymbolUtilities.replaceInvalidChars(dataTypeName, true); + SymbolTable symbolTable = program.getSymbolTable(); SymbolIterator symbols = symbolTable.getSymbolsAsIterator(address); for (Symbol symbol : symbols) { - if (symbol.getName().contains(dataTypeName)) { + if (symbol.getName().contains(dataTypeName) && + symbol.getParentNamespace().equals(classNamespace)) { return null; // Already have one with dataTypeName. } } - String appliedPrefix = (prefix != null) ? (prefix) : ""; - String appliedSuffix = (suffix != null) ? (suffix) : ""; - String appliedSymbol = appliedPrefix + dataTypeName + appliedSuffix; - appliedSymbol = SymbolUtilities.replaceInvalidChars(appliedSymbol, true); + Symbol symbol = + symbolTable.createLabel(address, dataTypeName, classNamespace, SourceType.IMPORTED); + symbol.setPrimary(); - return symbolTable.createLabel(address, appliedSymbol, SourceType.ANALYSIS); + return symbol; } /** diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/RttiUtil.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/RttiUtil.java index 050ff96bee..9992a0e9e3 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/RttiUtil.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/RttiUtil.java @@ -68,28 +68,11 @@ public class RttiUtil { rttiSuffix = SymbolUtilities.replaceInvalidChars(rttiSuffix, true); - // Get or create the namespace for this RTTI's type descriptor. + // Get the namespace for this RTTI's type descriptor. Namespace classNamespace = typeDescriptorModel.getDescriptorAsNamespace(); - // If the RTTI's type descriptor is for a class or struct then promote its - // namespace to a class. - //
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 = typeDescriptorModel.getRefType(); // Can be null. - boolean makeClass = "class".equals(refType) || "struct".equals(refType); SymbolTable symbolTable = program.getSymbolTable(); - if (makeClass && (classNamespace != null) && !(classNamespace instanceof GhidraClass)) { - try { - classNamespace = NamespaceUtils.convertNamespaceToClass(classNamespace); - } - catch (InvalidInputException iie) { - Msg.error(RttiUtil.class, - "Unable to convert namespace to class for namespace " + classNamespace + ".", - iie); - } - } + // See if the symbol already exists for the RTTI data. Symbol matchingSymbol = symbolTable.getSymbol(rttiSuffix, rttiAddress, classNamespace); @@ -103,17 +86,15 @@ public class RttiUtil { if (name.contains(rttiSuffix)) { return false; // Similar symbol already exists. } - // assume any imported symbol is better than what we would put down - // if mangled, it will get demangled later - SourceType source = symbol.getSource(); - if (source == SourceType.IMPORTED) { - return false; - } } try { - // Didn't find the symbol, so create it. - symbolTable.createLabel(rttiAddress, rttiSuffix, classNamespace, + + // Ignore imported mangled symbol because demangling would add tick marks into the name. + // The name created here is better. Set the symbol to be primary so that the demangler + // won't demangle. + Symbol symbol = symbolTable.createLabel(rttiAddress, rttiSuffix, classNamespace, SourceType.IMPORTED); + symbol.setPrimary(); return true; } catch (InvalidInputException e) { @@ -123,6 +104,26 @@ public class RttiUtil { } } + /** + * Method to promote the given namespace to a class namespace + * @param program the given program + * @param namespace the given namespace + * @return the promoted class namespace + */ + public static Namespace promoteToClassNamespace(Program program, Namespace namespace) { + + if (!(namespace instanceof GhidraClass)) { + try { + namespace = NamespaceUtils.convertNamespaceToClass(namespace); + } + catch (InvalidInputException iie) { + Msg.error(RttiUtil.class, + "Unable to convert namespace to class for namespace " + namespace + ".", iie); + } + } + return namespace; + } + /** * Determines the number of vf addresses in the vf table that begins at the specified base * address. @@ -377,6 +378,8 @@ public class RttiUtil { program.getName() + " Couldn't create type_info vftable symbol. "); return; } + // This fixes the double label issue that happens when there is pdb + vftableSymbol.setPrimary(); } catch (InvalidInputException e) { Msg.error(RttiUtil.class,