diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java index 4900d71920..a61f9a8f9a 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.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. @@ -120,7 +120,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { // They are either undefined bytes or code that is not in a function. private static final boolean FIXUP_PROGRAM = true; - // bookmark all constructor/destructor functions figured out by this script + // bookmark all constructor/destructor functions recognized by script private static final boolean BOOKMARK_FOUND_FUNCTIONS = true; // show a graph of class hierarchies after script is complete @@ -323,12 +323,9 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { getNumberOfConstructorsOrDestructors(recoveredClasses) + " class member functions to assign."); - if (!hasDebugSymbols) { - - if (BOOKMARK_FOUND_FUNCTIONS) { - bookmarkFunctions(recoveredClasses); - println("See Bookmark Manager for a list of functions by type."); - } + if (BOOKMARK_FOUND_FUNCTIONS) { + bookmarkFunctions(recoveredClasses); + println("See Bookmark Manager for a list of functions by type."); } callOptionalOutputMethods(recoveredClasses, out); @@ -468,17 +465,18 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { if (status == Status.FAILURE) { return true; } - + // if any relocations for special typeinfo class symbols are unsupported then // determine where the symbol is located before determining if it is an issue - if(status == Status.UNSUPPORTED) { + if (status == Status.UNSUPPORTED) { //if relocation symbol is the same as the symbol at the relcation address //then this situation is not an issue - it indicates a copy relocation at the //location of the special typeinfo vtable which is a use case that can be handled Address address = r.getAddress(); - Symbol symbolAtAddress = currentProgram.getSymbolTable().getSymbol(symbolName, address, currentProgram.getGlobalNamespace()); - if(symbolAtAddress != null) { + Symbol symbolAtAddress = currentProgram.getSymbolTable() + .getSymbol(symbolName, address, currentProgram.getGlobalNamespace()); + if (symbolAtAddress != null) { continue; } return true; @@ -489,7 +487,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return false; } - private void analyzeProgramChanges(AddressSetView beforeChanges) throws Exception { AddressSetView addressSet = currentProgram.getChanges().getAddressSet(); diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java index d3fdf6194a..69eb2c5a08 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java @@ -2562,7 +2562,11 @@ public class RecoveredClassHelper { Function function = functionIterator.next(); Namespace namespace = function.getParentNamespace(); if (!namespace.equals(recoveredClass.getClassNamespace())) { - continue; + Symbol functionSymbol = function.getSymbol(); + if (functionSymbol.getSource().equals(SourceType.IMPORTED)) { + functionIterator.remove(); // remove named functions belonging to other class + } + continue; // continue in either case to skip functions in other namespaces } String name = function.getName(); if (name.equals(recoveredClass.getName())) { @@ -8465,7 +8469,8 @@ public class RecoveredClassHelper { Symbol symbol = symbols.next(); if (symbol.getName().equals("vftable") || symbol.getName().substring(1).startsWith("vftable") || - symbol.getName().contains("vftable_for_")) { + symbol.getName().contains("vftable_for_") || + symbol.getName().contains("vftable{for")) { vftableSymbols.add(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 abc0a1c718..61bfdd545c 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 @@ -23,6 +23,8 @@ import ghidra.app.cmd.data.TypeDescriptorModel; import ghidra.app.util.NamespaceUtils; import ghidra.app.util.PseudoDisassembler; import ghidra.app.util.datatype.microsoft.MSDataTypeUtils; +import ghidra.app.util.demangler.DemangledObject; +import ghidra.app.util.demangler.DemanglerUtil; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSetView; import ghidra.program.model.listing.*; @@ -73,29 +75,71 @@ public class RttiUtil { SymbolTable symbolTable = program.getSymbolTable(); - // See if the symbol already exists for the RTTI data. + // See if the symbol already exists for the RTTI data Symbol matchingSymbol = symbolTable.getSymbol(rttiSuffix, rttiAddress, classNamespace); if (matchingSymbol != null) { return false; } - // NOTE: This code was originally put here to skip applying labels the pdb put down if the - // above check failed but symbols were similar. This check has been removed because of - // cases where this check stopped the full namespace path from being created. The code is - // here commented out because we might want to use this to do extra checking and possibly - // remove the similar symbol instead of leaving it as a secondary symbol. - // Don't create it if a similar symbol already exists at the address of the data. -// SymbolIterator symbols = symbolTable.getSymbolsAsIterator(rttiAddress); -// for (Symbol symbol : symbols) { -// String name = symbol.getName(); -// if (name.contains(rttiSuffix)) { -// return false; // Similar symbol already exists. -// } -// } + // check for similar symbol + DemangledObject matchingDemangledObject = null; + SymbolIterator symbols = symbolTable.getSymbolsAsIterator(rttiAddress); + for (Symbol symbol : symbols) { + String name = symbol.getName(); + + // if mangled get the matching demangled object if there is one and save for after loop + // in case symbols are not demangled yet + DemangledObject demangledObject = DemanglerUtil.demangle(name); + if (demangledObject != null && demangledObject.getName().contains(rttiSuffix)) { + matchingDemangledObject = demangledObject; + continue; + } + + // Similar symbol already exists - more checking/fixing needed + if (name.contains(rttiSuffix)) { + + // check for differing namespace to correct pdb in rare cases + Namespace currentNamespace = symbol.getParentNamespace(); + if (!currentNamespace.equals(classNamespace)) { + Msg.warn(program, "Removed incorrect pdb symbol: " + symbol.getName(true)); + symbol.delete(); + continue; + } + // if symbol contains the matching string and ticks, remove the ticks + if (replaceSymbolWithNoTicks(symbol)) { + return true; + } + } + } + + // if it gets here then there were no demangled symbols that contained the rttisuffix + // indicating that the mangled matching symbol has not been demangled yet and needs to be + // demangled + if (matchingDemangledObject != null) { + + String name = matchingDemangledObject.getName(); + if (name.contains(rttiSuffix)) { + + try { + Symbol symbol = symbolTable.createLabel(rttiAddress, name, classNamespace, + SourceType.IMPORTED); + // Set the symbol to be primary so that the demangler + // won't demangle again + symbol.setPrimary(); + if (replaceSymbolWithNoTicks(symbol)) { + return true; + } + + } + catch (InvalidInputException e) { + //fall through and make a symbol using the rttiSuffix string even though + // it might really be one with extra information + } + + } + } + // if code gets here then no pdb info so have to make the symbol here try { - // 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(); @@ -108,6 +152,30 @@ public class RttiUtil { } } + /** + * Method to remove all ' and ` from symbol if it starts with ` + * @param symbol the symbol + * @return true if the symbol has been replaced, false otherwise + */ + private static boolean replaceSymbolWithNoTicks(Symbol symbol) { + + String name = symbol.getName(); + if (name.startsWith("`")) { + name = name.replace("'", "").replace("`", ""); + try { + symbol.setName(name, symbol.getSource()); + return true; + } + catch (DuplicateNameException e) { + return false; + } + catch (InvalidInputException e) { + return false; + } + } + return false; + } + /** * Method to promote the given namespace to a class namespace * @param program the given program