diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java index 8b25e52ac35..4900d719202 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java @@ -80,6 +80,7 @@ import ghidra.program.model.listing.*; import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.reloc.Relocation; +import ghidra.program.model.reloc.Relocation.Status; import ghidra.program.model.reloc.RelocationTable; import ghidra.program.model.symbol.Symbol; import ghidra.program.util.GhidraProgramUtilities; @@ -210,8 +211,7 @@ else if (isPE() && isGcc()) { if (!runGcc) { return; } - //run fixup old elf relocations script - runScript("FixElfExternalOffsetDataRelocationScript.java"); + recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols, monitor); @@ -232,9 +232,6 @@ else if (isGcc()) { return; } - //run fixup old elf relocations script - runScript("FixElfExternalOffsetDataRelocationScript.java"); - hasDebugSymbols = isDwarfLoadedInProgram(); if (hasDwarf() && !hasDebugSymbols) { println( @@ -379,7 +376,7 @@ private boolean isDwarfLoadedInProgram() { DWARFProgram.DWARF_ROOT_NAME) || options.getBoolean("DWARF Loaded", false)); } - public String validate() throws CancelledException { + public String validate() throws Exception { if (currentProgram == null) { return ("There is no open program"); @@ -417,6 +414,8 @@ public String validate() throws CancelledException { // check that gcc loader or mingw analyzer has fixed the relocations correctly if (isGcc()) { + runScript("FixElfExternalOffsetDataRelocationScript.java"); + // first check that there is even rtti by searching the special string in memory if (!isStringInProgramMemory("class_type_info")) { return ("This program does not contain RTTI."); @@ -432,7 +431,7 @@ public String validate() throws CancelledException { "contact the Ghidra team so this issue can be fixed."); } - if (hasUnhandledRelocations()) { + if (hasRelocationIssue()) { return ("This program has unhandled elf relocations so cannot continue. Please " + "contact the Ghidra team for assistance."); } @@ -442,7 +441,13 @@ public String validate() throws CancelledException { } - private boolean hasUnhandledRelocations() throws CancelledException { + /** + * Method to determine if the gcc relocations needed to find the special typeinfos/vtables + * have any issues that would keep script from running correctly. + * @return true if there are any issues with the relocations, false otherwise + * @throws CancelledException if cancelled + */ + private boolean hasRelocationIssue() throws CancelledException { RelocationTable relocationTable = currentProgram.getRelocationTable(); @@ -452,17 +457,39 @@ private boolean hasUnhandledRelocations() throws CancelledException { monitor.checkCancelled(); Relocation r = relocations.next(); - if (r.getSymbolName().contains("class_type_info") && - (r.getStatus() != Relocation.Status.APPLIED && - r.getStatus() != Relocation.Status.APPLIED_OTHER && - r.getStatus() != Relocation.Status.SKIPPED)) { - return true; - } + String symbolName = r.getSymbolName(); + + if (symbolName != null && symbolName.contains("class_type_info")) { + + Status status = r.getStatus(); + // if any relocations for special typeinfo class symbols have failed then there + // is an issue + 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 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) { + continue; + } + return true; + } + + } } return false; } + private void analyzeProgramChanges(AddressSetView beforeChanges) throws Exception { AddressSetView addressSet = currentProgram.getChanges().getAddressSet(); diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/GccTypeinfo.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/GccTypeinfo.java index 9ea15572428..6b84125ff4f 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/GccTypeinfo.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/GccTypeinfo.java @@ -15,10 +15,7 @@ */ package classrecovery; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import ghidra.program.model.address.Address; import ghidra.program.model.symbol.Namespace; @@ -30,7 +27,7 @@ public class GccTypeinfo extends Typeinfo { private static final String VMI_CLASS_TYPEINFO_NAMESPACE = "__vmi_class_type_info"; boolean isSpecialTypeinfo; - GccTypeinfo inheritedSpecialTypeinfo = null; + Namespace inheritedSpecialTypeinfoNamespace = null; Address vtableAddress; boolean inProgramMemory; String mangledNamespaceString = null; @@ -53,13 +50,13 @@ public boolean isInProgramMemory() { return inProgramMemory; } - public void setInheritedSpecialTypeinfo(GccTypeinfo specialTypeinfo) { - inheritedSpecialTypeinfo = specialTypeinfo; + public void setInheritedSpecialTypeinfoNamespace(Namespace specialTypeinfoNamespace) { + inheritedSpecialTypeinfoNamespace = specialTypeinfoNamespace; } - public GccTypeinfo getInheritedSpecialTypeinfo() { - return inheritedSpecialTypeinfo; + public Namespace getInheritedSpecialTypeinfoNamespace() { + return inheritedSpecialTypeinfoNamespace; } @@ -156,21 +153,21 @@ public long getInheritanceFlagValue() { } public boolean isClassTypeinfo() { - if(inheritedSpecialTypeinfo.getNamespace().getName().equals(CLASS_TYPEINFO_NAMESPACE)) { + if (inheritedSpecialTypeinfoNamespace.getName().equals(CLASS_TYPEINFO_NAMESPACE)) { return true; } return false; } public boolean isSiClassTypeinfo() { - if(inheritedSpecialTypeinfo.getNamespace().getName().equals(SI_CLASS_TYPEINFO_NAMESPACE)) { + if (inheritedSpecialTypeinfoNamespace.getName().equals(SI_CLASS_TYPEINFO_NAMESPACE)) { return true; } return false; } public boolean isVmiClassTypeinfo() { - if(inheritedSpecialTypeinfo.getNamespace().getName().equals(VMI_CLASS_TYPEINFO_NAMESPACE)) { + if (inheritedSpecialTypeinfoNamespace.getName().equals(VMI_CLASS_TYPEINFO_NAMESPACE)) { return true; } return false; diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java index e14a5893959..092f8a32a13 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java @@ -19,6 +19,8 @@ import java.io.UnsupportedEncodingException; import java.util.*; +import org.apache.commons.lang3.StringUtils; + import ghidra.app.cmd.label.DemanglerCmd; import ghidra.app.plugin.core.analysis.ReferenceAddressPair; import ghidra.app.util.NamespaceUtils; @@ -101,6 +103,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { protected final FunctionManager functionManager; protected final Listing listing; + protected final Memory memory; public RTTIGccClassRecoverer(Program program, ServiceProvider serviceProvider, FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates, @@ -113,6 +116,9 @@ public RTTIGccClassRecoverer(Program program, ServiceProvider serviceProvider, functionManager = program.getFunctionManager(); listing = program.getListing(); + + memory = program.getMemory(); + } @Override @@ -156,7 +162,6 @@ public List createRecoveredClasses() throws CancelledException, List specialTypeinfos = createSpecialTypeinfos(); if (specialTypeinfos.isEmpty()) { Msg.debug(this, "Could not create special typeinfos"); - return null; } Msg.debug(this, "Creating Special Vtables"); @@ -169,7 +174,6 @@ public List createRecoveredClasses() throws CancelledException, if (specialVtables.size() != specialTypeinfos.size()) { Msg.debug(this, "Not equal number of special vtables and special typeinfos"); - return null; } setComponentOffset(); @@ -355,7 +359,7 @@ private Symbol findTypeinfoUsingNotInProgramMemoryVtableSymbol(String namespaceN // in a non-loaded section that isn't real memory then it shouldn't be the case where the // typeinfo is at the same location as the vtable since it should have enough memory and // real bytes that point to a real typeinfo in program memory - if (hasAssociatedFileByes(vtableAddress)) { + if (isLoadedAndInitializedMemory(vtableAddress)) { return null; } @@ -381,7 +385,7 @@ private Symbol findTypeinfoUsingNotInProgramMemoryVtableSymbol(String namespaceN } - private boolean hasAssociatedFileByes(Address address) { + private boolean isLoadedAndInitializedMemory(Address address) { if (inExternalBlock(address)) { return false; @@ -391,9 +395,9 @@ private boolean hasAssociatedFileByes(Address address) { } Memory memory = program.getMemory(); - long fileOffset = memory.getAddressSourceInfo(address).getFileOffset(); - if (fileOffset == -1) { - return false; + AddressSetView initMem = memory.getLoadedAndInitializedAddressSet(); + if (initMem.contains(address)) { + return true; } return true; @@ -451,7 +455,6 @@ private Symbol findAndReturnDemangledSymbol(String mangledSymbolName, return null; } - // TODO: can this be used for regular ones too? private Symbol findTypeinfoSymbolUsingMangledNamespaceString(String mangledNamespace, String namespaceName) throws CancelledException { @@ -2220,6 +2223,19 @@ public SpecialVtable createSpecialVtable(Address vtableAddress, GccTypeinfo spec SpecialVtable specialVtable = new SpecialVtable(program, vtableAddress, typeinfoRef, isExternal, vtableSymbol.getParentNamespace(), monitor); + + if (specialTypeinfo != null) { + specialTypeinfo.setVtableAddress(vtableAddress); + } + + if (!specialVtable.isExternal()) { + specialVtable.applyVtableData(); + vtableToSizeMap.put(specialVtable.getAddress(), specialVtable.getLength()); + createVtableLabel(specialVtable); + createVtableComment(specialVtable); + createVfunctionSymbol(specialVtable); + } + return specialVtable; } @@ -2362,9 +2378,14 @@ else if (specialVtable.getNamespace() typeinfoSymbol = createDemangledTypeinfoSymbol(typeinfoAddress); if (typeinfoSymbol == null) { - Msg.debug(this, "Could not create demangled typeinfo symbol at " + - typeinfoAddress.toString()); - continue; + //If no mangled class name, check for non-mangled pascal type class name + typeinfoSymbol = + createTypeinfoSymbolFromNonMangledString(typeinfoAddress); + if (typeinfoSymbol == null) { + Msg.debug(this, "Could not create typeinfo symbol at " + + typeinfoAddress.toString()); + continue; + } } } @@ -2374,9 +2395,9 @@ else if (specialVtable.getNamespace() if (specialTypeinfoNamespaceName == null) { continue; } - GccTypeinfo specialTypeinfo = - getTypeinfo(specialTypeinfoNamespaceName, specialTypeinfos); - typeinfo.setInheritedSpecialTypeinfo(specialTypeinfo); + + typeinfo.setInheritedSpecialTypeinfoNamespace(specialVtable.getNamespace()); + typeinfos.add(typeinfo); continue; } @@ -2390,7 +2411,7 @@ else if (specialVtable.getNamespace() for (GccTypeinfo typeinfo : typeinfos) { monitor.checkCancelled(); Address typeinfoAddress = typeinfo.getAddress(); - if (typeinfo.getInheritedSpecialTypeinfo() == null) { + if (typeinfo.getInheritedSpecialTypeinfoNamespace() == null) { typeinfosToRemove.add(typeinfo); continue; @@ -2436,9 +2457,7 @@ private void updateTypeinfosWithBases(List typeinfos, continue; } - // TODO: update the typeinfo with the correct namespace based on the structure - - String namespaceName = typeinfo.getInheritedSpecialTypeinfo().getNamespace().getName(); + String namespaceName = typeinfo.getInheritedSpecialTypeinfoNamespace().getName(); // if typeinfo inherits class_type_info then no Base to update if (namespaceName.equals(CLASS_TYPEINFO_NAMESPACE)) { @@ -2652,6 +2671,7 @@ private boolean canContainPointer(Address pointer) throws CancelledException { // ok if has symbol at the actual addr so don't check it if (offset == 0) { + offset++; continue; } @@ -2848,6 +2868,103 @@ private Symbol createDemangledTypeinfoSymbol(Address typeinfoAddress) return newSymbol; } + + private Symbol createTypeinfoSymbolFromNonMangledString(Address typeinfoAddress) + throws DuplicateNameException, InvalidInputException, CancelledException { + + Address typeinfoNameAddress = getTypeinfoNameAddress(typeinfoAddress); + + if (typeinfoNameAddress == null) { + Msg.debug(this, + "Could not get typeinfo-name address from " + typeinfoAddress.toString()); + return null; + } + + String typeinfoNameString = getStringFromMemory(typeinfoNameAddress); + + if (typeinfoNameString == null) { + Msg.debug(this, "Could not get typeinfo string from " + typeinfoNameAddress.toString()); + return null; + } + + // get length from start of string + String lenString = getAsciiLengthString(typeinfoNameString); + if (lenString.isEmpty()) { + Msg.debug(this, + "Could not get typeinfo-name string len from " + typeinfoNameAddress.toString()); + return null; + } + + // convert lenString to int len + try { + int len = Integer.parseInt(lenString); + + // get className from string - if not exactly the correct len then return null + String className = typeinfoNameString.substring(lenString.length()); + if (className.length() != len) { + Msg.debug(this, "Expected typeinfo-name to be len " + len + " but it was " + + className.length()); + return null; + } + + program.getListing() + .clearCodeUnits(typeinfoNameAddress, + typeinfoNameAddress.add(typeinfoNameString.length()), true); + boolean created = createString(typeinfoNameAddress, typeinfoNameString.length()); + if (!created) { + Msg.debug(this, "Could not create string at " + typeinfoNameAddress); + } + + // create typeinfo name symbol + Namespace classNamespace = + symbolTable.getOrCreateNameSpace(globalNamespace, className, SourceType.ANALYSIS); + Symbol typeinfoNameSymbol = symbolTable.createLabel(typeinfoNameAddress, + "typeinfo-name", classNamespace, SourceType.ANALYSIS); + typeinfoNameSymbol.setPrimary(); + + // create the new typeinfo symbol in the demangled namespace + Symbol typeinfoSymbol = symbolTable.createLabel(typeinfoAddress, "typeinfo", + classNamespace, SourceType.ANALYSIS); + typeinfoSymbol.setPrimary(); + + api.setPlateComment(typeinfoAddress, "typeinfo for " + classNamespace.getName(true)); + + return typeinfoSymbol; + } + catch (NumberFormatException ex) { + return null; + } + } + + private String getAsciiLengthString(String string) throws CancelledException { + + boolean isDigit = true; + int len = 0; + String lenString = new String(); + while (isDigit) { + monitor.checkCancelled(); + String charString = string.substring(len, len); + if (!StringUtils.isNumeric(charString)) { + return lenString; + } + lenString.concat(charString); + len++; + } + return lenString; + } + + private boolean isAllAscii(Address address, int len) throws CancelledException { + + for (int i = 0; i < len; i++) { + monitor.checkCancelled(); + + if (!isAscii(address.add(i))) { + return false; + } + } + return true; + } + private boolean isTypeinfoNameString(String string) { DemangledObject demangledObject = DemanglerUtil.demangle(string); @@ -2934,6 +3051,14 @@ private String getStringFromMemory(Address address) { } + private String getStringFromMemory(Address address, int len) { + + TerminatedStringDataType sdt = new TerminatedStringDataType(); + MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), address); + return (String) sdt.getValue(buf, sdt.getDefaultSettings(), len); + + } + private int getStringLen(Address addr) { int len = 0; @@ -3544,80 +3669,91 @@ private List addClassParentsAndFlagsForVmiClass(RecoveredClass r } - private Address findSpecialVtable(GccTypeinfo specialTypeinfo, - List specialTypeinfos) throws CancelledException { + private List findSpecialVtables(List specialTypeinfos) + throws Exception { - String namespaceName = specialTypeinfo.getNamespace().getName(); - String mangledNamespaceString = specialTypeinfo.getMangledNamespaceString(); + List specialVtables = new ArrayList(); - // try finding with normal symbol name and namespace - Symbol vtableSymbol = - getSymbolInNamespaces(SPECIAL_CLASS_NAMESPACE, namespaceName, VTABLE_LABEL); - if (vtableSymbol == null) { - // then try finding with mangled symbol - vtableSymbol = - findAndReturnDemangledSymbol(MANGLED_VTABLE_PREFIX + mangledNamespaceString, - SPECIAL_CLASS_NAMESPACE, namespaceName, VTABLE_LABEL); + Map namespaceMap = new HashMap(); + namespaceMap.put(CLASS_TYPEINFO_NAMESPACE, MANGLED_CLASS_TYPEINFO_NAMESPACE); + namespaceMap.put(SI_CLASS_TYPEINFO_NAMESPACE, MANGLED_SI_CLASS_TYPEINFO_NAMESPACE); + namespaceMap.put(VMI_CLASS_TYPEINFO_NAMESPACE, MANGLED_VMI_CLASS_TYPEINFO_NAMESPACE); - // then try finding top of special vtable by finding ref to special typeinfo - if (vtableSymbol == null) { - Address vtableAddress = findSpecialVtableUsingSpecialTypeinfo( - specialTypeinfo.getAddress(), specialTypeinfos); + for (String namespaceName : namespaceMap.keySet()) { - if (vtableAddress == null) { - return null; - } + GccTypeinfo specTypeinfo = getSpecialTypeinfo(specialTypeinfos, namespaceName); - try { - vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL, - specialTypeinfo.getNamespace(), SourceType.ANALYSIS); - api.setPlateComment(vtableAddress, - "vtable for " + specialTypeinfo.getNamespace()); + Address vtableAddress = findSpecialVtableAddress(namespaceName, + namespaceMap.get(namespaceName), specialTypeinfos); + if (vtableAddress == null) { + continue; + } - } - catch (InvalidInputException e) { - // ignore - } + SpecialVtable specialVtable = + createSpecialVtable(vtableAddress, specTypeinfo); + specialVtables.add(specialVtable); - } } - if (vtableSymbol != null) { - return vtableSymbol.getAddress(); - } - return null; + return specialVtables; } - private List findSpecialVtables(List specialTypeinfos) - throws Exception { + private Address findSpecialVtableAddress(String namespaceName, String mangledNamespace, + List specialTypeinfos) throws CancelledException { - List specialVtables = new ArrayList(); + //First try to find with special symbols + Symbol vtableSymbol = getSymbolInNamespaces(namespaceName, mangledNamespace, VTABLE_LABEL); - for (GccTypeinfo specialTypeinfo : specialTypeinfos) { - monitor.checkCancelled(); + if (vtableSymbol != null) { + return vtableSymbol.getAddress(); - Address vtableAddress = findSpecialVtable(specialTypeinfo, specialTypeinfos); + } + + // then try finding with mangled symbol + vtableSymbol = findAndReturnDemangledSymbol(MANGLED_VTABLE_PREFIX + mangledNamespace, + SPECIAL_CLASS_NAMESPACE, namespaceName, VTABLE_LABEL); + if (vtableSymbol != null) { + return vtableSymbol.getAddress(); + } + + //Then with special typeinfo if there is one + GccTypeinfo specTypeinfo = getSpecialTypeinfo(specialTypeinfos, namespaceName); + if (specTypeinfo != null) { + Address vtableAddress = findSpecialVtableUsingSpecialTypeinfo(specTypeinfo.getAddress(), + specialTypeinfos); if (vtableAddress == null) { - continue; + return null; } + try { + vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL, + specTypeinfo.getNamespace(), SourceType.ANALYSIS); + api.setPlateComment(vtableAddress, "vtable for " + specTypeinfo.getNamespace()); + return vtableSymbol.getAddress(); - SpecialVtable specialVtable = createSpecialVtable(vtableAddress, specialTypeinfo); - if (specialVtable != null) { - specialVtables.add(specialVtable); - specialTypeinfo.setVtableAddress(vtableAddress); - if (!specialVtable.isExternal()) { - specialVtable.applyVtableData(); - vtableToSizeMap.put(specialVtable.getAddress(), specialVtable.getLength()); - createVtableLabel(specialVtable); - createVtableComment(specialVtable); - createVfunctionSymbol(specialVtable); - } } + catch (InvalidInputException e) { + Msg.warn(this, + "Found vtable at " + vtableAddress + " but cannot create symbol" + e); + return null; + } + } + + return null; + } + + private GccTypeinfo getSpecialTypeinfo(List specialTypeinfos, + String namespaceName) { + + for (GccTypeinfo specialTypeinfo : specialTypeinfos) { + if (specialTypeinfo.getNamespace().getName().equals(namespaceName)) { + return specialTypeinfo; + } } - return specialVtables; + return null; } + /* * Method to find special vtable using special typeinfo references. This * assumption that vtable is defaultPtrSize above ref to single specialTypeinfo diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/SpecialVtable.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/SpecialVtable.java index a401bd5f276..210a4336bf2 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/SpecialVtable.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/SpecialVtable.java @@ -15,9 +15,15 @@ */ package classrecovery; +import java.util.List; + import ghidra.program.model.address.Address; import ghidra.program.model.listing.Program; +import ghidra.program.model.reloc.Relocation; +import ghidra.program.model.reloc.Relocation.Status; +import ghidra.program.model.reloc.RelocationTable; import ghidra.program.model.symbol.Namespace; +import ghidra.program.model.symbol.Symbol; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; @@ -45,7 +51,20 @@ protected void setup() throws CancelledException { return; } - typeinfoRefAddress = vtableAddress.add(defaultPointerSize); + typeinfoRefAddress = vtableAddress.add(defaultPointerSize); + + // check for vtable has memory but all zeros or has possible invalid values which in both + // cases would make the pointer to special typeinfo invalid + if (hasSpecialCopyUnhandledRelocation(vtableAddress)) { + isConstruction = false; + isPrimary = true; + typeinfoAddress = null; + length = 3 * defaultPointerSize; //actually prob 11*defPtr but are all zeros in this case + hasVfunctions = true; // they are null though so will count as num=0, need this to be true so check for refs to vfunction top will work + numVfunctions = 0; + vfunctionTop = vtableAddress.add(2 * defaultPointerSize); + return; + } setTypeinfoAddress(); @@ -71,7 +90,9 @@ protected void setup() throws CancelledException { isConstruction = false; - classNamespace = typeinfoNamespace; + if (classNamespace == null) { + classNamespace = typeinfoNamespace; + } setLength(); @@ -82,4 +103,34 @@ public Address getRefFromTypeinfos() { return refFromTypeinfos; } + private boolean hasSpecialCopyUnhandledRelocation(Address address) { + + RelocationTable relocationTable = program.getRelocationTable(); + + List relocations = relocationTable.getRelocations(address); + + for (Relocation relocation : relocations) { + + Status status = relocation.getStatus(); + if (status == Status.UNSUPPORTED) { + + String symbolName = relocation.getSymbolName(); + + if (symbolName == null || !symbolName.contains("class_type_info")) { + continue; + } + + //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 + Symbol symbolAtAddress = program.getSymbolTable() + .getSymbol(symbolName, address, program.getGlobalNamespace()); + if (symbolAtAddress != null) { + return true; + } + } + } + return false; + } + } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/Vtable.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/Vtable.java index e2ad612628e..edaf2d020d0 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/Vtable.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/Vtable.java @@ -80,7 +80,9 @@ public Vtable(Program program, Address vtableAddress, GccTypeinfoRef typeinfoRef this.monitor = monitor; this.typeinfoRefAddress = typeinfoRef.getAddress(); this.typeinfo = (GccTypeinfo) typeinfoRef.getReferencedTypeinfo(); - this.typeinfoNamespace = typeinfo.getNamespace(); + if (this.typeinfo != null) { + this.typeinfoNamespace = typeinfo.getNamespace(); + } AddressSpace addressSpace = vtableAddress.getAddressSpace(); defaultPointerSize = addressSpace.getPointerSize(); @@ -390,9 +392,6 @@ private boolean isPossibleNullPointer(Address address) throws CancelledException */ private boolean isPossibleFunctionPointer(Address address) throws CancelledException { - // TODO: make one that works for all casea in helper - // TODO: make sure it recognizes the external functions - long longValue = extendedFlatAPI.getLongValueAt(address); Register lowBitCodeMode = program.getRegister("LowBitCodeMode"); @@ -605,26 +604,6 @@ private void addInternalVtable(Vtable internalVtable) { public List getInternalVtables() { return internalVtables; } - - - // TODO: put in helper or ext api - private boolean inExternalBlock(Address address) { - - MemoryBlock externalBlock = getExternalBlock(); - if (externalBlock == null) { - return false; - } - if (externalBlock.contains(address)) { - return true; - } - return false; - - } - - private MemoryBlock getExternalBlock() { - return program.getMemory().getBlock("EXTERNAL"); - } - public void setIsConstructionVtable(Boolean setting) { isConstruction = setting;