diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SpecExtensionPanel.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SpecExtensionPanel.java index a88dec924f..8a2e2048ba 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SpecExtensionPanel.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SpecExtensionPanel.java @@ -546,6 +546,23 @@ public class SpecExtensionPanel extends JPanel { } } + private static PrototypeModel findPrototypeModel(CompilerSpec compilerSpec, String name) { + PrototypeModel model = compilerSpec.getCallingConvention(name); + if (model != null) { + return model; + } + for (PrototypeModel candidate : compilerSpec.getAllModels()) { + if (name.equals(candidate.getName())) { + return candidate; + } + } + return null; + } + + private static String toExportFilename(String name) { + return name.replace('/', '_').replace('\\', '_'); + } + private String getXmlString(CompilerElement element) throws IOException { CompilerSpec compilerSpec = program.getCompilerSpec(); PcodeInjectLibrary injectLibrary = compilerSpec.getPcodeInjectLibrary(); @@ -570,7 +587,7 @@ public class SpecExtensionPanel extends JPanel { break; case PROTOTYPE_MODEL: case MERGE_MODEL: - model = compilerSpec.getCallingConvention(element.name); + model = findPrototypeModel(compilerSpec, element.name); if (model != null) { model.encode(encoder, injectLibrary); } @@ -596,7 +613,7 @@ public class SpecExtensionPanel extends JPanel { if (!compilerElement.isExisting()) { return; // Only export existing elements } - String suggestedName = compilerElement.name + PREFERENCES_FILE_EXTENSION; + String suggestedName = toExportFilename(compilerElement.name) + PREFERENCES_FILE_EXTENSION; File outputFile = getFileFromUser(suggestedName); if (outputFile == null) { return; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/SpecExtension.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/SpecExtension.java index 8259ce5a6f..2a15fd4163 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/SpecExtension.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/SpecExtension.java @@ -369,7 +369,7 @@ public class SpecExtension { } for (int i = 0; i < formalName.length(); ++i) { char c = formalName.charAt(i); - if (!Character.isLetterOrDigit(c) && c != '_' && c != '.' && c != '-') { + if (!Character.isLetterOrDigit(c) && c != '_' && c != '.' && c != '-' && c != '/') { return false; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/SpecExtensionTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/SpecExtensionTest.java new file mode 100644 index 0000000000..f7eeffc951 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/SpecExtensionTest.java @@ -0,0 +1,36 @@ +/* ### + * 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.program.database; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class SpecExtensionTest { + + @Test + public void testIsValidFormalName_allowsSlashInMergeModelNames() { + assertTrue(SpecExtension.isValidFormalName("__fastcall/__thiscall/__stdcall")); + assertTrue(SpecExtension.isValidFormalName("__cdecl/__regparm")); + } + + @Test + public void testIsValidFormalName_rejectsEmptyAndInvalidCharacters() { + assertFalse(SpecExtension.isValidFormalName("")); + assertFalse(SpecExtension.isValidFormalName("bad name")); + assertFalse(SpecExtension.isValidFormalName("bad|name")); + } +}