Merge branch 'GP-7045_ryanmkurtz_swift' into patch

This commit is contained in:
Ryan Kurtz
2026-07-07 05:57:56 -04:00
7 changed files with 19 additions and 60 deletions

View File

@@ -1,7 +1,7 @@
# SwiftDemangler
This module provides support for demanling mangled [Swift](https://www.swift.org) symbols. Supported
mangled symbols begin with `$S`, `$s`, `_$S"`, `_$s`, or `_T`.
This module provides support for demangling mangled [Swift](https://www.swift.org) symbols.
Supported mangled symbols begin with `$S`, `$s`, `_$S"`, `_$s`, or `_T`.
The demangler currently relies on making direct calls to the native Swift demangler tool, which
comes [bundled with Swift](https://www.swift.org/download/). For example:
@@ -21,5 +21,4 @@ protocol descriptor for SwiftUI.View
The resulting tree is parsed by the Ghidra Swift Demangler to form and apply a demangled symbol
name.
By default, the `Demangler Swift` Analyzer will search for the native Swift Demangler on the `PATH`.
If it resides elsewhere, its path can be specified in the analyzer's options.
The `Demangler Swift` Analyzer assumes that the native Swift Demangler is on the `PATH`.

View File

@@ -55,7 +55,7 @@ public class SwiftDemanglerScript extends GhidraScript {
return;
}
SwiftNativeDemangler nativeDemangler = new SwiftNativeDemangler(options.getSwiftDir());
SwiftNativeDemangler nativeDemangler = new SwiftNativeDemangler();
SwiftNativeDemangledOutput demangledOutput = nativeDemangler.demangle(mangled);
println(demangledOutput.toString());

View File

@@ -15,7 +15,6 @@
*/
package ghidra.app.plugin.core.analysis;
import java.io.File;
import java.io.IOException;
import ghidra.app.util.demangler.*;
@@ -36,10 +35,7 @@ public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
private static final String NAME = "Demangler Swift";
private static final String DESCRIPTION =
"Demangles Swift symbols and applies appropriate datatype and calling conventions where possible. Requires Swift to be installed.";
private static final String OPTION_NAME_SWIFT_DIR = "Swift binary directory";
private static final String OPTION_DESCRIPTION_SWIFT_DIR =
"Path to the Swift installation binary directory, if not on PATH";
"Demangles Swift symbols and applies appropriate datatype and calling conventions where possible. Requires Swift to be on the PATH.";
private static final String OPTION_NAME_INCOMPLETE_PREFIX =
"Use incomplete demangle label prefix (%s)"
@@ -54,7 +50,6 @@ public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
"Prefix unsupported demangled labels with '%s'"
.formatted(SwiftDemanglerOptions.UNSUPPORTED_PREFIX);
private File swiftDir;
private boolean useIncompletePrefix = true;
private boolean useUnsupportedPrefix = true;
@@ -94,8 +89,6 @@ public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
@Override
public void registerOptions(Options options, Program program) {
HelpLocation help = new HelpLocation("AutoAnalysisPlugin", "Demangler_Analyzer");
options.registerOption(OPTION_NAME_SWIFT_DIR, OptionType.FILE_TYPE, swiftDir, help,
OPTION_DESCRIPTION_SWIFT_DIR);
options.registerOption(OPTION_NAME_INCOMPLETE_PREFIX, OptionType.BOOLEAN_TYPE,
useIncompletePrefix, help, OPTION_DESCRIPTION_INCOMPLETE_PREFIX);
options.registerOption(OPTION_NAME_UNSUPPORTED_PREFIX, OptionType.BOOLEAN_TYPE,
@@ -104,9 +97,9 @@ public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
@Override
protected boolean validateOptions(DemanglerOptions options, MessageLog log) {
if (options instanceof SwiftDemanglerOptions swiftDemanglerOptions) {
if (options instanceof SwiftDemanglerOptions) {
try {
new SwiftNativeDemangler(swiftDemanglerOptions.getSwiftDir());
new SwiftNativeDemangler();
return true;
}
catch (IOException e) {
@@ -120,7 +113,6 @@ public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
@Override
public void optionsChanged(Options options, Program program) {
swiftDir = options.getFile(OPTION_NAME_SWIFT_DIR, swiftDir);
useIncompletePrefix =
options.getBoolean(OPTION_NAME_INCOMPLETE_PREFIX, useIncompletePrefix);
useUnsupportedPrefix =
@@ -130,7 +122,6 @@ public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
@Override
protected DemanglerOptions getOptions() {
SwiftDemanglerOptions swiftDemanglerOptions = new SwiftDemanglerOptions();
swiftDemanglerOptions.setSwiftDir(swiftDir);
swiftDemanglerOptions.setIncompletePrefix(useIncompletePrefix);
swiftDemanglerOptions.setUnsupportedPrefix(useUnsupportedPrefix);
return swiftDemanglerOptions;

View File

@@ -189,7 +189,7 @@ public class SwiftDemangler implements Demangler {
private void setSwiftNativeDemangler(SwiftDemanglerOptions options) throws DemangledException {
if (nativeDemangler == null) {
try {
nativeDemangler = new SwiftNativeDemangler(options.getSwiftDir());
nativeDemangler = new SwiftNativeDemangler();
}
catch (IOException e) {
throw new DemangledException(e);

View File

@@ -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,8 +15,6 @@
*/
package ghidra.app.util.demangler.swift;
import java.io.File;
import ghidra.app.util.demangler.DemanglerOptions;
/**
@@ -27,33 +25,9 @@ public class SwiftDemanglerOptions extends DemanglerOptions {
public static final String INCOMPLETE_PREFIX = "$";
public static final String UNSUPPORTED_PREFIX = "$$";
private File swiftDir;
private boolean useIncompletePrefix;
private boolean useUnsupportedPrefix;
/**
* Gets the Swift directory
* <p>
* If the Swift directory is on the PATH environment variable, this may return null
*
* @return The Swift directory
*/
public File getSwiftDir() {
return swiftDir;
}
/**
* Sets the Swift directory
* <p>
* If the Swift directory is on the PATH environment variable, it is fine to set this to
* null
*
* @param swiftDir The Swift directory
*/
public void setSwiftDir(File swiftDir) {
this.swiftDir = swiftDir;
}
/**
* {@return the "incomplete prefix" character to use in label names}
*/

View File

@@ -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.
@@ -34,7 +34,7 @@ import java.util.stream.Collectors;
*/
public class SwiftNativeDemangler {
private String nativeDemanglerPath;
private String nativeDemanglerCmd;
private boolean standaloneDemanglerBinary;
/**
@@ -54,25 +54,20 @@ public class SwiftNativeDemangler {
/**
* Creates a new {@link SwiftNativeDemangler}
*
* @param swiftDir The Swift directory
* @throws IOException if there was a problem finding or running the Swift native demangler
*/
public SwiftNativeDemangler(File swiftDir) throws IOException {
public SwiftNativeDemangler() throws IOException {
List<String> demanglerNames = List.of("swift-demangle", "swift");
IOException ioe = null;
for (String demanglerName : demanglerNames) {
nativeDemanglerPath = demanglerName;
if (swiftDir != null) {
nativeDemanglerPath = swiftDir + File.separator + nativeDemanglerPath;
}
nativeDemanglerCmd = demanglerName; // expect swift demangler to be on the PATH
try {
int exitCode =
new ProcessBuilder(List.of(nativeDemanglerPath, "--version")).start()
.waitFor();
new ProcessBuilder(List.of(nativeDemanglerCmd, "--version")).start().waitFor();
if (exitCode == 0) {
ioe = null;
standaloneDemanglerBinary =
new File(nativeDemanglerPath).getName().contains("-demangle");
new File(nativeDemanglerCmd).getName().contains("-demangle");
break;
}
ioe = new IOException("Native Swift demangler exited with code: " + exitCode);
@@ -144,7 +139,7 @@ public class SwiftNativeDemangler {
*/
private BufferedReader demangle(String mangled, List<String> options) throws IOException {
List<String> command = new ArrayList<>();
command.add(nativeDemanglerPath);
command.add(nativeDemanglerCmd);
if (!standaloneDemanglerBinary) {
command.add("demangle");
}

View File

@@ -43,7 +43,7 @@ public class SwiftDemanglerTest extends AbstractGenericTest {
// Ghidra does not ship the native Swift demangler binary, so it may not be present to run
// these tests. In this scenario, we just want these tests skipped (as opposed to failing).
try {
new SwiftNativeDemangler(new SwiftDemanglerOptions().getSwiftDir());
new SwiftNativeDemangler();
}
catch (IOException e) {
assumeNoException(e); // skip test, don't fail