diff --git a/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm b/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm index a3f98c399a..75d88be43f 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm @@ -398,7 +398,15 @@ Apply any recovered function signature type information - in addition to the function name + in addition to the function name. + + + + Apply Function Calling Convention + + + Apply any recovered function calling convention information. This option is + ignored if the Apply Function Signatures option is false. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.java index ca7fcd63d3..23ddaf8c26 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.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. @@ -207,6 +207,7 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer { // analysis options change DemanglerOptions options = new DemanglerOptions(); options.setApplySignature(true); + options.setApplyCallingConvention(true); options.setDoDisassembly(true); options.setDemangleOnlyKnownPatterns(false); return options; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java index 25b78ea2ff..16a1ac12f6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java @@ -434,7 +434,8 @@ public class DemangledFunction extends DemangledObject { return true; } - Structure classStructure = maybeUpdateCallingConventionAndCreateClass(program, function); + Structure classStructure = + maybeUpdateCallingConventionAndCreateClass(program, function, options); FunctionDefinitionDataType signature = new FunctionDefinitionDataType(function, true); @@ -598,9 +599,9 @@ public class DemangledFunction extends DemangledObject { } private Structure maybeUpdateCallingConventionAndCreateClass(Program program, - Function function) { + Function function, DemanglerOptions options) { - String convention = validateCallingConvention(program, function); + String convention = validateCallingConvention(program, function, options); if (convention == null) { if (!isThisCall(function)) { return null; @@ -619,7 +620,12 @@ public class DemangledFunction extends DemangledObject { return null; } - private String validateCallingConvention(Program program, Function function) { + private String validateCallingConvention(Program program, Function function, + DemanglerOptions options) { + + if (!options.applyCallingConvention()) { + return null; + } if (callingConvention == null) { return null; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemanglerOptions.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemanglerOptions.java index 64fd4ffb85..101153f5b7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemanglerOptions.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemanglerOptions.java @@ -20,6 +20,7 @@ package ghidra.app.util.demangler; */ public class DemanglerOptions { + private boolean applyCallingConvention = true; private boolean applySignature = true; private boolean doDisassembly = true; private boolean demangleOnlyKnownPatterns = true; @@ -62,6 +63,24 @@ public class DemanglerOptions { return doDisassembly; } + /** + * Checks if the apply function signature calling convention option is currently set + * + * @return true if set to apply calling conventions + */ + public boolean applyCallingConvention() { + return applyCallingConvention; + } + + /** + * Set the option to apply function signature calling conventions + * + * @param applyCallingConvention true to apply calling conventions + */ + public void setApplyCallingConvention(boolean applyCallingConvention) { + this.applyCallingConvention = applyCallingConvention; + } + /** * Sets the option to perform disassembly for known data structures (like functions) when * demangling diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToAddressLabelPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToAddressLabelPluginTest.java index 132a10fe1b..6fc6d1381b 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToAddressLabelPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToAddressLabelPluginTest.java @@ -506,20 +506,19 @@ public class GoToAddressLabelPluginTest extends AbstractGhidraHeadedIntegrationT public void testQueryResultsMaxHitsDynamicFound() throws Exception { loadProgram("x86"); Options opt = plugin.getTool().getOptions(PluginConstants.SEARCH_OPTION_NAME); - opt.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, 20); + opt.setInt(GhidraOptions.OPTION_SEARCH_LIMIT, 20); setText("L*"); performOkCallback(); GhidraProgramTableModel model = waitForModel(); assertEquals(20, model.getRowCount()); - } @Test public void testQueryResultsMaxHitsDefinedFound() throws Exception { loadProgram("x86"); Options opt = plugin.getTool().getOptions(PluginConstants.SEARCH_OPTION_NAME); - opt.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, 5); + opt.setInt(GhidraOptions.OPTION_SEARCH_LIMIT, 5); createLabel("1006960", "abc1"); createLabel("1006961", "abc2"); @@ -533,7 +532,6 @@ public class GoToAddressLabelPluginTest extends AbstractGhidraHeadedIntegrationT performOkCallback(); GhidraProgramTableModel model = waitForModel(); assertEquals(5, model.getRowCount()); - } @Test diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java index 2c419fda54..6f02ec70d0 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java @@ -231,7 +231,11 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { private void processGccRTTI() throws CancelledException, Exception { // create the appropriate type of type info struct at the various typeinfo symbol locations - createTypeinfoStructs(); + List
typeinfoAddresses = createTypeinfoStructs(); + + if (typeinfoAddresses.isEmpty()) { + return; + } processVtables(); @@ -240,11 +244,16 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { recoveredClasses = recoverClassesFromVftables(vftableSymbols, true, true); - // find all typeinfo symbols and get their class namespace and create RecoveredClass object - List typeinfoSymbols = extendedFlatAPI.getListOfSymbolsInAddressSet( - program.getAddressFactory().getAddressSet(), "typeinfo", true); + // find all valid typeinfo symbols and get their class namespace and create RecoveredClass + // object + AddressSet nonExecutableAddressSet = program.getAddressFactory() + .getAddressSet() + .subtract(program.getMemory().getExecuteSet()); - // create class objects for each typeinfo struct and make a class to typeinfo mapping for each + List typeinfoSymbols = + extendedFlatAPI.getListOfSymbolsInAddressSet(nonExecutableAddressSet, "typeinfo", true); + + // create class objects for each typeinfo struct and make class to typeinfo mapping for each createClassesFromTypeinfoSymbols(typeinfoSymbols); updateClassesWithParentsAndFlags(typeinfoSymbols); @@ -312,7 +321,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } } - Address specialTypeinfoRef = extendedFlatAPI.getSingleReferencedAddress(typeinfoAddress); + Address specialTypeinfoRef = + extendedFlatAPI.getSingleReferencedAddress(typeinfoAddress); if (specialTypeinfoRef == null) { if (DEBUG) { Msg.debug(this, @@ -328,7 +338,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { if (!hasExternalBlock()) { if (DEBUG) { Msg.debug(this, - "Special typeinfo reference is not equal to one of the three special type infos. Cannot process typeinfo struct at " + + "Special typeinfo reference is not equal to one of the three special " + + "type infos. Cannot process typeinfo struct at " + typeinfoAddress.toString()); } continue; @@ -338,7 +349,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { if (!isSpecialVtable(specialTypeinfoRef)) { if (DEBUG) { Msg.debug(this, - "Special typeinfo reference is not equal to one of the three special type infos. Cannot process typeinfo struct at " + + "Special typeinfo reference is not equal to one of the three special " + + "type infos. Cannot process typeinfo struct at " + typeinfoAddress.toString()); } continue; @@ -451,7 +463,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { while (vtableIterator.hasNext()) { - monitor.checkCanceled(); Symbol vtableSymbol = vtableIterator.next(); @@ -801,7 +812,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // if not already named a construction-vtable then check to see if it is one so it can // be renamed and the new namespace figured out - // know it isn't null because the of the vtable symbol iterator used to call this method in the first place + // know it isn't null because the of the vtable symbol iterator used to call this method in + // the first place Symbol vtableSymbol = symbolTable.getPrimarySymbol(vtableAddress); if (!vtableSymbol.getName().equals("construction-vtable") && listOfAllVtables != null) { // get first VTT before this vtable @@ -1039,7 +1051,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { if (pointer == null) { return false; } - // check to see if pointer is to the class vftable or to a class internal vtable or to itself + // check if pointer is to the class vftable or to a class internal vtable or to itself // if not one of those things it isn't a VTT Symbol symbol = symbolTable.getPrimarySymbol(pointer); if ((!symbol.getName().equals(VFTABLE_LABEL) || @@ -1156,7 +1168,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return false; } - List
referenceFromAddresses = extendedFlatAPI.getReferenceFromAddresses(address); + List
referenceFromAddresses = + extendedFlatAPI.getReferenceFromAddresses(address); if (referenceFromAddresses.size() > 0) { return false; @@ -1316,8 +1329,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { api.createData(address, pointer); Address referencedAddress = extendedFlatAPI.getSingleReferencedAddress(address); - // if it isn't a valid pointer, clear what we just created and increment to offset so - // the next can be checked + // if it isn't a valid pointer, clear what we just created and increment to offset + // so the next can be checked if (referencedAddress == null || !programAddressSet.contains(referencedAddress)) { api.clearListing(address); api.createData(address, longDT); @@ -1342,7 +1355,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { * @throws CancelledException if cancelled * @throws Exception if could not apply a type info structure */ - private void createTypeinfoStructs() throws CancelledException, Exception { + private List
createTypeinfoStructs() throws CancelledException, Exception { StructureDataType classTypeInfoStructure = createClassTypeInfoStructure(); StructureDataType siClassTypeInfoStructure = @@ -1367,12 +1380,13 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } if (typeinfoAddresses.isEmpty()) { - return; + return typeinfoAddresses; } for (Address typeinfoAddress : typeinfoAddresses) { - Address specialTypeinfoRef = extendedFlatAPI.getSingleReferencedAddress(typeinfoAddress); + Address specialTypeinfoRef = + extendedFlatAPI.getSingleReferencedAddress(typeinfoAddress); if (specialTypeinfoRef == null) { continue; } @@ -1439,6 +1453,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } } + return typeinfoAddresses; } private Data applyTypeinfoStructure(Structure typeInfoStructure, Address typeinfoAddress) @@ -1582,8 +1597,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { return null; } - Address stringReference = - extendedFlatAPI.getSingleReferencedAddress(address.add(typeinfoNameComponent.getOffset())); + Address stringReference = extendedFlatAPI + .getSingleReferencedAddress(address.add(typeinfoNameComponent.getOffset())); Data stringData = api.getDataAt(stringReference); if (stringData == null) { @@ -1610,8 +1625,12 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { List
typeinfoAddresses = new ArrayList
(); - List typeinfoSymbols = extendedFlatAPI.getListOfSymbolsInAddressSet( - program.getAddressFactory().getAddressSet(), "typeinfo", true); + AddressSet nonExecutableAddressSet = program.getAddressFactory() + .getAddressSet() + .subtract(program.getMemory().getExecuteSet()); + + List typeinfoSymbols = + extendedFlatAPI.getListOfSymbolsInAddressSet(nonExecutableAddressSet, "typeinfo", true); Iterator typeinfoIterator = typeinfoSymbols.iterator(); while (typeinfoIterator.hasNext()) { @@ -1645,14 +1664,18 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { List
typeinfoAddresses = new ArrayList
(); + AddressSetView executeSet = program.getMemory().getExecuteSet(); + Iterator bookmarksIterator = program.getBookmarkManager().getBookmarksIterator(BookmarkType.ERROR); while (bookmarksIterator.hasNext()) { monitor.checkCanceled(); Bookmark bookmark = bookmarksIterator.next(); + Address bookmarkAddress = bookmark.getAddress(); if (bookmark.getCategory().equals("EXTERNAL Relocation") && - bookmarkContainsSpecialTypeinfoName(bookmark.getComment())) { - typeinfoAddresses.add(bookmark.getAddress()); + bookmarkContainsSpecialTypeinfoName(bookmark.getComment()) && + !executeSet.contains(bookmarkAddress)) { + typeinfoAddresses.add(bookmarkAddress); } } return typeinfoAddresses; @@ -1679,7 +1702,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { * @throws CancelledException if cancelled */ private boolean hasExternalRelocationRefs() throws CancelledException { - // if no external block then there won't be any refernces to special typeinfos in the external + // if no external block then there won't be any refernces to special typeinfos in external // block so return empty list if (!hasExternalBlock()) { return false; @@ -1703,13 +1726,18 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { */ private List
getTypeinfoAddressesUsingSpecialTypeinfos() throws CancelledException { + AddressSetView executeSet = program.getMemory().getExecuteSet(); List
specialTypeinfoRefs = new ArrayList
(); if (class_type_info != null) { Reference[] refsToClassTypeinfo = api.getReferencesTo(class_type_info); for (Reference ref : refsToClassTypeinfo) { monitor.checkCanceled(); - specialTypeinfoRefs.add(ref.getFromAddress()); + Address typeinfoAddress = ref.getFromAddress(); + if (executeSet.contains(typeinfoAddress)) { + continue; + } + specialTypeinfoRefs.add(typeinfoAddress); } } @@ -1717,7 +1745,11 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { Reference[] refsToSiClassTypeinfo = api.getReferencesTo(si_class_type_info); for (Reference ref : refsToSiClassTypeinfo) { monitor.checkCanceled(); - specialTypeinfoRefs.add(ref.getFromAddress()); + Address typeinfoAddress = ref.getFromAddress(); + if (executeSet.contains(typeinfoAddress)) { + continue; + } + specialTypeinfoRefs.add(typeinfoAddress); } } @@ -1725,7 +1757,11 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { Reference[] refsToVmiClassTypeinfo = api.getReferencesTo(vmi_class_type_info); for (Reference ref : refsToVmiClassTypeinfo) { monitor.checkCanceled(); - specialTypeinfoRefs.add(ref.getFromAddress()); + Address typeinfoAddress = ref.getFromAddress(); + if (executeSet.contains(typeinfoAddress)) { + continue; + } + specialTypeinfoRefs.add(typeinfoAddress); } } @@ -1896,7 +1932,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { * @param recoveredClass the given class * @param typeinfoAddress the address of the typeinfo * @return list of parents for the given class - * @throws Exception if cannot access the given typeinfo structure, one of its components, or it is not a vmi structure + * @throws Exception if cannot access the given typeinfo structure, one of its components, + * or it is not a vmi structure */ private List addGccClassParentsFromVmiStruct(RecoveredClass recoveredClass, Address typeinfoAddress) throws Exception { @@ -1947,6 +1984,13 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { numBaseClassesDataType.getDefaultSettings(), numBaseClassesDataType.getLength()); int numBaseClasses = (int) scalar.getUnsignedValue(); + if (numBaseClasses < 0) { + throw new IllegalArgumentException("Could not process vmi class " + + recoveredClass.getName() + + " because getting the number of bases from the vmi typeinfo structure at address " + + typeinfoAddress.toString()); + } + if (numBaseClasses > 1) { recoveredClass.setHasMultipleInheritance(true); recoveredClass.setHasSingleInheritance(false); @@ -2123,8 +2167,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } /** - * Method to find the (up to three) special gcc vtables and replace the incorrectly made array with the - * correct data types. Also creates a type info symbol at the correct offset in the table. + * Method to find the (up to three) special gcc vtables and replace the incorrectly made array + * with the correct data types. Also creates typeinfo symbol at the correct offset in the table. * @return true if all found tables have a typeinfo symbol created successfully * @throws CancelledException if cancelled * @throws InvalidInputException if bad characters creating labels @@ -2154,7 +2198,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { si_class_type_info = createSpecialVtable(si_class_type_info_vtable); if (si_class_type_info == null) { Msg.debug(this, - "__si_class_type_info typeinfo not found -- cannot continue gcc rtti processing"); + "__si_class_type_info typeinfo not found -- cannot continue gcc rtti " + + "processing"); return false; } } @@ -2168,7 +2213,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { vmi_class_type_info = createSpecialVtable(vmi_class_type_info_vtable); if (vmi_class_type_info == null) { Msg.debug(this, - "__vmi_class_type_info typeinfo not found -- cannot continue gcc rtti processing"); + "__vmi_class_type_info typeinfo not found -- cannot continue gcc rtti " + + "processing"); return false; } } @@ -2176,7 +2222,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { if (class_type_info_vtable == null && si_class_type_info_vtable == null && vmi_class_type_info_vtable == null) { Msg.debug(this, - "Since there are no class typeinfo tables this program does not appear to have RTTI."); + "Since there are no class typeinfo tables this program does not appear to have " + + "RTTI."); return false; } return true; @@ -2269,7 +2316,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { continue; } - Address vftableAddress = extendedFlatAPI.getAddress(typeinfoAddress, defaultPointerSize); + Address vftableAddress = + extendedFlatAPI.getAddress(typeinfoAddress, defaultPointerSize); // no valid address here so continue if (vftableAddress == null) { //createNewClass(vtableNamespace, false); @@ -2350,7 +2398,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { recoveredClasses.add(recoveredClass); } - Address specialTypeinfoRef = extendedFlatAPI.getSingleReferencedAddress(typeinfoAddress); + Address specialTypeinfoRef = + extendedFlatAPI.getSingleReferencedAddress(typeinfoAddress); if (specialTypeinfoRef == null) { if (DEBUG) { Msg.debug(this, @@ -2470,8 +2519,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } // update the inherits virtual ancestor flag using ancestors - previously was only done for - // parents but now have all classes with flag set for direct parent so can get the other ancestors - // too + // parents but now have all classes with flag set for direct parent so can get the other + // ancestors too recoveredClassIterator = recoveredClasses.iterator(); while (recoveredClassIterator.hasNext()) { monitor.checkCanceled(); @@ -2750,7 +2799,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { } /** - * Method to create all the class data types for the current class, name all the class functions, and put them all into the class namespace + * Method to create all the class data types for the current class, name all the class + * functions, and put them all into the class namespace * @param recoveredClass current class * @throws CancelledException when cancelled * @throws Exception naming exception @@ -2791,8 +2841,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // then filled in later Map vfPointerDataTypes = createEmptyVfTableStructs(recoveredClass); - // create current class structure and add pointer to vftable, all parent member data strutures, - // and class member data structure + // create current class structure and add pointer to vftable, all parent member data + // structures, and class member data structure Structure classStruct = createSimpleClassStructure(recoveredClass, vfPointerDataTypes); // Now that we have a class data type @@ -2809,10 +2859,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // createInlinedDestructorComments(recoveredClass); // createIndeterminateInlineComments(recoveredClass); - // add label on constructor destructor functions that could not be determined which were which + // add label on constructor destructor functions that could not be determined createIndeterminateLabels(recoveredClass, classStruct); - // This is done after the class structure is created and added to the dtmanager // because if done before the class structures are created // then empty classes will get auto-created in the wrong place @@ -2830,8 +2879,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { CategoryPath classPath = recoveredClass.getClassPath(); - // get either existing structure if prog has a structure created by pdb or computed structure - // from decompiled construtor(s) info + // get either existing structure if prog has a structure created by pdb or computed + // structure from decompiled construtor(s) info Structure classStructure; if (recoveredClass.hasExistingClassStructure()) { classStructure = recoveredClass.getExistingClassStructure(); @@ -2858,11 +2907,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { // simple case the offset for vftablePtr is 0 if (EditStructureUtils.canAdd(classStructureDataType, 0, - classVftablePointer.getLength(), - monitor)) { + classVftablePointer.getLength(), monitor)) { classStructureDataType = - EditStructureUtils.addDataTypeToStructure(classStructureDataType, - 0, classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor); + EditStructureUtils.addDataTypeToStructure(classStructureDataType, 0, + classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor); } } @@ -2898,8 +2946,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { int parentOffset = parentOffsetLong.intValue(); Structure baseClassStructure = getClassStructureFromDataTypeManager(parent); - // if we can't get the parent throw exception because it shouldn't get here if the parent - // doesn't exist + // if we can't get the parent throw exception because it shouldn't get here if the + // parent doesn't exist if (baseClassStructure == null) { throw new Exception(parent.getClassNamespace().getName(true) + " : structure should exist but doesn't."); @@ -2907,10 +2955,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { if (EditStructureUtils.canAdd(classStructureDataType, parentOffset, baseClassStructure.getLength(), monitor)) { - classStructureDataType = - EditStructureUtils.addDataTypeToStructure(classStructureDataType, - parentOffset, - baseClassStructure, baseClassStructure.getName(), monitor); + classStructureDataType = EditStructureUtils.addDataTypeToStructure( + classStructureDataType, parentOffset, baseClassStructure, + baseClassStructure.getName(), monitor); } } @@ -2920,9 +2967,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { int dataOffset = getDataOffset(recoveredClass, classStructureDataType); int dataLen = UNKNOWN; if (dataOffset != NONE) { - dataLen = - EditStructureUtils.getNumberOfUndefinedsStartingAtOffset(classStructureDataType, - dataOffset, monitor); + dataLen = EditStructureUtils.getNumberOfUndefinedsStartingAtOffset( + classStructureDataType, dataOffset, monitor); } if (dataLen != UNKNOWN && dataLen > 0) { @@ -2932,8 +2978,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer { if (recoveredClassDataStruct != null) { classStructureDataType = EditStructureUtils.addDataTypeToStructure( - classStructureDataType, - dataOffset, recoveredClassDataStruct, "data", monitor); + classStructureDataType, dataOffset, recoveredClassDataStruct, "data", monitor); } } diff --git a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/plugin/core/analysis/GnuDemanglerAnalyzer.java b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/plugin/core/analysis/GnuDemanglerAnalyzer.java index 442bee35d3..52a70190c5 100644 --- a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/plugin/core/analysis/GnuDemanglerAnalyzer.java +++ b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/plugin/core/analysis/GnuDemanglerAnalyzer.java @@ -48,6 +48,11 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer { private static final String OPTION_DESCRIPTION_APPLY_SIGNATURE = "Apply any recovered function signature, in addition to the function name"; + private static final String OPTION_NAME_APPLY_CALLING_CONVENTION = + "Apply Function Calling Conventions"; + private static final String OPTION_DESCRIPTION_APPLY_CALLING_CONVENTION = + "Apply any recovered function signature calling convention"; + static final String OPTION_NAME_USE_DEPRECATED_DEMANGLER = "Use Deprecated Demangler"; private static final String OPTION_DESCRIPTION_DEPRECATED_DEMANGLER = "Signals to use the deprecated demangler when the modern demangler cannot demangle a " + @@ -57,7 +62,8 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer { private static final String OPTION_DESCRIPTION_DEMANGLER_FORMAT = "The demangling format to use"; - private boolean doSignatureEnabled = true; + private boolean applyFunctionSignature = true; + private boolean applyCallingConvention = true; private boolean demangleOnlyKnownPatterns = false; private GnuDemanglerFormat demanglerFormat = GnuDemanglerFormat.AUTO; private boolean useDeprecatedDemangler = false; @@ -78,9 +84,12 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer { public void registerOptions(Options options, Program program) { HelpLocation help = new HelpLocation("AutoAnalysisPlugin", "Demangler_Analyzer"); - options.registerOption(OPTION_NAME_APPLY_SIGNATURE, doSignatureEnabled, help, + options.registerOption(OPTION_NAME_APPLY_SIGNATURE, applyFunctionSignature, help, OPTION_DESCRIPTION_APPLY_SIGNATURE); + options.registerOption(OPTION_NAME_APPLY_CALLING_CONVENTION, applyCallingConvention, help, + OPTION_DESCRIPTION_APPLY_CALLING_CONVENTION); + options.registerOption(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns, help, OPTION_DESCRIPTION_USE_KNOWN_PATTERNS); @@ -106,7 +115,10 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer { @Override public void optionsChanged(Options options, Program program) { - doSignatureEnabled = options.getBoolean(OPTION_NAME_APPLY_SIGNATURE, doSignatureEnabled); + applyFunctionSignature = + options.getBoolean(OPTION_NAME_APPLY_SIGNATURE, applyFunctionSignature); + applyCallingConvention = + options.getBoolean(OPTION_NAME_APPLY_CALLING_CONVENTION, applyCallingConvention); demangleOnlyKnownPatterns = options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns); demanglerFormat = options.getEnum(OPTION_NAME_DEMANGLER_FORMAT, GnuDemanglerFormat.AUTO); @@ -119,7 +131,8 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer { GnuDemanglerOptions options = new GnuDemanglerOptions(demanglerFormat, useDeprecatedDemangler); options.setDoDisassembly(true); - options.setApplySignature(doSignatureEnabled); + options.setApplySignature(applyFunctionSignature); + options.setApplyCallingConvention(applyCallingConvention); options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns); return options; } diff --git a/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/plugin/core/analysis/MicrosoftDemanglerAnalyzer.java b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/plugin/core/analysis/MicrosoftDemanglerAnalyzer.java index f191e0cb96..3d7107a403 100644 --- a/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/plugin/core/analysis/MicrosoftDemanglerAnalyzer.java +++ b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/plugin/core/analysis/MicrosoftDemanglerAnalyzer.java @@ -31,10 +31,17 @@ public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer { "After a function is created, this analyzer will attempt to demangle " + "the name and apply datatypes to parameters."; - private final static String OPTION_NAME_APPLY_SIGNATURE = "Apply Function Signatures"; + public static final String OPTION_NAME_APPLY_SIGNATURE = "Apply Function Signatures"; private static final String OPTION_DESCRIPTION_APPLY_SIGNATURE = "Apply any recovered function signature, in addition to the function name"; + + public static final String OPTION_NAME_APPLY_CALLING_CONVENTION = + "Apply Function Calling Conventions"; + private static final String OPTION_DESCRIPTION_APPLY_CALLING_CONVENTION = + "Apply any recovered function signature calling convention"; + private boolean applyFunctionSignature = true; + private boolean applyCallingConvention = true; private MicrosoftDemangler demangler = new MicrosoftDemangler(); public MicrosoftDemanglerAnalyzer() { @@ -51,6 +58,9 @@ public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer { public void registerOptions(Options options, Program program) { options.registerOption(OPTION_NAME_APPLY_SIGNATURE, applyFunctionSignature, null, OPTION_DESCRIPTION_APPLY_SIGNATURE); + + options.registerOption(OPTION_NAME_APPLY_CALLING_CONVENTION, applyCallingConvention, null, + OPTION_DESCRIPTION_APPLY_CALLING_CONVENTION); } @Override @@ -59,6 +69,14 @@ public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer { options.getBoolean(OPTION_NAME_APPLY_SIGNATURE, applyFunctionSignature); } + @Override + protected DemanglerOptions getOptions() { + DemanglerOptions options = new DemanglerOptions(); + options.setApplySignature(applyFunctionSignature); + options.setApplyCallingConvention(applyCallingConvention); + return options; + } + @Override protected DemangledObject doDemangle(String mangled, DemanglerOptions options, MessageLog log) throws DemangledException { diff --git a/Ghidra/Features/MicrosoftDemangler/src/test/java/ghidra/app/plugin/core/analysis/MicrosoftDemanglerAnalyzerTest.java b/Ghidra/Features/MicrosoftDemangler/src/test/java/ghidra/app/plugin/core/analysis/MicrosoftDemanglerAnalyzerTest.java new file mode 100644 index 0000000000..480c3a4fcb --- /dev/null +++ b/Ghidra/Features/MicrosoftDemangler/src/test/java/ghidra/app/plugin/core/analysis/MicrosoftDemanglerAnalyzerTest.java @@ -0,0 +1,140 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.plugin.core.analysis; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + +import ghidra.app.cmd.label.AddLabelCmd; +import ghidra.app.util.importer.MessageLog; +import ghidra.framework.options.Options; +import ghidra.program.database.ProgramBuilder; +import ghidra.program.database.ProgramDB; +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.*; +import ghidra.program.model.symbol.SourceType; +import ghidra.test.AbstractGhidraHeadedIntegrationTest; +import ghidra.test.ToyProgramBuilder; +import ghidra.util.Msg; +import ghidra.util.task.TaskMonitor; + +public class MicrosoftDemanglerAnalyzerTest extends AbstractGhidraHeadedIntegrationTest { + + private ProgramDB program; + private MicrosoftDemanglerAnalyzer analyzer = new MicrosoftDemanglerAnalyzer(); + + private MessageLog log = new MessageLog() { + + // overridden to prevent stack traces from appearing in the console + @Override + public void appendException(Throwable t) { + appendMsg(t.toString()); + } + }; + + @Before + public void setUp() throws Exception { + + ProgramBuilder builder = new ToyProgramBuilder("test", true); + builder.createMemory(".text", "0x0100", 0x100); + program = builder.getProgram(); + registerOptions(); + } + + @Override + protected void testFailed(Throwable e) { + Msg.error(this, "Test failed - analysis log:\n" + log); + } + + @Test + public void testOptions__ApplyFunctionSignature() throws Exception { + + String mangled = "?InvokeHelperV@COleDispatchDriver@@QAEXJGGPAXPBEPAD@Z"; + + Address addr = addr("0x110"); + createSymbol(addr, mangled); + + setOption(MicrosoftDemanglerAnalyzer.OPTION_NAME_APPLY_SIGNATURE, true); + + analyze(); + + FunctionManager fm = program.getFunctionManager(); + Function function = fm.getFunctionAt(addr); + assertNotNull(function); + assertTrue("Funciton signature not applied", function.getParameterCount() > 0); + } + + @Test + public void testOptions__DoNotApplyFunctionSignature() throws Exception { + + String mangled = "?InvokeHelperV@COleDispatchDriver@@QAEXJGGPAXPBEPAD@Z"; + + Address addr = addr("0x110"); + createSymbol(addr, mangled); + + setOption(MicrosoftDemanglerAnalyzer.OPTION_NAME_APPLY_SIGNATURE, false); + + analyze(); + + FunctionManager fm = program.getFunctionManager(); + Function function = fm.getFunctionAt(addr); + assertNotNull(function); + assertEquals("undefined InvokeHelperV(void)", function.getSignature().toString()); + } + +//================================================================================================== +// Private Methods +//================================================================================================== + + private void analyze() { + tx(program, () -> analyzer.added(program, program.getMemory(), TaskMonitor.DUMMY, log)); + } + + private void setOption(String optionName, boolean doUse) { + + String fullOptionName = analyzer.getName() + Options.DELIMITER_STRING + optionName; + Options options = program.getOptions("Analyzers"); + + for (String name : options.getOptionNames()) { + if (name.equals(fullOptionName)) { + tx(program, () -> options.setBoolean(optionName, doUse)); + + // we must call this manually, since we are not using a tool + analyzer.optionsChanged(options, program); + return; + } + } + + fail("Could not find option '" + optionName + "'"); + } + + private void registerOptions() { + Options options = program.getOptions(Program.ANALYSIS_PROPERTIES); + Options analyzerOptions = options.getOptions(analyzer.getName()); + analyzer.registerOptions(analyzerOptions, program); + } + + private void createSymbol(Address addr, String mangled) { + AddLabelCmd cmd = new AddLabelCmd(addr, mangled, SourceType.ANALYSIS); + applyCmd(program, cmd); + } + + private Address addr(String addr) { + return program.getAddressFactory().getAddress(addr); + } +} diff --git a/Ghidra/Processors/6805/data/languages/6x09.sinc b/Ghidra/Processors/6805/data/languages/6x09.sinc index 17bc8551fd..7f7549ff89 100644 --- a/Ghidra/Processors/6805/data/languages/6x09.sinc +++ b/Ghidra/Processors/6805/data/languages/6x09.sinc @@ -237,7 +237,7 @@ REL2: addr is simm16 [ addr = inst_next + simm16; ] { export *:2 addr; } # 1-byte operand, immediate/direct/indexed/extended addressing mode OP1: "#"imm8 is op45=0; imm8 { - export imm8; + export *[const]:1 imm8; } OP1: "<"imm8 is (op47=0 | op47=9 | op47=0xD); imm8 { @@ -257,7 +257,7 @@ OP1: imm16 is op45=3; imm16 # 2-byte operand, direct/indexed/extended addressing mode OP2: "#"imm16 is (op47=8 | op47=0xC); imm16 { - export imm16; + export *[const]:2 imm16; } OP2: "<"imm8 is (op47=0 | op47=9 | op47=0xD); imm8 { diff --git a/Ghidra/Processors/PowerPC/data/languages/Scalar_SPFP.sinc b/Ghidra/Processors/PowerPC/data/languages/Scalar_SPFP.sinc index a0b8aac192..f1c10dec52 100644 --- a/Ghidra/Processors/PowerPC/data/languages/Scalar_SPFP.sinc +++ b/Ghidra/Processors/PowerPC/data/languages/Scalar_SPFP.sinc @@ -141,7 +141,7 @@ define pcodeop ConvertFloatingPointFromUnsignedFraction; #define pcodeop FloatingPointCompareEqual; :efscmpeq CRFD,A,B is OP=4 & CRFD & A & B & XOP_0_10=0x2CE & BITS_21_22=0 { - CRFD = A:4 f== B:4; + CRFD[2,1] = A:4 f== B:4; } # ================================================================= @@ -151,14 +151,14 @@ define pcodeop ConvertFloatingPointFromUnsignedFraction; #define pcodeop FloatingPointCompareGreaterThan; :efscmpgt CRFD,A,B is OP=4 & CRFD & A & B & XOP_0_10=0x2CC & BITS_21_22=0 { - CRFD = A:4 f> B:4; + CRFD[2,1] = A:4 f> B:4; } # efscmplt CRFD,rA,rB 010 1100 1101 #define pcodeop FloatingPointCompareLessThan; :efscmplt CRFD,A,B is OP=4 & CRFD & A & B & XOP_0_10=0x2CD & BITS_21_22=0 { - CRFD = A:4 f< B:4; + CRFD[2,1] = A:4 f< B:4; } # efsctsf rT,rB 010 1101 0111 @@ -451,14 +451,14 @@ define pcodeop ConvertFloatingPointFromUnsignedFraction; #define pcodeop FloatingPointTestEqual; :efststeq CRFD,A,B is OP=4 & CRFD & A & B & XOP_0_10=0x2DE & BITS_21_22=0 { - CRFD = A:4 f== B:4; + CRFD[2,1] = A:4 f== B:4; } # efststgt CRFD,rA,rB 010 1101 1100 #define pcodeop FloatingPointTestGreaterThan; :efststgt CRFD,A,B is OP=4 & CRFD & A & B & XOP_0_10=0x2DC & BITS_21_22=0 { - CRFD = A:4 f> B:4; + CRFD[2,1] = A:4 f> B:4; } # ================================================================= @@ -468,5 +468,5 @@ define pcodeop ConvertFloatingPointFromUnsignedFraction; #define pcodeop FloatingPointTestLessThan; :efststlt CRFD,A,B is OP=4 & CRFD & A & B & XOP_0_10=0x2DD & BITS_21_22=0 { - CRFD = A:4 f< B:4; + CRFD[2,1] = A:4 f< B:4; } diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/demangler/DemangledFunctionTest.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/demangler/DemangledFunctionTest.java index 706cbe4344..8d324c3011 100644 --- a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/demangler/DemangledFunctionTest.java +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/demangler/DemangledFunctionTest.java @@ -26,6 +26,7 @@ import ghidra.program.database.ProgramDB; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSet; import ghidra.program.model.data.VoidDataType; +import ghidra.program.model.lang.CompilerSpec; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.*; import ghidra.test.AbstractGhidraHeadlessIntegrationTest; @@ -86,7 +87,7 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest /* * Test that the DemangledFunction will properly update a thunk function * with its namespace, and ripple through to the underlying default thunked - * function. The thunk 'this' parameter should utilize the Class + * function. The thunk 'this' parameter should utilize the Class * within which the thunk resides. */ @Test @@ -338,7 +339,7 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest public void testFunctionVariable() throws Exception { // - // This makes sure that a variable inside of a function namespace prevents a class + // This makes sure that a variable inside of a function namespace prevents a class // namespace object from being created when a function does not exist. Instead it should // create a simple namespace. // @@ -371,6 +372,25 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest assertEquals("__gthread_active_p()", ns.getName(false)); } + @Test + public void testApply_Function_DoNotApplyCallingConvention() throws Exception { + + String mangled = "?CloseM@CRegKeyM@ATL@@QAEJXZ"; + DemangledObject demangled = DemanglerUtil.demangle(mangled); + assertTrue(demangled instanceof DemangledFunction); + + DemangledFunction demangledFunction = (DemangledFunction) demangled; + demangledFunction.setCallingConvention(CompilerSpec.CALLING_CONVENTION_stdcall); + + Address addr = addr("0x0101"); + DemanglerOptions options = new DemanglerOptions(); + options.setApplyCallingConvention(false); + assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY)); + + Function function = assertFunction("CloseM", addr); + assertEquals("unknown", function.getCallingConventionName()); + } + private void assertNoBookmarkAt(Address addr) { BookmarkManager bm = program.getBookmarkManager(); Bookmark[] bookmarks = bm.getBookmarks(addr);