@@ -90,6 +106,35 @@ package ghidra.app.util.demangler;
*/
public interface Demangled {
+ /**
+ * Sets the mangled context
+ *
+ * This method currently has a {@code default} implementation so not to break existing
+ * class implementations. However, at some point the {@code default} tag and implementation,
+ * which is empty, will be removed. Thus, all implementers need to implement this method
+ * before the removal of the {@code default}
+ * @param mangledContextArg the mangled context
+ * @since 11.3
+ */
+ public default void setMangledContext(MangledContext mangledContextArg) {
+ // currently this does nothing; implementers must override this even though marked as
+ // default... the default implementation will be removed in a future release
+ }
+
+ /**
+ * Returns the mangled context
+ *
+ * This method currently has a {@code default} implementation so not to break existing
+ * class implementations. However, at some point the {@code default} tag and implementation,
+ * which returns null, will be removed. Thus, all implementers need to implement this method
+ * before the removal of the {@code default}
+ * @return the context or null if no context
+ * @since 11.3
+ */
+ public default MangledContext getMangledContext() {
+ return null;
+ }
+
/**
* Returns the original mangled string
* @return the string
@@ -102,7 +147,7 @@ public interface Demangled {
*/
public String getOriginalDemangled();
- /**
+ /**
* Returns the demangled name of this object.
* NOTE: unsupported symbol characters, like whitespace, will be converted to an underscore.
* @return name of this DemangledObject with unsupported characters converted to underscore
@@ -116,9 +161,9 @@ public interface Demangled {
*/
public void setName(String name);
- /**
- * Returns the unmodified demangled name of this object. This name may contain whitespace
- * and other characters not supported for symbol or data type creation. See {@link #getName()}
+ /**
+ * Returns the unmodified demangled name of this object. This name may contain whitespace
+ * and other characters not supported for symbol or data type creation. See {@link #getName()}
* for the same name modified for use within Ghidra.
* @return name of this DemangledObject
*/
@@ -137,7 +182,7 @@ public interface Demangled {
public void setNamespace(Demangled ns);
/**
- * Returns a representation of this object as fully-qualified namespace. The
+ * Returns a representation of this object as fully-qualified namespace. The
* value returned here may have had some special characters replaced, such as ' ' replaced
* with '_' and '::' replaced with '--'.
* @return the full namespace
@@ -145,17 +190,17 @@ public interface Demangled {
public String getNamespaceString();
/**
- * Returns this object's namespace name without the fully-qualified parent path. The
+ * Returns this object's namespace name without the fully-qualified parent path. The
* value returned here may have had some special characters replaced, such as ' ' replaced
* with '_' and '::' replaced with '--'.
- *
+ *
* @return the name
*/
public String getNamespaceName();
/**
* Generates a complete representation of this object to include all know attributes of this
- * object
+ * object
* @return the signature
*/
public String getSignature();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledObject.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledObject.java
index 0173aa710d..cf1b01e898 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledObject.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledObject.java
@@ -44,37 +44,38 @@ public abstract class DemangledObject implements Demangled {
/*
The following names probably need to be refactored. Until then, this is how the following
fields are used.
-
+
mangled -
Source: The original mangled string as seen in the program
Usage: Can be used to see if a program symbol has already been demangled
-
+
originalDemangled -
Source: The raw demangled string returned from the demangler
Usage: for display
-
+
demangledName -
Source: The name as created by the parser which may transform or even replace the
string returned from the demangler
Usage: for display
-
+
name -
Source: This is derived from the 'demangledName' This is updated to be suitable
for use as a symbol name. This may be null while building, but is
expected to be non-null when applyTo() is called
Usage: The name that will be applied when applyTo() is called.
-
-
-
+
+
+
Future: These variables should be refactored and renamed to be clearer and more cohesive,
something like:
-
+
mangled
rawDemangled
escapedDemangled
symbolName
-
+
*/
+ protected MangledContext mangledContext; // the mangled context, which includes mangled string
protected final String mangled; // original mangled string
protected String originalDemangled; // raw demangled string
private String demangledName; // updated demangled string
@@ -110,11 +111,29 @@ public abstract class DemangledObject implements Demangled {
private boolean demangledNameSucceeded = false;
private String errorMessage = null;
+ /**
+ * Constructor. This is the older constructor that does not take a mangled context
+ * @param mangled the mangled string
+ * @param originalDemangled the raw demangled string; usually what comes from the upstream
+ * demangler process, if there is one
+ */
DemangledObject(String mangled, String originalDemangled) {
this.mangled = mangled;
this.originalDemangled = originalDemangled;
}
+ /**
+ * Constructor.
+ * @param mangledContext the context, which includes the mangled string
+ * @param originalDemangled the raw demangled string; usually what comes from the upstream
+ * demangler process, if there is one
+ */
+ DemangledObject(MangledContext mangledContext, String originalDemangled) {
+ this.mangledContext = mangledContext;
+ this.mangled = mangledContext.getMangled();
+ this.originalDemangled = originalDemangled;
+ }
+
@Override
public String getDemangledName() {
return demangledName;
@@ -230,6 +249,16 @@ public abstract class DemangledObject implements Demangled {
return demangledNameSucceeded;
}
+ @Override
+ public void setMangledContext(MangledContext mangledContextArg) {
+ mangledContext = mangledContextArg;
+ }
+
+ @Override
+ public MangledContext getMangledContext() {
+ return mangledContext;
+ }
+
@Override
public String getMangledString() {
return mangled;
@@ -378,7 +407,7 @@ public abstract class DemangledObject implements Demangled {
* Apply this demangled object detail to the specified program.
*
* NOTE: An open Program transaction must be established prior to invoking this method.
- *
+ *
* @param program program to which demangled data should be applied.
* @param address address which corresponds to this demangled object
* @param options options which control how demangled data is applied
@@ -391,6 +420,25 @@ public abstract class DemangledObject implements Demangled {
return applyPlateCommentOnly(program, address);
}
+ /**
+ * Apply this demangled object detail to the specified program. This method only works
+ * if the {@link MangledContext} was set with the appropriate constructor or with the
+ * {@link #setMangledContext(MangledContext)} method
+ *
+ * NOTE: An open Program transaction must be established prior to invoking this method.
+ *
+ * @param monitor task monitor
+ * @return true if successfully applied, else false
+ * @throws Exception if an error occurs during the apply operation or if the context is null
+ */
+ public boolean applyUsingContext(TaskMonitor monitor) throws Exception {
+ if (mangledContext == null) {
+ throw new DemangledException("Null context found for: " + mangled);
+ }
+ return applyTo(mangledContext.getProgram(), mangledContext.getAddress(),
+ mangledContext.getOptions(), monitor);
+ }
+
/**
* @param program The program for which to apply the comment
* @param address The address for the comment
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/Demangler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/Demangler.java
index ac0519e7aa..e2204baa6b 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/Demangler.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/Demangler.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,6 +15,7 @@
*/
package ghidra.app.util.demangler;
+import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.util.classfinder.ExtensionPoint;
@@ -24,46 +25,53 @@ import ghidra.util.classfinder.ExtensionPoint;
*/
public interface Demangler extends ExtensionPoint {
+ // Note: Consider deprecating this method and creating one that takes the MangledContext.
+ // Another option might be to find a smarter utility method that contains the complete
+ // knowledge of when a particular demangler is appropriate.. but that would have to consider
+ // demanglers written by others.
public boolean canDemangle(Program program);
/**
- * Deprecated. Use {@link #demangle(String)} or
- * {@link #demangle(String, DemanglerOptions)}.
+ * Attempts to demangle the given string using a context
+ * ({@link #createMangledContext(String, DemanglerOptions, Program, Address)} with
+ * default options ({@link #createDefaultOptions()}.
*
* @param mangled the mangled string
- * @param demangleOnlyKnownPatterns true signals to avoid demangling strings that do
- * not fit known demangled patterns for this demangler
- * @return the result
- * @throws DemangledException if the string cannot be demangled
- * @deprecated see above
- */
- @Deprecated(since = "9.2", forRemoval = true)
- public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
- throws DemangledException;
-
- /**
- * Attempts to demangle the given string using the default options
- * ({@link #createDefaultOptions()}
- *
- * @param mangled the mangled string
* @return the result
* @throws DemangledException if the string cannot be demangled
*/
public default DemangledObject demangle(String mangled) throws DemangledException {
- return demangle(mangled, createDefaultOptions());
+ MangledContext mangledContext = createMangledContext(mangled, null, null, null);
+ return demangle(mangledContext);
}
/**
+ * Deprecated. Use {@link #demangle(String)} or
+ * {@link #demangle(MangledContext)}.
+ *
* Attempts to demangle the given string using the given options
- *
+ *
* @param mangled the mangled string
* @param options the options
* @return the result
* @throws DemangledException if the string cannot be demangled
+ * @deprecated see above
*/
+ @Deprecated(since = "11.3", forRemoval = true)
public DemangledObject demangle(String mangled, DemanglerOptions options)
throws DemangledException;
+ /**
+ * Attempts to demangle the string of the mangled context
+ *
+ * @param context the mangled context
+ * @return the result
+ * @throws DemangledException if the string cannot be demangled
+ */
+ public default DemangledObject demangle(MangledContext context) throws DemangledException {
+ return demangle(context.getMangled(), context.getOptions());
+ }
+
/**
* Creates default options for this particular demangler
* @return the options
@@ -71,4 +79,21 @@ public interface Demangler extends ExtensionPoint {
public default DemanglerOptions createDefaultOptions() {
return new DemanglerOptions();
}
+
+ /**
+ * Creates a mangled context
+ * @param mangled the mangled name
+ * @param options the demangler options; if null, the default options are created
+ * @param program the program; can be null
+ * @param address the address for the name in the program; can be null
+ * @return the mangled context
+ */
+ public default MangledContext createMangledContext(String mangled, DemanglerOptions options,
+ Program program, Address address) {
+ if (options == null) {
+ options = createDefaultOptions();
+ }
+ return new MangledContext(program, options, mangled, address);
+ }
+
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemanglerUtil.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemanglerUtil.java
index 7517ae882f..d869d36432 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemanglerUtil.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemanglerUtil.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,39 +15,59 @@
*/
package ghidra.app.util.demangler;
+import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.util.classfinder.ClassSearcher;
+/**
+ * Demangler Utility class. For version 11.3, we have migrated to a new Demangler API that
+ * requires a {@link MangledContext} be passed to the demangler. This provides more information
+ * for properly demangling symbols.
+ *
+ * Two methods below have been deprecated, as they do not provide enough information to produce
+ * the {@link MangledContext}. A new method @link demangle(Program, String, Address) is provided
+ * to permit proper operation using a completed context. Moreover, this new method returns all
+ * results instead of the first one found, as is how the deprecated methods work.
+ */
public class DemanglerUtil {
//
- // Patterns used to remove superfluous spaces within parameter list.
+ // Patterns used to remove superfluous spaces within parameter list.
//
private static final Pattern LEADING_PARAMETER_SPACE_PATTERN =
Pattern.compile(" ([\\*\\&\\)])");
private static final Pattern TRAILING_PARAMETER_SPACE_PATTERN = Pattern.compile("([\\(\\,]) ");
/**
+ * Deprecated. Use {@link #demangle(Program, String, Address)}. See class header for more
+ * details.
+ *
* Locates all available demanglers, then it attempts to demangle. This method will
- * query all demanglers regardless of architecture.
- *
- *
This method will use only the default options for demangling. If you need to
+ * query all demanglers regardless of architecture.
+ *
+ *
This method will use only the default options for demangling. If you need to
* specify options, then you will have to call each specific demangler directly, creating
- * the options specifically needed for each demangler. See
+ * the options and mangled context specifically needed for each demangler. See
+ * {@link Demangler#createMangledContext(String, DemanglerOptions, Program, Address)} and
* {@link Demangler#createDefaultOptions()}.
- *
+ *
* @param mangled the mangled name
* @return the demangled object or null
+ * @deprecated see above
*/
+ @Deprecated(since = "11.3", forRemoval = true)
public static DemangledObject demangle(String mangled) {
List demanglers = getDemanglers();
for (Demangler demangler : demanglers) {
try {
- DemangledObject demangledObject = demangler.demangle(mangled);
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, null, null);
+ DemangledObject demangledObject = demangler.demangle(mangledContext);
if (demangledObject != null) {
return demangledObject;
}
@@ -60,18 +80,24 @@ public class DemanglerUtil {
}
/**
- * Locates all available demanglers and checks to see if the supplied program is
+ * Deprecated. Use {@link #demangle(Program, String, Address)}. See class header for more
+ * details.
+ *
+ * Locates all available demanglers and checks to see if the supplied program is
* supported, then it attempts to demangle.
- *
- * This method will use only the default options for demangling. If you need to
+ *
+ *
This method will use only the default options for demangling. If you need to
* specify options, then you will have to call each specific demangler directly, creating
- * the options specifically needed for each demangler. See
+ * the options and mangled context specifically needed for each demangler. See
+ * {@link Demangler#createMangledContext(String, DemanglerOptions, Program, Address)} and
* {@link Demangler#createDefaultOptions()}.
- *
+ *
* @param program the program containing the mangled name
* @param mangled the mangled name
* @return the demangled object or null
+ * @deprecated see above
*/
+ @Deprecated(since = "11.3", forRemoval = true)
public static DemangledObject demangle(Program program, String mangled) {
List demanglers = getDemanglers();
for (Demangler demangler : demanglers) {
@@ -80,7 +106,9 @@ public class DemanglerUtil {
continue;
}
- DemangledObject demangledObject = demangler.demangle(mangled);
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, null, null);
+ DemangledObject demangledObject = demangler.demangle(mangledContext);
if (demangledObject != null) {
return demangledObject;
}
@@ -92,9 +120,48 @@ public class DemanglerUtil {
return null;
}
+ /**
+ * Locates all available demanglers and checks to see if the supplied program is
+ * supported, then it attempts to demangle. Returns a list of {@link DemangledObject} of
+ * successful demanglings
+ *
+ * This method will use only the default options for demangling. If you need to
+ * specify options, then you will have to call each specific demangler directly, creating
+ * the options and mangled context specifically needed for each demangler. See
+ * {@link Demangler#createMangledContext(String, DemanglerOptions, Program, Address)} and
+ * {@link Demangler#createDefaultOptions()}.
+ *
+ * @param program the program containing the mangled name
+ * @param mangled the mangled name
+ * @param address the address of the mangled name
+ * @return the list of {@link DemangledObject}
+ */
+ public static List demangle(Program program, String mangled, Address address) {
+ List results = new ArrayList<>();
+ List demanglers = getDemanglers();
+ for (Demangler demangler : demanglers) {
+ try {
+ if (!demangler.canDemangle(program)) {
+ continue;
+ }
+
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, program, address);
+ DemangledObject demangledObject = demangler.demangle(mangledContext);
+ if (demangledObject != null) {
+ results.add(demangledObject);
+ }
+ }
+ catch (DemangledException e) {
+ // ignore
+ }
+ }
+ return results;
+ }
+
/**
* Dynamically locates all available demangler implementations.
- *
+ *
* @return a list of all demanglers
*/
private static List getDemanglers() {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/MangledContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/MangledContext.java
new file mode 100644
index 0000000000..6c0cbc781c
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/MangledContext.java
@@ -0,0 +1,80 @@
+/* ###
+ * 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.util.demangler;
+
+import java.util.Objects;
+
+import ghidra.program.model.address.Address;
+import ghidra.program.model.listing.Program;
+
+/**
+ * A simple class to contain the context of a mangled symbol for demangling
+ */
+public class MangledContext {
+
+ protected Program program;
+ protected DemanglerOptions options;
+ protected String mangled;
+ protected Address address;
+
+ /**
+ * Constructor for mangled context
+ * @param program the program; can be null
+ * @param options the demangler options
+ * @param mangled the mangled string
+ * @param address the address; can be null
+ */
+ public MangledContext(Program program, DemanglerOptions options, String mangled,
+ Address address) {
+ this.program = program;
+ this.options = Objects.requireNonNull(options, "Options cannot be null");
+ this.mangled = Objects.requireNonNull(mangled, "Mangled cannot be null");
+ this.address = address;
+ }
+
+ /**
+ * Returns the program
+ * @return the program; can be null
+ */
+ public Program getProgram() {
+ return program;
+ }
+
+ /**
+ * Returns the demangler options
+ * @return the options
+ */
+ public DemanglerOptions getOptions() {
+ return options;
+ }
+
+ /**
+ * Returns the mangled string
+ * @return the mangled string
+ */
+ public String getMangled() {
+ return mangled;
+ }
+
+ /**
+ * Returns the address
+ * @return the address; can be null
+ */
+ public Address getAddress() {
+ return address;
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractPeDebugLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractPeDebugLoader.java
index 8dbed8d3db..813204067f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractPeDebugLoader.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractPeDebugLoader.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.
@@ -259,15 +259,21 @@ abstract class AbstractPeDebugLoader extends AbstractOrdinalSupportLoader {
}
private void demangle(Address address, String name, Program program) {
- DemangledObject demangledObj = null;
+ StringBuilder builder = new StringBuilder();
try {
- demangledObj = DemanglerUtil.demangle(program, name);
+ List demangledObjects = DemanglerUtil.demangle(program, name, address);
+ for (DemangledObject demangledObj : demangledObjects) {
+ if (builder.length() > 0) {
+ builder.append("\t");
+ }
+ builder.append(demangledObj.getSignature(true));
+ }
}
catch (Exception e) {
//log.appendMsg("Unable to demangle: "+name);
}
- if (demangledObj != null) {
- setComment(CodeUnit.PLATE_COMMENT, address, demangledObj.getSignature(true));
+ if (builder.length() > 0) {
+ setComment(CodeUnit.PLATE_COMMENT, address, builder.toString());
}
}
@@ -426,7 +432,7 @@ abstract class AbstractPeDebugLoader extends AbstractOrdinalSupportLoader {
Symbol newSymbol =
program.getSymbolTable().createLabel(address, sym, SourceType.IMPORTED);
- // Force non-section symbols to be primary. We never want section symbols (.text,
+ // Force non-section symbols to be primary. We never want section symbols (.text,
// .text$func_name) to be primary because we don't want to use them for function names
// or demangling.
if (!sym.equals(section.getName()) && !sym.startsWith(section.getName() + "$")) {
diff --git a/Ghidra/Features/GnuDemangler/ghidra_scripts/DemangleElfWithOptionScript.java b/Ghidra/Features/GnuDemangler/ghidra_scripts/DemangleElfWithOptionScript.java
index 82dc4981c7..7d5db9e56a 100644
--- a/Ghidra/Features/GnuDemangler/ghidra_scripts/DemangleElfWithOptionScript.java
+++ b/Ghidra/Features/GnuDemangler/ghidra_scripts/DemangleElfWithOptionScript.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 @@
//@category Examples.Demangler
import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledObject;
+import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.gnu.*;
import ghidra.program.model.symbol.Symbol;
@@ -56,7 +57,9 @@ public class DemangleElfWithOptionScript extends GhidraScript {
options = options.withDemanglerFormat(GnuDemanglerFormat.ARM, true);
*/
- DemangledObject demangledObject = demangler.demangle(mangled, options);
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, options, currentProgram, currentAddress);
+ DemangledObject demangledObject = demangler.demangle(mangledContext);
if (demangledObject == null) {
println("Could not demangle: " + mangled);
return;
diff --git a/Ghidra/Features/GnuDemangler/ghidra_scripts/VxWorksSymTab_5_4.java b/Ghidra/Features/GnuDemangler/ghidra_scripts/VxWorksSymTab_5_4.java
index f0af2fe43e..759e8e824f 100644
--- a/Ghidra/Features/GnuDemangler/ghidra_scripts/VxWorksSymTab_5_4.java
+++ b/Ghidra/Features/GnuDemangler/ghidra_scripts/VxWorksSymTab_5_4.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.
@@ -53,6 +53,7 @@ import java.util.List;
import ghidra.app.cmd.label.DemanglerCmd;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledException;
+import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.program.model.address.Address;
import ghidra.program.model.mem.Memory;
@@ -143,7 +144,9 @@ public class VxWorksSymTab_5_4 extends GhidraScript {
String symDemangledName = null;
try {
// if successful, symDemangledName will be non-NULL
- symDemangledName = demangler.demangle(symName).getSignature(false);
+ MangledContext mangledContext = demangler.createMangledContext(symDemangledName,
+ null, currentProgram, symNameAddr);
+ symDemangledName = demangler.demangle(mangledContext).getSignature(false);
}
catch (DemangledException e) {
// if symName wasn't a mangled name, silently continue
diff --git a/Ghidra/Features/GnuDemangler/ghidra_scripts/VxWorksSymTab_6_1.java b/Ghidra/Features/GnuDemangler/ghidra_scripts/VxWorksSymTab_6_1.java
index beeeab2a94..2bcc6678e5 100644
--- a/Ghidra/Features/GnuDemangler/ghidra_scripts/VxWorksSymTab_6_1.java
+++ b/Ghidra/Features/GnuDemangler/ghidra_scripts/VxWorksSymTab_6_1.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.
@@ -51,6 +51,7 @@ import java.util.List;
import ghidra.app.cmd.label.DemanglerCmd;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledException;
+import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.program.model.address.Address;
import ghidra.program.model.mem.Memory;
@@ -139,7 +140,9 @@ public class VxWorksSymTab_6_1 extends GhidraScript {
String symDemangledName = null;
try {
// if successful, symDemangledName will be non-NULL
- symDemangledName = demangler.demangle(symName).getSignature(false);
+ MangledContext mangledContext = demangler.createMangledContext(symDemangledName,
+ null, currentProgram, symNameAddr);
+ symDemangledName = demangler.demangle(mangledContext).getSignature(false);
}
catch (DemangledException e) {
// if symName wasn't a mangled name, silently continue
diff --git a/Ghidra/Features/GnuDemangler/ghidra_scripts/VxWorksSymTab_Finder.java b/Ghidra/Features/GnuDemangler/ghidra_scripts/VxWorksSymTab_Finder.java
index 9988dfc075..1fae02a542 100644
--- a/Ghidra/Features/GnuDemangler/ghidra_scripts/VxWorksSymTab_Finder.java
+++ b/Ghidra/Features/GnuDemangler/ghidra_scripts/VxWorksSymTab_Finder.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.
@@ -49,6 +49,7 @@ import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.script.GhidraScript;
import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.demangler.DemangledException;
+import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
@@ -604,7 +605,7 @@ public class VxWorksSymTab_Finder extends GhidraScript {
/**
* Look before/after the table to see if there is a size value there and mark it if it agrees with TableLen
- *
+ *
* @param symTbl
* @param vxSymbol
* @param tableLen
@@ -784,7 +785,9 @@ public class VxWorksSymTab_Finder extends GhidraScript {
// Demangle symName
String symDemangledName = null;
try {
- symDemangledName = demangler.demangle(symName).getSignature(false);
+ MangledContext mangledContext =
+ demangler.createMangledContext(symName, null, currentProgram, symNameAddr);
+ symDemangledName = demangler.demangle(mangledContext).getSignature(false);
}
catch (DemangledException e) { // report demangling error
if (!e.isInvalidMangledName()) {
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 8cd55ecd91..31beb384f0 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
@@ -73,10 +73,9 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
private GnuDemanglerFormat demanglerFormat = GnuDemanglerFormat.AUTO;
private boolean useDeprecatedDemangler = false;
- private GnuDemangler demangler = new GnuDemangler();
-
public GnuDemanglerAnalyzer() {
super(NAME, DESCRIPTION);
+ demangler = new GnuDemangler();
setDefaultEnablement(true);
}
@@ -142,9 +141,9 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
}
@Override
- protected DemangledObject doDemangle(String mangled, DemanglerOptions demanglerOtions,
- MessageLog log) throws DemangledException {
- return demangler.demangle(mangled, demanglerOtions);
+ protected DemangledObject doDemangle(MangledContext mangledContext, MessageLog log)
+ throws DemangledException {
+ return demangler.demangle(mangledContext);
}
//==================================================================================================
diff --git a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemangler.java b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemangler.java
index 2e84fcb1f1..48a8098322 100644
--- a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemangler.java
+++ b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemangler.java
@@ -66,19 +66,27 @@ public class GnuDemangler implements Demangler {
}
@Override
- @Deprecated(since = "9.2", forRemoval = true)
- public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
+ @Deprecated(since = "11.3", forRemoval = true)
+ public DemangledObject demangle(String mangled, DemanglerOptions demanglerOptions)
throws DemangledException {
- GnuDemanglerOptions options = new GnuDemanglerOptions();
- options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
- return demangle(mangled, options);
+ MangledContext mangledContext = createMangledContext(mangled, demanglerOptions, null, null);
+ return demangle(mangledContext);
}
@Override
- public DemangledObject demangle(String mangled, DemanglerOptions demanglerOtions)
+ public DemangledObject demangle(MangledContext mangledContext)
+ throws DemangledException {
+ DemangledObject demangled = demangleInternal(mangledContext);
+ demangled.setMangledContext(mangledContext);
+ return demangled;
+ }
+
+ private DemangledObject demangleInternal(MangledContext mangledContext)
throws DemangledException {
- GnuDemanglerOptions options = getGnuOptions(demanglerOtions);
+ DemanglerOptions demanglerOptions = mangledContext.getOptions();
+ String mangled = mangledContext.getMangled();
+ GnuDemanglerOptions options = getGnuOptions(demanglerOptions);
if (skip(mangled, options)) {
return null;
}
diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/build.gradle b/Ghidra/Features/MicrosoftCodeAnalyzer/build.gradle
index aef84ea4de..d02f4f681b 100644
--- a/Ghidra/Features/MicrosoftCodeAnalyzer/build.gradle
+++ b/Ghidra/Features/MicrosoftCodeAnalyzer/build.gradle
@@ -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.
@@ -22,6 +22,6 @@ apply plugin: 'eclipse'
eclipse.project.name = 'Features MicrosoftCodeAnalyzer'
dependencies {
- api project(":MicrosoftDmang")
+ api project(":MicrosoftDemangler")
api project(":Base")
}
diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java
index 7815cfcfa3..8502b5ca43 100644
--- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java
+++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.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.
@@ -19,6 +19,7 @@ import ghidra.app.cmd.data.rtti.RttiUtil;
import ghidra.app.util.datatype.microsoft.DataValidationOptions;
import ghidra.app.util.datatype.microsoft.MSDataTypeUtils;
import ghidra.app.util.demangler.*;
+import ghidra.app.util.demangler.microsoft.MicrosoftDemangler;
import ghidra.docking.settings.SettingsImpl;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
@@ -33,8 +34,6 @@ import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
-import mdemangler.MDException;
-import mdemangler.MDMangGhidra;
/**
* Model for the TypeDescriptor data type.
@@ -446,7 +445,8 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
Object value = terminatedStringDt.getValue(nameMemBuffer, SettingsImpl.NO_SETTINGS, 1);
if (value instanceof String) {
originalTypeName = (String) value;
- demangledDataType = getDemangledDataType(originalTypeName); // Can be null
+ // The returned demangledDataType an be null
+ demangledDataType = getDemangledDataType(originalTypeName, program, nameAddress);
}
hasProcessedName = true;
return originalTypeName;
@@ -597,20 +597,22 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
/**
* Gets a DemangledDataType for the indicated mangled string
* @param mangledString the mangled string to be demangled
+ * @param program the program
+ * @param address address of the mangled string
* @return the DemangledDataType or null if couldn't demangle or is not a class type
*/
- private static DemangledDataType getDemangledDataType(String mangledString) {
- MDMangGhidra demangler = new MDMangGhidra();
+ private static DemangledDataType getDemangledDataType(String mangledString, Program program,
+ Address address) {
+ MicrosoftDemangler demangler = new MicrosoftDemangler();
try {
- // Note that we could play with the return value, but it is not needed; instead, we
- // get the DemangledDataType by calling the appropriate method
- demangler.demangleType(mangledString, true);
- DemangledDataType demangledType = demangler.getDataType();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangledString, null, program, address);
+ DemangledDataType demangledType = demangler.demangleType(mangledContext);
if (isPermittedType(demangledType)) {
return demangledType;
}
}
- catch (MDException e) {
+ catch (DemangledException e) {
// Couldn't demangle.
}
return null;
diff --git a/Ghidra/Features/MicrosoftDemangler/developer_scripts/MicrosoftDemanglerScript.java b/Ghidra/Features/MicrosoftDemangler/developer_scripts/MicrosoftDemanglerScript.java
index 97b1eae8ec..a74b8b034a 100644
--- a/Ghidra/Features/MicrosoftDemangler/developer_scripts/MicrosoftDemanglerScript.java
+++ b/Ghidra/Features/MicrosoftDemangler/developer_scripts/MicrosoftDemanglerScript.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.
@@ -17,6 +17,7 @@
//@category Symbol
import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledObject;
+import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.microsoft.MicrosoftDemangler;
public class MicrosoftDemanglerScript extends GhidraScript {
@@ -33,7 +34,7 @@ public class MicrosoftDemanglerScript extends GhidraScript {
demangle("??$?0G@?$allocator@U_Container_proxy@std@@@std@@QAE@ABV?$allocator@G@1@@Z");
/*
-
+
demangle("??0__non_rtti_object@@QAE@PBD@Z");
demangle("??0bad_cast@@AAE@PBQBD@Z");
demangle("??0bad_cast@@QAE@ABQBD@Z");
@@ -94,7 +95,11 @@ public class MicrosoftDemanglerScript extends GhidraScript {
}
private void demangle(String mangled) throws Exception {
- DemangledObject demangled = demangler.demangle(mangled);
- printf("magled %s\ndemangled %s", mangled, demangled);
+ // Using a null address instead of currentAddress because we are not demangling a symbol
+ // at the address... just a symbol to dump to the output
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, currentProgram, null);
+ DemangledObject demangled = demangler.demangle(mangledContext);
+ printf("mangled %s\ndemangled %s", mangled, demangled);
}
}
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 7cc6e2ecd0..ef10a5c9c5 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
@@ -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.
@@ -16,10 +16,11 @@
package ghidra.app.plugin.core.analysis;
import ghidra.app.util.demangler.*;
-import ghidra.app.util.demangler.microsoft.MicrosoftDemangler;
+import ghidra.app.util.demangler.microsoft.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.model.listing.Program;
+import ghidra.util.HelpLocation;
/**
* A version of the demangler analyzer to handle microsoft symbols
@@ -40,12 +41,26 @@ public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
private static final String OPTION_DESCRIPTION_APPLY_CALLING_CONVENTION =
"Apply any recovered function signature calling convention";
+ private static final String OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS =
+ "Demangle Only Known Mangled Symbols";
+ private static final String OPTION_DESCRIPTION_USE_KNOWN_PATTERNS =
+ "Only demangle symbols that follow known compiler mangling patterns. " +
+ "Leaving this option off may cause non-mangled symbols to get demangled.";
+
+ public static final String OPTION_NAME_MS_C_INTERPRETATION =
+ "C-Style Symbol Interpretation";
+ private static final String OPTION_DESCRIPTION_MS_C_INTERPRETATION =
+ "When ambiguous, treat C-Style mangled symbol as: function, variable," +
+ " or function if a function exists";
+
private boolean applyFunctionSignature = true;
private boolean applyCallingConvention = true;
- private MicrosoftDemangler demangler = new MicrosoftDemangler();
+ private boolean demangleOnlyKnownPatterns = false;
+ private MsCInterpretation interpretation = MsCInterpretation.FUNCTION_IF_EXISTS;
public MicrosoftDemanglerAnalyzer() {
super(NAME, DESCRIPTION);
+ demangler = new MicrosoftDemangler();
setDefaultEnablement(true);
}
@@ -56,11 +71,20 @@ public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
@Override
public void registerOptions(Options options, Program program) {
- options.registerOption(OPTION_NAME_APPLY_SIGNATURE, applyFunctionSignature, null,
+
+ HelpLocation help = new HelpLocation("AutoAnalysisPlugin", "Demangler_Analyzer");
+
+ options.registerOption(OPTION_NAME_APPLY_SIGNATURE, applyFunctionSignature, help,
OPTION_DESCRIPTION_APPLY_SIGNATURE);
- options.registerOption(OPTION_NAME_APPLY_CALLING_CONVENTION, applyCallingConvention, null,
+ 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);
+
+ options.registerOption(OPTION_NAME_MS_C_INTERPRETATION, interpretation, help,
+ OPTION_DESCRIPTION_MS_C_INTERPRETATION);
}
@Override
@@ -70,20 +94,28 @@ public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
applyCallingConvention =
options.getBoolean(OPTION_NAME_APPLY_CALLING_CONVENTION, applyCallingConvention);
+
+ demangleOnlyKnownPatterns =
+ options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns);
+
+ interpretation = options.getEnum(OPTION_NAME_MS_C_INTERPRETATION, interpretation);
}
@Override
protected DemanglerOptions getOptions() {
- DemanglerOptions options = new DemanglerOptions();
+ MicrosoftDemanglerOptions options = new MicrosoftDemanglerOptions();
options.setApplySignature(applyFunctionSignature);
options.setApplyCallingConvention(applyCallingConvention);
+ options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
+ options.setInterpretation(interpretation);
+ options.setErrorOnRemainingChars(true);
return options;
}
@Override
- protected DemangledObject doDemangle(String mangled, DemanglerOptions options, MessageLog log)
+ protected DemangledObject doDemangle(MangledContext context, MessageLog log)
throws DemangledException {
- DemangledObject demangled = demangler.demangle(mangled, options);
+ DemangledObject demangled = demangler.demangle(context);
return demangled;
}
}
diff --git a/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemangler.java b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemangler.java
index 2e879d17b1..4ba4ff5b6a 100644
--- a/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemangler.java
+++ b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemangler.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.
@@ -18,18 +18,29 @@ package ghidra.app.util.demangler.microsoft;
import ghidra.app.util.demangler.*;
import ghidra.app.util.opinion.MSCoffLoader;
import ghidra.app.util.opinion.PeLoader;
+import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
-import mdemangler.MDException;
-import mdemangler.MDMangGhidra;
+import mdemangler.*;
+import mdemangler.datatype.MDDataType;
/**
* A class for demangling debug symbols created using Microsoft Visual Studio.
*/
public class MicrosoftDemangler implements Demangler {
+ private MDMangGhidra demangler;
+ private MDParsableItem item;
+ private DemangledObject object;
+ private MDDataType mdType;
+ private DemangledDataType dataType;
+
public MicrosoftDemangler() {
}
+ // Note: Consider deprecating this method and creating one that takes the MangledContext.
+ // Another option might be to find a smarter, utility method that contains the complete
+ // knowledge of when a particular demangler is appropriate.. but that would have to consider
+ // demanglers written by others.
@Override
public boolean canDemangle(Program program) {
String executableFormat = program.getExecutableFormat();
@@ -38,47 +49,128 @@ public class MicrosoftDemangler implements Demangler {
}
@Override
- @Deprecated(since = "9.2", forRemoval = true)
- public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
+ @Deprecated(since = "11.3", forRemoval = true)
+ public DemangledObject demangle(String mangled, DemanglerOptions options)
throws DemangledException {
- try {
- DemangledObject demangled = demangleMS(mangled, demangleOnlyKnownPatterns);
- return demangled;
- }
- catch (DemangledException e) {
- throw new DemangledException(true);
- }
+ MangledContext mangledContext = new MangledContext(null, options, mangled, null);
+ return demangle(mangledContext);
}
@Override
- public DemangledObject demangle(String mangled, DemanglerOptions options)
- throws DemangledException {
+ public DemangledObject demangle(MangledContext context) throws DemangledException {
+ if (!(context instanceof MicrosoftMangledContext mContext)) {
+ throw new DemangledException("Wrong context type");
+ }
+ if (!(context.getOptions() instanceof MicrosoftDemanglerOptions options)) {
+ throw new DemangledException("MicrosoftDemanglerOptions expected");
+ }
+ String mangled = context.getMangled();
+ demangler = new MDMangGhidra();
+ demangler.setMangledSymbol(mangled);
+ demangler.setErrorOnRemainingChars(options.errorOnRemainingChars());
+ demangler.setDemangleOnlyKnownPatterns(options.demangleOnlyKnownPatterns());
+ demangler.setArchitectureSize(mContext.getArchitectureSize());
+ demangler.setIsFunction(mContext.shouldInterpretAsFunction());
try {
- DemangledObject demangled = demangleMS(mangled, options.demangleOnlyKnownPatterns());
- return demangled;
- }
- catch (DemangledException e) {
- throw new DemangledException(true);
- }
- }
-
- private DemangledObject demangleMS(String mangled, boolean demangleOnlyKnownPatterns)
- throws DemangledException {
- if (mangled == null || mangled.length() == 0) {
- throw new DemangledException(true);
- }
-
- MDMangGhidra demangler = new MDMangGhidra();
- try {
- demangler.demangle(mangled, true, demangleOnlyKnownPatterns);
- DemangledObject object = demangler.getObject();
+ item = demangler.demangle();
+ object = MicrosoftDemanglerUtil.convertToDemangledObject(item, mangled);
+ if (object != null) {
+ object.setMangledContext(context);
+ }
return object;
}
catch (MDException e) {
- DemangledException de = new DemangledException("Unable to demangle symbol: " + mangled);
+ DemangledException de = new DemangledException(true);
de.initCause(e);
throw de;
}
}
+
+ /**
+ * Attempts to demangle the type string of the mangled context into a type
+ *
+ * @param context the mangled context
+ * @return the result
+ * @throws DemangledException if the string cannot be demangled
+ */
+ public DemangledDataType demangleType(MangledContext context) throws DemangledException {
+ if (!(context instanceof MicrosoftMangledContext mContext)) {
+ throw new DemangledException("Wrong context type");
+ }
+ if (!(context.getOptions() instanceof MicrosoftDemanglerOptions options)) {
+ throw new DemangledException("MicrosoftDemanglerOptions expected");
+ }
+ String mangled = context.getMangled();
+
+ demangler = new MDMangGhidra();
+ demangler.setMangledSymbol(mangled);
+ demangler.setErrorOnRemainingChars(options.errorOnRemainingChars());
+ demangler.setDemangleOnlyKnownPatterns(options.demangleOnlyKnownPatterns());
+ demangler.setArchitectureSize(mContext.getArchitectureSize());
+ demangler.setIsFunction(mContext.shouldInterpretAsFunction());
+ try {
+ mdType = demangler.demangleType();
+ dataType = MicrosoftDemanglerUtil.convertToDemangledDataType(mdType, mangled);
+ if (dataType != null) {
+ dataType.setMangledContext(context);
+ }
+ return dataType;
+ }
+ catch (MDException e) {
+ DemangledException de = new DemangledException(true);
+ de.initCause(e);
+ throw de;
+ }
+ }
+
+ /**
+ * Returns the {@link MDParsableItem} used in demangling to a {@link DemangledObject}
+ * @return the item; can be null if item wasn't demangled
+ */
+ public MDParsableItem getMdItem() {
+ return item;
+ }
+
+ /**
+ * Returns the {@link MDDataType} used in demangling to a @link DemangledDataType}
+ * @return the type; can be null if type wasn't demangled
+ */
+ public MDDataType getMdType() {
+ return mdType;
+ }
+
+ /**
+ * Creates default options for microsoft demangler
+ * @return the options
+ */
+ @Override
+ public MicrosoftDemanglerOptions createDefaultOptions() {
+ return new MicrosoftDemanglerOptions();
+ }
+
+ /**
+ * Creates a microsoft mangled context
+ * @param mangled the mangled name
+ * @param options the demangler options; if null, the default options are created
+ * @param program the program; can be null
+ * @param address the address for the name in the program; can be null
+ * @return the mangled context
+ */
+ @Override
+ public MicrosoftMangledContext createMangledContext(String mangled, DemanglerOptions options,
+ Program program, Address address) {
+ return new MicrosoftMangledContext(program, getMicrosoftOptions(options), mangled, address);
+ }
+
+ private MicrosoftDemanglerOptions getMicrosoftOptions(DemanglerOptions options) {
+ if (options instanceof MicrosoftDemanglerOptions mOptions) {
+ return mOptions;
+ }
+ if (options == null) {
+ return createDefaultOptions();
+ }
+ return new MicrosoftDemanglerOptions(options);
+ }
+
}
diff --git a/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerOptions.java b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerOptions.java
new file mode 100644
index 0000000000..ecf8360f8c
--- /dev/null
+++ b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerOptions.java
@@ -0,0 +1,109 @@
+/* ###
+ * 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.util.demangler.microsoft;
+
+import ghidra.app.util.demangler.DemanglerOptions;
+
+/**
+ * Microsoft demangler options
+ */
+public class MicrosoftDemanglerOptions extends DemanglerOptions {
+
+ private boolean errorOnRemainingChars;
+ private MsCInterpretation interpretation;
+
+ /**
+ * Default constructor for MicrosoftDemanglerOptions
+ */
+ public MicrosoftDemanglerOptions() {
+ this(true);
+ interpretation = MsCInterpretation.FUNCTION_IF_EXISTS;
+ }
+
+ /**
+ * Constructor for MicrosoftDemanglerOptions
+ * @param errorOnRemainingChars {@code true} to error on remaining characters
+ */
+ public MicrosoftDemanglerOptions(boolean errorOnRemainingChars) {
+ super();
+ this.errorOnRemainingChars = errorOnRemainingChars;
+ }
+
+ /**
+ * Copy constructor to create a version of this class from a more generic set of options
+ * @param copy the options to copy
+ */
+ public MicrosoftDemanglerOptions(DemanglerOptions copy) {
+ super(copy);
+
+ if (copy instanceof MicrosoftDemanglerOptions mCopy) {
+ errorOnRemainingChars = mCopy.errorOnRemainingChars;
+ interpretation = mCopy.interpretation;
+ }
+ else {
+ errorOnRemainingChars = true;
+ interpretation = MsCInterpretation.FUNCTION_IF_EXISTS;
+ }
+ }
+
+ /**
+ * Sets the control for erroring on remaining characters at demangler completion
+ * @param errorOnRemainingCharsArg {@code true} to error when remaining characters exist
+ */
+ public void setErrorOnRemainingChars(boolean errorOnRemainingCharsArg) {
+ errorOnRemainingChars = errorOnRemainingCharsArg;
+ }
+
+ /**
+ * Returns {@code true} if the process will error when remaining characters exist at the end
+ * of processing
+ * @return {@code true} if will error
+ */
+ public boolean errorOnRemainingChars() {
+ return errorOnRemainingChars;
+ }
+
+ /**
+ * Sets the interpretation for processing a C-style mangled symbol if there could be multiple
+ * interpretations
+ * @param interpretationArg the interpretation to use
+ */
+ public void setInterpretation(MsCInterpretation interpretationArg) {
+ interpretation = interpretationArg;
+ }
+
+ /**
+ * Returns the interpretation for processing a C-style mangled symbol if there could be multiple
+ * interpretations
+ * @return the interpretation used
+ */
+ public MsCInterpretation getInterpretation() {
+ return interpretation;
+ }
+
+ @Override
+ public String toString() {
+ //@formatter:off
+ return "{\n" +
+ "\tdoDisassembly: " + doDisassembly() + ",\n" +
+ "\tapplySignature: " + applySignature() + ",\n" +
+ "\terrorOnRemainingChars: " + errorOnRemainingChars + ",\n" +
+ "\tinterpretation: " + interpretation + ",\n" +
+ "\tdemangleOnlyKnownPatterns: " + demangleOnlyKnownPatterns() + ",\n" +
+ "}";
+ //@formatter:on
+ }
+}
diff --git a/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerUtil.java b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerUtil.java
new file mode 100644
index 0000000000..d31121fe2a
--- /dev/null
+++ b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerUtil.java
@@ -0,0 +1,975 @@
+/* ###
+ * 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.util.demangler.microsoft;
+
+import java.util.Iterator;
+
+import ghidra.app.util.demangler.*;
+import ghidra.program.model.lang.CompilerSpec;
+import ghidra.program.model.symbol.SourceType;
+import mdemangler.*;
+import mdemangler.datatype.MDDataType;
+import mdemangler.datatype.MDVarArgsType;
+import mdemangler.datatype.complex.*;
+import mdemangler.datatype.extended.MDArrayReferencedType;
+import mdemangler.datatype.modifier.*;
+import mdemangler.functiontype.*;
+import mdemangler.naming.*;
+import mdemangler.object.*;
+import mdemangler.template.MDTemplateNameAndArguments;
+import mdemangler.typeinfo.*;
+
+/**
+ * A utility class to aid the MicrosoftDemangler
+ *
+ * The contents of this class that do the processing came from {@link MDMangGhidra}, and will
+ * likely go through future rounds of clean-up. {@link MDMangGhidra}, an extension of
+ * {@link MDMang}, might eventually be removed.
+ */
+public class MicrosoftDemanglerUtil {
+
+ private MicrosoftDemanglerUtil() {
+ // purposefully empty
+ }
+
+ /**
+ * Method to convert an {@link MDParsableItem} into a {@link DemangledObject}. This method
+ * is not appropriate for {@link MDDataType} and some other types of {@link MDParsableItem}
+ * @param item the item to convert
+ * @param mangled the original mangled string
+ * @return the {@link DemangledObject} result
+ * @throws DemangledException up issue converting to a {@link DemangledObject}
+ */
+ static DemangledObject convertToDemangledObject(MDParsableItem item, String mangled)
+ throws DemangledException {
+ return processItem(item, mangled, item.toString());
+ }
+
+ /**
+ * Method to convert an {@link MDDataType} into a {@link DemangledDataType}
+ * @param type the type to convert
+ * @param mangled the original mangled string
+ * @return the result
+ */
+ static DemangledDataType convertToDemangledDataType(MDDataType type, String mangled) {
+ return processDataType(null, type, mangled, type.toString());
+ }
+
+ //==============================================================================================
+
+ private static Demangled processNamespace(MDQualifiedName qualifiedName, String mangled,
+ String demangledSource) {
+ return processNamespace(qualifiedName.getQualification(), mangled, demangledSource);
+ }
+
+ private static Demangled processNamespace(MDQualification qualification, String mangled,
+ String demangledSource) {
+ Iterator it = qualification.iterator();
+ if (!it.hasNext()) {
+ return null;
+ }
+
+ MDQualifier qual = it.next();
+ Demangled type = getDemangled(qual, mangled, demangledSource);
+ Demangled current = type;
+ // Note that qualifiers come in reverse order, from most refined to root being the last
+ while (it.hasNext()) {
+ qual = it.next();
+ Demangled parent = getDemangled(qual, mangled, demangledSource);
+ current.setNamespace(parent);
+ current = parent;
+ }
+ return type;
+ }
+
+ private static Demangled getDemangled(MDQualifier qual, String mangled,
+ String demangledSource) {
+ Demangled demangled = null;
+ if (qual.isNested()) {
+ String subMangled = qual.getNested().getMangled();
+ MDObjectCPP obj = qual.getNested().getNestedObject();
+ if (!obj.isHashObject()) {
+ MDTypeInfo typeInfo = obj.getTypeInfo();
+ MDType type = typeInfo.getMDType();
+ if (type instanceof MDDataType dt) {
+ demangled = new DemangledType(subMangled, qual.toString(), qual.toString());
+ }
+ else if (type instanceof MDFunctionType ft) {
+ // We currently cannot handle functions as part of a namespace, so we will just
+ // treat the demangled function namespace string as a plain namespace.
+ //demangled = new DemangledFunction(subMangled, qual.toString(), qual.toString());
+ demangled =
+ new DemangledNamespaceNode(subMangled, qual.toString(), qual.toString());
+ }
+ }
+ if (demangled == null) {
+ demangled =
+ new DemangledNamespaceNode(subMangled, qual.toString(), qual.toString());
+ }
+ }
+ else if (qual.isAnon()) {
+ // Instead of using the standard qual.toString() method, which returns
+ // "`anonymous namespace'" for anonymous qualifiers, we use qual.getAnonymousName()
+ // which will have the underlying anonymous name of the form "A0xfedcba98" to create
+ // a standardized anonymous name that is distinguishable from other anonymous names.
+ // The standardized name comes from createStandardAnonymousNamespaceNode(). This
+ // is especially important when there are sibling anonymous names.
+ String anon = MDMangUtils.createStandardAnonymousNamespaceNode(qual.getAnonymousName());
+ demangled = new DemangledNamespaceNode(mangled, qual.toString(), anon);
+ }
+ else if (qual.isInterface()) {
+ // TODO: need to do better; setting namespace for now
+ demangled = new DemangledNamespaceNode(mangled, qual.toString(), qual.toString());
+ }
+ else if (qual.isNameQ()) {
+ // TODO: need to do better; setting namespace for now, as it looks like interface
+ demangled = new DemangledNamespaceNode(mangled, qual.toString(), qual.toString());
+ }
+ else if (qual.isNameC()) {
+ // TODO: need to do better; setting type for now, but not processed yet and not sure
+ // what it is
+ demangled = new DemangledType(mangled, qual.toString(), qual.toString());
+ }
+ else if (qual.isLocalNamespace()) {
+ String local =
+ MDMangUtils.createStandardLocalNamespaceNode(qual.getLocalNamespaceNumber());
+ demangled = new DemangledNamespaceNode(mangled, qual.toString(), local);
+ }
+ else {
+ demangled = new DemangledNamespaceNode(mangled, qual.toString(), qual.toString());
+ }
+ return demangled;
+ }
+
+ private static DemangledObject processItem(MDParsableItem item, String mangled,
+ String demangledSource) throws DemangledException {
+ DemangledObject result = null;
+ if (item instanceof MDObjectReserved) {
+ result = processObjectReserved((MDObjectReserved) item, mangled, demangledSource);
+ }
+ else if (item instanceof MDObjectCodeView codeView) {
+ result = processObjectCPP(codeView, mangled, demangledSource);
+ result.setSpecialPrefix(codeView.getPrefix());
+ }
+ else if (item instanceof MDObjectCPP objCpp) { // Base class of MDObjectBracket/MDObjectCodeView.
+ result = processObjectCPP(objCpp, mangled, demangledSource);
+ }
+ else if (item instanceof MDObjectC objC) {
+ result = processObjectC(objC, mangled, demangledSource);
+ }
+ else if (item instanceof MDDataType dataType) {
+ // TODO: how do we fix this? DemangledDataType extends DemangledType, but not
+ // DemangleObject...
+ throw new DemangledException("DemangledDataType instead of DemangledObject");
+ //result = processDataType(null, dataType, mangled, demangledSource);
+ // object = getDemangledDataType();
+ }
+ else if (item instanceof MDTemplateNameAndArguments templateNameAndArgs) {
+ result = processTemplate(templateNameAndArgs, mangled, demangledSource);
+ }
+ return result;
+ }
+
+ private static DemangledObject processObjectReserved(
+ MDObjectReserved objectReserved,
+ String mangled, String demangledSource) {
+ DemangledObject object = null;
+ if (objectReserved.getClass().equals(MDObjectReserved.class)) {
+ //Testing if the class is not a derived class of MDObjectReserved;
+ // In other words, is it exactly a MDObjectReserved?
+ // If so, then return null, which will allow it to get processed
+ // outside of the demangler.
+ return null;
+ }
+ if (objectReserved instanceof MDObjectBracket objectBracket) {
+ MDObjectCPP objectCPP = objectBracket.getObjectCPP();
+ object = processObjectCPP(objectCPP, mangled, demangledSource);
+ object.setSpecialPrefix(objectBracket.getPrefix());
+ }
+ //TODO: put other objectReserved derivative types here and return something that Ghidra
+ // can use.
+ else {
+ object =
+ new DemangledUnknown(mangled, demangledSource, objectReserved.toString());
+ }
+ return object;
+ }
+
+ private static DemangledObject processObjectC(MDObjectC objectC, String mangled,
+ String demangledSource) {
+ // 20240905: modification to MDObjectC to processing C-style mangling has been added.
+ // If null is returned here, then we have a standard variable.
+ DemangledFunction demangledFunction =
+ processObjectCFunction(objectC, mangled, demangledSource);
+ if (demangledFunction != null) {
+ return demangledFunction;
+ }
+ // We are returning null here because we do not want Ghidra to put up a plate
+ // comment for a standard C symbol.
+ // FUTURE WORK: After discussion, easiest way to deal with this for now (without
+ // exploding work into other demanglers) is to keep the "return null" for now.
+ // The problem is with the DemangledObject making a revision of the
+ // success/failure of demangling by doing a comparison of the input string to
+ // the output string in the applyTo() method. In a previous encoding, I moved
+ // this logic into other demanglers and set a flag in DemangledObject, that way
+ // my MDMangGhidra could set a flag to succeed when we have a C-language variable
+ // (vs. C++) where the input == output is valid. We didn't like this pattern.
+ // The better way forward, which will require digging into the other demanglers
+ // further (keeping this for future work), is to throw an exception on failure
+ // instead of returning null as well as pushing this success/failure logic
+ // upstream (where I was attempting to put it) and removing the input == output
+ // test from DemangledObject; an object is only returned upon success and no
+ // rescinding of the success determination is made later.
+ return null;
+ // Following is the code that we had originally intended to use.
+ // DemangledVariable variable = new DemangledVariable(objectC.toString());
+ // return variable;
+ }
+
+ private static DemangledFunction processObjectCFunction(MDObjectC objectC, String mangled,
+ String demangledSource) {
+ String callingConvention = objectC.getCallingConvention();
+ if (callingConvention == null) {
+ // null means it is a standard variable; not a function
+ return null;
+ }
+ DemangledFunction function =
+ new DemangledFunction(mangled, demangledSource, objectC.getName());
+ // Setting the signature SourceType to DEFAULT allows us to set the calling convention
+ // without changing or locking in parameters or return type.
+ function.setSignatureSourceType(SourceType.DEFAULT);
+ function.setCallingConvention(callingConvention);
+ return function;
+ }
+
+ private static DemangledObject processObjectCPP(MDObjectCPP objectCPP, String mangled,
+ String demangledSource) {
+ MDTypeInfo typeinfo = objectCPP.getTypeInfo();
+ DemangledObject result = null;
+ if (typeinfo != null) {
+ if (typeinfo instanceof MDVariableInfo) {
+ DemangledVariable variable;
+ MDVariableInfo variableInfo = (MDVariableInfo) typeinfo;
+ MDType mdtype = variableInfo.getMDType();
+ DemangledDataType dt =
+ processDataType(null, (MDDataType) mdtype, mangled, demangledSource);
+ if ("std::nullptr_t".equals(dt.getName())) {
+ variable = new DemangledVariable(mangled, demangledSource, "");
+ }
+ else {
+ variable =
+ new DemangledVariable(mangled, demangledSource, objectCPP.getName());
+ variable.setNamespace(
+ processNamespace(objectCPP.getQualification(), mangled, demangledSource));
+ }
+ variable.setDatatype(dt);
+ result = variable;
+ variable.setConst(variableInfo.isConst());
+ variable.setVolatile(variableInfo.isVolatile());
+ variable.setPointer64(variableInfo.isPointer64());
+ if (variableInfo.isRestrict()) {
+ variable.setRestrict();
+ }
+ if (variableInfo.isUnaligned()) {
+ variable.setUnaligned();
+ }
+ variable.setBasedName(variableInfo.getBasedName());
+ if (variableInfo.isMember()) {
+ variable.setMemberScope(variableInfo.getMemberScope());
+ }
+ }
+ else if (typeinfo instanceof MDFunctionInfo) {
+ if (typeinfo.getSpecialHandlingCode() == 'F') {
+ result = new DemangledUnknown(mangled, demangledSource, null);
+ }
+ else {
+ DemangledFunction function =
+ new DemangledFunction(mangled, demangledSource, objectCPP.getName());
+ function.setSignatureSourceType(SourceType.IMPORTED);
+ function.setNamespace(
+ processNamespace(objectCPP.getQualification(), mangled, demangledSource));
+ result = function;
+ processFunction((MDFunctionInfo) typeinfo, function, mangled,
+ demangledSource);
+ // Any other special values to be set?
+ if (typeinfo instanceof MDMemberFunctionInfo) {
+ if (typeinfo instanceof MDVCall) {
+ // Empty for now--placeholder for possible future logic.
+ }
+ else if (typeinfo instanceof MDVFAdjustor) {
+ // Empty for now--placeholder for possible future logic.
+ }
+ else if (typeinfo instanceof MDVtordisp) {
+ // Empty for now--placeholder for possible future logic.
+ }
+ else if (typeinfo instanceof MDVtordispex) {
+ // Empty for now--placeholder for possible future logic.
+ }
+ else {
+ // plain member function
+ }
+ }
+ else {
+ // global function
+ }
+ }
+ }
+ else if (typeinfo instanceof MDVxTable) { //Includes VFTable, VBTable, and RTTI4
+ MDVxTable vxtable = (MDVxTable) typeinfo;
+ DemangledVariable variable =
+ new DemangledVariable(mangled, demangledSource, objectCPP.getName());
+ variable.setNamespace(
+ processNamespace(objectCPP.getQualification(), mangled, demangledSource));
+ variable.setConst(vxtable.isConst());
+ variable.setVolatile(vxtable.isVolatile());
+ variable.setPointer64(vxtable.isPointer64());
+ result = variable;
+ // The following code would be an alternative, depending on whether we get
+ // customer complaints or other fall-out from having created a variable here.
+ //resultObject = new DemangledUnknown();
+ }
+ else if (typeinfo instanceof AbstractMDMetaClass) { //Includes all RTTI, except RTTI4
+ DemangledVariable variable =
+ new DemangledVariable(mangled, demangledSource, objectCPP.getName());
+ variable.setNamespace(
+ processNamespace(objectCPP.getQualification(), mangled, demangledSource));
+ result = variable;
+ // The following code would be an alternative, depending on whether we get
+ // customer complaints or other fall-out from having created a variable here.
+ //resultObject = new DemangledUnknown();
+ }
+ else if (typeinfo instanceof MDGuard) {
+ DemangledVariable variable =
+ new DemangledVariable(mangled, demangledSource, objectCPP.getName());
+ variable.setNamespace(
+ processNamespace(objectCPP.getQualification(), mangled, demangledSource));
+ result = variable;
+ // The following code would be an alternative, depending on whether we get
+ // customer complaints or other fall-out from having created a variable here.
+ //resultObject = new DemangledUnknown();
+ }
+ else {
+ // Any others (e.g., case '9')
+ DemangledVariable variable =
+ new DemangledVariable(mangled, demangledSource, objectCPP.getName());
+ variable.setNamespace(
+ processNamespace(objectCPP.getQualification(), mangled, demangledSource));
+ result = variable;
+ // The following code would be an alternative, depending on whether we get
+ // customer complaints or other fall-out from having created a variable here.
+ //resultObject = new DemangledUnknown();
+ }
+ if (typeinfo.isPrivate()) {
+ result.setVisibilty("private");
+ }
+ else if (typeinfo.isProtected()) {
+ result.setVisibilty("protected");
+ }
+ else if (typeinfo.isPublic()) {
+ result.setVisibilty("public");
+ }
+ result.setStatic(typeinfo.isStatic());
+ result.setVirtual(typeinfo.isVirtual());
+ result.setThunk(typeinfo.isThunk());
+ if (typeinfo.isExternC()) {
+ result.setSpecialPrefix("extern \"C\"");
+ }
+ }
+ else {
+ String baseName = objectCPP.getName();
+ if (objectCPP.isString()) {
+ MDString mstring = objectCPP.getMDString();
+ DemangledString demangledString =
+ new DemangledString(mangled, demangledSource, mstring.getName(),
+ mstring.toString(), mstring.getLength(), mstring.isUnicode());
+ result = demangledString;
+ }
+ else if (baseName.length() != 0) {
+ DemangledVariable variable;
+ variable = new DemangledVariable(mangled, demangledSource, baseName);
+ variable.setNamespace(
+ processNamespace(objectCPP.getQualification(), mangled, demangledSource));
+ result = variable;
+ }
+ }
+ return result;
+ // //Various RTTI types (MDType '8' or '9')
+ // DemangledVariable variable =
+ // new
+ // DemangledVariable(objectCPP.getQualifiedName().getBasicName().toString());
+ // variable.setNamespace(processNamespace(objectCPP.getQualifiedName()));
+ // return variable;
+ // TODO: fill in lots of object.____ items
+ // object.setVisibilty(typeinfo.g);
+ // object.setConst(isConst);
+ }
+
+ // I think that this is a kludge. The mapping of MDTemplateNameAndArguments
+ // doesn't match
+ // well to the current DemangledObject hierarchy.
+ private static DemangledVariable processTemplate(MDTemplateNameAndArguments template,
+ String mangled, String demangledSource) {
+ DemangledVariable variable =
+ new DemangledVariable(mangled, demangledSource, template.toString());
+ // NO NAMESPACE for high level template: variable.setNamespace(XXX);
+ // DemangledTemplate objectTemplate = new DemangledTemplate();
+ // DemangledDataType dataType = new DemangledDataType((String) null);
+ // MDTemplateArgumentsList args = template.getArgumentsList();
+ // if (args != null) {
+ // for (int index = 0; index < args.getNumArgs(); index++) {
+ // objectTemplate.addParameter(processDataType(null, (MDDataType)
+ // args.getArg(index)));
+ // }
+ // }
+ // dataType.setTemplate(objectTemplate);
+ // variable.setDatatype(dataType);
+ return variable;
+ }
+
+ private static DemangledFunction processFunction(MDFunctionInfo functionInfo,
+ DemangledFunction function, String mangled, String demangledSource) {
+ MDFunctionType functionType = (MDFunctionType) functionInfo.getMDType();
+ String convention = functionType.getCallingConvention().toString();
+ if ("__cdecl".equals(convention) && functionInfo.isMember() && !functionInfo.isStatic()) {
+ // TODO: ultimately the presence of a 'this' parareter will not be keyed
+ // to the calling convention, but for now we need to force it
+ convention = CompilerSpec.CALLING_CONVENTION_thiscall;
+ }
+ function.setCallingConvention(convention);
+ if (functionType.hasReturn() && functionType.getReturnType() != null) {
+ MDDataType retType = functionType.getReturnType();
+ if (!retType.toString().isEmpty()) {
+ function.setReturnType(processDataType(null, retType, mangled, demangledSource));
+ }
+ }
+ MDArgumentsList args = functionType.getArgumentsList();
+ if (functionType.hasArgs() && args != null) {
+ for (int index = 0; index < args.getNumArgs(); index++) {
+ function.addParameter(
+ new DemangledParameter(
+ processDataType(null, args.getArg(index), mangled, demangledSource)));
+ }
+ }
+ if (functionType.isTypeCast()) {
+ function.setTypeCast();
+ }
+ // function.setVirtual(functionType.isVirtual());
+ // function.setStatic(functionType.isStatic());
+ // if (functionType.isPrivate()) {
+ // function.setVisibilty("private");
+ // }
+ // else if (functionType.isProtected()) {
+ // function.setVisibilty("protected");
+ // }
+ // else if (functionType.isPublic()) {
+ // function.setVisibilty("public");
+ // }
+
+ // TODO: fix this kludge. Need to add appropriate suffixes to DemangledFunction (look
+ // at DemangledFunctionPointer?). Missing other possible suffixes from
+ // functionType.getCVMod().
+ // String suffix = "";
+ MDCVMod thisPointerCVMod = functionType.getThisPointerCVMod();
+ if (thisPointerCVMod != null) {
+ if (thisPointerCVMod.isConst()) {
+ function.setTrailingConst();
+ }
+ if (thisPointerCVMod.isVolatile()) {
+ function.setTrailingVolatile();
+ }
+ if (thisPointerCVMod.isPointer64()) {
+ function.setTrailingPointer64();
+ }
+ if (thisPointerCVMod.isRestricted()) {
+ function.setTrailingRestrict();
+ }
+ if (thisPointerCVMod.isUnaligned()) {
+ function.setTrailingUnaligned();
+ }
+ }
+ MDThrowAttribute ta = functionType.getThrowAttribute();
+ if (ta != null) {
+ function.setThrowAttribute(ta.toString());
+ }
+
+ // TODO: fill in lots of function.____ items
+ return function;
+ }
+
+ private static DemangledFunctionPointer processDemangledFunctionPointer(
+ MDPointerType pointerType, String mangled, String demangledSource) {
+ DemangledFunctionPointer functionPointer =
+ new DemangledFunctionPointer(mangled, demangledSource);
+ MDFunctionType functionType = (MDFunctionType) pointerType.getReferencedType();
+ functionPointer.setCallingConvention(functionType.getCallingConvention().toString());
+ functionPointer.setModifier(pointerType.getCVMod().toString());
+ if (functionType.hasReturn() && functionType.getReturnType() != null) {
+ functionPointer.setReturnType(
+ processDataType(null, functionType.getReturnType(), mangled, demangledSource));
+ }
+ MDArgumentsList args = functionType.getArgumentsList();
+ if (functionType.hasArgs() && args != null) {
+ for (int index = 0; index < args.getNumArgs(); index++) {
+ functionPointer.addParameter(
+ processDataType(null, args.getArg(index), mangled, demangledSource));
+ }
+ }
+ MDCVMod thisPointerCVMod = functionType.getThisPointerCVMod();
+ if (thisPointerCVMod != null) {
+ if (thisPointerCVMod.isConst()) {
+ functionPointer.setConst();
+ }
+ if (thisPointerCVMod.isVolatile()) {
+ functionPointer.setVolatile();
+ }
+ if (thisPointerCVMod.isPointer64()) {
+ functionPointer.setTrailingPointer64();
+ }
+ if (thisPointerCVMod.isRestricted()) {
+ functionPointer.setTrailingRestrict();
+ }
+ if (thisPointerCVMod.isUnaligned()) {
+ functionPointer.setTrailingUnaligned();
+ }
+ }
+ // TODO: fill in lots of functionPointer.____ items
+ return functionPointer;
+ }
+
+ private static DemangledFunctionReference processDemangledFunctionReference(
+ MDModifierType refType, String mangled, String demangledSource) {
+ if (!((refType instanceof MDReferenceType) ||
+ (refType instanceof MDDataRightReferenceType))) {
+ return null; // Not planning on anything else yet.
+ }
+ DemangledFunctionReference functionReference =
+ new DemangledFunctionReference(mangled, demangledSource);
+ MDFunctionType functionType = (MDFunctionType) refType.getReferencedType();
+ functionReference.setCallingConvention(functionType.getCallingConvention().toString());
+ functionReference.setModifier(refType.getCVMod().toString());
+ if (functionType.hasReturn() && functionType.getReturnType() != null) {
+ functionReference.setReturnType(
+ processDataType(null, functionType.getReturnType(), mangled, demangledSource));
+ }
+ MDArgumentsList args = functionType.getArgumentsList();
+ if (functionType.hasArgs() && args != null) {
+ for (int index = 0; index < args.getNumArgs(); index++) {
+ functionReference.addParameter(
+ processDataType(null, args.getArg(index), mangled, demangledSource));
+ }
+ }
+ // TODO: fill in lots of functionReference.____ items
+ return functionReference;
+ }
+
+ private static DemangledFunctionIndirect processDemangledFunctionIndirect(
+ MDFunctionIndirectType functionIndirectType, String mangled, String demangledSource) {
+ DemangledFunctionIndirect functionDefinition =
+ new DemangledFunctionIndirect(mangled, demangledSource);
+ MDFunctionType functionType = (MDFunctionType) functionIndirectType.getReferencedType();
+ functionDefinition.setCallingConvention(functionType.getCallingConvention().toString());
+ functionDefinition.setModifier(functionIndirectType.getCVMod().toString());
+ functionDefinition.incrementPointerLevels();
+ if (functionType.hasReturn() && functionType.getReturnType() != null) {
+ functionDefinition.setReturnType(
+ processDataType(null, functionType.getReturnType(), mangled, demangledSource));
+ }
+ MDArgumentsList args = functionType.getArgumentsList();
+ if (functionType.hasArgs() && args != null) {
+ for (int index = 0; index < args.getNumArgs(); index++) {
+ functionDefinition.addParameter(
+ processDataType(null, args.getArg(index), mangled, demangledSource));
+ }
+ }
+ // TODO: fill in lots of functionIndirect.____ items
+ return functionDefinition;
+ }
+
+ // The following is/might be a kludge: using DemangledFunctionIndirect to see if it will
+ // hold the things that we need; regardless, the follow-on use of the DemangledFunction
+ // indirect might be clouded between the real, two underlying types.
+ private static DemangledFunctionIndirect processDemangledFunctionQuestion(
+ MDModifierType modifierType, String mangled, String demangledSource) {
+ DemangledFunctionIndirect functionDefinition =
+ new DemangledFunctionIndirect(mangled, demangledSource);
+ MDFunctionType functionType = (MDFunctionType) modifierType.getReferencedType();
+ functionDefinition.setCallingConvention(functionType.getCallingConvention().toString());
+ functionDefinition.setModifier(modifierType.getCVMod().toString());
+ functionDefinition.incrementPointerLevels();
+ if (functionType.hasReturn() && functionType.getReturnType() != null) {
+ functionDefinition.setReturnType(
+ processDataType(null, functionType.getReturnType(), mangled, demangledSource));
+ }
+ MDArgumentsList args = functionType.getArgumentsList();
+ if (functionType.hasArgs() && args != null) {
+ for (int index = 0; index < args.getNumArgs(); index++) {
+ functionDefinition.addParameter(
+ processDataType(null, args.getArg(index), mangled, demangledSource));
+ }
+ }
+ // TODO: fill in lots of functionIndirect.____ items
+ return functionDefinition;
+ }
+
+ // Passing "DemangledDataType resultDataType" in is a kludge, as this is done so
+ // incrementPointerLevels() can be used, but doing this recursion like this loses all
+ // storageClass information from the various nested pointers and such. TODO: need to add
+ // a "pointer type" with a contained "referenced data type" to DemangledObject (perhaps
+ // PointerObject?)
+ private static DemangledDataType processDataType(DemangledDataType resultDataType,
+ MDDataType datatype, String mangled, String demangledSource) {
+ if (resultDataType == null) {
+ resultDataType =
+ new DemangledDataType(mangled, demangledSource, getDataTypeName(datatype));
+ }
+ if (datatype.isSpecifiedSigned()) {
+ // Returns true if default signed or specified signed. TODO: There is no place to
+ // capture default signed versus specified signed (i.e., there are three types of
+ // char: default signed, specified signed, and unsigned)
+ resultDataType.setSigned();
+ }
+ if (datatype.isUnsigned()) {
+ resultDataType.setUnsigned();
+ }
+
+ // Bunch of else-ifs for exclusive types
+ if (datatype instanceof MDModifierType) {
+ MDModifierType modifierType = (MDModifierType) datatype;
+ // if (modifierType.isBased()) {
+ // resultDataType.set___();
+ // modifierType.getCVMod().getBasedName();
+ // }
+ if (modifierType.isConst()) {
+ resultDataType.setConst();
+ }
+ if (modifierType.isVolatile()) {
+ resultDataType.setVolatile();
+ }
+ if (modifierType.isPointer64()) {
+ resultDataType.setPointer64();
+ }
+ if (modifierType.isRestrict()) {
+ resultDataType.setRestrict();
+ }
+ if (modifierType.isUnaligned()) {
+ resultDataType.setUnaligned();
+ }
+ resultDataType.setBasedName(modifierType.getBasedName());
+ // if (modifierType.isMember()) {
+ resultDataType.setMemberScope(modifierType.getMemberScope());
+ // }
+ // TODO: fix. Following is a kludge because DemangledObject has no DemangledReference
+ // with corresponding referencedType.
+ if (modifierType instanceof MDArrayBasicType) {
+ resultDataType.setArray(1);
+ if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
+ // MDType ref = modifierType.getReferencedType();
+ // TODO: A demangled function reference is needed here.
+ // DemangledFunction function = new
+ // DemangledFunction(objectCPP.getQualifiedName().getBasicName().toString());
+ // function.setNamespace(processNamespace(objectCPP.getQualifiedName()));
+ // //resultObject = function;
+ // return processFunction(ref, resultDataType);
+ }
+ else if (modifierType.getReferencedType() instanceof MDDataType) {
+ return processDataType(resultDataType,
+ (MDDataType) modifierType.getReferencedType(), mangled, demangledSource);
+ }
+ else {
+ // Empty for now--placeholder for possible future logic.
+ }
+ }
+ else if (modifierType instanceof MDPointerType) {
+ if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
+ // TODO---------what are we returning... need to work on called routine.
+ DemangledFunctionPointer fp =
+ processDemangledFunctionPointer((MDPointerType) modifierType, mangled,
+ demangledSource);
+ // TODO: fix. Following is a kludge because DemangledObject has no
+ // DemangledPointer with corresponding referencedType.
+ for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
+ fp.incrementPointerLevels();
+ }
+ if (resultDataType.isConst()) {
+ fp.setConst();
+ }
+ if (resultDataType.isVolatile()) {
+ fp.setVolatile();
+ }
+ if (resultDataType.isPointer64()) {
+ fp.setPointer64();
+ }
+ return fp;
+ }
+ // modifierType.getArrayString();
+ // resultDataType.setArray();
+ //Processing the referenced type (for Ghidra, and then setting attributes on it)
+ DemangledDataType newResult =
+ processDataType(resultDataType, (MDDataType) modifierType.getReferencedType(),
+ mangled, demangledSource);
+ newResult.incrementPointerLevels();
+ if (modifierType.getCVMod().isConst()) {
+ newResult.setConst();
+ }
+ if (modifierType.getCVMod().isVolatile()) {
+ newResult.setVolatile();
+ }
+ if (modifierType.getCVMod().isPointer64()) {
+ newResult.setPointer64();
+ }
+ return newResult;
+ }
+ // TODO: fix. Following is a kludge because DemangledObject has no
+ // DemangledReference
+ // with corresponding referencedType.
+ else if (modifierType instanceof MDReferenceType) {
+ // TODO---------what are we returning... need to work on called
+ // routine.
+ if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
+ DemangledFunctionReference fr =
+ processDemangledFunctionReference(modifierType, mangled, demangledSource);
+ // TODO: fix. Following is a kludge because DemangledObject has no
+ // DemangledPointer with corresponding referencedType.
+ for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
+ fr.incrementPointerLevels();
+ }
+ if (resultDataType.isConst()) {
+ fr.setConst();
+ }
+ if (resultDataType.isVolatile()) {
+ fr.setVolatile();
+ }
+ if (resultDataType.isPointer64()) {
+ fr.setPointer64();
+ }
+ return fr;
+ }
+ //Processing the referenced type (for Ghidra, and then setting attributes on it)
+ DemangledDataType newResult =
+ processDataType(resultDataType, (MDDataType) modifierType.getReferencedType(),
+ mangled, demangledSource);
+ newResult.setLValueReference();
+ if (modifierType.getCVMod().isConst()) {
+ newResult.setConst();
+ }
+ if (modifierType.getCVMod().isVolatile()) {
+ newResult.setVolatile();
+ }
+ if (modifierType.getCVMod().isPointer64()) {
+ newResult.setPointer64();
+ }
+ return newResult;
+ }
+ // TODO: fix. Following is a kludge because DemangledObject has no DemangledReference
+ // with corresponding referencedType.
+ else if (modifierType instanceof MDFunctionIndirectType) {
+ // TODO---------what are we returning... need to work on called routine.
+ DemangledFunctionIndirect fd =
+ processDemangledFunctionIndirect((MDFunctionIndirectType) modifierType, mangled,
+ demangledSource);
+ for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
+ fd.incrementPointerLevels();
+ }
+ if (resultDataType.isConst()) {
+ fd.setConst();
+ }
+ if (resultDataType.isVolatile()) {
+ fd.setVolatile();
+ }
+ if (resultDataType.isPointer64()) {
+ fd.setPointer64();
+ }
+ return fd;
+ }
+ else if (modifierType instanceof MDPointerRefDataType) {
+ resultDataType.setName(getDataTypeName(datatype));
+ // Not sure if this is the correct thing to do for MDPointerRefDataType, but we
+ // are just going to assign the referred-to type:
+ //Processing the referenced type (for Ghidra, and then setting attributes on it)
+ return processDataType(resultDataType,
+ (MDDataType) modifierType.getReferencedType(), mangled, demangledSource);
+ }
+ else if (modifierType instanceof MDDataReferenceType) {
+ // Not sure if this is the correct thing to do for MDDataReferenceType, but we
+ // are just going to assign the referred-to type:
+ //Processing the referenced type (for Ghidra, and then setting attributes on it)
+ processDataType(resultDataType, (MDDataType) modifierType.getReferencedType(),
+ mangled, demangledSource);
+ if (modifierType.getCVMod().isConst()) {
+ resultDataType.setConst();
+ }
+ if (modifierType.getCVMod().isVolatile()) {
+ resultDataType.setVolatile();
+ }
+ return resultDataType;
+ }
+ else if (modifierType instanceof MDDataRightReferenceType) {
+ if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
+ resultDataType.setName(getDataTypeName(datatype));
+ // TODO---------what are we returning... need to work on called routine.
+ DemangledFunctionReference fr =
+ processDemangledFunctionReference(modifierType, mangled, demangledSource);
+ // TODO: fix. Following is a kludge because DemangledObject has no
+ // DemangledPointer with corresponding referencedType.
+ for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
+ fr.incrementPointerLevels();
+ }
+ if (resultDataType.isConst()) {
+ fr.setConst();
+ }
+ if (resultDataType.isVolatile()) {
+ fr.setVolatile();
+ }
+ if (resultDataType.isPointer64()) {
+ fr.setPointer64();
+ }
+ return fr;
+ }
+ //Processing the referenced type (for Ghidra, and then setting attributes on it)
+ processDataType(resultDataType, (MDDataType) modifierType.getReferencedType(),
+ mangled, demangledSource);
+ resultDataType.setRValueReference();
+ if (modifierType.getCVMod().isConst()) {
+ resultDataType.setConst();
+ }
+ if (modifierType.getCVMod().isVolatile()) {
+ resultDataType.setVolatile();
+ }
+ if (modifierType.getCVMod().isPointer64()) {
+ resultDataType.setPointer64();
+ }
+ return resultDataType;
+ }
+ else {
+ // not pointer, reference, or array type
+ if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
+ // TODO---------what are we returning... need to work on called routine.
+ DemangledFunctionIndirect fx =
+ processDemangledFunctionQuestion(modifierType, mangled, demangledSource);
+ // TODO: fix. Following is a kludge because DemangledObject has no
+ // DemangledPointer with corresponding referencedType.
+ if (resultDataType.isConst()) {
+ fx.setConst();
+ }
+ if (resultDataType.isVolatile()) {
+ fx.setVolatile();
+ }
+ if (resultDataType.isPointer64()) {
+ fx.setPointer64();
+ }
+ return fx;
+ }
+ // resultDataType.incrementPointerLevels();//Not sure if we should do/use this.
+ DemangledDataType dataType =
+ processDataType(resultDataType, (MDDataType) modifierType.getReferencedType(),
+ mangled, demangledSource);
+ if (modifierType.getCVMod().isConst()) {
+ resultDataType.setConst();
+ }
+ if (modifierType.getCVMod().isVolatile()) {
+ resultDataType.setVolatile();
+ }
+ if (modifierType.getCVMod().isPointer64()) {
+ resultDataType.setPointer64();
+ }
+ return dataType;
+ }
+ }
+ else if (datatype instanceof MDComplexType) {
+ MDComplexType complexType = (MDComplexType) datatype;
+ // Hope this is correct... will return "class" or other
+ resultDataType.setName(complexType.getNamespace().getName());
+ // TODO: setNamespace() wants a "DemangledType" for a namespace.
+ // Two problems:
+ // 1) we don't have an appropriate method to use
+ // 2) not sure DemangledType is appropriate; in MDComplexType we have an
+ // MDQualification--not an MDQualifiedName
+ resultDataType.setNamespace(
+ processNamespace(complexType.getNamespace(), mangled, demangledSource));
+
+ // Bunch of else-ifs for exclusive types
+ if (datatype instanceof MDEnumType) {
+ resultDataType.setEnum();
+ // Put in underlying type (for sizing too).
+ MDEnumType enumType = (MDEnumType) datatype;
+ resultDataType.setEnumType(enumType.getUnderlyingFullTypeName());
+ }
+ else if (datatype instanceof MDClassType) {
+ resultDataType.setClass();
+ }
+ else if (datatype instanceof MDStructType) {
+ resultDataType.setStruct();
+ }
+ else if (datatype instanceof MDUnionType) {
+ resultDataType.setUnion();
+ }
+ else if (datatype instanceof MDCoclassType) {
+ resultDataType.setCoclass();
+ }
+ else if (datatype instanceof MDCointerfaceType) {
+ resultDataType.setCointerface();
+ }
+ }
+ else if (datatype instanceof MDReferenceType) {
+ resultDataType.setLValueReference();
+ }
+ else if (datatype instanceof MDArrayBasicType) {
+ resultDataType.setArray(1);
+ }
+ else if (datatype instanceof MDVarArgsType) {
+ resultDataType.setVarArgs();
+ }
+ else if (datatype instanceof MDArrayReferencedType arrRefType) {
+ return processDataType(resultDataType, arrRefType.getReferencedType(), mangled,
+ demangledSource);
+ }
+ else if (datatype instanceof MDStdNullPtrType) {
+ resultDataType.setName(datatype.toString());
+ }
+ else {
+ // MDDataType
+ // TODO MDW64Type needs repeated reference type parsing, just as modifier types need
+ // them.
+ resultDataType.setName(getDataTypeName(datatype));
+ }
+ // TODO: No place to indicate a general pointer--we can indicate Pointer64
+ // TODO: Not sure if anything fits this: resultDataType.setComplex();
+ // TODO: resultDataType.setTemplate(); //TODO: Not sure templates are data types
+ // according to how MSFT demangles them.
+ // TODO: resultDataType.setTemplate(null); //TODO: Not sure templates are data types
+ // according to how MSFT demangles them.
+
+ return resultDataType;
+ }
+
+ /**
+ * Returns either a formal type name or a representative type name to fill into a
+ * MangledDataType if the formal name is blank
+ * @return the name
+ */
+ private static String getDataTypeName(MDDataType dataType) {
+ String name = dataType.getName();
+ if (!name.isBlank()) {
+ return name;
+ }
+ name = dataType.getTypeName();
+ if (!name.isBlank()) {
+ return name;
+ }
+ return dataType.toString();
+ }
+
+}
diff --git a/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftMangledContext.java b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftMangledContext.java
new file mode 100644
index 0000000000..e260ef8a37
--- /dev/null
+++ b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MicrosoftMangledContext.java
@@ -0,0 +1,77 @@
+/* ###
+ * 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.util.demangler.microsoft;
+
+import ghidra.app.util.demangler.MangledContext;
+import ghidra.program.model.address.Address;
+import ghidra.program.model.listing.Function;
+import ghidra.program.model.listing.Program;
+
+/**
+ * A simple class to contain the context of a mangled symbol for demangling
+ */
+public class MicrosoftMangledContext extends MangledContext {
+
+ /**
+ * Constructor for mangled context
+ * @param program the program; can be null
+ * @param options the demangler options
+ * @param mangled the mangled string
+ * @param address the address; can be null
+ */
+ public MicrosoftMangledContext(Program program, MicrosoftDemanglerOptions options,
+ String mangled, Address address) {
+ super(program, options, mangled, address);
+ }
+
+ /**
+ * Returns the program architecture size
+ * @return the architecture size or zero if not known (program is null)
+ */
+ public int getArchitectureSize() {
+ if (program == null) {
+ return 0;
+ }
+ return program.getAddressFactory().getDefaultAddressSpace().getSize();
+ }
+
+ /**
+ * Returns whether the symbol should be interpreted as a function
+ * @return {@code true} if should be interpreted as a function
+ */
+ boolean shouldInterpretAsFunction() {
+ MsCInterpretation control =
+ ((MicrosoftDemanglerOptions) options).getInterpretation();
+ return switch (control) {
+ case FUNCTION -> true;
+ case NON_FUNCTION -> false;
+ case FUNCTION_IF_EXISTS -> getExistingFunction() != null;
+ default -> throw new AssertionError("Invalid case");
+ };
+ }
+
+ /**
+ * Returns the function at the context address
+ * @return the function or null if program or address is null
+ */
+ private Function getExistingFunction() {
+ if (program == null || address == null) {
+ return null;
+ }
+ return program.getFunctionManager().getFunctionAt(address);
+ }
+
+}
diff --git a/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MsCInterpretation.java b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MsCInterpretation.java
new file mode 100644
index 0000000000..3010ead1a2
--- /dev/null
+++ b/Ghidra/Features/MicrosoftDemangler/src/main/java/ghidra/app/util/demangler/microsoft/MsCInterpretation.java
@@ -0,0 +1,37 @@
+/* ###
+ * 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.util.demangler.microsoft;
+
+/**
+ * Class to control whether a symbol should be demangled as a function symbols or a some other
+ * (e.g., variable) symbol
+ */
+public enum MsCInterpretation {
+ /**
+ * Forces processing as a function symbol if there are multiple symbol interpretations
+ */
+ FUNCTION,
+ /**
+ * Forces processing as a non-function (e.g., variable) if there are multiple symbol
+ * interpretations
+ */
+ NON_FUNCTION,
+ /**
+ * If there are multiple symbol interpretations, forces processing as a function only if
+ * there is already a function at the address
+ */
+ FUNCTION_IF_EXISTS
+}
diff --git a/Ghidra/Features/MicrosoftDemangler/src/test/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerExtraTest.java b/Ghidra/Features/MicrosoftDemangler/src/test/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerExtraTest.java
new file mode 100644
index 0000000000..6470c8f337
--- /dev/null
+++ b/Ghidra/Features/MicrosoftDemangler/src/test/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerExtraTest.java
@@ -0,0 +1,428 @@
+/* ###
+ * 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.util.demangler.microsoft;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import generic.test.AbstractGenericTest;
+import ghidra.app.util.demangler.*;
+import ghidra.program.database.ProgramBuilder;
+import ghidra.program.database.ProgramDB;
+import ghidra.program.model.address.Address;
+import ghidra.program.model.data.VoidDataType;
+import mdemangler.MDMangBaseTest;
+import mdemangler.object.MDObjectC;
+
+/**
+ * This class performs extra demangler testing for special cases that do not fit
+ * the testing pattern found in {@link MDMangBaseTest} and {@link MicrosoftDemanglerTest}
+ */
+public class MicrosoftDemanglerExtraTest extends AbstractGenericTest {
+
+ ProgramBuilder builder32;
+ ProgramBuilder builder64;
+ private ProgramDB program32;
+ private ProgramDB program64;
+
+ private Address address32;
+ private Address functionAddress32;
+ private Address address64;
+ private Address functionAddress64;
+
+ @Before
+ public void setUp() throws Exception {
+ String blockAddress = "0x01001000";
+ String nonFunctionAddress = "0x01001000";
+ String functionAddress = "0x01001010";
+
+ builder32 = new ProgramBuilder("test32", "x86:LE:32:default");
+ builder32.createMemory(".text", blockAddress, 0x100);
+ builder32.createEmptyFunction("function", functionAddress, 1, VoidDataType.dataType);
+ program32 = builder32.getProgram();
+ address32 = program32.getAddressFactory().getAddress(nonFunctionAddress);
+ functionAddress32 = program32.getAddressFactory().getAddress(functionAddress);
+
+ builder64 = new ProgramBuilder("test64", "x86:LE:64:default");
+ builder64.createMemory(".text", blockAddress, 0x100);
+ builder64.createEmptyFunction("function", functionAddress, 1, VoidDataType.dataType);
+ program64 = builder64.getProgram();
+ address64 = program64.getAddressFactory().getAddress(nonFunctionAddress);
+ functionAddress64 = program64.getAddressFactory().getAddress(functionAddress);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ builder32.dispose();
+ builder64.dispose();
+ }
+
+ //==============================================================================================
+ // Helpers
+
+ private void processWith32Function(String mangled, String expectDemangled,
+ String expectedFunction, String expectedConvention, int expectedNumBytes)
+ throws DemangledException {
+ MicrosoftDemangler demangler = new MicrosoftDemangler();
+
+ MicrosoftMangledContext context =
+ demangler.createMangledContext(mangled, null, program32, functionAddress32);
+ // We do not need to do this here: options.setErrorOnRemainingChars(false);
+
+ // Testing Demangled hierarchy
+ DemangledFunction demangledFunction = (DemangledFunction) demangler.demangle(context);
+ assertEquals(expectedFunction,
+ demangledFunction == null ? null : demangledFunction.toString());
+
+ // Testing MDMang hierarchy
+ MDObjectC objc = (MDObjectC) demangler.getMdItem();
+ String convention = objc.getCallingConvention();
+ int numParameterBytes = objc.getNumParameterBytes();
+ assertEquals(expectedConvention, convention);
+ assertEquals(expectedNumBytes, numParameterBytes);
+ assertEquals(expectDemangled, objc.toString());
+ }
+
+ private void processWith32NonFunction(String mangled, String expectDemangled)
+ throws DemangledException {
+ MicrosoftDemangler demangler = new MicrosoftDemangler();
+
+ MicrosoftMangledContext context =
+ demangler.createMangledContext(mangled, null, program32, address32);
+ MicrosoftDemanglerOptions options = (MicrosoftDemanglerOptions) context.getOptions();
+ // Important to set to false to standardize our test results to simple expected
+ // results. When the C-style symbols do not create function results either because
+ // there is not a function at the address or because of the architecture, we might end
+ // up with remaining charactes because the demangler sets its index back tot he start.
+ options.setErrorOnRemainingChars(false);
+
+ // Testing Demangled hierarchy
+ DemangledFunction demangledFunction = (DemangledFunction) demangler.demangle(context);
+ assertEquals(null, demangledFunction);
+
+ // Testing MDMang hierarchy
+ MDObjectC objc = (MDObjectC) demangler.getMdItem();
+ String convention = objc.getCallingConvention();
+ int numParameterBytes = objc.getNumParameterBytes();
+ assertEquals(null, convention);
+ assertEquals(0, numParameterBytes);
+ assertEquals(expectDemangled, objc.toString());
+ }
+
+ private void processWith64Function(String mangled, String expectDemangled,
+ String expectedFunction, String expectedConvention, int expectedNumBytes)
+ throws DemangledException {
+ MicrosoftDemangler demangler = new MicrosoftDemangler();
+
+ MicrosoftMangledContext context =
+ demangler.createMangledContext(mangled, null, program64, functionAddress64);
+ MicrosoftDemanglerOptions options = (MicrosoftDemanglerOptions) context.getOptions();
+ // Important to set to false to standardize our test results to simple expected
+ // results. When the C-style symbols do not create function results either because
+ // there is not a function at the address or because of the architecture, we might end
+ // up with remaining charactes because the demangler sets its index back tot he start.
+ options.setErrorOnRemainingChars(false);
+
+ // Testing Demangled hierarchy
+ DemangledFunction demangledFunction = (DemangledFunction) demangler.demangle(context);
+ assertEquals(expectedFunction,
+ demangledFunction == null ? null : demangledFunction.toString());
+
+ // Testing MDMang hierarchy
+ MDObjectC objc = (MDObjectC) demangler.getMdItem();
+ String convention = objc.getCallingConvention();
+ int numParameterBytes = objc.getNumParameterBytes();
+ assertEquals(expectedConvention, convention);
+ assertEquals(expectedNumBytes, numParameterBytes);
+ assertEquals(expectDemangled, objc.toString());
+ }
+
+ private void processWith64NonFunction(String mangled, String expectDemangled)
+ throws DemangledException {
+ MicrosoftDemangler demangler = new MicrosoftDemangler();
+
+ MicrosoftMangledContext context =
+ demangler.createMangledContext(mangled, null, program64, address64);
+ MicrosoftDemanglerOptions options = (MicrosoftDemanglerOptions) context.getOptions();
+ // Important to set to false to standardize our test results to simple expected
+ // results. When the C-style symbols do not create function results either because
+ // there is not a function at the address or because of the architecture, we might end
+ // up with remaining charactes because the demangler sets its index back tot he start.
+ options.setErrorOnRemainingChars(false);
+
+ // Testing Demangled hierarchy
+ DemangledFunction demangledFunction = (DemangledFunction) demangler.demangle(context);
+ assertEquals(null, demangledFunction);
+
+ // Testing MDMang hierarchy
+ MDObjectC objc = (MDObjectC) demangler.getMdItem();
+ String convention = objc.getCallingConvention();
+ int numParameterBytes = objc.getNumParameterBytes();
+ assertEquals(null, convention);
+ assertEquals(0, numParameterBytes);
+ assertEquals(expectDemangled, objc.toString());
+ }
+
+ //==============================================================================================
+
+ @Test
+ //This test checks that we can provide a mangled string for a function namespace.
+ // The return String from getOriginalMangled() is not null only for this special
+ // circumstance. So, in normal processing, we should check it for non-null to
+ // determine that we have a result of this form.
+ // The symbol here is from our cn3.cpp source target.
+ public void testFunctionNamespace() throws Exception {
+ String mangled = "?fn3@?2??Bar3@Foo2b@@SAHXZ@4HA";
+ String wholeTruth = "int `public: static int __cdecl Foo2b::Bar3(void)'::`3'::fn3";
+ String functionNamespaceMangledTruth = "?Bar3@Foo2b@@SAHXZ";
+ String functionNamespaceTruth = "public: static int __cdecl Foo2b::Bar3(void)";
+
+ MicrosoftDemangler demangler = new MicrosoftDemangler();
+
+ MicrosoftMangledContext context =
+ demangler.createMangledContext(mangled, null, program32, address32);
+ DemangledObject obj = demangler.demangle(context);
+ String demangled = demangler.getMdItem().toString();
+ assertEquals(wholeTruth, demangled);
+
+ String mangledFunctionNS = obj.getNamespace().getNamespace().getMangledString();
+ assertEquals(functionNamespaceMangledTruth, mangledFunctionNS);
+
+ context = demangler.createMangledContext(mangledFunctionNS, null, program32, address32);
+ demangler.demangle(context);
+ demangled = demangler.getMdItem().toString();
+ assertEquals(functionNamespaceTruth, demangled);
+ }
+
+ //==============================================================================================
+ /*
+ * Follow are C-style mangling scheme under 32-bit model; __vectorcall also valid for 64-bit
+ * __cdecl: '_' prefix; no suffix; example "_name"
+ * __stdcall: '_' prefix; "@" suffix; example "_name@12"
+ * __fastcall: '@' prefix; "@" suffix; example "@name@12"
+ * __vectorcall: no prefix; "@@" suffix; example "name@@12"
+ */
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: cdecl; Architecture size: 32; Function present: yes
+ // Result: cdecl function (stripped '_'); 0 bytes
+ public void testCStyleCdeclWith32Function() throws Exception {
+ String mangled = "_func_cdecl";
+ String expectedDemangled = "func_cdecl";
+ String expectedFunction = "__cdecl func_cdecl(void)";
+ String expectedConvention = "__cdecl";
+ int expectedNumBytes = 0;
+ processWith32Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
+ expectedNumBytes);
+ }
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: cdecl; Architecture size: 32; Function present: no
+ // Result: no function; 0 bytes
+ public void testCStyleCdeclWith32NoFunction() throws Exception {
+ String mangled = "_func_cdecl";
+ String expectedDemangled = "_func_cdecl";
+ processWith32NonFunction(mangled, expectedDemangled);
+ }
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: cdecl; Architecture size: 64; Function present: yes
+ // Result: no function; 0 bytes
+ public void testCStyleCdeclWith64Function() throws Exception {
+ String mangled = "_func_cdecl";
+ String expectedDemangled = "_func_cdecl";
+ String expectedFunction = null;
+ String expectedConvention = null;
+ int expectedNumBytes = 0;
+ processWith64Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
+ expectedNumBytes);
+ }
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: cdecl; Architecture size: 64; Function present: no
+ // Result: no function; 0 bytes
+ public void testCStyleCdeclWith64NoFunction() throws Exception {
+ String mangled = "_func_cdecl";
+ String expectedDemangled = "_func_cdecl";
+ processWith64NonFunction(mangled, expectedDemangled);
+ }
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: stdcall; Architecture size: 32; Function present: yes
+ // Result: stdcall function; 12 bytes
+ public void testCStyleStdcallWith32Function() throws Exception {
+ String mangled = "_func_stdcall@12";
+ String expectedDemangled = "func_stdcall";
+ String expectedFunction = "__stdcall func_stdcall(undefined4,undefined4,undefined4)";
+ String expectedConvention = "__stdcall";
+ int expectedNumBytes = 12;
+ processWith32Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
+ expectedNumBytes);
+ }
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: stdcall; Architecture size: 32; Function present: no
+ // Result: no function; 0 bytes
+ public void testCStyleStdcallWith32NoFunction() throws Exception {
+ String mangled = "_func_stdcall@12";
+ String expectedDemangled = "_func_stdcall";
+ processWith32NonFunction(mangled, expectedDemangled);
+ }
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: stdcall; Architecture size: 64; Function present: yes
+ // Result: no function; 0 bytes
+ public void testCStyleStdcallWith64Function() throws Exception {
+ String mangled = "_func_stdcall@12";
+ String expectedDemangled = "_func_stdcall";
+ String expectedFunction = null;
+ String expectedConvention = null;
+ int expectedNumBytes = 0;
+ processWith64Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
+ expectedNumBytes);
+ }
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: stdcall; Architecture size: 64; Function present: no
+ // Result: no function; 0 bytes
+ public void testCStyleStdcallWith64NoFunction() throws Exception {
+ String mangled = "_func_stdcall@12";
+ String expectedDemangled = "_func_stdcall";
+ processWith64NonFunction(mangled, expectedDemangled);
+ }
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: fastcall; Architecture size: 32; Function present: yes
+ // Result: fastcall function (stripped '@'); 12 bytes
+ public void testCStyleFastcallWith32Function() throws Exception {
+ String mangled = "@func_fastcall@12";
+ String expectedDemangled = "func_fastcall";
+ String expectedFunction = "__fastcall func_fastcall(undefined4,undefined4,undefined4)";
+ String expectedConvention = "__fastcall";
+ int expectedNumBytes = 12;
+ processWith32Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
+ expectedNumBytes);
+ }
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: fastcall; Architecture size: 32; Function present: no
+ // Result: no function; 12 bytes
+ public void testCStyleFastcallWith32NoFunction() throws Exception {
+ String mangled = "@func_fastcall@12";
+ String expectedDemangled = ""; // empty because the prefix '@' causes an empty name
+ processWith32NonFunction(mangled, expectedDemangled);
+ }
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: fastcall; Architecture size: 64; Function present: yes
+ // Result: no function; 12 bytes
+ public void testCStyleFastcallWith64Function() throws Exception {
+ String mangled = "@func_fastcall@12";
+ String expectedDemangled = ""; // empty because the prefix '@' causes an empty name
+ String expectedFunction = null;
+ String expectedConvention = null;
+ int expectedNumBytes = 0;
+ processWith64Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
+ expectedNumBytes);
+ }
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: fastcall; Architecture size: 64; Function present: no
+ // Result: fastcall function; 12 bytes
+ public void testCStyleFastcallWith64NoFunction() throws Exception {
+ String mangled = "@func_fastcall@12";
+ String expectedDemangled = ""; // empty because the prefix '@' causes an empty name
+ processWith64NonFunction(mangled, expectedDemangled);
+ }
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: vectorcall; Architecture size: 32; Function present: yes
+ // Result: vectorcall function; 12 bytes
+ public void testCStyleVectorcallWith32Function() throws Exception {
+ String mangled = "func_vectorcall@@12";
+ String expectedDemangled = "func_vectorcall";
+ String expectedFunction = "__vectorcall func_vectorcall(undefined4,undefined4,undefined4)";
+ String expectedConvention = "__vectorcall";
+ int expectedNumBytes = 12;
+ processWith32Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
+ expectedNumBytes);
+ }
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: vectorcall; Architecture size: 32; Function present: no
+ // Result: no function; 0 bytes
+ public void testCStyleVectorcallWith32NoFunction() throws Exception {
+ String mangled = "func_vectorcall@@12";
+ String expectedDemangled = "func_vectorcall";
+ processWith32NonFunction(mangled, expectedDemangled);
+ }
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: vectorcall; Architecture size: 32; Function present: yes
+ // Result: vectorcall function; 12 bytes
+ public void testCStyleVectorcallWith64Function() throws Exception {
+ String mangled = "func_vectorcall@@12";
+ String expectedDemangled = "func_vectorcall";
+ String expectedFunction = "__vectorcall func_vectorcall(undefined4,undefined4,undefined4)";
+ String expectedConvention = "__vectorcall";
+ int expectedNumBytes = 12;
+ processWith64Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
+ expectedNumBytes);
+ }
+
+ @Test
+ //Uses additional context information for demangling: architecture size and whether
+ // demangling symbol for a known function
+ // Scheme: vectorcall; Architecture size: 64; Function present: no
+ // Result: no function; 0 bytes
+ public void testCStyleVectorcallWith64NoFunction() throws Exception {
+ String mangled = "func_vectorcall@@12";
+ String expectedDemangled = "func_vectorcall";
+ processWith64NonFunction(mangled, expectedDemangled);
+ }
+
+}
diff --git a/Ghidra/Features/MicrosoftDemangler/src/test/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerTest.java b/Ghidra/Features/MicrosoftDemangler/src/test/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerTest.java
index 82432229f8..e7fecec70f 100644
--- a/Ghidra/Features/MicrosoftDemangler/src/test/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerTest.java
+++ b/Ghidra/Features/MicrosoftDemangler/src/test/java/ghidra/app/util/demangler/microsoft/MicrosoftDemanglerTest.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.
@@ -45,21 +45,24 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
public void testUnsignedShortParameter() throws Exception {
String mangled = "?InvokeHelperV@COleDispatchDriver@@QAEXJGGPAXPBEPAD@Z";
-
+ Address address = addr("01001000");
MicrosoftDemangler demangler = new MicrosoftDemangler();
- DemangledObject demangledObject = demangler.demangle(mangled);
+ DemanglerOptions options = new MicrosoftDemanglerOptions();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, options, program, address);
+ DemangledObject demangledObject = demangler.demangle(mangledContext);
int txID = program.startTransaction("Test");
SymbolTable st = program.getSymbolTable();
- st.createLabel(addr("01001000"), mangled, SourceType.ANALYSIS);
+ st.createLabel(address, mangled, SourceType.ANALYSIS);
+
+ demangledObject.applyTo(program, address, options, TaskMonitor.DUMMY);
- DemanglerOptions options = new DemanglerOptions();
- demangledObject.applyTo(program, addr("01001000"), options, TaskMonitor.DUMMY);
program.endTransaction(txID, true);
FunctionManager fm = program.getFunctionManager();
- Function function = fm.getFunctionAt(addr("01001000"));
+ Function function = fm.getFunctionAt(address);
Parameter[] parameters = function.getParameters();
// this was broken at one point, returning 'unsigned_short'
@@ -69,17 +72,19 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
@Test
public void testArrayVariable() throws Exception { // NullPointerException
String mangled = "?Te@NS1@BobsStuff@@0QAY0BAA@$$CBIA";
-
+ Address address = addr("01001000");
MicrosoftDemangler demangler = new MicrosoftDemangler();
- DemangledObject demangledObject = demangler.demangle(mangled);
+ DemanglerOptions options = new MicrosoftDemanglerOptions();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, options, program, address);
+ DemangledObject demangledObject = demangler.demangle(mangledContext);
int txID = program.startTransaction("Test");
SymbolTable st = program.getSymbolTable();
- st.createLabel(addr("01001000"), mangled, SourceType.ANALYSIS);
+ st.createLabel(address, mangled, SourceType.ANALYSIS);
- DemanglerOptions options = new DemanglerOptions();
- demangledObject.applyTo(program, addr("01001000"), options, TaskMonitor.DUMMY);
+ demangledObject.applyTo(program, address, options, TaskMonitor.DUMMY);
program.endTransaction(txID, false);
}
@@ -203,8 +208,11 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
String mangled = "?BobsStuffIO@344GPAUHINSTANCE__@@U_COMMPROP@@+W";
MicrosoftDemangler demangler = new MicrosoftDemangler();
+
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, program, null);
try {
- demangler.demangle(mangled);
+ demangler.demangle(mangledContext);
}
catch (DemangledException e) {
// Expected
@@ -218,8 +226,10 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
String mangled = "?BobsStuffIO@344GPAUHINSTANCE__@@U_COMMPROP@@/W";
MicrosoftDemangler demangler = new MicrosoftDemangler();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, program, null);
try {
- demangler.demangle(mangled);
+ demangler.demangle(mangledContext);
}
catch (DemangledException e) {
// Expected
diff --git a/Ghidra/Features/MicrosoftDmang/developer_scripts/DeveloperDumpMDMangParseInfoScript.java b/Ghidra/Features/MicrosoftDmang/developer_scripts/DeveloperDumpMDMangParseInfoScript.java
index 1c14b01111..ba9c788d30 100644
--- a/Ghidra/Features/MicrosoftDmang/developer_scripts/DeveloperDumpMDMangParseInfoScript.java
+++ b/Ghidra/Features/MicrosoftDmang/developer_scripts/DeveloperDumpMDMangParseInfoScript.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.
@@ -93,8 +93,9 @@ public class DeveloperDumpMDMangParseInfoScript extends GhidraScript {
StringBuilder builder = new StringBuilder();
builder.append("\nName: " + name + "\n");
MDMangParseInfo demangler = new MDMangParseInfo();
+ demangler.setMangledSymbol(name);
try {
- demangler.demangle(name, false);
+ demangler.demangle();
String parseInfo = demangler.getParseInfoIncremental();
builder.append(parseInfo);
builder.append("Num remaining chars:" + demangler.getNumCharsRemaining() + "\n");
diff --git a/Ghidra/Features/MicrosoftDmang/developer_scripts/MDMangDeveloperGenericizeMangledNamesScript.java b/Ghidra/Features/MicrosoftDmang/developer_scripts/MDMangDeveloperGenericizeMangledNamesScript.java
index 4258dbbb97..4cb8aefe81 100644
--- a/Ghidra/Features/MicrosoftDmang/developer_scripts/MDMangDeveloperGenericizeMangledNamesScript.java
+++ b/Ghidra/Features/MicrosoftDmang/developer_scripts/MDMangDeveloperGenericizeMangledNamesScript.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.
@@ -125,8 +125,9 @@ public class MDMangDeveloperGenericizeMangledNamesScript extends GhidraScript {
return getError(name, "contains white space");
}
MDMangGenericize demangler = new MDMangGenericize();
+ demangler.setMangledSymbol(name);
try {
- demangler.demangle(name, false);
+ demangler.demangle();
}
catch (MDException e) {
return getError(name, e.getMessage());
diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDCharacterIterator.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDCharacterIterator.java
index 53509bb92a..7c8746409c 100644
--- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDCharacterIterator.java
+++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDCharacterIterator.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.
@@ -17,13 +17,13 @@ package mdemangler;
/**
* A class for bidirectional iteration over a string.
- *
+ *
* Iterators maintain a current character index, whose valid range is from
* 0 to string.length()-1.
- *
+ *
* The current index can be retrieved by calling getIndex() and set directly
* by calling setIndex().
- *
+ *
* The methods previous() and next() are used for iteration. They return DONE if
* they would move outside the range from 0 to string.length()-1.
*/
@@ -71,13 +71,13 @@ public class MDCharacterIterator {
}
/**
- * Sets the position to the specified position in the text.
- * @param index the position within the text.
- * @return the character at the specified position
- * @throws IllegalArgumentException if index is not in range from 0 to string.length()-1
+ * Sets the position to the specified position in the text. Can set index to just beyond
+ * the text to represent the iterator being at the end of the text
+ * @param index the position within the text.
+ * @throws IllegalArgumentException if index is not in range from 0 to string.length()
*/
public void setIndex(int index) {
- if (index < 0 || index > string.length() - 1) {
+ if (index < 0 || index > string.length()) {
throw new IllegalArgumentException();
}
this.index = index;
@@ -92,7 +92,7 @@ public class MDCharacterIterator {
}
/**
- * Returns the next character without incrementing the current index.
+ * Returns the next character without incrementing the current index.
* @return the next character without incrementing the current index
*/
public char peek() {
@@ -137,7 +137,7 @@ public class MDCharacterIterator {
}
/**
- * Returns the character at the current index and then increments the index by one.
+ * Returns the character at the current index and then increments the index by one.
* If the resulting index is greater or equal
* to the end index, the current index is reset to the end index and
* a value of DONE is returned.
@@ -154,7 +154,7 @@ public class MDCharacterIterator {
}
/**
- * Increments the index by one.
+ * Increments the index by one.
* Does no testing for whether the index surpasses the length of the string.
*/
public void increment() {
@@ -162,7 +162,7 @@ public class MDCharacterIterator {
}
/**
- * Increments the index by the amount of count.
+ * Increments the index by the amount of count.
* Does no testing for whether the index surpasses the length of the string.
*/
public void increment(int count) {
diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDDotSeparatedItem.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDDotSeparatedItem.java
index 12452fec20..ad6bc314e2 100644
--- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDDotSeparatedItem.java
+++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDDotSeparatedItem.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.
@@ -59,7 +59,10 @@ public class MDDotSeparatedItem extends MDParsableItem {
try {
Constructor extends MDMang> ctor = dmang.getClass().getDeclaredConstructor();
MDMang subDmang = ctor.newInstance();
- subItem = subDmang.demangle(sub, false);
+ subDmang.setArchitectureSize(dmang.getArchitectureSize());
+ subDmang.setIsFunction(dmang.isFunction);
+ subDmang.setMangledSymbol(sub);
+ subItem = subDmang.demangle();
}
// might want to handle these separately for now... later can possibly group all
// together
diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMang.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMang.java
index 8dfda5c9a3..fcc8cc4d92 100644
--- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMang.java
+++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMang.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.
@@ -19,6 +19,8 @@ import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+
import mdemangler.MDContext.MDContextType;
import mdemangler.datatype.MDDataType;
import mdemangler.datatype.MDDataTypeParser;
@@ -38,6 +40,9 @@ import mdemangler.template.MDTemplateArgumentsList;
public class MDMang {
public static final char DONE = MDCharacterIterator.DONE;
+ protected int architectureSize = 32;
+ protected boolean isFunction = false;
+
protected String mangled;
protected MDCharacterIterator iter;
protected String errorMessage;
@@ -45,12 +50,147 @@ public class MDMang {
protected List contextStack;
+ protected boolean errorOnRemainingChars = false;
+
public enum ProcessingMode {
DEFAULT_STANDARD, LLVM
}
private ProcessingMode processingMode;
+ //==============================================================================================
+ // Mangled Context
+
+ /**
+ * Sets the mangled string to be demangled
+ * @param mangledIn the string to be demangled
+ */
+ public void setMangledSymbol(String mangledIn) {
+ this.mangled = mangledIn;
+ }
+
+ /**
+ * Gets the mangled string being demangled
+ * @return the string being demangled
+ */
+ public String getMangledSymbol() {
+ return mangled;
+ }
+
+ /**
+ * Sets the architecture size. Default is 64 bits
+ * @param size the architecture size
+ */
+ public void setArchitectureSize(int size) {
+ architectureSize = size;
+ }
+
+ /**
+ * Returns the architecture size (bits)
+ * @return the architecture size
+ */
+ public int getArchitectureSize() {
+ return architectureSize;
+ }
+
+ /**
+ * Sets whether the symbol is known to be for a function
+ * @param isFunction {@code true} if known to be a symbol for a function
+ */
+ public void setIsFunction(boolean isFunction) {
+ this.isFunction = isFunction;
+ }
+
+ /**
+ * Returns whether the symbol is known to be for a function
+ * @return {@code true} if known to be a symbol for a function
+ */
+ public boolean isFunction() {
+ return isFunction;
+ }
+
+ //==============================================================================================
+ // Control
+
+ /**
+ * Controls whether an exception is thrown if there are remaining characters after demangling.
+ * Default is {@code false}
+ * @param errorOnRemainingCharsArg {@code true} to error if characters remaining
+ */
+ public void setErrorOnRemainingChars(boolean errorOnRemainingCharsArg) {
+ errorOnRemainingChars = errorOnRemainingCharsArg;
+ }
+
+ /**
+ * Returns {@code true} if the process will throw an exception if characters remain after
+ * demangling
+ * @return {@code true} if errors will occur on remaining characters
+ */
+ public boolean errorOnRemainingChars() {
+ return errorOnRemainingChars;
+ }
+
+ /**
+ * Returns the error message when demangle() returns null.
+ * @return the error message for the demangle() call.
+ */
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ /**
+ * Returns the number of unprocessed mangled characters. Note that
+ * demangle() has a flag controlling whether remaining characters causes an
+ * error
+ * @return the integer number of characters that remain
+ */
+ public int getNumCharsRemaining() {
+ return iter.getLength() - iter.getIndex();
+ }
+
+ //==============================================================================================
+ // Processing
+
+ /**
+ * Demangles the string already stored and returns a parsed item
+ * @return item detected and parsed
+ * @throws MDException upon error parsing item
+ */
+ public MDParsableItem demangle() throws MDException {
+ initState();
+ item = MDMangObjectParser.determineItemAndParse(this);
+ if (item instanceof MDObjectCPP) {
+ // MDMANG SPECIALIZATION USED.
+ item = getEmbeddedObject((MDObjectCPP) item);
+ }
+ int numCharsRemaining = getNumCharsRemaining();
+ if (errorOnRemainingChars && (numCharsRemaining > 0)) {
+ throw new MDException(
+ "MDMang: characters remain after demangling: " + numCharsRemaining + ".");
+ }
+ return item;
+ }
+
+ /**
+ * Demangles the mangled "type" name already stored and returns a parsed MDDataType
+ * @return the parsed MDDataType
+ * @throws MDException upon parsing error
+ */
+ public MDDataType demangleType() throws MDException {
+ initState();
+ MDDataType mdDataType = MDDataTypeParser.determineAndParseDataType(this, false);
+ item = mdDataType;
+ int numCharsRemaining = getNumCharsRemaining();
+ if (errorOnRemainingChars && (numCharsRemaining > 0)) {
+ throw new MDException(
+ "MDMang: characters remain after demangling: " + numCharsRemaining + ".");
+ }
+ return mdDataType;
+ }
+
+ //==============================================================================================
+ // Internal processing control
+
public void setProcessingMode(ProcessingMode processingMode) {
this.processingMode = processingMode;
}
@@ -67,33 +207,13 @@ public class MDMang {
return processingMode == ProcessingMode.LLVM;
}
- /**
- * Demangles the string passed in and returns a parsed item.
- *
- * @param mangledIn
- * the string to be demangled.
- * @param errorOnRemainingChars
- * boolean flag indicating whether remaining characters causes an
- * error.
- * @return the item that has been parsed.
- * @throws MDException upon parsing error
- */
- public MDParsableItem demangle(String mangledIn, boolean errorOnRemainingChars)
- throws MDException {
- if (mangledIn == null || mangledIn.isEmpty()) {
- throw new MDException("Invalid mangled symbol.");
- }
- setMangledSymbol(mangledIn);
- return demangle(errorOnRemainingChars);
- }
-
/**
* Variables that get set at the very beginning.
* @throws MDException if mangled name is not set
*/
protected void initState() throws MDException {
- if (mangled == null) {
- throw new MDException("MDMang: Mangled string is null.");
+ if (StringUtils.isBlank(mangled)) {
+ throw new MDException("MDMang: Mangled string is null or blank.");
}
errorMessage = "";
processingMode = ProcessingMode.DEFAULT_STANDARD;
@@ -109,108 +229,7 @@ public class MDMang {
setIndex(0);
}
- /**
- * Demangles the string already stored and returns a parsed item.
- *
- * @param errorOnRemainingChars
- * boolean flag indicating whether remaining characters causes an
- * error.
- * @return item detected and parsed
- * @throws MDException upon error parsing item
- */
- public MDParsableItem demangle(boolean errorOnRemainingChars) throws MDException {
- initState();
- item = MDMangObjectParser.determineItemAndParse(this);
- if (item instanceof MDObjectCPP) {
- // MDMANG SPECIALIZATION USED.
- item = getEmbeddedObject((MDObjectCPP) item);
- }
- int numCharsRemaining = getNumCharsRemaining();
- if (errorOnRemainingChars && (numCharsRemaining > 0)) {
- throw new MDException(
- "MDMang: characters remain after demangling: " + numCharsRemaining + ".");
- }
- return item;
- }
-
- /**
- * Demangles the mangled "type" name and returns a parsed MDDataType
- *
- * @param mangledIn the mangled "type" string to be demangled
- * @param errorOnRemainingChars
- * boolean flag indicating whether remaining characters causes an
- * error
- * @return the parsed MDDataType
- * @throws MDException upon parsing error
- */
- public MDDataType demangleType(String mangledIn, boolean errorOnRemainingChars)
- throws MDException {
- if (mangledIn == null || mangledIn.isEmpty()) {
- throw new MDException("Invalid mangled symbol.");
- }
- setMangledSymbol(mangledIn);
- return demangleType(errorOnRemainingChars);
- }
-
- /**
- * Demangles the mangled "type" name already stored and returns a parsed MDDataType
- *
- * @param errorOnRemainingChars
- * boolean flag indicating whether remaining characters causes an
- * error
- * @return the parsed MDDataType
- * @throws MDException upon parsing error
- */
- public MDDataType demangleType(boolean errorOnRemainingChars) throws MDException {
- initState();
- MDDataType mdDataType = MDDataTypeParser.determineAndParseDataType(this, false);
- item = mdDataType;
- int numCharsRemaining = getNumCharsRemaining();
- if (errorOnRemainingChars && (numCharsRemaining > 0)) {
- throw new MDException(
- "MDMang: characters remain after demangling: " + numCharsRemaining + ".");
- }
- return mdDataType;
- }
-
- /**
- * Sets the mangled string to be demangled.
- *
- * @param mangledIn
- * the string to be demangled.
- */
- public void setMangledSymbol(String mangledIn) {
- this.mangled = mangledIn;
- }
-
- /**
- * Gets the mangled string being demangled.
- *
- * @return the string being demangled.
- */
- public String getMangledSymbol() {
- return mangled;
- }
-
- /**
- * Returns the error message when demangle() returns null.
- *
- * @return the error message for the demangle() call.
- */
- public String getErrorMessage() {
- return errorMessage;
- }
-
- /**
- * Returns the number of unprocessed mangled characters. Note that
- * demangle() has a flag controlling whether remaining characters causes an
- * error.
- *
- * @return the integer number of characters that remain.
- */
- public int getNumCharsRemaining() {
- return iter.getLength() - iter.getIndex();
- }
+ //==============================================================================================
/******************************************************************************/
/******************************************************************************/
@@ -252,9 +271,10 @@ public class MDMang {
}
/**
- * Sets the current index.
- * @param index the position to set.
- * @throws IllegalArgumentException if index is not in range from 0 to string.length()-1
+ * Sets the current index. Can set index to just beyond the text to represent the iterator
+ * being at the end of the text
+ * @param index the position to set
+ * @throws IllegalArgumentException if index is not in range from 0 to string.length()
*/
public void setIndex(int index) {
iter.setIndex(index);
diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGenericize.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGenericize.java
index d0f35de0bd..05f728c01f 100644
--- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGenericize.java
+++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGenericize.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.
@@ -67,7 +67,7 @@ public class MDMangGenericize extends MDMang {
// return item;
// }
@Override
- public MDParsableItem demangle(boolean errorOnRemainingChars) throws MDException {
+ public MDParsableItem demangle() throws MDException {
// ignoring the 'errorOnRemainingChars' parameter (for now)
initState();
item = MDMangObjectParser.determineItemAndParse(this);
diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGhidra.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGhidra.java
index cbba084a63..b2943bb366 100644
--- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGhidra.java
+++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangGhidra.java
@@ -15,918 +15,64 @@
*/
package mdemangler;
-import java.util.Iterator;
-
-import ghidra.app.util.demangler.*;
-import ghidra.program.model.lang.CompilerSpec;
-import ghidra.program.model.symbol.SourceType;
import mdemangler.datatype.MDDataType;
-import mdemangler.datatype.MDVarArgsType;
-import mdemangler.datatype.complex.*;
-import mdemangler.datatype.extended.MDArrayReferencedType;
-import mdemangler.datatype.modifier.*;
-import mdemangler.functiontype.*;
-import mdemangler.naming.*;
-import mdemangler.object.*;
-import mdemangler.template.MDTemplateNameAndArguments;
-import mdemangler.typeinfo.*;
/**
* A new built-from-scratch class for demangling debug symbols created using
* Microsoft Visual Studio.
+ *
+ * Note: the processing of {@link MDParsableItem} that was in this class was moved to a
+ * package-projected utility class of the MicrosoftDemangler. Ghidra users should defer to
+ * using the MicrosoftDemangler.
+ *
+ * This {@link MDMangGhidra} class might be removed in the future, with deferred use to MDMang.
*/
public class MDMangGhidra extends MDMang {
- private DemangledObject objectResult;
- private DemangledDataType dataTypeResult;
+ private boolean demangleOnlyKnownPatterns = false;
- private String mangledSource;
- private String demangledSource;
+ //==============================================================================================
+ // Control
- public DemangledObject getObject() {
- return objectResult;
+ /**
+ * Controls whether a symbol is skipped (returns null) if it doesn't match a known mangling
+ * pattern, which is generally the start pattern of a symbol. Default is {@code false}
+ * @param demangleOnlyKnownPatternsArg {@code true} to skip a symbol that doesn't match a
+ * known pattern
+ */
+ public void setDemangleOnlyKnownPatterns(boolean demangleOnlyKnownPatternsArg) {
+ demangleOnlyKnownPatterns = demangleOnlyKnownPatternsArg;
}
- public DemangledDataType getDataType() {
- return dataTypeResult;
+ /**
+ * Returns {@code true} if the process will skip a symbol that doesn't match a known pattern
+ * @return {@code true} if a symbol that doesn't a known pattern will be skipped
+ */
+ public boolean demangleOnlyKnownPatterns() {
+ return demangleOnlyKnownPatterns;
}
- public MDParsableItem demangle(String mangledArg, boolean errorOnRemainingChars,
- boolean demangleOnlyKnownPatterns) throws MDException {
- // TODO: Could possibly just ignore "demangleOnlyKnownpatterns"
+ //==============================================================================================
+ @Override
+ public MDParsableItem demangle() throws MDException {
if (demangleOnlyKnownPatterns) {
- if (!(mangledArg.startsWith("?") || mangledArg.startsWith(".") ||
- mangledArg.startsWith("__") || (mangledArg.charAt(0) < 'a') ||
- (mangledArg.charAt(0) > 'z') || (mangledArg.charAt(0) < 'A') ||
- (mangledArg.charAt(0) > 'Z'))) {
+ if (!(mangled.startsWith("?") || mangled.startsWith(".") || mangled.startsWith("_") ||
+ (mangled.charAt(0) < 'a') ||
+ (mangled.charAt(0) >= 'a') && (mangled.charAt(0) <= 'z') ||
+ (mangled.charAt(0) >= 'A') && (mangled.charAt(0) <= 'Z'))) {
return null;
}
}
-
- return demangle(mangledArg, errorOnRemainingChars);
- }
-
- @Override
- public MDParsableItem demangle(String mangledArg, boolean errorOnRemainingChars)
- throws MDException {
-
- this.mangledSource = mangledArg;
-
- MDParsableItem returnedItem = super.demangle(mangledArg, true);
-
- this.demangledSource = item.toString();
-
- objectResult = processItem();
+ MDParsableItem returnedItem = super.demangle();
+ // TODO: Investigate... seems that mangledSource should be eliminated throughout and
+ // that mangled should be used instead.
return returnedItem;
}
@Override
- public MDDataType demangleType(String mangledArg, boolean errorOnRemainingChars)
- throws MDException {
-
- this.mangledSource = mangledArg;
-
- MDDataType returnedType = super.demangleType(mangledArg, errorOnRemainingChars);
-
- this.demangledSource = returnedType.toString();
-
- dataTypeResult = processDataType(null, returnedType);
+ public MDDataType demangleType() throws MDException {
+ MDDataType returnedType = super.demangleType();
return returnedType;
}
- public Demangled processNamespace(MDQualifiedName qualifiedName) {
- return processNamespace(qualifiedName.getQualification());
- }
-
- private Demangled processNamespace(MDQualification qualification) {
- Iterator it = qualification.iterator();
- if (!it.hasNext()) {
- return null;
- }
-
- MDQualifier qual = it.next();
- Demangled type = getDemangled(qual);
- Demangled current = type;
- // Note that qualifiers come in reverse order, from most refined to root being the last
- while (it.hasNext()) {
- qual = it.next();
- Demangled parent = getDemangled(qual);
- current.setNamespace(parent);
- current = parent;
- }
- return type;
- }
-
- private Demangled getDemangled(MDQualifier qual) {
- Demangled demangled;
- if (qual.isNested()) {
- String subMangled = qual.getNested().getMangled();
- MDObjectCPP obj = qual.getNested().getNestedObject();
- MDTypeInfo typeInfo = obj.getTypeInfo();
- MDType type = typeInfo.getMDType();
- if (type instanceof MDDataType dt) {
- demangled = new DemangledType(subMangled, qual.toString(), qual.toString());
- }
- else if (type instanceof MDFunctionType ft) {
- // We currently cannot handle functions as part of a namespace, so we will just
- // treat the demangled function namespace string as a plain namespace.
- //demangled = new DemangledFunction(subMangled, qual.toString(), qual.toString());
- demangled =
- new DemangledNamespaceNode(subMangled, qual.toString(), qual.toString());
- }
- else {
- demangled =
- new DemangledNamespaceNode(subMangled, qual.toString(), qual.toString());
- }
- }
- else if (qual.isAnon()) {
- // Instead of using the standard qual.toString() method, which returns
- // "`anonymous namespace'" for anonymous qualifiers, we use qual.getAnonymousName()
- // which will have the underlying anonymous name of the form "A0xfedcba98" to create
- // a standardized anonymous name that is distinguishable from other anonymous names.
- // The standardized name comes from createStandardAnonymousNamespaceNode(). This
- // is especially important when there are sibling anonymous names.
- String anon = MDMangUtils.createStandardAnonymousNamespaceNode(qual.getAnonymousName());
- demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), anon);
- }
- else if (qual.isInterface()) {
- // TODO: need to do better; setting namespace for now
- demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), qual.toString());
- }
- else if (qual.isNameQ()) {
- // TODO: need to do better; setting namespace for now, as it looks like interface
- demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), qual.toString());
- }
- else if (qual.isNameC()) {
- // TODO: need to do better; setting type for now, but not processed yet and not sure
- // what it is
- demangled = new DemangledType(mangledSource, qual.toString(), qual.toString());
- }
- else if (qual.isLocalNamespace()) {
- String local =
- MDMangUtils.createStandardLocalNamespaceNode(qual.getLocalNamespaceNumber());
- demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), local);
- }
- else {
- demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), qual.toString());
- }
- return demangled;
- }
-
- private DemangledObject processItem() {
- objectResult = null;
- if (item instanceof MDObjectReserved) {
- objectResult = processObjectReserved((MDObjectReserved) item);
- }
- else if (item instanceof MDObjectCodeView codeView) {
- objectResult = processObjectCPP(codeView);
- objectResult.setSpecialPrefix(codeView.getPrefix());
- }
- else if (item instanceof MDObjectCPP objCpp) { // Base class of MDObjectBracket/MDObjectCodeView.
- objectResult = processObjectCPP(objCpp);
- }
- else if (item instanceof MDObjectC objC) {
- objectResult = processObjectC(objC);
- }
- else if (item instanceof MDDataType dataType) {
- // TODO: how do we fix this? DemangledDataType extends DemangledType, but not
- // DemangleObject...
- dataTypeResult = processDataType(null, dataType);
- // object = getDemangledDataType();
- }
- else if (item instanceof MDTemplateNameAndArguments templateNameAndArgs) {
- objectResult = processTemplate(templateNameAndArgs);
- }
- return objectResult;
- }
-
- private DemangledObject processObjectReserved(MDObjectReserved objectReserved) {
- DemangledObject object = null;
- if (objectReserved.getClass().equals(MDObjectReserved.class)) {
- //Testing if the class is not a derived class of MDObjectReserved;
- // In other words, is it exactly a MDObjectReserved?
- // If so, then return null, which will allow it to get processed
- // outside of the demangler.
- return null;
- }
- if (objectReserved instanceof MDObjectBracket) {
- MDObjectBracket objectBracket = (MDObjectBracket) objectReserved;
- MDObjectCPP objectCPP = objectBracket.getObjectCPP();
- object = processObjectCPP(objectCPP);
- object.setSpecialPrefix(((MDObjectBracket) item).getPrefix());
- }
- //TODO: put other objectReserved derivative types here and return something that Ghidra
- // can use.
- else {
- object =
- new DemangledUnknown(mangledSource, demangledSource, objectReserved.toString());
- }
- return object;
- }
-
- private DemangledObject processObjectC(MDObjectC objectC) {
- // We are returning null here because we do not want Ghidra to put up a plate
- // comment for a standard C symbol.
- // FUTURE WORK: After discussion, easiest way to deal with this for now (without
- // exploding work into other demanglers) is to keep the "return null" for now.
- // The problem is with the DemangledObject making a revision of the
- // success/failure of demangling by doing a comparison of the input string to
- // the output string in the applyTo() method. In a previous encoding, I moved
- // this logic into other demanglers and set a flag in DemangledObject, that way
- // my MDMangGhidra could set a flag to succeed when we have a C-language variable
- // (vs. C++) where the input == output is valid. We didn't like this pattern.
- // The better way forward, which will require digging into the other demanglers
- // further (keeping this for future work), is to throw an exception on failure
- // instead of returning null as well as pushing this success/failure logic
- // upstream (where I was attempting to put it) and removing the input == output
- // test from DemangledObject; an object is only returned upon success and no
- // rescinding of the success determination is made later.
- return null;
- // Following is the code that we had originally intended to use.
- // DemangledVariable variable = new DemangledVariable(objectC.toString());
- // return variable;
- }
-
- private DemangledObject processObjectCPP(MDObjectCPP objectCPP) {
- MDTypeInfo typeinfo = objectCPP.getTypeInfo();
- DemangledObject resultObject = null;
- if (typeinfo != null) {
- if (typeinfo instanceof MDVariableInfo) {
- DemangledVariable variable;
- MDVariableInfo variableInfo = (MDVariableInfo) typeinfo;
- MDType mdtype = variableInfo.getMDType();
- DemangledDataType dt = processDataType(null, (MDDataType) mdtype);
- if ("std::nullptr_t".equals(dt.getName())) {
- variable = new DemangledVariable(mangledSource, demangledSource, "");
- }
- else {
- variable =
- new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
- variable.setNamespace(processNamespace(objectCPP.getQualification()));
- }
- variable.setDatatype(dt);
- resultObject = variable;
- variable.setConst(variableInfo.isConst());
- variable.setVolatile(variableInfo.isVolatile());
- variable.setPointer64(variableInfo.isPointer64());
- if (variableInfo.isRestrict()) {
- variable.setRestrict();
- }
- if (variableInfo.isUnaligned()) {
- variable.setUnaligned();
- }
- variable.setBasedName(variableInfo.getBasedName());
- if (variableInfo.isMember()) {
- variable.setMemberScope(variableInfo.getMemberScope());
- }
- }
- else if (typeinfo instanceof MDFunctionInfo) {
- if (typeinfo.getSpecialHandlingCode() == 'F') {
- resultObject = new DemangledUnknown(mangledSource, demangledSource, null);
- }
- else {
- DemangledFunction function =
- new DemangledFunction(mangledSource, demangledSource, objectCPP.getName());
- function.setSignatureSourceType(SourceType.IMPORTED);
- function.setNamespace(processNamespace(objectCPP.getQualification()));
- resultObject = function;
- objectResult = processFunction((MDFunctionInfo) typeinfo, function);
- // Any other special values to be set?
- if (typeinfo instanceof MDMemberFunctionInfo) {
- if (typeinfo instanceof MDVCall) {
- // Empty for now--placeholder for possible future logic.
- }
- else if (typeinfo instanceof MDVFAdjustor) {
- // Empty for now--placeholder for possible future logic.
- }
- else if (typeinfo instanceof MDVtordisp) {
- // Empty for now--placeholder for possible future logic.
- }
- else if (typeinfo instanceof MDVtordispex) {
- // Empty for now--placeholder for possible future logic.
- }
- else {
- // plain member function
- }
- }
- else {
- // global function
- }
- }
- }
- else if (typeinfo instanceof MDVxTable) { //Includes VFTable, VBTable, and RTTI4
- MDVxTable vxtable = (MDVxTable) typeinfo;
- DemangledVariable variable =
- new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
- variable.setNamespace(processNamespace(objectCPP.getQualification()));
- variable.setConst(vxtable.isConst());
- variable.setVolatile(vxtable.isVolatile());
- variable.setPointer64(vxtable.isPointer64());
- resultObject = variable;
- // The following code would be an alternative, depending on whether we get
- // customer complaints or other fall-out from having created a variable here.
- //resultObject = new DemangledUnknown();
- }
- else if (typeinfo instanceof AbstractMDMetaClass) { //Includes all RTTI, except RTTI4
- DemangledVariable variable =
- new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
- variable.setNamespace(processNamespace(objectCPP.getQualification()));
- resultObject = variable;
- // The following code would be an alternative, depending on whether we get
- // customer complaints or other fall-out from having created a variable here.
- //resultObject = new DemangledUnknown();
- }
- else if (typeinfo instanceof MDGuard) {
- DemangledVariable variable =
- new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
- variable.setNamespace(processNamespace(objectCPP.getQualification()));
- resultObject = variable;
- // The following code would be an alternative, depending on whether we get
- // customer complaints or other fall-out from having created a variable here.
- //resultObject = new DemangledUnknown();
- }
- else {
- // Any others (e.g., case '9')
- DemangledVariable variable =
- new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
- variable.setNamespace(processNamespace(objectCPP.getQualification()));
- resultObject = variable;
- // The following code would be an alternative, depending on whether we get
- // customer complaints or other fall-out from having created a variable here.
- //resultObject = new DemangledUnknown();
- }
- if (typeinfo.isPrivate()) {
- resultObject.setVisibilty("private");
- }
- else if (typeinfo.isProtected()) {
- resultObject.setVisibilty("protected");
- }
- else if (typeinfo.isPublic()) {
- resultObject.setVisibilty("public");
- }
- resultObject.setStatic(typeinfo.isStatic());
- resultObject.setVirtual(typeinfo.isVirtual());
- resultObject.setThunk(typeinfo.isThunk());
- if (typeinfo.isExternC()) {
- resultObject.setSpecialPrefix("extern \"C\"");
- }
- }
- else {
- String baseName = objectCPP.getName();
- if (objectCPP.isString()) {
- MDString mstring = objectCPP.getMDString();
- DemangledString demangledString =
- new DemangledString(mangledSource, demangledSource, mstring.getName(),
- mstring.toString(), mstring.getLength(), mstring.isUnicode());
- resultObject = demangledString;
- }
- else if (baseName.length() != 0) {
- DemangledVariable variable;
- variable = new DemangledVariable(mangledSource, demangledSource, baseName);
- variable.setNamespace(processNamespace(objectCPP.getQualification()));
- resultObject = variable;
- }
- }
- return resultObject;
- // //Various RTTI types (MDType '8' or '9')
- // DemangledVariable variable =
- // new
- // DemangledVariable(objectCPP.getQualifiedName().getBasicName().toString());
- // variable.setNamespace(processNamespace(objectCPP.getQualifiedName()));
- // return variable;
- // TODO: fill in lots of object.____ items
- // object.setVisibilty(typeinfo.g);
- // object.setConst(isConst);
- }
-
- // I think that this is a kludge. The mapping of MDTemplateNameAndArguments
- // doesn't match
- // well to the current DemangledObject hierarchy.
- private DemangledVariable processTemplate(MDTemplateNameAndArguments template) {
- DemangledVariable variable =
- new DemangledVariable(mangledSource, demangledSource, template.toString());
- // NO NAMESPACE for high level template: variable.setNamespace(XXX);
- // DemangledTemplate objectTemplate = new DemangledTemplate();
- // DemangledDataType dataType = new DemangledDataType((String) null);
- // MDTemplateArgumentsList args = template.getArgumentsList();
- // if (args != null) {
- // for (int index = 0; index < args.getNumArgs(); index++) {
- // objectTemplate.addParameter(processDataType(null, (MDDataType)
- // args.getArg(index)));
- // }
- // }
- // dataType.setTemplate(objectTemplate);
- // variable.setDatatype(dataType);
- return variable;
- }
-
- private DemangledFunction processFunction(MDFunctionInfo functionInfo,
- DemangledFunction function) {
- MDFunctionType functionType = (MDFunctionType) functionInfo.getMDType();
- String convention = functionType.getCallingConvention().toString();
- if ("__cdecl".equals(convention) && functionInfo.isMember() && !functionInfo.isStatic()) {
- // TODO: ultimately the presence of a 'this' parareter will not be keyed
- // to the calling convention, but for now we need to force it
- convention = CompilerSpec.CALLING_CONVENTION_thiscall;
- }
- function.setCallingConvention(convention);
- if (functionType.hasReturn() && functionType.getReturnType() != null) {
- MDDataType retType = functionType.getReturnType();
- if (!retType.toString().isEmpty()) {
- function.setReturnType(processDataType(null, retType));
- }
- }
- MDArgumentsList args = functionType.getArgumentsList();
- if (functionType.hasArgs() && args != null) {
- for (int index = 0; index < args.getNumArgs(); index++) {
- function.addParameter(
- new DemangledParameter(processDataType(null, args.getArg(index))));
- }
- }
- if (functionType.isTypeCast()) {
- function.setTypeCast();
- }
- // function.setVirtual(functionType.isVirtual());
- // function.setStatic(functionType.isStatic());
- // if (functionType.isPrivate()) {
- // function.setVisibilty("private");
- // }
- // else if (functionType.isProtected()) {
- // function.setVisibilty("protected");
- // }
- // else if (functionType.isPublic()) {
- // function.setVisibilty("public");
- // }
-
- // TODO: fix this kludge. Need to add appropriate suffixes to DemangledFunction (look
- // at DemangledFunctionPointer?). Missing other possible suffixes from
- // functionType.getCVMod().
- // String suffix = "";
- MDCVMod thisPointerCVMod = functionType.getThisPointerCVMod();
- if (thisPointerCVMod != null) {
- if (thisPointerCVMod.isConst()) {
- function.setTrailingConst();
- }
- if (thisPointerCVMod.isVolatile()) {
- function.setTrailingVolatile();
- }
- if (thisPointerCVMod.isPointer64()) {
- function.setTrailingPointer64();
- }
- if (thisPointerCVMod.isRestricted()) {
- function.setTrailingRestrict();
- }
- if (thisPointerCVMod.isUnaligned()) {
- function.setTrailingUnaligned();
- }
- }
- MDThrowAttribute ta = functionType.getThrowAttribute();
- if (ta != null) {
- function.setThrowAttribute(ta.toString());
- }
-
- // TODO: fill in lots of function.____ items
- return function;
- }
-
- private DemangledFunctionPointer processDemangledFunctionPointer(MDPointerType pointerType) {
- DemangledFunctionPointer functionPointer =
- new DemangledFunctionPointer(mangledSource, demangledSource);
- MDFunctionType functionType = (MDFunctionType) pointerType.getReferencedType();
- functionPointer.setCallingConvention(functionType.getCallingConvention().toString());
- functionPointer.setModifier(pointerType.getCVMod().toString());
- if (functionType.hasReturn() && functionType.getReturnType() != null) {
- functionPointer.setReturnType(processDataType(null, functionType.getReturnType()));
- }
- MDArgumentsList args = functionType.getArgumentsList();
- if (functionType.hasArgs() && args != null) {
- for (int index = 0; index < args.getNumArgs(); index++) {
- functionPointer.addParameter(processDataType(null, args.getArg(index)));
- }
- }
- MDCVMod thisPointerCVMod = functionType.getThisPointerCVMod();
- if (thisPointerCVMod != null) {
- if (thisPointerCVMod.isConst()) {
- functionPointer.setConst();
- }
- if (thisPointerCVMod.isVolatile()) {
- functionPointer.setVolatile();
- }
- if (thisPointerCVMod.isPointer64()) {
- functionPointer.setTrailingPointer64();
- }
- if (thisPointerCVMod.isRestricted()) {
- functionPointer.setTrailingRestrict();
- }
- if (thisPointerCVMod.isUnaligned()) {
- functionPointer.setTrailingUnaligned();
- }
- }
- // TODO: fill in lots of functionPointer.____ items
- return functionPointer;
- }
-
- private DemangledFunctionReference processDemangledFunctionReference(MDModifierType refType) {
- if (!((refType instanceof MDReferenceType) ||
- (refType instanceof MDDataRightReferenceType))) {
- return null; // Not planning on anything else yet.
- }
- DemangledFunctionReference functionReference =
- new DemangledFunctionReference(mangledSource, demangledSource);
- MDFunctionType functionType = (MDFunctionType) refType.getReferencedType();
- functionReference.setCallingConvention(functionType.getCallingConvention().toString());
- functionReference.setModifier(refType.getCVMod().toString());
- if (functionType.hasReturn() && functionType.getReturnType() != null) {
- functionReference.setReturnType(processDataType(null, functionType.getReturnType()));
- }
- MDArgumentsList args = functionType.getArgumentsList();
- if (functionType.hasArgs() && args != null) {
- for (int index = 0; index < args.getNumArgs(); index++) {
- functionReference.addParameter(processDataType(null, args.getArg(index)));
- }
- }
- // TODO: fill in lots of functionReference.____ items
- return functionReference;
- }
-
- private DemangledFunctionIndirect processDemangledFunctionIndirect(
- MDFunctionIndirectType functionIndirectType) {
- DemangledFunctionIndirect functionDefinition =
- new DemangledFunctionIndirect(mangledSource, demangledSource);
- MDFunctionType functionType = (MDFunctionType) functionIndirectType.getReferencedType();
- functionDefinition.setCallingConvention(functionType.getCallingConvention().toString());
- functionDefinition.setModifier(functionIndirectType.getCVMod().toString());
- functionDefinition.incrementPointerLevels();
- if (functionType.hasReturn() && functionType.getReturnType() != null) {
- functionDefinition.setReturnType(processDataType(null, functionType.getReturnType()));
- }
- MDArgumentsList args = functionType.getArgumentsList();
- if (functionType.hasArgs() && args != null) {
- for (int index = 0; index < args.getNumArgs(); index++) {
- functionDefinition.addParameter(processDataType(null, args.getArg(index)));
- }
- }
- // TODO: fill in lots of functionIndirect.____ items
- return functionDefinition;
- }
-
- // The following is/might be a kludge: using DemangledFunctionIndirect to see if it will
- // hold the things that we need; regardless, the follow-on use of the DemangledFunction
- // indirect might be clouded between the real, two underlying types.
- private DemangledFunctionIndirect processDemangledFunctionQuestion(
- MDModifierType modifierType) {
- DemangledFunctionIndirect functionDefinition =
- new DemangledFunctionIndirect(mangledSource, demangledSource);
- MDFunctionType functionType = (MDFunctionType) modifierType.getReferencedType();
- functionDefinition.setCallingConvention(functionType.getCallingConvention().toString());
- functionDefinition.setModifier(modifierType.getCVMod().toString());
- functionDefinition.incrementPointerLevels();
- if (functionType.hasReturn() && functionType.getReturnType() != null) {
- functionDefinition.setReturnType(processDataType(null, functionType.getReturnType()));
- }
- MDArgumentsList args = functionType.getArgumentsList();
- if (functionType.hasArgs() && args != null) {
- for (int index = 0; index < args.getNumArgs(); index++) {
- functionDefinition.addParameter(processDataType(null, args.getArg(index)));
- }
- }
- // TODO: fill in lots of functionIndirect.____ items
- return functionDefinition;
- }
-
- // Passing "DemangledDataType resultDataType" in is a kludge, as this is done so
- // incrementPointerLevels() can be used, but doing this recursion like this loses all
- // storageClass information from the various nested pointers and such. TODO: need to add
- // a "pointer type" with a contained "referenced data type" to DemangledObject (perhaps
- // PointerObject?)
- private DemangledDataType processDataType(DemangledDataType resultDataType,
- MDDataType datatype) {
- if (resultDataType == null) {
- resultDataType =
- new DemangledDataType(mangledSource, demangledSource, getDataTypeName(datatype));
- }
- if (datatype.isSpecifiedSigned()) {
- // Returns true if default signed or specified signed. TODO: There is no place to
- // capture default signed versus specified signed (i.e., there are three types of
- // char: default signed, specified signed, and unsigned)
- resultDataType.setSigned();
- }
- if (datatype.isUnsigned()) {
- resultDataType.setUnsigned();
- }
-
- // Bunch of else-ifs for exclusive types
- if (datatype instanceof MDModifierType) {
- MDModifierType modifierType = (MDModifierType) datatype;
- // if (modifierType.isBased()) {
- // resultDataType.set___();
- // modifierType.getCVMod().getBasedName();
- // }
- if (modifierType.isConst()) {
- resultDataType.setConst();
- }
- if (modifierType.isVolatile()) {
- resultDataType.setVolatile();
- }
- if (modifierType.isPointer64()) {
- resultDataType.setPointer64();
- }
- if (modifierType.isRestrict()) {
- resultDataType.setRestrict();
- }
- if (modifierType.isUnaligned()) {
- resultDataType.setUnaligned();
- }
- resultDataType.setBasedName(modifierType.getBasedName());
- // if (modifierType.isMember()) {
- resultDataType.setMemberScope(modifierType.getMemberScope());
- // }
- // TODO: fix. Following is a kludge because DemangledObject has no DemangledReference
- // with corresponding referencedType.
- if (modifierType instanceof MDArrayBasicType) {
- resultDataType.setArray(1);
- if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
- // MDType ref = modifierType.getReferencedType();
- // TODO: A demangled function reference is needed here.
- // DemangledFunction function = new
- // DemangledFunction(objectCPP.getQualifiedName().getBasicName().toString());
- // function.setNamespace(processNamespace(objectCPP.getQualifiedName()));
- // //resultObject = function;
- // return processFunction(ref, resultDataType);
- }
- else if (modifierType.getReferencedType() instanceof MDDataType) {
- return processDataType(resultDataType,
- (MDDataType) modifierType.getReferencedType());
- }
- else {
- // Empty for now--placeholder for possible future logic.
- }
- }
- else if (modifierType instanceof MDPointerType) {
- if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
- // TODO---------what are we returning... need to work on called routine.
- DemangledFunctionPointer fp =
- processDemangledFunctionPointer((MDPointerType) modifierType);
- // TODO: fix. Following is a kludge because DemangledObject has no
- // DemangledPointer with corresponding referencedType.
- for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
- fp.incrementPointerLevels();
- }
- if (resultDataType.isConst()) {
- fp.setConst();
- }
- if (resultDataType.isVolatile()) {
- fp.setVolatile();
- }
- if (resultDataType.isPointer64()) {
- fp.setPointer64();
- }
- return fp;
- }
- // modifierType.getArrayString();
- // resultDataType.setArray();
- //Processing the referenced type (for Ghidra, and then setting attributes on it)
- DemangledDataType newResult =
- processDataType(resultDataType, (MDDataType) modifierType.getReferencedType());
- newResult.incrementPointerLevels();
- if (modifierType.getCVMod().isConst()) {
- newResult.setConst();
- }
- if (modifierType.getCVMod().isVolatile()) {
- newResult.setVolatile();
- }
- if (modifierType.getCVMod().isPointer64()) {
- newResult.setPointer64();
- }
- return newResult;
- }
- // TODO: fix. Following is a kludge because DemangledObject has no
- // DemangledReference
- // with corresponding referencedType.
- else if (modifierType instanceof MDReferenceType) {
- // TODO---------what are we returning... need to work on called
- // routine.
- if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
- DemangledFunctionReference fr = processDemangledFunctionReference(modifierType);
- // TODO: fix. Following is a kludge because DemangledObject has no
- // DemangledPointer with corresponding referencedType.
- for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
- fr.incrementPointerLevels();
- }
- if (resultDataType.isConst()) {
- fr.setConst();
- }
- if (resultDataType.isVolatile()) {
- fr.setVolatile();
- }
- if (resultDataType.isPointer64()) {
- fr.setPointer64();
- }
- return fr;
- }
- //Processing the referenced type (for Ghidra, and then setting attributes on it)
- DemangledDataType newResult =
- processDataType(resultDataType, (MDDataType) modifierType.getReferencedType());
- newResult.setLValueReference();
- if (modifierType.getCVMod().isConst()) {
- newResult.setConst();
- }
- if (modifierType.getCVMod().isVolatile()) {
- newResult.setVolatile();
- }
- if (modifierType.getCVMod().isPointer64()) {
- newResult.setPointer64();
- }
- return newResult;
- }
- // TODO: fix. Following is a kludge because DemangledObject has no DemangledReference
- // with corresponding referencedType.
- else if (modifierType instanceof MDFunctionIndirectType) {
- // TODO---------what are we returning... need to work on called routine.
- DemangledFunctionIndirect fd =
- processDemangledFunctionIndirect((MDFunctionIndirectType) modifierType);
- for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
- fd.incrementPointerLevels();
- }
- if (resultDataType.isConst()) {
- fd.setConst();
- }
- if (resultDataType.isVolatile()) {
- fd.setVolatile();
- }
- if (resultDataType.isPointer64()) {
- fd.setPointer64();
- }
- return fd;
- }
- else if (modifierType instanceof MDPointerRefDataType) {
- resultDataType.setName(getDataTypeName(datatype));
- // Not sure if this is the correct thing to do for MDPointerRefDataType, but we
- // are just going to assign the referred-to type:
- //Processing the referenced type (for Ghidra, and then setting attributes on it)
- return processDataType(resultDataType,
- (MDDataType) modifierType.getReferencedType());
- }
- else if (modifierType instanceof MDDataReferenceType) {
- // Not sure if this is the correct thing to do for MDDataReferenceType, but we
- // are just going to assign the referred-to type:
- //Processing the referenced type (for Ghidra, and then setting attributes on it)
- processDataType(resultDataType, (MDDataType) modifierType.getReferencedType());
- if (modifierType.getCVMod().isConst()) {
- resultDataType.setConst();
- }
- if (modifierType.getCVMod().isVolatile()) {
- resultDataType.setVolatile();
- }
- return resultDataType;
- }
- else if (modifierType instanceof MDDataRightReferenceType) {
- if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
- resultDataType.setName(getDataTypeName(datatype));
- // TODO---------what are we returning... need to work on called routine.
- DemangledFunctionReference fr = processDemangledFunctionReference(modifierType);
- // TODO: fix. Following is a kludge because DemangledObject has no
- // DemangledPointer with corresponding referencedType.
- for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
- fr.incrementPointerLevels();
- }
- if (resultDataType.isConst()) {
- fr.setConst();
- }
- if (resultDataType.isVolatile()) {
- fr.setVolatile();
- }
- if (resultDataType.isPointer64()) {
- fr.setPointer64();
- }
- return fr;
- }
- //Processing the referenced type (for Ghidra, and then setting attributes on it)
- processDataType(resultDataType, (MDDataType) modifierType.getReferencedType());
- resultDataType.setRValueReference();
- if (modifierType.getCVMod().isConst()) {
- resultDataType.setConst();
- }
- if (modifierType.getCVMod().isVolatile()) {
- resultDataType.setVolatile();
- }
- if (modifierType.getCVMod().isPointer64()) {
- resultDataType.setPointer64();
- }
- return resultDataType;
- }
- else {
- // not pointer, reference, or array type
- if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
- // TODO---------what are we returning... need to work on called routine.
- DemangledFunctionIndirect fx = processDemangledFunctionQuestion(modifierType);
- // TODO: fix. Following is a kludge because DemangledObject has no
- // DemangledPointer with corresponding referencedType.
- if (resultDataType.isConst()) {
- fx.setConst();
- }
- if (resultDataType.isVolatile()) {
- fx.setVolatile();
- }
- if (resultDataType.isPointer64()) {
- fx.setPointer64();
- }
- return fx;
- }
- // resultDataType.incrementPointerLevels();//Not sure if we should do/use this.
- DemangledDataType dataType =
- processDataType(resultDataType, (MDDataType) modifierType.getReferencedType());
- if (modifierType.getCVMod().isConst()) {
- resultDataType.setConst();
- }
- if (modifierType.getCVMod().isVolatile()) {
- resultDataType.setVolatile();
- }
- if (modifierType.getCVMod().isPointer64()) {
- resultDataType.setPointer64();
- }
- return dataType;
- }
- }
- else if (datatype instanceof MDComplexType) {
- MDComplexType complexType = (MDComplexType) datatype;
- // Hope this is correct... will return "class" or other
- resultDataType.setName(complexType.getNamespace().getName());
- // TODO: setNamespace() wants a "DemangledType" for a namespace.
- // Two problems:
- // 1) we don't have an appropriate method to use
- // 2) not sure DemangledType is appropriate; in MDComplexType we have an
- // MDQualification--not an MDQualifiedName
- resultDataType.setNamespace(processNamespace(complexType.getNamespace()));
-
- // Bunch of else-ifs for exclusive types
- if (datatype instanceof MDEnumType) {
- resultDataType.setEnum();
- // Put in underlying type (for sizing too).
- MDEnumType enumType = (MDEnumType) datatype;
- resultDataType.setEnumType(enumType.getUnderlyingFullTypeName());
- }
- else if (datatype instanceof MDClassType) {
- resultDataType.setClass();
- }
- else if (datatype instanceof MDStructType) {
- resultDataType.setStruct();
- }
- else if (datatype instanceof MDUnionType) {
- resultDataType.setUnion();
- }
- else if (datatype instanceof MDCoclassType) {
- resultDataType.setCoclass();
- }
- else if (datatype instanceof MDCointerfaceType) {
- resultDataType.setCointerface();
- }
- }
- else if (datatype instanceof MDReferenceType) {
- resultDataType.setLValueReference();
- }
- else if (datatype instanceof MDArrayBasicType) {
- resultDataType.setArray(1);
- }
- else if (datatype instanceof MDVarArgsType) {
- resultDataType.setVarArgs();
- }
- else if (datatype instanceof MDArrayReferencedType arrRefType) {
- return processDataType(resultDataType, arrRefType.getReferencedType());
- }
- else if (datatype instanceof MDStdNullPtrType) {
- resultDataType.setName(datatype.toString());
- }
- else {
- // MDDataType
- // TODO MDW64Type needs repeated reference type parsing, just as modifier types need
- // them.
- resultDataType.setName(getDataTypeName(datatype));
- }
- // TODO: No place to indicate a general pointer--we can indicate Pointer64
- // TODO: Not sure if anything fits this: resultDataType.setComplex();
- // TODO: resultDataType.setTemplate(); //TODO: Not sure templates are data types
- // according to how MSFT demangles them.
- // TODO: resultDataType.setTemplate(null); //TODO: Not sure templates are data types
- // according to how MSFT demangles them.
-
- return resultDataType;
- }
-
- /**
- * Returns either a formal type name or a representative type name to fill into a
- * MangledDataType if the formal name is blank
- * @return the name
- */
- private String getDataTypeName(MDDataType dataType) {
- String name = dataType.getName();
- if (!name.isBlank()) {
- return name;
- }
- name = dataType.getTypeName();
- if (!name.isBlank()) {
- return name;
- }
- return dataType.toString();
- }
}
diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangVS2015.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangVS2015.java
index 71f2e8cf81..a876b23d13 100644
--- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangVS2015.java
+++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/MDMangVS2015.java
@@ -28,9 +28,8 @@ import mdemangler.template.MDTemplateArgumentsList;
public class MDMangVS2015 extends MDMang {
@Override
- public MDParsableItem demangle(String mangledIn, boolean errorOnRemainingChars)
- throws MDException {
- MDParsableItem returnedItem = super.demangle(mangledIn, errorOnRemainingChars);
+ public MDParsableItem demangle() throws MDException {
+ MDParsableItem returnedItem = super.demangle();
//VS2015 does not understand all of the object types that we made up. These all fall
// under MDObjectReserved; but it does understand MDObjectBracket objects.
if (returnedItem instanceof MDObjectBracket) {
diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectC.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectC.java
index c1e81b1344..db2f43bfb7 100644
--- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectC.java
+++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectC.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.
@@ -25,21 +25,131 @@ import mdemangler.naming.MDFragmentName;
*/
public class MDObjectC extends MDObject {
protected MDFragmentName name;
+ int conventionIndex;
+ int numParameterBytes;
+
+ private final String callingConvention[] =
+ { "__cdecl", "__stdcall", "__fastcall", "__vectorcall" };
public MDObjectC(MDMang dmang) {
super(dmang);
+ conventionIndex = -1;
+ numParameterBytes = 0;
name = new MDFragmentName(dmang);
}
+ /**
+ * Returns the name
+ * @return the name
+ */
+ public String getName() {
+ if (name == null) {
+ return null;
+ }
+ return name.getName();
+ }
+
+ /**
+ * Returns a calling convention string if the C object is determined to be a function with
+ * a specified convention
+ * @return the convention or {@code null} if not determined to be a function with convention
+ */
+ public String getCallingConvention() {
+ if (conventionIndex == -1) {
+ return null;
+ }
+ return callingConvention[conventionIndex];
+ }
+
+ /**
+ * Returns the number of parameter bytes if the C object is determined to be a function with
+ * a specified convention
+ * @return the number of bytes; will always be zero for __cdecl
+ */
+ public int getNumParameterBytes() {
+ return numParameterBytes;
+ }
+
@Override
public void insert(StringBuilder builder) {
+ // We've come up with the demangling output for the function format ourselves. This
+ // format does not output anything for __cdecl (default) convention
+ if (conventionIndex >= 1 && conventionIndex <= 3) {
+ builder.append(callingConvention[conventionIndex]);
+ builder.append(' ');
+ }
builder.append(name);
+ if (conventionIndex >= 1 && conventionIndex <= 3) {
+ builder.append(',');
+ builder.append(numParameterBytes);
+ }
}
+ /*
+ * Follow are C-style mangling scheme under 32-bit model; __vectorcall also valid for 64-bit
+ * __cdecl: '_' prefix; no suffix; example "_name"
+ * __stdcall: '_' prefix; "@" suffix; example "_name@12"
+ * __fastcall: '@' prefix; "@" suffix; example "@name@12"
+ * __vectorcall: no prefix; "@@" suffix; example "name@@12"
+ */
@Override
protected void parseInternal() throws MDException {
- name.parse();
+ if (!dmang.isFunction()) {
+ name.parse();
+ return;
+ }
+
+ int index = dmang.getIndex();
+ char c = dmang.peek();
+ if (c == '@') {
+ conventionIndex = 2;
+ dmang.next();
+ }
+ else if (c == '_') {
+ conventionIndex = 0; // will be 0 or 1
+ dmang.next();
+ }
+ else {
+ conventionIndex = 3;
+ }
+ name.parse(); // This strips a trailing '@' if it exists
+ c = dmang.peek();
+ if (c == '@') {
+ if (conventionIndex != 3) {
+ throw new MDException("Error parsing C Object calling convention");
+ }
+ dmang.next(); // skip the '@'
+ }
+ else if (conventionIndex == 0 &&
+ dmang.getMangledSymbol().charAt(dmang.getIndex() - 1) == '@') {
+ conventionIndex = 1;
+ }
+
+ if (dmang.getArchitectureSize() != 32 && conventionIndex != 3) {
+ conventionIndex = -1;
+ dmang.setIndex(index); // reset iterator back to original location
+ name.parse();
+ return;
+ }
+
+ if (conventionIndex != 0) {
+ numParameterBytes = parseNumParameterBytes();
+ }
+
}
+
+ private int parseNumParameterBytes() throws MDException {
+ int loc = dmang.getIndex();
+ String str = dmang.getMangledSymbol().substring(loc);
+ dmang.setIndex(loc + dmang.getNumCharsRemaining());
+ try {
+ return Integer.parseInt(str);
+ }
+ catch (NumberFormatException e) {
+ throw new MDException("Error parsing C Object calling convention");
+ }
+ }
+
}
/******************************************************************************/
diff --git a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectCPP.java b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectCPP.java
index c529b55ec8..b61c19e994 100644
--- a/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectCPP.java
+++ b/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectCPP.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.
@@ -56,6 +56,14 @@ public class MDObjectCPP extends MDObject {
return this;
}
+ /**
+ * Returns whether the object was a hashed object
+ * @return {@code true} if was a hashed object
+ */
+ public boolean isHashObject() {
+ return hashedObjectFlag;
+ }
+
/**
* Returns the name of the symbol, minus any namespace component.
* @return the name.
diff --git a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDBaseTestConfiguration.java b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDBaseTestConfiguration.java
index d0ae855f55..c81d33aa2e 100644
--- a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDBaseTestConfiguration.java
+++ b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDBaseTestConfiguration.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.
@@ -44,6 +44,7 @@ public class MDBaseTestConfiguration {
// Internal variables
protected String mangled;
protected MDParsableItem demangItem;
+ protected boolean isFunction = false;
protected String demangled;
protected String truth;
@@ -61,6 +62,10 @@ public class MDBaseTestConfiguration {
}
}
+ public void setIsFunction(boolean isFunctionArg) {
+ isFunction = isFunctionArg;
+ }
+
/**
* Runs through the process of creating a demangler, demangling a symbol string,
* testing the output, and performing other ancillary outputs and tests.
@@ -85,6 +90,7 @@ public class MDBaseTestConfiguration {
outputInfo.append(getTestHeader());
}
+ mdm.setIsFunction(isFunction);
// Meant to be overridden, as needed by extended classes
demangItem = doDemangleSymbol(mdm, mangled);
demangled = (demangItem == null) ? "" : demangItem.toString();
@@ -123,6 +129,7 @@ public class MDBaseTestConfiguration {
}
}
+ // Need to do a better job here
private boolean isMangled(String s) {
if (s.charAt(0) == '?') {
return true;
@@ -130,9 +137,9 @@ public class MDBaseTestConfiguration {
else if (s.startsWith("__")) {
return true;
}
- else if ((s.charAt(0) == '_') || Character.isUpperCase(s.charAt(1))) {
- return true;
- }
+// else if ((s.charAt(0) == '_') || Character.isUpperCase(s.charAt(1))) {
+// return true;
+// }
return false;
}
@@ -193,8 +200,10 @@ public class MDBaseTestConfiguration {
// Meant to be overridden, as needed by extended classes
protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception {
+ mdmIn.setMangledSymbol(mangledIn);
+ mdmIn.setErrorOnRemainingChars(true);
try {
- return mdmIn.demangle(mangledIn, true);
+ return mdmIn.demangle();
}
catch (MDException e) {
return null;
diff --git a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDGhidraTestConfiguration.java b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDGhidraTestConfiguration.java
index 09959ff954..0b647e3545 100644
--- a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDGhidraTestConfiguration.java
+++ b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDGhidraTestConfiguration.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,8 +15,6 @@
*/
package mdemangler;
-import ghidra.app.util.demangler.DemangledObject;
-
/**
* This class is a derivation of MDBaseTestConfiguration (see javadoc there). This
* class must choose the appropriate truth from MDMangBaseTest (new truths might
@@ -26,9 +24,9 @@ import ghidra.app.util.demangler.DemangledObject;
*/
public class MDGhidraTestConfiguration extends MDBaseTestConfiguration {
- protected DemangledObject demangledObject;
- protected String demangledGhidraObject;
- protected DemangledObject demangledObjectCheck;
+// protected DemangledObject demangledObject;
+// protected String demangledGhidraObject;
+// protected DemangledObject demangledObjectCheck;
public MDGhidraTestConfiguration(boolean quiet) {
super(quiet);
@@ -48,10 +46,12 @@ public class MDGhidraTestConfiguration extends MDBaseTestConfiguration {
@Override
protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception {
MDParsableItem returnItem;
+ mdmIn.setMangledSymbol(mangledIn);
+ mdmIn.setErrorOnRemainingChars(true);
try {
// For first boolean: set true in operational mode.
- returnItem = ((MDMangGhidra) mdmIn).demangle(mangledIn, false, false);
- demangledObject = ((MDMangGhidra) mdmIn).getObject();
+ returnItem = mdmIn.demangle();
+// demangledObject = ((MDMangGhidra) mdmIn).getObject();
}
catch (MDException e) {
returnItem = null;
@@ -62,14 +62,14 @@ public class MDGhidraTestConfiguration extends MDBaseTestConfiguration {
@Override
protected void doBasicTestsAndOutput() throws Exception {
super.doBasicTestsAndOutput();
- if (demangledObject != null) {
- demangledGhidraObject = demangledObject.toString();
- outputInfo.append("demangl: " + demangledGhidraObject + "\n");
- }
- else {
- demangledGhidraObject = "";
- outputInfo.append("demangled: NO RESULT\n");
- }
+// if (demangledObject != null) {
+// demangledGhidraObject = demangledObject.toString();
+// outputInfo.append("demangl: " + demangledGhidraObject + "\n");
+// }
+// else {
+// demangledGhidraObject = "";
+// outputInfo.append("demangled: NO RESULT\n");
+// }
// For checking the original results, for comparison purposes, this code should probably
// be calling the MicrosoftWineDemangler.
// try {
@@ -86,38 +86,38 @@ public class MDGhidraTestConfiguration extends MDBaseTestConfiguration {
// }
}
- @Override
- protected void doExtraProcCheck() throws Exception {
- if ((demangledObjectCheck != null) && (demangledObject != null)) {
- if (demangledObjectCheck.getClass() != demangledObject.getClass()) {
- outputInfo.append("ObjComp: notequal NEW: " + demangledObject.getClass().getName() +
- ", OLD: " + demangledObjectCheck.getClass().getName() + "\n");
- }
- else {
- outputInfo.append("ObjComp: equal NEW: " + demangledObject.getClass().getName() +
- ", OLD: " + demangledObjectCheck.getClass().getName() + "\n");
- }
- }
- else {
- if ((demangledObjectCheck == null) && (demangledObject == null)) {
- outputInfo.append("ObjComp: Not possible -- both null\n");
- }
- else if (demangledObjectCheck == null) {
- outputInfo.append("ObjComp: Not possible -- OLD null; NEW: " +
- demangledObject.getClass().getName() + "\n");
- }
- else {
- outputInfo.append("ObjComp: Not possible -- NEW null; OLD: " +
- demangledObjectCheck.getClass().getName() + "\n");
- }
- }
- if (ghidraTestStringCompare(outputInfo, demangled, demangledGhidraObject)) {
- outputInfo.append("RESULTS MATCH------******\n");
- }
- else {
- outputInfo.append("RESULTS MISMATCH------*********************************\n");
- }
- }
+// @Override
+// protected void doExtraProcCheck() throws Exception {
+// if ((demangledObjectCheck != null) && (demangledObject != null)) {
+// if (demangledObjectCheck.getClass() != demangledObject.getClass()) {
+// outputInfo.append("ObjComp: notequal NEW: " + demangledObject.getClass().getName() +
+// ", OLD: " + demangledObjectCheck.getClass().getName() + "\n");
+// }
+// else {
+// outputInfo.append("ObjComp: equal NEW: " + demangledObject.getClass().getName() +
+// ", OLD: " + demangledObjectCheck.getClass().getName() + "\n");
+// }
+// }
+// else {
+// if ((demangledObjectCheck == null) && (demangledObject == null)) {
+// outputInfo.append("ObjComp: Not possible -- both null\n");
+// }
+// else if (demangledObjectCheck == null) {
+// outputInfo.append("ObjComp: Not possible -- OLD null; NEW: " +
+// demangledObject.getClass().getName() + "\n");
+// }
+// else {
+// outputInfo.append("ObjComp: Not possible -- NEW null; OLD: " +
+// demangledObjectCheck.getClass().getName() + "\n");
+// }
+// }
+// if (ghidraTestStringCompare(outputInfo, demangled, demangledGhidraObject)) {
+// outputInfo.append("RESULTS MATCH------******\n");
+// }
+// else {
+// outputInfo.append("RESULTS MISMATCH------*********************************\n");
+// }
+// }
private boolean ghidraTestStringCompare(StringBuilder outputInfoArg, String truthString,
String ghidraString) {
diff --git a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.java b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.java
index b592b64cbf..11b71a3ffa 100644
--- a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.java
+++ b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangBaseTest.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.
@@ -194,6 +194,12 @@ public class MDMangBaseTest extends AbstractGenericTest {
ms2013Truth);
}
+ private void demangleAndTestFunction() throws Exception {
+ testConfiguration.setIsFunction(true);
+ testConfiguration.demangleAndTest(testName, mangled, mdTruth, msTruth, ghTruth,
+ ms2013Truth);
+ }
+
@Test
public void testTripleQ0() throws Exception {
mangled = "???__E??_7name0@name1@@6B@@@YMXXZ@?A0x647dec29@@$$FYMXXZ";
@@ -15312,6 +15318,81 @@ public class MDMangBaseTest extends AbstractGenericTest {
demangleAndTest();
}
+ //=====================
+ /*
+ * Follow are C-style mangling scheme under 32-bit model; __vectorcall also valid for 64-bit
+ * __cdecl: '_' prefix; no suffix; example "_name"
+ * __stdcall: '_' prefix; "@" suffix; example "_name@12"
+ * __fastcall: '@' prefix; "@" suffix; example "@name@12"
+ * __vectorcall: no prefix; "@@" suffix; example "name@@12"
+ *
+ * We've come up with the string output formats for the C-style mangling scheme.
+ */
+
+ @Test
+ public void testCStyleCdeclFunction() throws Exception {
+ mangled = "_name";
+ mdTruth = "name";
+ msTruth = "";
+ demangleAndTestFunction();
+ }
+
+ @Test
+ public void testCStyleCdeclNoFunction() throws Exception {
+ mangled = "_name";
+ mdTruth = "_name";
+ msTruth = "";
+ demangleAndTest();
+ }
+
+ @Test
+ public void testCStyleStdcallFunction() throws Exception {
+ mangled = "_name@12";
+ mdTruth = "__stdcall name,12";
+ msTruth = "";
+ demangleAndTestFunction();
+ }
+
+ @Test
+ public void testCStyleStdcallNoFunction() throws Exception {
+ mangled = "_name@12";
+ mdTruth = "";
+ msTruth = "";
+ demangleAndTest();
+ }
+
+ @Test
+ public void testCStyleFastcallFunction() throws Exception {
+ mangled = "@name@12";
+ mdTruth = "__fastcall name,12";
+ msTruth = "";
+ demangleAndTestFunction();
+ }
+
+ @Test
+ public void testCStyleFastcallNoFunction() throws Exception {
+ mangled = "@name@12";
+ mdTruth = "";
+ msTruth = "";
+ demangleAndTest();
+ }
+
+ @Test
+ public void testCStyleVectorcallFunction() throws Exception {
+ mangled = "name@@12";
+ mdTruth = "__vectorcall name,12";
+ msTruth = "";
+ demangleAndTestFunction();
+ }
+
+ @Test
+ public void testCStyleVectorcallNoFunction() throws Exception {
+ mangled = "name@@12";
+ mdTruth = "";
+ msTruth = "";
+ demangleAndTest();
+ }
+
//=====================
//TODO: ignore for now.
diff --git a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangExtraTest.java b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangExtraTest.java
index c3c5fcf105..5cfb137c6c 100644
--- a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangExtraTest.java
+++ b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangExtraTest.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.
@@ -22,7 +22,6 @@ import java.util.List;
import org.junit.Test;
import generic.test.AbstractGenericTest;
-import ghidra.app.util.demangler.DemangledObject;
import mdemangler.naming.MDQualification;
import mdemangler.object.MDObjectCPP;
import mdemangler.typeinfo.MDVxTable;
@@ -33,32 +32,6 @@ import mdemangler.typeinfo.MDVxTable;
*/
public class MDMangExtraTest extends AbstractGenericTest {
- @Test
- //This test checks that we can provide a mangled string for a function namespace.
- // The return String from getOriginalMangled() is not null only for this special
- // circumstance. So, in normal processing, we should check it for non-null to
- // determine that we have a result of this form.
- // The symbol here is from our cn3.cpp source target.
- public void testFunctionNamespace() throws Exception {
- String mangled = "?fn3@?2??Bar3@Foo2b@@SAHXZ@4HA";
- String wholeTruth = "int `public: static int __cdecl Foo2b::Bar3(void)'::`3'::fn3";
- String functionNamespaceMangledTruth = "?Bar3@Foo2b@@SAHXZ";
- String functionNamespaceTruth = "public: static int __cdecl Foo2b::Bar3(void)";
-
- MDMangGhidra demangler = new MDMangGhidra();
- MDParsableItem item = demangler.demangle(mangled, true, true);
-
- String demangled = item.toString();
- assertEquals(wholeTruth, demangled);
- DemangledObject obj = demangler.getObject();
- String mangledFunctionNamespace = obj.getNamespace().getNamespace().getMangledString();
- assertEquals(functionNamespaceMangledTruth, mangledFunctionNamespace);
-
- item = demangler.demangle(mangledFunctionNamespace, true, true);
- demangled = item.toString();
- assertEquals(functionNamespaceTruth, demangled);
- }
-
@Test
public void testVxTableNestedQualifications() throws Exception {
// Test string taken from MDMangBaseTest
@@ -66,7 +39,10 @@ public class MDMangExtraTest extends AbstractGenericTest {
String truth = "const b::a::`vftable'{for `e::d::c's `h::g::f's `k::j::i'}";
MDMangGhidra demangler = new MDMangGhidra();
- MDParsableItem item = demangler.demangle(mangled, true, true);
+ demangler.setMangledSymbol(mangled);
+ demangler.setErrorOnRemainingChars(true);
+ demangler.setDemangleOnlyKnownPatterns(true);
+ MDParsableItem item = demangler.demangle();
String demangled = item.toString();
assertEquals(truth, demangled);
@@ -88,7 +64,9 @@ public class MDMangExtraTest extends AbstractGenericTest {
String truth = "enum `void __cdecl name2::name1(bool)'::name0";
MDMangGhidra demangler = new MDMangGhidra();
- MDParsableItem item = demangler.demangleType(mangled, true); // note demangleType()
+ demangler.setMangledSymbol(mangled);
+ demangler.setErrorOnRemainingChars(true);
+ MDParsableItem item = demangler.demangleType(); // note demangleType()
String demangled = item.toString();
assertEquals(truth, demangled);
diff --git a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangUtilsTest.java b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangUtilsTest.java
index 79f5f756ee..a41ec7a5b8 100644
--- a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangUtilsTest.java
+++ b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDMangUtilsTest.java
@@ -43,7 +43,9 @@ public class MDMangUtilsTest extends AbstractGenericTest {
"class `struct name1::name2 __cdecl name1::name0(struct name1::name3,struct name1::name4)'::`1'::";
MDMangGhidra demangler = new MDMangGhidra();
- MDDataType item = demangler.demangleType(mangled, true);
+ demangler.setMangledSymbol(mangled);
+ demangler.setErrorOnRemainingChars(true);
+ MDDataType item = demangler.demangleType();
String demangled = item.toString();
SymbolPath symbolPath = MDMangUtils.getSymbolPath(item);
@@ -69,7 +71,9 @@ public class MDMangUtilsTest extends AbstractGenericTest {
"struct name8::name7::name0 && __ptr64>";
MDMangGhidra demangler = new MDMangGhidra();
- MDDataType item = demangler.demangleType(mangled, true);
+ demangler.setMangledSymbol(mangled);
+ demangler.setErrorOnRemainingChars(true);
+ MDDataType item = demangler.demangleType();
String demangled = item.toString();
SymbolPath symbolPath = MDMangUtils.getSymbolPath(item);
@@ -94,7 +98,9 @@ public class MDMangUtilsTest extends AbstractGenericTest {
"struct name4::name3::name0 && __ptr64>";
MDMangGhidra demangler = new MDMangGhidra();
- MDDataType item = demangler.demangleType(mangled, true);
+ demangler.setMangledSymbol(mangled);
+ demangler.setErrorOnRemainingChars(true);
+ MDDataType item = demangler.demangleType();
String demangled = item.toString();
SymbolPath symbolPath = MDMangUtils.getSymbolPath(item);
diff --git a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDVS2013TestConfiguration.java b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDVS2013TestConfiguration.java
index a8e0143158..7226ee7e3f 100644
--- a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDVS2013TestConfiguration.java
+++ b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDVS2013TestConfiguration.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.
@@ -41,8 +41,10 @@ public class MDVS2013TestConfiguration extends MDBaseTestConfiguration {
@Override
protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception {
+ mdmIn.setMangledSymbol(mangledIn);
+ // We are not setting errorOnRemainingChars to true (diff from base test)
try {
- return mdmIn.demangle(mangledIn, false); // "false" is different
+ return mdmIn.demangle();
}
catch (MDException e) {
return null;
diff --git a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDVS2015TestConfiguration.java b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDVS2015TestConfiguration.java
index 2ab8e3c80b..a113ca20d4 100644
--- a/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDVS2015TestConfiguration.java
+++ b/Ghidra/Features/MicrosoftDmang/src/test/java/mdemangler/MDVS2015TestConfiguration.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.
@@ -36,8 +36,10 @@ public class MDVS2015TestConfiguration extends MDBaseTestConfiguration {
@Override
protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception {
+ mdmIn.setMangledSymbol(mangledIn);
+ // We are not setting errorOnRemainingChars to true (diff from base test)
try {
- return mdmIn.demangle(mangledIn, false); // "false" is different
+ return mdmIn.demangle();
}
catch (MDException e) {
return null;
diff --git a/Ghidra/Features/PDB/developer_scripts/DumpAllSymbolsDemangledScript.java b/Ghidra/Features/PDB/developer_scripts/DumpAllSymbolsDemangledScript.java
index 2645ab3a3d..9d3148a9c1 100644
--- a/Ghidra/Features/PDB/developer_scripts/DumpAllSymbolsDemangledScript.java
+++ b/Ghidra/Features/PDB/developer_scripts/DumpAllSymbolsDemangledScript.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.
@@ -75,8 +75,10 @@ public class DumpAllSymbolsDemangledScript extends GhidraScript {
*/
private static String getDemangledString(String mangledString) {
MDMangGhidra demangler = new MDMangGhidra();
+ demangler.setMangledSymbol(mangledString);
+ demangler.setErrorOnRemainingChars(true);
try {
- MDParsableItem parsableItem = demangler.demangle(mangledString, true);
+ MDParsableItem parsableItem = demangler.demangle();
if (parsableItem instanceof MDObjectCPP) {
MDObjectCPP mdObject = (MDObjectCPP) parsableItem;
return mdObject.getQualifiedName().toString();
diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java
index dfa9499cbe..afd8bec998 100644
--- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java
+++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java
@@ -118,8 +118,10 @@ public abstract class AbstractComplexTypeApplier extends MsDataTypeApplier {
private static SymbolPath getSymbolPathFromMangledTypeName(String mangledString,
String fullPathName) {
MDMang demangler = new MDMangGhidra();
+ demangler.setErrorOnRemainingChars(true);
+ demangler.setMangledSymbol(mangledString);
try {
- MDDataType mdDataType = demangler.demangleType(mangledString, true);
+ MDDataType mdDataType = demangler.demangleType();
// 20240626: Ultimately, it might be better to retrieve the Demangled-type to pass
// to the DemangledObject.createNamespace() method to convert to a true Ghidra
// Namespace that are flagged as functions (not capable at this time) or types or
diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java
index d619b9b627..0446724034 100644
--- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java
+++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.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.
@@ -798,8 +798,10 @@ public class PdbResearch {
return null;
}
MDMangGhidra demangler = new MDMangGhidra();
+ demangler.setMangledSymbol(mangledString);
+ demangler.setErrorOnRemainingChars(true);
try {
- MDParsableItem parsableItem = demangler.demangle(mangledString, true);
+ MDParsableItem parsableItem = demangler.demangle();
if (parsableItem instanceof MDObjectCPP) {
MDObjectCPP mdObject = (MDObjectCPP) parsableItem;
return mdObject.getQualifiedName().toString();
diff --git a/Ghidra/Features/SwiftDemangler/ghidra_scripts/SwiftDemanglerScript.java b/Ghidra/Features/SwiftDemangler/ghidra_scripts/SwiftDemanglerScript.java
index 8b046a3a26..7dcdcb0ab4 100644
--- a/Ghidra/Features/SwiftDemangler/ghidra_scripts/SwiftDemanglerScript.java
+++ b/Ghidra/Features/SwiftDemangler/ghidra_scripts/SwiftDemanglerScript.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.
@@ -19,6 +19,7 @@
//@category Demangler
import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledObject;
+import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.swift.*;
import ghidra.app.util.demangler.swift.SwiftNativeDemangler.SwiftNativeDemangledOutput;
import ghidra.program.model.symbol.*;
@@ -53,12 +54,14 @@ public class SwiftDemanglerScript extends GhidraScript {
println("No mangled Swift symbols found at " + currentAddress);
return;
}
-
+
SwiftNativeDemangler nativeDemangler = new SwiftNativeDemangler(options.getSwiftDir());
SwiftNativeDemangledOutput demangledOutput = nativeDemangler.demangle(mangled);
println(demangledOutput.toString());
-
- DemangledObject demangledObject = demangler.demangle(mangled);
+
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, options, currentProgram, currentAddress);
+ DemangledObject demangledObject = demangler.demangle(mangledContext);
if (demangledObject != null) {
println(demangledObject.getClass().getSimpleName() + " " + mangled + " --> " +
demangledObject);
diff --git a/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/plugin/core/analysis/SwiftDemanglerAnalyzer.java b/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/plugin/core/analysis/SwiftDemanglerAnalyzer.java
index 5937c9b8b1..48c58cd410 100644
--- a/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/plugin/core/analysis/SwiftDemanglerAnalyzer.java
+++ b/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/plugin/core/analysis/SwiftDemanglerAnalyzer.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.
@@ -57,13 +57,13 @@ public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
private File swiftDir;
private boolean useIncompletePrefix = true;
private boolean useUnsupportedPrefix = true;
- private SwiftDemangler demangler = new SwiftDemangler();
/**
* Creates a new {@link SwiftDemanglerAnalyzer}
*/
public SwiftDemanglerAnalyzer() {
super(NAME, DESCRIPTION);
+ demangler = new SwiftDemangler();
setDefaultEnablement(true);
}
@@ -76,7 +76,7 @@ public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
try {
- demangler.initialize(program);
+ ((SwiftDemangler) demangler).initialize(program);
}
catch (IOException e) {
log.appendMsg(e.getMessage());
@@ -86,9 +86,9 @@ public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
}
@Override
- protected DemangledObject doDemangle(String mangled, DemanglerOptions options, MessageLog log)
+ protected DemangledObject doDemangle(MangledContext mangledContext, MessageLog log)
throws DemangledException {
- return demangler.demangle(mangled, options);
+ return demangler.demangle(mangledContext);
}
@Override
diff --git a/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/util/demangler/swift/SwiftDemangler.java b/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/util/demangler/swift/SwiftDemangler.java
index 4fe64833ff..a36d05a8f7 100644
--- a/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/util/demangler/swift/SwiftDemangler.java
+++ b/Ghidra/Features/SwiftDemangler/src/main/java/ghidra/app/util/demangler/swift/SwiftDemangler.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.
@@ -54,7 +54,7 @@ public class SwiftDemangler implements Demangler {
/**
* Creates a new {@link SwiftDemangler} that is associated with the given {@link Program}
- *
+ *
* @param program The {@link Program} to demangle
* @throws IOException if there was a problem parsing the Swift type metadata
*/
@@ -73,12 +73,6 @@ public class SwiftDemangler implements Demangler {
return new SwiftDemanglerOptions();
}
- @Override
- public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
- throws DemangledException {
- return demangle(mangled);
- }
-
public void initialize(Program program) throws IOException {
cache = new HashMap<>();
nativeDemangler = null;
@@ -95,6 +89,7 @@ public class SwiftDemangler implements Demangler {
}
@Override
+ @Deprecated(since = "11.3", forRemoval = true)
public DemangledObject demangle(String mangled, DemanglerOptions op) throws DemangledException {
SwiftDemanglerOptions options = getSwiftDemanglerOptions(op);
Demangled demangled = getDemangled(mangled, options);
@@ -111,9 +106,18 @@ public class SwiftDemangler implements Demangler {
return null;
}
+ @Override
+ public DemangledObject demangle(MangledContext context) throws DemangledException {
+ DemanglerOptions op = context.getOptions();
+ String mangled = context.getMangled();
+ DemangledObject demangledObject = demangle(mangled, op);
+ demangledObject.setMangledContext(context);
+ return demangledObject;
+ }
+
/**
* Get a new {@link Demangled} by demangling the given mangled string
- *
+ *
* @param mangled The mangled string
* @param op The options (could be null)
* @return A new {@link Demangled}
@@ -145,7 +149,7 @@ public class SwiftDemangler implements Demangler {
/**
* Gets the {@link SwiftTypeMetadata}
- *
+ *
* @return The {@link SwiftTypeMetadata}, or null if it is not available
*/
public SwiftTypeMetadata getTypeMetadata() {
@@ -154,7 +158,7 @@ public class SwiftDemangler implements Demangler {
/**
* Checks to see whether the given symbol name is a mangled Swift symbol
- *
+ *
* @param symbolName The symbol name to check
* @return True if the given symbol name is a mangled Swift symbol; otherwise, false
*/
@@ -165,7 +169,7 @@ public class SwiftDemangler implements Demangler {
/**
* Gets the {@link SwiftDemanglerOptions} from the given {@link DemanglerOptions}
- *
+ *
* @param opt The options
* @return The @link SwiftDemanglerOptions}
* @throws DemangledException If the given options are not {@link SwiftDemanglerOptions}
@@ -180,7 +184,7 @@ public class SwiftDemangler implements Demangler {
/**
* Ensures that this demangler has access to a {@link SwiftNativeDemangler}
- *
+ *
* @param options The options
* @throws DemangledException if there was a problem getting the {@link SwiftNativeDemangler}
*/
diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/demangler/DemangledAddressTableTest.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/demangler/DemangledAddressTableTest.java
index 6889b77e14..1a2afffcc3 100644
--- a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/demangler/DemangledAddressTableTest.java
+++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/demangler/DemangledAddressTableTest.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.
@@ -19,6 +19,7 @@ import static org.junit.Assert.*;
import org.junit.*;
+import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
@@ -74,9 +75,10 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
}
/**
- * Test that the DemangledAddressTable will properly create a sequence of data
+ * Test that the DemangledAddressTable will properly create a sequence of data
* pointers. This test deals with the simple case where no existing data
* is present. End of block considered end of address table.
+ * @throws Exception upon error
*/
@Test
public void testApply_NoNextSymbol_NoData() throws Exception {
@@ -88,10 +90,13 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
SymbolTable symbolTable = program.getSymbolTable();
symbolTable.createLabel(addr, mangled, SourceType.IMPORTED);
- DemangledObject demangled = DemanglerUtil.demangle(mangled);
+ GnuDemangler demangler = new GnuDemangler();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, program, addr);
+ DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledAddressTable);
-
- assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
+ assertTrue(demangled.getMangledContext() != null);
+ assertTrue(demangled.applyUsingContext(TaskMonitor.DUMMY));
// expected: UniqueSpace::vtable
Symbol[] symbols = symbolTable.getSymbols(addr);
@@ -107,9 +112,10 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
}
/**
- * Test that the DemangledAddressTable will not create a sequence of data
- * pointers due to a data collision. This test deals with the case where primitive types have been
+ * Test that the DemangledAddressTable will not create a sequence of data
+ * pointers due to a data collision. This test deals with the case where primitive types have been
* previously created. End of block considered end of address table.
+ * @throws Exception upon error
*/
@Test
public void testApply_NoNextSymbol_DataCollision() throws Exception {
@@ -126,10 +132,13 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
listing.createData(addr("0x118"), Undefined4DataType.dataType);
listing.createData(addr("0x120"), DWordDataType.dataType);
- DemangledObject demangled = DemanglerUtil.demangle(mangled);
+ GnuDemangler demangler = new GnuDemangler();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, program, addr);
+ DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledAddressTable);
-
- assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
+ assertTrue(demangled.getMangledContext() != null);
+ assertTrue(demangled.applyUsingContext(TaskMonitor.DUMMY));
// expected: UniqueSpace::vtable
Symbol[] symbols = symbolTable.getSymbols(addr);
@@ -146,9 +155,10 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
}
/**
- * Test that the DemangledAddressTable will properly create a sequence of data
- * pointers. This test deals with the case where primitive types have been
+ * Test that the DemangledAddressTable will properly create a sequence of data
+ * pointers. This test deals with the case where primitive types have been
* previously created. Next label considered end of address table.
+ * @throws Exception upon error
*/
@Test
public void testApply_WithNextSymbol_UndefinedData() throws Exception {
@@ -167,10 +177,13 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
symbolTable.createLabel(addr("0x120"), "NextLabel", SourceType.IMPORTED);
- DemangledObject demangled = DemanglerUtil.demangle(mangled);
+ GnuDemangler demangler = new GnuDemangler();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, program, addr);
+ DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledAddressTable);
-
- assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
+ assertTrue(demangled.getMangledContext() != null);
+ assertTrue(demangled.applyUsingContext(TaskMonitor.DUMMY));
// expected: UniqueSpace::vtable
Symbol[] symbols = symbolTable.getSymbols(addr);
@@ -185,10 +198,11 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
}
/**
- * Test that the DemangledAddressTable will properly create a sequence of data
- * pointers. This test deals with the case where primitive types have been
- * previously created where the first is an undefined array which dictates the
+ * Test that the DemangledAddressTable will properly create a sequence of data
+ * pointers. This test deals with the case where primitive types have been
+ * previously created where the first is an undefined array which dictates the
* extent of the address table. Next label beyond end of address table.
+ * @throws Exception upon error
*/
@Test
public void testApply_WithUndefinedArray() throws Exception {
@@ -207,10 +221,13 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
symbolTable.createLabel(addr("0x120"), "NextLabel", SourceType.IMPORTED);
- DemangledObject demangled = DemanglerUtil.demangle(mangled);
+ GnuDemangler demangler = new GnuDemangler();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, program, addr);
+ DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledAddressTable);
-
- assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
+ assertTrue(demangled.getMangledContext() != null);
+ assertTrue(demangled.applyUsingContext(TaskMonitor.DUMMY));
// expected: UniqueSpace::vtable
Symbol[] symbols = symbolTable.getSymbols(addr);
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 8d324c3011..cdca51a6f6 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
@@ -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,8 @@ import java.util.Arrays;
import org.junit.*;
+import ghidra.app.util.demangler.gnu.GnuDemangler;
+import ghidra.app.util.demangler.microsoft.*;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address;
@@ -62,11 +64,16 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
// this is: public long __thiscall ATL::CRegKey::Close(void)
String mangled = "?CloseM@CRegKeyM@ATL@@QAEJXZ";
- DemangledObject demangled = DemanglerUtil.demangle(mangled);
+ Address addr = addr("0x0101");
+ MicrosoftDemangler demangler = new MicrosoftDemangler();
+ MicrosoftDemanglerOptions options = demangler.createDefaultOptions();
+ MicrosoftMangledContext mangledContext =
+ demangler.createMangledContext(mangled, options, program, addr);
+ options.setInterpretation(MsCInterpretation.FUNCTION);
+ DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
- Address addr = addr("0x0101");
- assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
+ assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
assertFunction("CloseM", addr);
@@ -95,7 +102,14 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
// this is: public long __thiscall ATL::CRegKey::Close(void)
String mangled = "?Close@CRegKey@ATL@@QAEJXZ";
- DemangledObject demangled = DemanglerUtil.demangle(mangled);
+ Address addr = addr("0x0100");
+ MicrosoftDemangler demangler = new MicrosoftDemangler();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, program, addr);
+ DemanglerOptions options = mangledContext.getOptions();
+ // TODO: need direct way to change "for function" vs. just address and program; which might mean MicrosoftDemanglerContext
+ //mangledContext.setIsFunction(true);
+ DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
FunctionManager functionMgr = program.getFunctionManager();
@@ -105,8 +119,7 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
new AddressSet(addr("0x0100")), SourceType.IMPORTED);
f2.setThunkedFunction(f1);
- Address addr = addr("0x0100");
- demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY);
+ demangled.applyTo(program, addr, options, TaskMonitor.DUMMY);
assertFunction("Close", addr);
assertNoBookmarkAt(addr);
@@ -148,10 +161,16 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
SymbolTable symbolTable = program.getSymbolTable();
symbolTable.createLabel(addr, mangled, SourceType.IMPORTED);
- DemangledObject demangled = DemanglerUtil.demangle(mangled);
+ MicrosoftDemangler demangler = new MicrosoftDemangler();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, program, addr);
+ DemanglerOptions options = mangledContext.getOptions();
+ // TODO: need direct way to change "for function" vs. just address and program; which might mean MicrosoftDemanglerContext
+ //mangledContext.setIsFunction(true);
+ DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
- assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
+ assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
assertFunction("Close", addr);
assertNoBookmarkAt(addr);
@@ -185,10 +204,16 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
String mangledWithAddr = SymbolUtilities.getAddressAppendedName(mangled, addr);
symbolTable.createLabel(addr, mangledWithAddr, SourceType.IMPORTED);
- DemangledObject demangled = DemanglerUtil.demangle(mangled);
+ MicrosoftDemangler demangler = new MicrosoftDemangler();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, program, addr);
+ DemanglerOptions options = mangledContext.getOptions();
+ // TODO: need direct way to change "for function" vs. just address and program; which might mean MicrosoftDemanglerContext
+ //mangledContext.setIsFunction(true);
+ DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
- assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
+ assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
assertFunction("Close", addr);
assertNoBookmarkAt(addr);
@@ -223,10 +248,16 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
symbolTable.createLabel(addr, "Close", SourceType.IMPORTED);
symbolTable.createLabel(addr, mangled, SourceType.IMPORTED);
- DemangledObject demangled = DemanglerUtil.demangle(mangled);
+ MicrosoftDemangler demangler = new MicrosoftDemangler();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, program, addr);
+ DemanglerOptions options = mangledContext.getOptions();
+ // TODO: need direct way to change "for function" vs. just address and program; which might mean MicrosoftDemanglerContext
+ //mangledContext.setIsFunction(true);
+ DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
- assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
+ assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
assertFunction("Close", addr);
assertNoBookmarkAt(addr);
@@ -258,9 +289,15 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
SymbolTable symbolTable = program.getSymbolTable();
symbolTable.createLabel(addr, mangled, SourceType.IMPORTED);
- DemangledObject demangled = DemanglerUtil.demangle(mangled);
+ MicrosoftDemangler demangler = new MicrosoftDemangler();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, program, addr);
+ DemanglerOptions options = mangledContext.getOptions();
+ // TODO: need direct way to change "for function" vs. just address and program; which might mean MicrosoftDemanglerContext
+ //mangledContext.setIsFunction(true);
+ DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
- assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
+ assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
String className =
"F,bool,enum_C::B_const&>_>";
@@ -306,10 +343,16 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
Address addr = extLoc.getExternalSpaceAddress();
- DemangledObject demangled = DemanglerUtil.demangle(mangled);
+ MicrosoftDemangler demangler = new MicrosoftDemangler();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, program, addr);
+ DemanglerOptions options = mangledContext.getOptions();
+ // TODO: need direct way to change "for function" vs. just address and program; which might mean MicrosoftDemanglerContext
+ //mangledContext.setIsFunction(true);
+ DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
- assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
+ assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
assertFunction("Close", addr);
assertNoBookmarkAt(addr);
@@ -348,16 +391,20 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
String functionName = "__gthread_active_p";
programBuilder.createEmptyFunction(functionName, "0x0101", 10, new VoidDataType());
+ Address addr = addr("0x0103");
programBuilder.createLabel("0x0103", mangled);
- DemangledObject demangled = DemanglerUtil.demangle(program, mangled);
+ GnuDemangler demangler = new GnuDemangler();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, program, addr);
+ DemanglerOptions options = mangledContext.getOptions();
+ DemangledObject demangled = demangler.demangle(mangledContext);
assertNotNull(demangled);
assertTrue(demangled instanceof DemangledVariable);
assertEquals("__gthread_active_p()::__gthread_active_ptr", demangled.getSignature(false));
- Address addr = addr("0x0103");
- demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY);
+ demangled.applyTo(program, addr, options, TaskMonitor.DUMMY);
assertSimpleNamespaceExists("__gthread_active_p()");
assertNoBookmarkAt(addr);
@@ -376,14 +423,19 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
public void testApply_Function_DoNotApplyCallingConvention() throws Exception {
String mangled = "?CloseM@CRegKeyM@ATL@@QAEJXZ";
- DemangledObject demangled = DemanglerUtil.demangle(mangled);
+ Address addr = addr("0x0101");
+ MicrosoftDemangler demangler = new MicrosoftDemangler();
+ MangledContext mangledContext =
+ demangler.createMangledContext(mangled, null, program, addr);
+ DemanglerOptions options = mangledContext.getOptions();
+ // TODO: need direct way to change "for function" vs. just address and program; which might mean MicrosoftDemanglerContext
+ //mangledContext.setIsFunction(true);
+ DemangledObject demangled = demangler.demangle(mangledContext);
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));