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);