diff --git a/Ghidra/Features/Base/src/main/help/help/topics/FunctionPlugin/Variables.htm b/Ghidra/Features/Base/src/main/help/help/topics/FunctionPlugin/Variables.htm index 5b3c50ee17..0ed73247cc 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/FunctionPlugin/Variables.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/FunctionPlugin/Variables.htm @@ -327,6 +327,10 @@
This text field can be used to change the name of the function.
+This combo box and browse button can be use to change the function namespace.
+This field is a combobox that allows you to choose a calling convention from the list of
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/FunctionPlugin/images/FunctionEditor.png b/Ghidra/Features/Base/src/main/help/help/topics/FunctionPlugin/images/FunctionEditor.png
index 9913c311e2..b2edbda959 100644
Binary files a/Ghidra/Features/Base/src/main/help/help/topics/FunctionPlugin/images/FunctionEditor.png and b/Ghidra/Features/Base/src/main/help/help/topics/FunctionPlugin/images/FunctionEditor.png differ
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionData.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionData.java
index a66dc66688..f89737e7a8 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionData.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionData.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.
@@ -21,6 +21,7 @@ import ghidra.program.model.data.*;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.PrototypeModel;
import ghidra.program.model.listing.*;
+import ghidra.program.model.symbol.Namespace;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.InvalidInputException;
@@ -40,19 +41,18 @@ class FunctionData extends FunctionDataView {
boolean checkStorage = false;
if (canCustomizeStorage()) {
-// if (!originalFunctionData.canCustomizeStorage()) {
-// // switched to using custom storage
-// return true;
-// }
checkStorage = true;
}
- if (!returnInfo.getFormalDataType()
- .equals(originalFunctionData.returnInfo.getFormalDataType())) {
+ DataType returnType = returnInfo.getFormalDataType();
+ DataType originalReturnType = originalFunctionData.returnInfo.getFormalDataType();
+ if (!returnType.equals(originalReturnType)) {
return true;
}
- if (checkStorage &&
- !returnInfo.getStorage().equals(originalFunctionData.returnInfo.getStorage())) {
+
+ VariableStorage returnStorage = returnInfo.getStorage();
+ VariableStorage originalReturnStorage = originalFunctionData.returnInfo.getStorage();
+ if (checkStorage && !returnStorage.equals(originalReturnStorage)) {
return true;
}
@@ -162,6 +162,10 @@ class FunctionData extends FunctionDataView {
this.name = n;
}
+ void setNamespace(Namespace ns) {
+ this.namespace = ns;
+ }
+
void setInline(boolean enable) {
this.isInLine = enable;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionDataView.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionDataView.java
index bfc48ca0ef..065f85bf95 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionDataView.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionDataView.java
@@ -20,6 +20,7 @@ import java.util.*;
import ghidra.program.model.data.VoidDataType;
import ghidra.program.model.lang.PrototypeModel;
import ghidra.program.model.listing.*;
+import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.SymbolUtilities;
/**
@@ -30,6 +31,7 @@ class FunctionDataView {
Function function;
+ Namespace namespace;
String name;
boolean hasVarArgs;
ParamInfo returnInfo;
@@ -47,7 +49,8 @@ class FunctionDataView {
*/
FunctionDataView(Function function) {
this.function = function;
- this.name = function.getName();
+ name = function.getName();
+ namespace = function.getParentNamespace();
allowCustomStorage = function.hasCustomVariableStorage();
hasVarArgs = function.hasVarArgs();
isInLine = function.isInline();
@@ -63,6 +66,7 @@ class FunctionDataView {
*/
FunctionDataView(FunctionDataView otherFunctionData) {
name = otherFunctionData.name;
+ namespace = otherFunctionData.namespace;
hasVarArgs = otherFunctionData.hasVarArgs;
returnInfo = otherFunctionData.returnInfo.copy();
for (ParamInfo p : otherFunctionData.parameters) {
@@ -82,6 +86,7 @@ class FunctionDataView {
return false;
}
if (!Objects.equals(name, otherFunctionData.name) ||
+ !Objects.equals(namespace, otherFunctionData.namespace) ||
!Objects.equals(callingConventionName, otherFunctionData.callingConventionName) ||
hasVarArgs != otherFunctionData.hasVarArgs ||
parameters.size() != otherFunctionData.parameters.size() ||
@@ -174,7 +179,7 @@ class FunctionDataView {
return buf.toString();
}
- public Program getProgram() {
+ Program getProgram() {
return function.getProgram();
}
@@ -190,10 +195,14 @@ class FunctionDataView {
return parameters.size();
}
- public String getName() {
+ String getName() {
return name;
}
+ Namespace getNamespace() {
+ return namespace;
+ }
+
String getNameString() {
return name.length() == 0 ? SymbolUtilities.getDefaultFunctionName(function.getEntryPoint())
: name;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java
index 9eb04cea1a..aa464e9beb 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java
@@ -17,8 +17,7 @@ package ghidra.app.plugin.core.function.editor;
import java.awt.*;
import java.awt.event.*;
-import java.util.Arrays;
-import java.util.EventObject;
+import java.util.*;
import java.util.List;
import javax.swing.*;
@@ -33,25 +32,29 @@ import org.apache.commons.lang3.StringUtils;
import docking.*;
import docking.widgets.OptionDialog;
+import docking.widgets.button.BrowseButton;
import docking.widgets.button.GButton;
import docking.widgets.checkbox.GCheckBox;
import docking.widgets.combobox.GComboBox;
+import docking.widgets.combobox.GhidraComboBox;
import docking.widgets.label.GLabel;
import docking.widgets.table.*;
import generic.theme.GIcon;
import generic.theme.GThemeDefaults.Colors;
import generic.util.WindowUtilities;
import ghidra.app.services.DataTypeManagerService;
-import ghidra.app.util.ToolTipUtils;
+import ghidra.app.util.*;
import ghidra.app.util.cparser.C.CParserUtils;
+import ghidra.app.util.cparser.C.ParseException;
import ghidra.app.util.viewer.field.ListingColors.FunctionColors;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.VoidDataType;
-import ghidra.program.model.listing.Function;
-import ghidra.program.model.listing.VariableStorage;
-import ghidra.program.model.symbol.ExternalLocation;
+import ghidra.program.model.listing.*;
+import ghidra.program.model.symbol.*;
import ghidra.util.*;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.exception.InvalidInputException;
import ghidra.util.layout.PairLayout;
import ghidra.util.layout.VerticalLayout;
import resources.Icons;
@@ -68,6 +71,7 @@ public class FunctionEditorDialog extends DialogComponentProvider implements Mod
private GTable parameterTable;
private JTextField nameField;
+ private GhidraComboBox Note: This class is not currently multi-threaded. Accesses are expected to be on the Swing
+ * thread.
*/
public class NamespaceCache {
public static final int MAX_RECENTS = 10;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/NamespaceChooserDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/NamespaceChooserDialog.java
index 43ddafac52..6b3a535f76 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/NamespaceChooserDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/NamespaceChooserDialog.java
@@ -48,7 +48,11 @@ public class NamespaceChooserDialog extends DialogComponentProvider {
addCancelButton();
}
- public Namespace getNameSpace(Program program) {
+ public void setText(String text) {
+ dropDownField.setText(text);
+ }
+
+ public Namespace getNamespace(Program program) {
List This class is handed a group of edges to processes. In this group there are vertices that
* do not need to be arranged, referred to as the {@code existing} vertices. This
- * classes uses {@link VertexCollection} to find and store the new vertices that need
+ * classes uses {@link FcgExpandingVertexCollection} to find and store the new vertices that need
* to be arranged.
*/
public class BowTieExpandVerticesJob extends AbstractGraphTransitionJob This offers exiting vertices and new vertices pre-sorted by position in the graph in
+ * This offers existing vertices and new vertices pre-sorted by position in the graph in
* order to minimize edge crossings. Specifically, the new vertices will be sorted
* by the level of the parent and then the x-value of the parent so that the
* immediate parent level will be preferred, with the x-value dictating where to place
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/combobox/GhidraComboBox.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/combobox/GhidraComboBox.java
index b1489076ff..af7831455c 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/combobox/GhidraComboBox.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/combobox/GhidraComboBox.java
@@ -131,6 +131,12 @@ public class GhidraComboBox
* Implementation intended for use with {@link FunctionSignatureParser}
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialogTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialogTest.java
index f73c8f717b..af4a4ca16c 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialogTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialogTest.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,34 +15,36 @@
*/
package ghidra.app.plugin.core.function.editor;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
+import javax.swing.AbstractButton;
+import javax.swing.ComboBoxModel;
import javax.swing.table.TableCellEditor;
import org.junit.*;
import docking.action.DockingActionIf;
import docking.widgets.DropDownSelectionTextField;
+import docking.widgets.button.BrowseButton;
+import docking.widgets.combobox.GhidraComboBox;
import docking.widgets.table.GTable;
import ghidra.app.cmd.function.DeleteFunctionCmd;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.function.FunctionPlugin;
import ghidra.app.plugin.core.navigation.GoToAddressLabelPlugin;
import ghidra.app.services.ProgramManager;
+import ghidra.app.util.*;
import ghidra.app.util.datatype.DataTypeSelectionEditor;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.listing.*;
+import ghidra.program.model.symbol.Namespace;
+import ghidra.program.model.symbol.SourceType;
import ghidra.test.*;
public class FunctionEditorDialogTest extends AbstractGhidraHeadedIntegrationTest {
- public FunctionEditorDialogTest() {
- super();
- }
-
private TestEnv env;
private PluginTool tool;
private AddressFactory addrFactory;
@@ -64,10 +66,11 @@ public class FunctionEditorDialogTest extends AbstractGhidraHeadedIntegrationTes
@After
public void tearDown() {
+ closeAllWindows();
env.dispose();
}
- /**
+ /*
* Tests that an invalid parameter type entry will generate the proper error message
* shown in the status box, and NOT present the user with a stack trace.
*/
@@ -93,10 +96,180 @@ public class FunctionEditorDialogTest extends AbstractGhidraHeadedIntegrationTes
assertTrue(dialog.getStatusText().contains("Invalid data type"));
}
+ @Test
+ public void testSetNamespace() throws Exception {
+
+ createFunctionAtEntry();
+
+ String newNamespaceName = "NewNamespace";
+ Namespace newNs = createNamespace(newNamespaceName);
+
+ FunctionEditorDialog dialog = editFunction();
+
+ pickNamespaceFromComboBox(dialog, newNs);
+
+ pressButtonByText(dialog, "OK");
+ waitForBusyTool(tool);
+
+ Function f = getFunction("0x1006420");
+ Namespace actualNamespace = f.getParentNamespace();
+ assertEquals(newNs, actualNamespace);
+ }
+
+ @Test
+ public void testSetNamespace_Browse_CreateNew() throws Exception {
+
+ createFunctionAtEntry();
+
+ String newNamespace = "NonExistingNamespace";
+
+ FunctionEditorDialog dialog = editFunction();
+
+ setNamespaceUsingNsChooserDilaog(dialog, newNamespace);
+
+ pressButtonByText(dialog, "OK");
+ waitForBusyTool(tool);
+
+ Function f = getFunction("0x1006420");
+ Namespace actualNamespace = f.getParentNamespace();
+ assertEquals(newNamespace, actualNamespace.toString());
+ }
+
+ @Test
+ public void testSetNamespace_Browse_CreateNew_NamespacePath() throws Exception {
+
+ createFunctionAtEntry();
+
+ String newNamespacePath = "Foo::Bar::NonExistingNamespace";
+
+ FunctionEditorDialog dialog = editFunction();
+
+ setNamespaceUsingNsChooserDilaog(dialog, newNamespacePath);
+
+ pressButtonByText(dialog, "OK");
+ waitForBusyTool(tool);
+
+ Function f = getFunction("0x1006420");
+ Namespace actualNamespace = f.getParentNamespace();
+ SymbolPath expectedPath = new SymbolPath(newNamespacePath);
+ SymbolPath actualPath = new SymbolPath(actualNamespace.getPathList(true));
+ assertEquals(expectedPath, actualPath);
+ }
+
+ @Test
+ public void testSetNamespace_ViaTextEditor() throws Exception {
+
+ createFunctionAtEntry();
+
+ String newNamespacePath = "Foo::Bar";
+
+ FunctionEditorDialog dialog = editFunction();
+
+ setNamespaceUsingTextEditor(dialog, newNamespacePath);
+ assertNamespaceNotVisibleInEditorAfterParsing(dialog);
+ assertNamespaceComboBoxIsShowingNamespace(dialog, newNamespacePath);
+
+ pressButtonByText(dialog, "OK");
+ waitForBusyTool(tool);
+
+ Function f = getFunction("0x1006420");
+ Namespace actualNamespace = f.getParentNamespace();
+ SymbolPath expectedPath = new SymbolPath(newNamespacePath);
+ SymbolPath actualPath = new SymbolPath(actualNamespace.getPathList(true));
+ assertEquals(expectedPath, actualPath);
+ }
+
//==================================================================================================
// Private Methods
//==================================================================================================
+ private void assertNamespaceComboBoxIsShowingNamespace(FunctionEditorDialog dialog,
+ String expectedNsPath) {
+
+ Namespace actualNs = runSwing(() -> dialog.getSelectedNamesapce());
+ assertEquals(expectedNsPath, actualNs.toString());
+ }
+
+ private void assertNamespaceNotVisibleInEditorAfterParsing(FunctionEditorDialog dialog) {
+ FunctionSignatureTextField field = dialog.getSignatureField();
+ String signature = runSwing(() -> field.getText());
+ assertFalse("Namespace should not be visible in the editor after parsing",
+ signature.contains("::"));
+ }
+
+ private void setNamespaceUsingTextEditor(FunctionEditorDialog dialog, String ns) {
+
+ FunctionSignatureTextField field = dialog.getSignatureField();
+ String signature = runSwing(() -> field.getText());
+
+ // Insert namespace in front of name. Format:
+ // undefined entry (void)
+ int paren = signature.indexOf('(');
+ int spaceBeforeParen = paren - 1;
+ int space = signature.lastIndexOf(' ', spaceBeforeParen - 1);
+ String beginning = signature.substring(0, space + 1);
+ String end = signature.substring(space + 1);
+ String updated = beginning + ns + "::" + end;
+
+ setText(field, updated);
+
+ runSwing(() -> dialog.triggerSignatureParsing());
+ }
+
+ private void pickNamespaceFromComboBox(FunctionEditorDialog dialog, Namespace ns) {
+
+ GhidraComboBox> combo =
+ (GhidraComboBox>) findComponentByName(dialog, "NamespaceComboBox");
+
+ int index = indexOf(combo, ns);
+ if (index < 0) {
+ fail("Could not find namespace in combo box: " + ns);
+ }
+ runSwing(() -> combo.setSelectedIndex(index));
+ }
+
+ private int indexOf(GhidraComboBox> combo, Namespace ns) {
+ return runSwing(() -> {
+
+ String nsName = ns.getName();
+ ComboBoxModel> model = combo.getModel();
+ int n = model.getSize();
+ for (int i = 0; i < n; i++) {
+ Object element = model.getElementAt(i);
+ String elementText = element.toString();
+ if (elementText.equals(nsName)) {
+ return i;
+ }
+ }
+ return -1;
+ });
+ }
+
+ private void setNamespaceUsingNsChooserDilaog(FunctionEditorDialog dialog,
+ String newNamespace) {
+
+ AbstractButton button = findButtonByName(dialog, BrowseButton.NAME);
+ pressButton(button, false);
+
+ NamespaceChooserDialog nsDialog = waitForDialogComponent(NamespaceChooserDialog.class);
+ runSwing(() -> nsDialog.setText(newNamespace));
+
+ pressButtonByText(nsDialog, "OK");
+ waitForBusyTool(tool);
+ }
+
+ private Namespace createNamespace(String newNamespace) {
+
+ Namespace newNs = tx(program, () -> {
+ return NamespaceUtils.createNamespaceHierarchy(newNamespace, null, program,
+ SourceType.USER_DEFINED);
+ });
+
+ runSwing(() -> NamespaceCache.add(program, newNs));
+
+ return newNs;
+ }
+
private void setEditorText(TableCellEditor cellEditor, String text) {
DropDownSelectionTextField> textField = getDataTypeEditor(cellEditor);
setText(textField, text);
@@ -106,7 +279,7 @@ public class FunctionEditorDialogTest extends AbstractGhidraHeadedIntegrationTes
private FunctionEditorDialog editFunction() {
performAction(editFunction, cb.getProvider(), false);
- return waitForDialogComponent(null, FunctionEditorDialog.class, DEFAULT_WINDOW_TIMEOUT);
+ return waitForDialogComponent(FunctionEditorDialog.class);
}
private void finishEditing(final TableCellEditor cellEditor) {
@@ -150,6 +323,11 @@ public class FunctionEditorDialogTest extends AbstractGhidraHeadedIntegrationTes
addrFactory = program.getAddressFactory();
}
+ private Function getFunction(String addr) {
+ FunctionManager fm = program.getFunctionManager();
+ return fm.getFunctionAt(addr(addr));
+ }
+
private void createFunctionAtEntry() {
FunctionManager fm = program.getFunctionManager();
Function f = fm.getFunctionAt(addr("0x1006420"));
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/parser/FunctionSignatureParserTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/parser/FunctionSignatureParserTest.java
index 3bcf031939..2cc7388504 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/parser/FunctionSignatureParserTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/parser/FunctionSignatureParserTest.java
@@ -132,6 +132,7 @@ public class FunctionSignatureParserTest extends AbstractGhidraHeadedIntegration
public void testExtractFunctionName() throws Exception {
assertEquals("bob", parser.extractFunctionName("void bob(int a)"));
assertEquals("bob", parser.extractFunctionName("void bob (int a)"));
+ assertEquals("Foo::Bar::bob", parser.extractFunctionName("void Foo::Bar::bob (int a)"));
}
@Test
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/function/editor/FunctionEditorModelTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/function/editor/FunctionEditorModelTest.java
index bd295ad46e..a93915548a 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/function/editor/FunctionEditorModelTest.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/function/editor/FunctionEditorModelTest.java
@@ -22,7 +22,6 @@ import java.util.List;
import org.junit.*;
import generic.test.AbstractGuiTest;
-import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
@@ -40,7 +39,6 @@ public class FunctionEditorModelTest extends AbstractGuiTest {
private volatile boolean dataChangeCalled;
private Structure bigStruct;
private ProgramDB program;
- private DataTypeManagerService service;
private volatile boolean tableRowsChanged;
class MyModelChangeListener implements ModelChangeListener {
@@ -1612,9 +1610,9 @@ public class FunctionEditorModelTest extends AbstractGuiTest {
assertEquals("R9D:4", storage.toString());
model.setUseCustomizeStorage(false);
- // no change to 'this', return ptr consumed and unfortunately
+ // no change to 'this', return pointer consumed and unfortunately
// injected before custom 'this' param
- // TODO: should we be removing 'this' param if not __thiscall ?
+ // Note: should we be removing 'this' param if not __thiscall ?
assertTrue(model.getReturnType().isEquivalent(new PointerDataType(bigStruct)));
assertTrue(model.getFormalReturnType().isEquivalent(bigStruct));
@@ -1843,7 +1841,6 @@ public class FunctionEditorModelTest extends AbstractGuiTest {
model.setUseCustomizeStorage(true);
VariableStorage paramStorage1 = model.getParameters().get(0).getStorage();
- VariableStorage paramStorage2 = model.getParameters().get(1).getStorage();
VariableStorage paramStorage3 = model.getParameters().get(2).getStorage();
model.setSignatureFieldText("int joe(int e, int c, int f, int g)");
diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/SpecifyCPrototypeAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/SpecifyCPrototypeAction.java
index aeffece704..4b6ce3fe58 100644
--- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/SpecifyCPrototypeAction.java
+++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/SpecifyCPrototypeAction.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.
@@ -27,6 +27,7 @@ import ghidra.program.model.data.*;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.VariableStorage;
import ghidra.program.model.pcode.*;
+import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.HelpLocation;
import ghidra.util.UndefinedFunction;
@@ -99,7 +100,10 @@ public class SpecifyCPrototypeAction extends AbstractDecompilerAction {
if (useCustom) {
// Force custom storage
model.setUseCustomizeStorage(true);
- model.setFunctionData(buildSignature(hf));
+ Function function = hf.getFunction();
+ Namespace ns = function.getParentNamespace();
+ FunctionDefinitionDataType signature = buildSignature(hf);
+ model.setFunctionData(ns, signature);
model.setReturnStorage(functionPrototype.getReturnStorage());
parameters = model.getParameters();
for (int i = 0; i < decompParamCnt; i++) {
@@ -169,7 +173,9 @@ public class SpecifyCPrototypeAction extends AbstractDecompilerAction {
if (function.getEntryPoint().equals(hf.getFunction().getEntryPoint())) {
if (function.getSignatureSource() == SourceType.DEFAULT) {
- model.setFunctionData(buildSignature(hf));
+ Namespace ns = function.getParentNamespace();
+ FunctionDefinitionDataType signature = buildSignature(hf);
+ model.setFunctionData(ns, signature);
verifyDynamicEditorModel(hf, model);
}
else if (function.getReturnType() == DataType.DEFAULT) {
diff --git a/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/FcgLevel.java b/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/FcgLevel.java
index 775b9396e0..821ab24c2f 100644
--- a/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/FcgLevel.java
+++ b/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/FcgLevel.java
@@ -145,8 +145,8 @@ public class FcgLevel implements Comparable