diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGhidra.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGhidra.java index cfcd4a4b0a..cbba084a63 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGhidra.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGhidra.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. @@ -162,8 +162,12 @@ public class MDMangGhidra extends MDMang { // what it is demangled = new DemangledType(mangledSource, qual.toString(), qual.toString()); } + else if (qual.isLocalNamespace()) { + String local = + MDMangUtils.createStandardLocalNamespaceNode(qual.getLocalNamespaceNumber()); + demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), local); + } else { - // This takes care of plain and local namespaces demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), qual.toString()); } return demangled; diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangUtils.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangUtils.java index 942470a8e2..f5b6a9b740 100644 --- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangUtils.java +++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangUtils.java @@ -169,7 +169,17 @@ public class MDMangUtils { return anon; } Long num = Long.valueOf(str, 16); - return String.format("anon_%08X", num); + return String.format("_anon_%08X", num); + } + + /** + * Given a number in string format as input, creates the standardized local namespace + * node string of the format {@code __l2} where {@code 2} is an an example number. + * @param localNumber the input string + * @return the standardized local namespace component + */ + public static String createStandardLocalNamespaceNode(String localNumber) { + return String.format("__l%s", localNumber); } // @formatter:off @@ -250,7 +260,7 @@ public class MDMangUtils { * @param symbolPath the symbol path to standardize * @return the standardized symbol path */ - public static SymbolPath standarizeSymbolPath(SymbolPath symbolPath) { + public static SymbolPath standarizeSymbolPathTicks(SymbolPath symbolPath) { List parts = symbolPath.asList(); for (int i = 0; i < parts.size(); i++) { String part = parts.get(i); @@ -283,7 +293,7 @@ public class MDMangUtils { * @param symbolPath the symbol path to standardize * @return the standardized symbol path */ - public static SymbolPath standarizeSymbolPathAlt(SymbolPath symbolPath) { + public static SymbolPath standarizeSymbolPathUnderscores(SymbolPath symbolPath) { List parts = symbolPath.asList(); for (int i = 0; i < parts.size(); i++) { String part = parts.get(i); diff --git a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangUtilsTest.java b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangUtilsTest.java index db135543d7..79f5f756ee 100644 --- a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangUtilsTest.java +++ b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangUtilsTest.java @@ -108,33 +108,33 @@ public class MDMangUtilsTest extends AbstractGenericTest { } @Test - public void testStandarizeSymbolPath() throws Exception { + public void testStandarizeSymbolPathTicks() throws Exception { SymbolPath sp = new SymbolPath(Arrays.asList("name0", "__l1", "name2")); - SymbolPath result = MDMangUtils.standarizeSymbolPath(sp); + SymbolPath result = MDMangUtils.standarizeSymbolPathTicks(sp); String expected = "name0::`1'::name2"; assertEquals(expected, result.toString()); } @Test - public void testStandarizeSymbolPathWithEmbedded() throws Exception { + public void testStandarizeSymbolPathWithEmbeddedTicks() throws Exception { SymbolPath sp = new SymbolPath(Arrays.asList("name0", "__l1", "name2(name3::__l4::name5)")); - SymbolPath result = MDMangUtils.standarizeSymbolPath(sp); + SymbolPath result = MDMangUtils.standarizeSymbolPathTicks(sp); String expected = "name0::`1'::name2(name3::`4'::name5)"; assertEquals(expected, result.toString()); } @Test - public void testStandarizeSymbolPathAlt() throws Exception { + public void testStandarizeSymbolPathUnderscores() throws Exception { SymbolPath sp = new SymbolPath(Arrays.asList("name0", "`1'", "name2")); - SymbolPath result = MDMangUtils.standarizeSymbolPathAlt(sp); + SymbolPath result = MDMangUtils.standarizeSymbolPathUnderscores(sp); String expected = "name0::__l1::name2"; assertEquals(expected, result.toString()); } @Test - public void testStandarizeSymbolPathWithEmbeddedAlt() throws Exception { + public void testStandarizeSymbolPathWithEmbeddedUnderscores() throws Exception { SymbolPath sp = new SymbolPath(Arrays.asList("name0", "`1'", "name2(name3::`4'::name5)")); - SymbolPath result = MDMangUtils.standarizeSymbolPathAlt(sp); + SymbolPath result = MDMangUtils.standarizeSymbolPathUnderscores(sp); String expected = "name0::__l1::name2(name3::__l4::name5)"; assertEquals(expected, result.toString()); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java index b7ea110b49..dfa9499cbe 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java @@ -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 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.type.AbstractComplexMsType; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.app.util.pdb.PdbNamespaceUtils; import ghidra.util.Msg; import mdemangler.*; @@ -45,22 +46,7 @@ public abstract class AbstractComplexTypeApplier extends MsDataTypeApplier { * @see #getFixedSymbolPath(AbstractComplexMsType type) */ SymbolPath getSymbolPath(AbstractComplexMsType type) { - SymbolPath symbolPath = null; - // We added logic to check the mangled name first because we found some LLVM "lambda" - // symbols where the regular name was a generic "" with a namespace, but this - // often had a member that also lambda that was marked with the exact same namespace/name - // as the containing structure. We found that the mangled names had more accurate and - // distinguished lambda numbers. -// Temporarily comment out main work of GP-4595 due to namespace/class issues (20240705) TODO: fix -// String mangledName = type.getMangledName(); -// if (mangledName != null) { -// symbolPath = getSymbolPathFromMangledTypeName(mangledName); -// } - if (symbolPath == null) { - String fullPathName = type.getName(); - symbolPath = new SymbolPath(SymbolPathParser.parse(fullPathName)); - } - return symbolPath; + return getSymbolPath(type.getName(), type.getMangledName()); } /** @@ -92,7 +78,45 @@ public abstract class AbstractComplexTypeApplier extends MsDataTypeApplier { return PdbNamespaceUtils.convertToGhidraPathName(path, num); } - private SymbolPath getSymbolPathFromMangledTypeName(String mangledString) { + /** + * Returns the symbol path for the data type referenced by the type record number provided + * @param applicator the applicator + * @param recordNumber the record number + * @return the symbol path + */ + public static SymbolPath getSymbolPath(DefaultPdbApplicator applicator, + RecordNumber recordNumber) { + AbstractMsType t = applicator.getTypeRecord(recordNumber); + if (!(t instanceof AbstractComplexMsType ct)) { + return null; + } + CppCompositeType cpp = applicator.getClassType(ct); + if (cpp != null) { + return cpp.getSymbolPath(); + } + return getSymbolPath(ct.getName(), ct.getMangledName()); + } + + private static SymbolPath getSymbolPath(String name, String mangledName) { + SymbolPath symbolPath = null; + // We added logic to check the mangled name first because we found some LLVM "lambda" + // symbols where the regular name was a generic "" with a namespace, but this + // often had a member that also lambda that was marked with the exact same namespace/name + // as the containing structure. We found that the mangled names had more accurate and + // distinguished lambda numbers. + if (mangledName != null) { + symbolPath = getSymbolPathFromMangledTypeName(mangledName, name); + } + if (symbolPath == null) { + symbolPath = + MDMangUtils.standarizeSymbolPathUnderscores( + new SymbolPath(SymbolPathParser.parse(name))); + } + return symbolPath; + } + + private static SymbolPath getSymbolPathFromMangledTypeName(String mangledString, + String fullPathName) { MDMang demangler = new MDMangGhidra(); try { MDDataType mdDataType = demangler.demangleType(mangledString, true); @@ -101,7 +125,7 @@ public abstract class AbstractComplexTypeApplier extends MsDataTypeApplier { // Namespace that are flagged as functions (not capable at this time) or types or // raw namespace nodes. Note, however, that the Demangler is still weak in this // area as there are codes that we still not know how to interpret. - return MDMangUtils.getSymbolPath(mdDataType); + return MDMangUtils.consolidateSymbolPath(mdDataType, fullPathName, true); // Could consider the following simplification method instead // return MDMangUtils.getSimpleSymbolPath(mdDataType); } @@ -110,7 +134,7 @@ public abstract class AbstractComplexTypeApplier extends MsDataTypeApplier { // Message might cause too much noise (we have a fallback, above, to use the regular // name, but this could cause an error... see the notes above about why a mangled // name is checked first). - Msg.info(this, + Msg.info(AbstractComplexTypeApplier.class, "PDB issue dmangling type name: " + e.getMessage() + " for : " + mangledString); } return null; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java index d10058c2b0..b9cf642f6d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -82,19 +82,19 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { myApplicator.predefineClass(fixedSymbolPath); myComposite = new StructureDataType(categoryPath, fixedSymbolPath.getName(), size, myApplicator.getDataTypeManager()); - myClassType = new CppCompositeType(myComposite, mangledName); + myClassType = new CppCompositeType(fixedSymbolPath, myComposite, mangledName); myClassType.setClass(); } else if (compositeMsType instanceof AbstractStructureMsType) { myComposite = new StructureDataType(categoryPath, fixedSymbolPath.getName(), size, myApplicator.getDataTypeManager()); - myClassType = new CppCompositeType(myComposite, mangledName); + myClassType = new CppCompositeType(fixedSymbolPath, myComposite, mangledName); myClassType.setStruct(); } else if (compositeMsType instanceof AbstractUnionMsType) { myComposite = new UnionDataType(categoryPath, fixedSymbolPath.getName(), myApplicator.getDataTypeManager()); - myClassType = new CppCompositeType(myComposite, mangledName); + myClassType = new CppCompositeType(fixedSymbolPath, myComposite, mangledName); myClassType.setUnion(); } else { // InterfaceMsType @@ -142,6 +142,16 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { boolean isClass = (type instanceof AbstractClassMsType); int size = getSizeInt(type); clearComponents(composite); + if (!lists.methods().isEmpty()) { + // See applyCpp where we store sp in CppCompositeType so we don't have to determine + // this again (including possible demangling)... need a place to store this or + // make sure our CppCompositeType (or its replacement) can be the union solution as + // well. Note that the namespace convention of making a Class namespace is what + // allows the "this" pointer to be a pointer to the appropriate container type (even + // though this is a "union"). + SymbolPath sp = getFixedSymbolPath(type); + applicator.predefineClass(sp); + } List myMembers = new ArrayList<>(); addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers); addMembers(composite, classType, lists.nonstaticMembers(), type, myMembers); @@ -159,6 +169,10 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { Composite composite = combo.dt(); CppCompositeType classType = combo.ct(); clearComponents(composite); + if (!lists.bases().isEmpty() || !lists.methods().isEmpty()) { + SymbolPath sp = classType.getSymbolPath(); + applicator.predefineClass(sp); + } List myMembers = new ArrayList<>(); addClassTypeBaseClasses(composite, classType, lists.bases(), type); addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java index 45f21c98a3..f077fd5ec6 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java @@ -20,6 +20,7 @@ import java.util.Map.Entry; import org.apache.commons.lang3.StringUtils; +import ghidra.app.util.SymbolPath; import ghidra.app.util.bin.format.pdb.*; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog; @@ -48,6 +49,7 @@ public class CppCompositeType { private String className; // String for now. private String mangledName; private int size; + private SymbolPath symbolPath; private Composite composite; private CategoryPath categoryPath; @@ -78,7 +80,8 @@ public class CppCompositeType { private Map placeholderVirtualBaseTables; //---------------------------------------------------------------------------------------------- - public CppCompositeType(Composite composite, String mangledName) { + public CppCompositeType(SymbolPath symbolPath, Composite composite, String mangledName) { + Objects.requireNonNull(symbolPath, "symbolPath may not be null"); Objects.requireNonNull(composite, "composite may not be null"); syntacticBaseClasses = new ArrayList<>(); layoutBaseClasses = new ArrayList<>(); @@ -90,46 +93,49 @@ public class CppCompositeType { isFinal = false; type = Type.UNKNOWN; + this.symbolPath = symbolPath; this.composite = composite; placeholderVirtualBaseTables = new HashMap<>(); categoryPath = new CategoryPath(composite.getCategoryPath(), composite.getName()); this.mangledName = mangledName; } - public static CppClassType createCppClassType(Composite composite, String mangledName) { - return new CppClassType(composite, mangledName); + public static CppClassType createCppClassType(SymbolPath symbolPath, Composite composite, + String mangledName) { + return new CppClassType(symbolPath, composite, mangledName); } - public static CppClassType createCppClassType(Composite composite, String name, - String mangledName, int size) { - CppClassType cppType = new CppClassType(composite, mangledName); + public static CppClassType createCppClassType(SymbolPath symbolPath, Composite composite, + String name, String mangledName, int size) { + CppClassType cppType = new CppClassType(symbolPath, composite, mangledName); cppType.setName(name); cppType.setSize(size); return cppType; } - public static CppStructType createCppStructType(Composite composite, String mangledName) { - return new CppStructType(composite, mangledName); + public static CppStructType createCppStructType(SymbolPath symbolPath, Composite composite, + String mangledName) { + return new CppStructType(symbolPath, composite, mangledName); } - public static CppStructType createCppStructType(Composite composite, String name, - String mangledName, int size) { - CppStructType cppType = new CppStructType(composite, mangledName); + public static CppStructType createCppStructType(SymbolPath symbolPath, Composite composite, + String name, String mangledName, int size) { + CppStructType cppType = new CppStructType(symbolPath, composite, mangledName); cppType.setName(name); cppType.setSize(size); return cppType; } private static class CppClassType extends CppCompositeType { - private CppClassType(Composite composite, String mangledName) { - super(composite, mangledName); + private CppClassType(SymbolPath symbolPath, Composite composite, String mangledName) { + super(symbolPath, composite, mangledName); setClass(); } } private static class CppStructType extends CppCompositeType { - private CppStructType(Composite composite, String mangledName) { - super(composite, mangledName); + private CppStructType(SymbolPath symbolPath, Composite composite, String mangledName) { + super(symbolPath, composite, mangledName); setStruct(); } } @@ -186,6 +192,10 @@ public class CppCompositeType { return layoutBaseClasses; } + SymbolPath getSymbolPath() { + return symbolPath; + } + Composite getComposite() { return composite; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java index 2502d2625c..1f63b9dcc8 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java @@ -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. @@ -49,6 +49,7 @@ import ghidra.util.Msg; import ghidra.util.exception.*; import ghidra.util.task.CancelOnlyWrappingTaskMonitor; import ghidra.util.task.TaskMonitor; +import mdemangler.MDMangUtils; /** * The main engine for applying an AbstractPdb to Ghidra, whether a Program or DataTypeManager. @@ -2249,42 +2250,23 @@ public class DefaultPdbApplicator implements PdbApplicator { } //============================================================================================== - @SuppressWarnings("unused") // For method not being called. In process of removing this version - boolean createSymbolOld(Address address, String symbolPathString, boolean forcePrimary) { - -// storeLabelByAddress(address, symbolPathString); - - try { - Namespace namespace = program.getGlobalNamespace(); - if (symbolPathString.startsWith(THUNK_NAME_PREFIX)) { - symbolPathString = symbolPathString.substring(THUNK_NAME_PREFIX.length(), - symbolPathString.length()); - } - SymbolPath symbolPath = new SymbolPath(symbolPathString); - symbolPath = symbolPath.replaceInvalidChars(); - String name = symbolPath.getName(); - String namespacePath = symbolPath.getParentPath(); - if (namespacePath != null) { - namespace = NamespaceUtils.createNamespaceHierarchy(namespacePath, namespace, - program, address, SourceType.IMPORTED); - } - - Symbol s = SymbolUtilities.createPreferredLabelOrFunctionSymbol(program, address, - namespace, name, SourceType.IMPORTED); - if (s != null && forcePrimary) { - // PDB contains both mangled, namespace names, and global names - // If mangled name does not remain primary it will not get demamgled - // and we may not get signature information applied - SetLabelPrimaryCmd cmd = - new SetLabelPrimaryCmd(address, s.getName(), s.getParentNamespace()); - cmd.applyTo(program); - } + boolean addToPlateUnique(Address address, String comment) { + if (StringUtils.isBlank(comment)) { + return false; + } + String plate = program.getListing().getComment(CodeUnit.PLATE_COMMENT, address); + if (plate == null) { + plate = ""; + } + else if (plate.contains(comment)) { return true; } - catch (InvalidInputException e) { - log.appendMsg("PDB Warning: Unable to create symbol: " + e.getMessage()); + else if (!comment.endsWith("\n")) { + comment += '\n'; } - return false; + plate = comment + plate; // putting new comment at top of existing plate + SetCommentCmd.createComment(program, address, plate, CodeUnit.PLATE_COMMENT); + return true; } //============================================================================================== @@ -2292,48 +2274,59 @@ public class DefaultPdbApplicator implements PdbApplicator { return createSymbol(address, symbolPathString, isNewFunctionSignature, null); } + Symbol createSymbol(Address address, SymbolPath symbolPath, boolean isNewFunctionSignature) { + symbolPath = MDMangUtils.standarizeSymbolPathUnderscores(symbolPath); + symbolPath = symbolPath.replaceInvalidChars(); + return createSymbolInternal(address, symbolPath, isNewFunctionSignature, null); + } + Symbol createSymbol(Address address, String symbolPathString, boolean isNewFunctionSignature, String plateAddition) { + SymbolPath symbolPath = getCleanSymbolPath(symbolPathString); + return createSymbolInternal(address, symbolPath, isNewFunctionSignature, plateAddition); + } - SymbolPath newSymbolPath = getCleanSymbolPath(symbolPathString); + private Symbol createSymbolInternal(Address address, SymbolPath symbolPath, + boolean isNewFunctionSignature, + String plateAddition) { Symbol existingSymbol = program.getSymbolTable().getPrimarySymbol(address); if (existingSymbol == null || isNewFunctionSignature) { - return createSymbol(address, newSymbolPath, true, plateAddition); + return doCreateSymbol(address, symbolPath, true, plateAddition); } if (existingSymbol.getSymbolType() == SymbolType.FUNCTION && existingSymbol.getSource() == SourceType.DEFAULT) { - return createSymbol(address, newSymbolPath, true, plateAddition); + return doCreateSymbol(address, symbolPath, true, plateAddition); } Function existingFunction = program.getListing().getFunctionAt(address); if (existingFunction != null) { // Maybe I should care if there is a data type there too. if (existingFunction.getSignatureSource().isHigherPriorityThan(SourceType.ANALYSIS)) { // Existing is USER or IMPORTED - return createSymbol(address, newSymbolPath, false, plateAddition); + return doCreateSymbol(address, symbolPath, false, plateAddition); } } if (!existingSymbol.getParentNamespace().equals(program.getGlobalNamespace())) { // existing symbol has a non-global namespace - return createSymbol(address, newSymbolPath, false, plateAddition); + return doCreateSymbol(address, symbolPath, false, plateAddition); } - if (newSymbolPath.getParent() != null) { + if (symbolPath.getParent() != null) { // new symbol has non-global namespace - return createSymbol(address, newSymbolPath, true, plateAddition); + return doCreateSymbol(address, symbolPath, true, plateAddition); } // Both existing and new symbols are in global namespace at this point - if (isMangled(symbolPathString) && !isMangled(existingSymbol.getName())) { + if (isMangled(symbolPath.getName()) && !isMangled(existingSymbol.getName())) { // new symbol is mangled, but don't override existing one if it is mangled - return createSymbol(address, newSymbolPath, true, plateAddition); + return doCreateSymbol(address, symbolPath, true, plateAddition); } - return createSymbol(address, newSymbolPath, false, plateAddition); + return doCreateSymbol(address, symbolPath, false, plateAddition); } - private Symbol createSymbol(Address address, SymbolPath symbolPath, boolean makePrimary, + private Symbol doCreateSymbol(Address address, SymbolPath symbolPath, boolean makePrimary, String plateAddition) { Symbol symbol = null; try { @@ -2362,25 +2355,6 @@ public class DefaultPdbApplicator implements PdbApplicator { return symbol; } - public boolean addToPlateUnique(Address address, String comment) { - if (StringUtils.isBlank(comment)) { - return false; - } - String plate = program.getListing().getComment(CodeUnit.PLATE_COMMENT, address); - if (plate == null) { - plate = ""; - } - else if (plate.contains(comment)) { - return true; - } - else if (!comment.endsWith("\n")) { - comment += '\n'; - } - plate = comment + plate; // putting new comment at top of existing plate - SetCommentCmd.createComment(program, address, plate, CodeUnit.PLATE_COMMENT); - return true; - } - private static boolean isMangled(String name) { return name.startsWith("?"); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java index 942bbdf9f7..ec0d3de804 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java @@ -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. @@ -123,6 +123,14 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { FieldListTypeApplier.FieldLists lists = fieldListApplier.getFieldLists(fieldListRecordNumber); + if (!lists.methods().isEmpty()) { + // See applyCpp where we store sp in CppCompositeType so we don't have to determine + // this again (including possible demangling)... can we store this symbol path + // somewhere as well so we do not need to re-create it? + SymbolPath sp = getFixedSymbolPath(type); + applicator.predefineClass(sp); + } + // Note: not doing anything with getNamespaceList() or getMethodsList() at this time. List enumerates = lists.enumerates(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java index 92c68d39f2..909e1f2ead 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java @@ -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. @@ -15,11 +15,14 @@ */ package ghidra.app.util.pdb.pdbapplicator; +import java.util.List; + import ghidra.app.cmd.function.ApplyFunctionSignatureCmd; import ghidra.app.cmd.function.CallDepthChangeInfo; +import ghidra.app.util.SymbolPath; import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; -import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSet; import ghidra.program.model.data.DataType; @@ -28,6 +31,7 @@ import ghidra.program.model.lang.Register; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.SourceType; import ghidra.util.InvalidNameException; +import ghidra.util.Msg; import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; @@ -103,7 +107,68 @@ public class FunctionSymbolApplier extends AbstractBlockContextApplier // If signature was set, then override existing primary mangled symbol with // the global symbol that provided this signature so that Demangler does not overwrite // the richer data type we get with global symbols. - applicator.createSymbol(address, name, succeededSetFunctionSignature); + applicator.createSymbol(address, getReconciledSymbolPath(), succeededSetFunctionSignature); + } + + private SymbolPath getReconciledSymbolPath() { + + String name = symbol.getName(); + SymbolPath symbolPath = new SymbolPath(name); + RecordNumber typeRecordNumber = symbol.getTypeRecordNumber(); + AbstractMsType fType = applicator.getTypeRecord(typeRecordNumber); + if (!(fType instanceof AbstractMemberFunctionMsType memberFunction)) { + return symbolPath; + } + + // Get containing type, and while we are at it, ensure that it is defined as a class + // namespace. + // This has likely already been done, but we want to be sure that it has. + RecordNumber rc = memberFunction.getContainingClassRecordNumber(); + SymbolPath containerSymbolPath = AbstractComplexTypeApplier.getSymbolPath(applicator, rc); + applicator.predefineClass(containerSymbolPath); + + // Make sure that the symbol path of the underlying type of the this pointer is also + // defined as a class namespace. + // Probably does not need to be done, as it likely was done for the underlying data type. + AbstractMsType p = memberFunction.getThisPointerType(); + if (p instanceof AbstractPointerMsType ptr) { + RecordNumber rpt = ptr.getUnderlyingRecordNumber(); + if (!rpt.equals(rc)) { + SymbolPath underlyingSymbolPath = + AbstractComplexTypeApplier.getSymbolPath(applicator, rc); + applicator.predefineClass(underlyingSymbolPath); + } + } + + // Only trying to fix up anonymous namespaces + if (!name.startsWith("`anonymous namespace'") && !name.startsWith("anonymous-namespace")) { + return symbolPath; + } + + // Reconcile path of function with path of container type. + // Logic is a little different from what is in MDMangUtils. + // Want all namespace nodes to match except possibly the first one, which should be + // the anonymous namespace one. + List containerParts = containerSymbolPath.asList(); + List parts = symbolPath.asList(); + if (containerParts.size() != parts.size() - 1) { + Msg.info(this, "Unmatched symbol path size during fn name reconcilation"); + return symbolPath; + } + for (int i = 0; i < containerParts.size(); i++) { + String containerPart = containerParts.get(i); + String part = parts.get(i); + if (!containerPart.equals(part)) { + if (i == 0) { + parts.set(i, containerPart); + } + else { + Msg.info(this, "Mismatch symbol path nodes during fn name reconcilation"); + return symbolPath; + } + } + } + return new SymbolPath(parts); } /** diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java index c5ea7aaed5..0f608beee7 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java @@ -99,6 +99,9 @@ public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier { if (!(applier instanceof CompositeTypeApplier compApplier)) { return; } + // 20240709: found example of "this" pointer of method that referenced a composite that + // did not have any base classes or methods. So we want to make sure we take the + // opportunity here to promote the namespace to a class. SymbolPath sp = compApplier.getFixedSymbolPath(msComposite); applicator.predefineClass(sp); } diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java index c5a350283d..57dca93678 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java @@ -15,7 +15,7 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import java.util.*; @@ -24,6 +24,7 @@ import org.junit.Test; import generic.test.AbstractGenericTest; import ghidra.app.plugin.core.checksums.MyTestMemory; +import ghidra.app.util.SymbolPath; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressIterator; import ghidra.program.model.data.*; @@ -476,14 +477,16 @@ public class CppCompositeTypeTest extends AbstractGenericTest { private static CppCompositeType createStruct32(String name, int size) { Composite composite = new StructureDataType(CategoryPath.ROOT, name, 0, dtm32); + SymbolPath symbolPath = new SymbolPath(name); String mangledName = createMangledName(name, CppCompositeType.Type.STRUCT); - return CppCompositeType.createCppStructType(composite, name, mangledName, size); + return CppCompositeType.createCppStructType(symbolPath, composite, name, mangledName, size); } private static CppCompositeType createStruct64(String name, int size) { Composite composite = new StructureDataType(CategoryPath.ROOT, name, 0, dtm64); + SymbolPath symbolPath = new SymbolPath(name); String mangledName = createMangledName(name, CppCompositeType.Type.STRUCT); - return CppCompositeType.createCppStructType(composite, name, mangledName, 0); + return CppCompositeType.createCppStructType(symbolPath, composite, name, mangledName, 0); } private static String createMangledName(String className, CppCompositeType.Type type) {