Merge remote-tracking branch

'origin/GP-94_dragonmacher_PR-2214_astrelsky_GnuDemangler' (fixes #2214)
This commit is contained in:
ghidra1
2021-02-16 13:24:50 -05:00
15 changed files with 750 additions and 501 deletions
@@ -386,43 +386,28 @@
<U><B>Use Deprecated Demangler</B></U> -
By default, GCC symbols will be demangled using the most up-to-date demangler
that Ghidra contains (<B>version 2.33.1</B> as of this writing). Turning this
option on will also invoke the now deprecated previous version of the demangler
(<B>version 2.24</B>) if the preferred demangler cannot demangle a given symbol.
option on will invoke the now deprecated version of the demangler (<B>version 2.24</B>).
</P>
<P>
Support for older demangling styles was removed in <CODE>c++filt (v2.32)</CODE>.
Specifically, the following formats are no longer supported:
<CODE>Lucid, ARM, HP, and EDG</CODE>. To use these formats, you must enable
usage of the deprecated demangler, which is <B>version 2.24</B>. Further, you
may have to pass the required external demangler options using the Ghidra
option below.
<CODE>Lucid, ARM, HP, GNU, and EDG</CODE>. For these formats, the deprecated
demangler, which is <B>version 2.24</B>, will automatically be used.
</P>
<P>
<U><B>Use External Demangler Options</B></U> -
This allows users to pass settings to the demangler. As an example, you can enter
in this Ghidra option text field the following text to use the <CODE>rust</CODE>
format: <CODE>-s rust</CODE>. This is not needed for
normal operation. To see a full list of supported options, query each demangler
directly using the <CODE>--help</CODE> switch.
</P>
<P>
The GNU demanglers can be found at:
<CODE CLASS="path">
&lt;GHIDRA_INSTALL_DIR&gt;/GPL/DemanglerGnu/build/os/&lt;OS&gt;/
</CODE><BR>
</P>
<BLOCKQUOTE>
<P>
The available programs are:
<UL>
<LI><CODE>demangler_gnu_v2_33_1</CODE></LI>
<LI><CODE>demangler_gnu_v2_24</CODE></LI>
<LI><CODE CLASS="path">
&lt;GHIDRA_INSTALL_DIR&gt;/GPL/DemanglerGnu/os/&lt;OS&gt;/
</CODE><CODE>demangler_gnu_v2_33_1</CODE></LI>
<LI><CODE CLASS="path">
&lt;GHIDRA_INSTALL_DIR&gt;/GPL/DemanglerGnu/os/&lt;OS&gt;/
</CODE><CODE>demangler_gnu_v2_24</CODE></LI>
</UL>
</P>
<P style="background-color: #FFF0E0;">
<IMG SRC="../../shared/warning.png" />When using an external GNU demangler,
please understand the risks associated with using that version of the
@@ -16,7 +16,7 @@
package ghidra.app.util.demangler;
/**
* A simple class to contain the various settings for demangling.
* A simple class to contain the various settings for demangling
*/
public class DemanglerOptions {
@@ -35,47 +35,47 @@ public class DemanglerOptions {
}
/**
* Checks if the apply signature option is currently set.
*
* @return true if set to apply function signatures that are demangled.
* Checks if the apply signature option is currently set
*
* @return true if set to apply function signatures that are demangled
*/
public boolean applySignature() {
return applySignature;
}
/**
* Set the option to apply function signatures that are demangled.
*
* @param applySignature true to apply function signatures that are demangled.
* Set the option to apply function signatures that are demangled
*
* @param applySignature true to apply function signatures that are demangled
*/
public void setApplySignature(boolean applySignature) {
this.applySignature = applySignature;
}
/**
* Checks if the option to perform disassembly for known data structures (like functions) when
* demangling is set.
*
* @return true if the option is set.
* Checks if the option to perform disassembly for known data structures (like functions) when
* demangling is set
*
* @return true if the option is set
*/
public boolean doDisassembly() {
return doDisassembly;
}
/**
* Sets the option to perform disassembly for known data structures (like functions) when
* demangling.
*
* @param doDisassembly true to perform disassembly when demangling.
* Sets the option to perform disassembly for known data structures (like functions) when
* demangling
*
* @param doDisassembly true to perform disassembly when demangling
*/
public void setDoDisassembly(boolean doDisassembly) {
this.doDisassembly = doDisassembly;
}
/**
* Checks if the option to only demangle known mangled patterns is set.
*
* @return true if only known mangled patterns will be demangled.
* Checks if the option to only demangle known mangled patterns is set
*
* @return true if only known mangled patterns will be demangled
*/
public boolean demangleOnlyKnownPatterns() {
return demangleOnlyKnownPatterns;
@@ -83,10 +83,15 @@ public class DemanglerOptions {
/**
* Sets the option to only demangle known mangled patterns. Setting this to false causes
* all symbols to be demangled, which may result in some symbols getting demangled that were not
* actually mangled symbols.
*
* @param demangleOnlyKnownPatterns true to only demangle known mangled patterns.
* most symbols to be demangled, which may result in some symbols getting demangled that were
* not actually mangled symbols.
*
* <P>Generally, a demangler will report an error if a symbol fails to demangle. Hence,
* clients can use this flag to prevent such errors, signalling to the demangler to only
* attempt those symbols that have a known start pattern. If the known start pattern list
* becomes comprehensive, then this flag can go away.
*
* @param demangleOnlyKnownPatterns true to only demangle known mangled patterns
*/
public void setDemangleOnlyKnownPatterns(boolean demangleOnlyKnownPatterns) {
this.demangleOnlyKnownPatterns = demangleOnlyKnownPatterns;
@@ -21,8 +21,7 @@
//@category Examples.Demangler
import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledObject;
import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.app.util.demangler.gnu.GnuDemanglerOptions;
import ghidra.app.util.demangler.gnu.*;
import ghidra.program.model.symbol.Symbol;
public class DemangleElfWithOptionScript extends GhidraScript {
@@ -33,8 +32,8 @@ public class DemangleElfWithOptionScript extends GhidraScript {
GnuDemangler demangler = new GnuDemangler();
if (!demangler.canDemangle(currentProgram)) {
String executableFormat = currentProgram.getExecutableFormat();
println("Cannot use the elf demangling options for executable format: " +
executableFormat);
println(
"Cannot use the elf demangling options for executable format: " + executableFormat);
return;
}
@@ -49,14 +48,12 @@ public class DemangleElfWithOptionScript extends GhidraScript {
String mangled = symbol.getName();
GnuDemanglerOptions options = new GnuDemanglerOptions();
GnuDemanglerOptions options = new GnuDemanglerOptions(GnuDemanglerFormat.AUTO, false);
options.setDoDisassembly(false);
options.setDemanglerApplicationArguments("-s auto");
/*
// for older formats use the deprecated demangler
options.setDemanglerName(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
options.setDemanglerApplicationArguments("-s arm");
options = options.withDemanglerFormat(GnuDemanglerFormat.ARM, true);
*/
DemangledObject demangledObject = demangler.demangle(mangled, options);
@@ -15,19 +15,20 @@
*/
package ghidra.app.plugin.core.analysis;
import java.io.IOException;
import org.apache.commons.lang3.StringUtils;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import docking.options.editor.BooleanEditor;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.gnu.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.framework.options.*;
import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
/**
* A version of the demangler analyzer to handle GNU GCC symbols
* A version of the demangler analyzer to handle GNU GCC symbols
*/
public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
@@ -51,15 +52,14 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
"Signals to use the deprecated demangler when the modern demangler cannot demangle a " +
"given string";
static final String OPTION_NAME_DEMANGLER_PARAMETERS =
"Use External Demangler Options";
private static final String OPTION_DESCRIPTION_DEMANGLER_PARAMETERS =
"Signals to use pass the given parameters to the demangler program";
static final String OPTION_NAME_DEMANGLER_FORMAT = "Demangler Format";
private static final String OPTION_DESCRIPTION_DEMANGLER_FORMAT =
"The demangling format to use";
private boolean doSignatureEnabled = true;
private boolean demangleOnlyKnownPatterns = false;
private GnuDemanglerFormat demanglerFormat = GnuDemanglerFormat.AUTO;
private boolean useDeprecatedDemangler = false;
private String demanglerParameters = "";
private GnuDemangler demangler = new GnuDemangler();
@@ -75,20 +75,23 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
@Override
public void registerOptions(Options options, Program program) {
BooleanEditor editor = new BooleanEditor();
editor.setValue(Boolean.valueOf(useDeprecatedDemangler));
FormatEditor formatEditor = new FormatEditor(demanglerFormat, editor);
editor.addPropertyChangeListener(formatEditor);
HelpLocation help = new HelpLocation("AutoAnalysisPlugin", "Demangler_Analyzer");
options.registerOption(OPTION_NAME_APPLY_SIGNATURE, doSignatureEnabled, help,
OPTION_DESCRIPTION_APPLY_SIGNATURE);
options.registerOption(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns,
help,
OPTION_DESCRIPTION_USE_KNOWN_PATTERNS);
help, OPTION_DESCRIPTION_USE_KNOWN_PATTERNS);
options.registerOption(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler, help,
OPTION_DESCRIPTION_DEPRECATED_DEMANGLER);
options.registerOption(OPTION_NAME_USE_DEPRECATED_DEMANGLER, OptionType.BOOLEAN_TYPE,
useDeprecatedDemangler, help, OPTION_DESCRIPTION_DEPRECATED_DEMANGLER, editor);
options.registerOption(OPTION_NAME_DEMANGLER_PARAMETERS, demanglerParameters, help,
OPTION_DESCRIPTION_DEMANGLER_PARAMETERS);
options.registerOption(OPTION_NAME_DEMANGLER_FORMAT, OptionType.ENUM_TYPE, demanglerFormat,
help, OPTION_DESCRIPTION_DEMANGLER_FORMAT, formatEditor);
}
@Override
@@ -96,94 +99,105 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
doSignatureEnabled = options.getBoolean(OPTION_NAME_APPLY_SIGNATURE, doSignatureEnabled);
demangleOnlyKnownPatterns =
options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns);
demanglerFormat = options.getEnum(OPTION_NAME_DEMANGLER_FORMAT, GnuDemanglerFormat.AUTO);
useDeprecatedDemangler =
options.getBoolean(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler);
demanglerParameters =
options.getString(OPTION_NAME_DEMANGLER_PARAMETERS, demanglerParameters);
}
@Override
protected DemanglerOptions getOptions() {
GnuDemanglerOptions options = new GnuDemanglerOptions();
GnuDemanglerOptions options =
new GnuDemanglerOptions(demanglerFormat, useDeprecatedDemangler);
options.setDoDisassembly(true);
options.setApplySignature(doSignatureEnabled);
options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
options.setDemanglerApplicationArguments(demanglerParameters);
return options;
}
@Override
protected boolean validateOptions(DemanglerOptions demanglerOtions, MessageLog log) {
GnuDemanglerOptions options = (GnuDemanglerOptions) demanglerOtions;
String applicationArguments = options.getDemanglerApplicationArguments();
if (StringUtils.isBlank(applicationArguments)) {
return true;
}
// Check that the supplied arguments will work with at least one of the requested
// demanglers. (Different versions of the GNU demangler support different arguments.)
String demanglerName = options.getDemanglerName();
try {
GnuDemanglerNativeProcess.getDemanglerNativeProcess(demanglerName,
applicationArguments);
return true;
}
catch (IOException e) {
log.appendMsg(getName(), "Invalid options for GNU dangler '" + demanglerName +
"': " + applicationArguments);
log.appendException(e);
}
if (useDeprecatedDemangler) {
// see if the options work in the deprecated demangler
GnuDemanglerOptions deprecatedOptions = options.withDeprecatedDemangler();
String deprecatedName = deprecatedOptions.getDemanglerName();
try {
GnuDemanglerNativeProcess.getDemanglerNativeProcess(deprecatedName,
applicationArguments);
return true;
}
catch (IOException e) {
log.appendMsg(getName(),
"Invalid options for GNU dangler '" + deprecatedName + "': " +
applicationArguments);
log.appendException(e);
}
}
return false;
protected DemangledObject doDemangle(String mangled, DemanglerOptions demanglerOtions,
MessageLog log) throws DemangledException {
return demangler.demangle(mangled, demanglerOtions);
}
@Override
protected DemangledObject doDemangle(String mangled, DemanglerOptions demanglerOtions,
MessageLog log)
throws DemangledException {
private static class FormatEditor extends EnumEditor implements PropertyChangeListener {
GnuDemanglerOptions options = (GnuDemanglerOptions) demanglerOtions;
DemangledObject demangled = null;
try {
demangled = demangler.demangle(mangled, options);
private final FormatSelector selector;
private final BooleanEditor isDeprecated;
FormatEditor(GnuDemanglerFormat value, BooleanEditor isDeprecated) {
setValue(value);
this.isDeprecated = isDeprecated;
this.selector = new FormatSelector(this);
}
catch (DemangledException e) {
if (!useDeprecatedDemangler) {
throw e; // let our parent handle this
@Override
public boolean supportsCustomEditor() {
return true;
}
@Override
public FormatSelector getCustomEditor() {
return selector;
}
@Override
public GnuDemanglerFormat[] getEnums() {
return Arrays.stream(GnuDemanglerFormat.values())
.filter(this::filter)
.toArray(GnuDemanglerFormat[]::new);
}
@Override
public String[] getTags() {
return Arrays.stream(GnuDemanglerFormat.values())
.filter(this::filter)
.map(GnuDemanglerFormat::name)
.toArray(String[]::new);
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
GnuDemanglerFormat format = selector.getFormat();
selector.reset(getTags());
if (format.isAvailable(isDeprecatedDemangler())) {
setValue(format);
selector.setFormat(format);
}
else {
setValue(GnuDemanglerFormat.AUTO);
}
}
if (demangled != null) {
return demangled;
private boolean isDeprecatedDemangler() {
return (Boolean) isDeprecated.getValue();
}
if (useDeprecatedDemangler) {
GnuDemanglerOptions newOptions = options.withDeprecatedDemangler();
demangled = demangler.demangle(mangled, newOptions);
private boolean filter(GnuDemanglerFormat f) {
return f.isAvailable(isDeprecatedDemangler());
}
}
private static class FormatSelector extends PropertySelector {
public FormatSelector(FormatEditor fe) {
super(fe);
}
void reset(String[] tags) {
removeAllItems();
for (String tag : tags) {
addItem(tag);
}
}
GnuDemanglerFormat getFormat() {
return GnuDemanglerFormat.valueOf((String) getSelectedItem());
}
void setFormat(GnuDemanglerFormat format) {
setSelectedItem(format.name());
}
return demangled;
}
}
@@ -72,11 +72,11 @@ public class GnuDemangler implements Demangler {
public DemangledObject demangle(String mangled, DemanglerOptions demanglerOtions)
throws DemangledException {
if (skip(mangled, demanglerOtions)) {
GnuDemanglerOptions options = getGnuOptions(demanglerOtions);
if (skip(mangled, options)) {
return null;
}
GnuDemanglerOptions options = getGnuOptions(demanglerOtions);
String originalMangled = mangled;
String globalPrefix = null;
if (mangled.startsWith(GLOBAL_PREFIX)) {
@@ -106,16 +106,14 @@ public class GnuDemangler implements Demangler {
}
boolean onlyKnownPatterns = options.demangleOnlyKnownPatterns();
DemangledObject demangledObject =
parse(mangled, process, demangled, onlyKnownPatterns);
DemangledObject demangledObject = parse(mangled, process, demangled, onlyKnownPatterns);
if (demangledObject == null) {
return demangledObject;
}
if (globalPrefix != null) {
DemangledFunction dfunc =
new DemangledFunction(originalMangled, demangled,
globalPrefix + demangledObject.getName());
DemangledFunction dfunc = new DemangledFunction(originalMangled, demangled,
globalPrefix + demangledObject.getName());
dfunc.setNamespace(demangledObject.getNamespace());
demangledObject = dfunc;
}
@@ -163,7 +161,20 @@ public class GnuDemangler implements Demangler {
applicationOptions);
}
private boolean skip(String mangled, DemanglerOptions options) {
/**
* Determines if the given mangled string should not be demangled. There are a couple
* patterns that will always be skipped.
* If {@link GnuDemanglerOptions#demangleOnlyKnownPatterns()} is true, then only mangled
* symbols matching a list of known start patters will not be skipped.
*
* <P>This demangler class will default to demangling most patterns, since we do not yet
* have a comprehensive list of known start patterns.
*
* @param mangled the mangled string
* @param options the options
* @return true if the string should not be demangled
*/
private boolean skip(String mangled, GnuDemanglerOptions options) {
// Ignore versioned symbols which are generally duplicated at the same address
if (mangled.indexOf("@") > 0) { // do not demangle versioned symbols
@@ -179,20 +190,21 @@ public class GnuDemangler implements Demangler {
return false; // let it go through
}
// add to this list if we find any other known GNU start patterns
// This is the current list of known demangler start patterns. Add to this list if we
// find any other known GNU start patterns.
if (mangled.startsWith("_Z")) {
return false;
}
else if (mangled.startsWith("__Z")) {
if (mangled.startsWith("__Z")) {
return false;
}
else if (mangled.startsWith("h__")) {
if (mangled.startsWith("h__")) {
return false; // not sure about this one
}
else if (mangled.startsWith("?")) {
if (mangled.startsWith("?")) {
return false; // not sure about this one
}
else if (isGnu2Or3Pattern(mangled)) {
if (isGnu2Or3Pattern(mangled)) {
return false;
}
@@ -200,8 +212,7 @@ public class GnuDemangler implements Demangler {
}
private DemangledObject parse(String mangled, GnuDemanglerNativeProcess process,
String demangled,
boolean demangleOnlyKnownPatterns) {
String demangled, boolean demangleOnlyKnownPatterns) {
if (demangleOnlyKnownPatterns && !isKnownMangledString(mangled, demangled)) {
return null;
@@ -217,7 +228,7 @@ public class GnuDemangler implements Demangler {
// We get requests to demangle strings that are not mangled. For newer mangled strings
// we know how to avoid that. However, older mangled strings can be of many forms. To
// detect whether a string is mangled, we have to resort to examining the output of
// the demangler.
// the demangler.
//
// check for the case where good strings have '__' in them (which is valid GNU2 mangling)
@@ -0,0 +1,92 @@
/* ###
* 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.gnu;
/**
* Enum representation of the available GnuDemangler formats
*/
public enum GnuDemanglerFormat {
// OLD: none,auto,gnu,lucid,arm,hp,edg,gnu-v3,java,gnat
// NEW: none,auto,gnu-v3,java,gnat,dlang,rust
/** Automatic mangling format detection */
AUTO("", Version.ALL),
/** GNUv2 mangling format */
GNU("gnu", Version.DEPRECATED),
/** lucid mangling format */
LUCID("lucid", Version.DEPRECATED),
/** arm mangling format */
ARM("arm", Version.DEPRECATED),
/** hp mangling format */
HP("hp", Version.DEPRECATED),
/** mangling format used by the Edison Design Group (EDG) compiler */
EDG("edg", Version.DEPRECATED),
/** GNUv3 mangling format */
GNUV3("gnu-v3", Version.ALL),
/** Java mangling format */
JAVA("java", Version.ALL),
/** GNAT Ada compiler mangling format */
GNAT("gnat", Version.ALL),
/** D mangling format */
DLANG("dlang", Version.MODERN),
/** Rust mangling format */
RUST("rust", Version.MODERN);
/** the format option string used by the native demangler */
private final String format;
private final Version version;
private GnuDemanglerFormat(String format, Version version) {
this.format = format;
this.version = version;
}
/**
* Checks if this format is available in the deprecated gnu demangler
* @return true if this format is available in the deprecated gnu demangler
*/
public boolean isDeprecatedFormat() {
return version == Version.DEPRECATED || version == Version.ALL;
}
/**
* Checks if this format is available in a modern version of the gnu demangler
* @return true if this format is available in a modern version of the gnu demangler
*/
public boolean isModernFormat() {
return version == Version.MODERN || version == Version.ALL;
}
/**
* Checks if this format is available for the specified demangler
* @param isDeprecated true for the deprecated demangler, false for the modern demangler
* @return true if the format is available
*/
public boolean isAvailable(boolean isDeprecated) {
return isDeprecated ? isDeprecatedFormat() : isModernFormat();
}
/**
* Gets the format option to be passed to the demangler via the <code>-s</code> option
* @return the format option to be passed to the demangler
*/
public String getFormat() {
return format;
}
private enum Version {
DEPRECATED, MODERN, ALL
}
}
@@ -43,38 +43,98 @@ public class GnuDemanglerOptions extends DemanglerOptions {
*/
public static final String GNU_DEMANGLER_DEFAULT = GNU_DEMANGLER_V2_33_1;
private String demanglerName = GNU_DEMANGLER_DEFAULT;
private String demanglerApplicationArguments;
private final GnuDemanglerFormat format;
private final boolean isDeprecated;
/**
* Default constructor to use the modern demangler with auto-detect for the format. This
* constructor will limit demangling to only known symbols.
*/
public GnuDemanglerOptions() {
// use default values
this(GnuDemanglerFormat.AUTO);
}
/**
* Constructor to specify a particular format
*
* @param format signals to use the given format
*/
public GnuDemanglerOptions(GnuDemanglerFormat format) {
this(format, !format.isModernFormat());
}
/**
* Constructor to specify the format to use and whether to prefer the deprecated format when
* both deprecated and modern are available
*
* @param format the format
* @param isDeprecated true if the format is not available in the modern demangler
* @throws IllegalArgumentException if the given format is not available in the deprecated
* demangler
*/
public GnuDemanglerOptions(GnuDemanglerFormat format, boolean isDeprecated) {
this.format = format;
this.isDeprecated = isDeprecated;
if (!format.isAvailable(isDeprecated)) {
throw new IllegalArgumentException(
format.name() + " is not available in the " + getDemanglerName());
}
}
/**
* Copy constructor to create a version of this class from a more generic set of options
* @param copy the options to copy
*/
public GnuDemanglerOptions(DemanglerOptions copy) {
super(copy);
if (copy instanceof GnuDemanglerOptions) {
GnuDemanglerOptions gCopy = (GnuDemanglerOptions) copy;
demanglerName = gCopy.demanglerName;
demanglerApplicationArguments = gCopy.demanglerApplicationArguments;
format = gCopy.format;
isDeprecated = gCopy.isDeprecated;
}
else {
format = GnuDemanglerFormat.AUTO;
isDeprecated = false;
}
}
private GnuDemanglerOptions(GnuDemanglerOptions copy, GnuDemanglerFormat format,
boolean deprecated) {
super(copy);
this.format = format;
this.isDeprecated = deprecated;
}
/**
* Returns the external demangler executable name to be used for demangling. The
* Returns the external demangler executable name to be used for demangling. The
* default value is {@link #GNU_DEMANGLER_DEFAULT}.
* @return the name
*/
public String getDemanglerName() {
return demanglerName;
return isDeprecated ? GNU_DEMANGLER_V2_24 : GNU_DEMANGLER_V2_33_1;
}
/**
* Sets the external demangler executable name to be used for demangling
* @param name the name
* A convenience method to copy the state of this options object, changing the
* demangler executable name and demangler format to the specified values
*
* @param demanglerFormat the demangling format to use
* @param useDeprecated true to use the deprecated gnu demangler, else false
* @return the new options
* @throws IllegalArgumentException if the current format is not available in the
* selected demangler.
*/
public void setDemanglerName(String name) {
this.demanglerName = name;
public GnuDemanglerOptions withDemanglerFormat(GnuDemanglerFormat demanglerFormat,
boolean useDeprecated) throws IllegalArgumentException {
if (this.format == demanglerFormat && this.isDeprecated == useDeprecated) {
return this;
}
if (demanglerFormat.isAvailable(useDeprecated)) {
return new GnuDemanglerOptions(this, demanglerFormat, useDeprecated);
}
throw new IllegalArgumentException(
demanglerFormat.name() + " is not available in the " + getDemanglerName());
}
/**
@@ -82,26 +142,19 @@ public class GnuDemanglerOptions extends DemanglerOptions {
* @return the arguments
*/
public String getDemanglerApplicationArguments() {
return demanglerApplicationArguments;
if (format == GnuDemanglerFormat.AUTO) {
// no format argument
return "";
}
return "-s " + format.getFormat();
}
/**
* Sets the arguments to be passed to the external demangler executable
* @param args the arguments
* Gets the current demangler format
* @return the demangler format
*/
public void setDemanglerApplicationArguments(String args) {
this.demanglerApplicationArguments = args;
}
/**
* A convenience method to copy the state of this options object, changing the
* demangler executable name to the deprecated demangler
* @return the new options
*/
public GnuDemanglerOptions withDeprecatedDemangler() {
GnuDemanglerOptions newOptions = new GnuDemanglerOptions(this);
newOptions.setDemanglerName(GNU_DEMANGLER_V2_24);
return newOptions;
public GnuDemanglerFormat getDemanglerFormat() {
return format;
}
@Override
@@ -111,8 +164,8 @@ public class GnuDemanglerOptions extends DemanglerOptions {
"\tdoDisassembly: " + doDisassembly() + ",\n" +
"\tapplySignature: " + applySignature() + ",\n" +
"\tdemangleOnlyKnownPatterns: " + demangleOnlyKnownPatterns() + ",\n" +
"\tdemanglerName: " + demanglerName + ",\n" +
"\tdemanglerApplicationArguments: " + demanglerApplicationArguments + ",\n" +
"\tdemanglerName: " + getDemanglerName() + ",\n" +
"\tdemanglerApplicationArguments: " + getDemanglerApplicationArguments() + ",\n" +
"}";
//@formatter:on
}
@@ -43,12 +43,8 @@ public class GnuDemanglerParser {
private static final String TYPEINFO_FOR = "typeinfo for ";
private static final String COVARIANT_RETURN_THUNK = "covariant return thunk";
private static final Set<String> ADDRESS_TABLE_PREFIXES = Set.of(
CONSTRUCTION_VTABLE_FOR,
VTT_FOR,
VTABLE_FOR,
TYPEINFO_FN_FOR,
TYPEINFO_FOR);
private static final Set<String> ADDRESS_TABLE_PREFIXES =
Set.of(CONSTRUCTION_VTABLE_FOR, VTT_FOR, VTABLE_FOR, TYPEINFO_FN_FOR, TYPEINFO_FOR);
private static final String OPERATOR = "operator";
private static final String LAMBDA = "lambda";
@@ -64,23 +60,23 @@ public class GnuDemanglerParser {
*
* Pattern: name(([const] [params]))
*
* Parts: -optional spaces
* Parts: -optional spaces
* -optional (const) (non-capture group)
* -followed by '()' with optional parameter text (capture group 1)
*
*
* Note: this pattern is used for matching the arguments string, in the above examples it
* would be:
* would be:
* Rect &, unsigned long
* and
* Rect &, bool
*
*
*/
private static final Pattern UNNECESSARY_PARENS_PATTERN =
Pattern.compile("\\s*(?:const){0,1}\\((.*)\\)\\s*");
/**
* Captures the contents of a varargs parameter that is inside of parentheses.
*
*
* Sample: (NS1::type&&)...
*
* Pattern: (namespace::name[modifiers])...
@@ -89,7 +85,7 @@ public class GnuDemanglerParser {
* -contents (capture group 1)
* -close paren
* -varargs
*
*
*/
private static final Pattern VARARGS_IN_PARENS =
Pattern.compile("\\((.*)\\)" + Pattern.quote("..."));
@@ -107,7 +103,7 @@ public class GnuDemanglerParser {
* -*optional: any other text (e.g., const[8]) (non-capture group)
* -followed by '()' that contain a '&' or a '*' (capture group 2)
* -followed by one or more '[]' with optional interior text (capture group 3)
*
*
* Group Samples:
* short (&)[7]
* 1 short
@@ -118,7 +114,7 @@ public class GnuDemanglerParser {
* 1 CanRxItem
* 2 &
* 3 [2][64u]
*
*
*/
private static final Pattern ARRAY_POINTER_REFERENCE_PATTERN =
Pattern.compile("([\\w:]+)\\*?\\s(?:.*)\\(([&*])\\)\\s*((?:\\[.*?\\])+)");
@@ -128,8 +124,8 @@ public class GnuDemanglerParser {
*
* Pattern: (*|&)[optional spaces][optional value]
*
* Parts:
* -'()' that contain a '&' or a '*'
* Parts:
* -'()' that contain a '&' or a '*'
* -followed by '[]' with optional text
* </pre>
*/
@@ -159,7 +155,7 @@ public class GnuDemanglerParser {
* std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char> >(std::basic_istream<char, std::char_traits<char> >&, char&)
* bool myContainer<int>::operator<< <double>(double)
* bool operator< <myContainer<int> >(myContainer<int> const&)
*
*
* Pattern: [return_type] operator operator_character(s) (opeartor_params) [trailing text]
*
* Parts:
@@ -168,7 +164,7 @@ public class GnuDemanglerParser {
* -optional space
* -optional templates (capture group 3)
* -parameters (capture group 4)
*
*
* Note: this regex is generated from all known operator patterns and looks like:
* (.*operator(generated_text).*)\s*(\(.*\))(.*)
*/
@@ -178,9 +174,9 @@ public class GnuDemanglerParser {
/*
* Sample: std::integral_constant<bool, false>::operator bool() const
* Magick::Color::operator std::basic_string<char, std::char_traits<char>, std::allocator<char> >() const
*
*
* Pattern: operator type() [trailing text]
*
*
* Parts:
* -operator (capture group 1)
* -space
@@ -211,13 +207,13 @@ public class GnuDemanglerParser {
/*
* Pattern for newer C++ lambda syntax:
*
*
* Sample: {lambda(void const*, unsigned int)#1}
* {lambda(NS1::Class1 const&, int, int)#1} const&
* {lambda(auto:1&&)#1}<NS1::NS2>&&
*
*
* Pattern: [optional text] brace lambda([parameters])#digits brace [trailing text]
*
*
* Parts:
* -full text without leading characters (capture group 1)
* -parameters of the lambda function (capture group 2)
@@ -229,9 +225,9 @@ public class GnuDemanglerParser {
/*
* Sample: {unnamed type#1}
*
*
* Pattern: [optional text] brace unnamed type#digits brace
*
*
* Parts:
* -full text without leading characters (capture group 1)
*/
@@ -239,18 +235,18 @@ public class GnuDemanglerParser {
/*
* Sample: covariant return thunk to Foo::Bar::copy(Foo::CoolStructure*) const
*
*
* Pattern: text for|to text
*
*
* Parts:
* -required text (capture group 2)
* -a space
* -'for' or 'to' (capture group 3)
* -a space
* -optional text (capture group 4)
*
*
* Note: capture group 1 is the combination of groups 2 and 3
*
*
* Examples:
* construction vtable for
* vtable for
@@ -258,33 +254,33 @@ public class GnuDemanglerParser {
* typeinfo for
* guard variable for
* covariant return thunk to
* virtual thunk to
* virtual thunk to
* non-virtual thunk to
*/
private static final Pattern DESCRIPTIVE_PREFIX_PATTERN =
Pattern.compile("((.+ )+(for|to) )(.+)");
/**
* The c 'decltype' keyword pattern
* The c 'decltype' keyword pattern
*/
private static final Pattern DECLTYPE_RETURN_TYPE_PATTERN =
Pattern.compile("decltype \\(.*\\)");
private static Pattern createOverloadedOperatorNamePattern() {
// note: the order of these matters--the single characters must come after the
// note: the order of these matters--the single characters must come after the
// multi-character entries; otherwise, the single characters will match before
// longer matches
//@formatter:off
List<String> operators = new LinkedList<>(List.of(
List<String> operators = new LinkedList<>(List.of(
"++", "--",
">>=", "<<=",
"->*", "->",
"==", "!=", ">=", "<=",
"&&", "||", ">>", "<<",
"+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=",
"+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=",
"+", "-", "*", "/", "%",
"~", "^", "&", "|", "!", "<", ">", "=",
"~", "^", "&", "|", "!", "<", ">", "=",
",", "()"
));
//@formatter:on
@@ -294,12 +290,12 @@ public class GnuDemanglerParser {
//
// We have some extra 'operator' style constructs to add to the normal operator overloading
//
// User Defined Literal
// Sample: operator"" _init(char const*, unsigned long)
//
//
// User Defined Literal
// Sample: operator"" _init(char const*, unsigned long)
//
// Pattern: operator"" _someText(opeartor_params)
//
//
String userDefinedLiteral = "\"\"\\s_.+";
String extra = userDefinedLiteral;
alternated += '|' + extra;
@@ -319,7 +315,7 @@ public class GnuDemanglerParser {
/**
* Parses the given demangled string and creates a {@link DemangledObject}
*
*
* @param mangled the original mangled text
* @param demangled the demangled text
* @return the demangled object
@@ -341,9 +337,9 @@ public class GnuDemanglerParser {
private DemangledObjectBuilder getSpecializedBuilder(String demangled) {
//
// Note: we check for the 'special handlers' first, since they are more specific than
// the other handlers here. Checking for the operator handler first can produce
// errors, since some 'special handler' strings actually contain 'operator'
// Note: we check for the 'special handlers' first, since they are more specific than
// the other handlers here. Checking for the operator handler first can produce
// errors, since some 'special handler' strings actually contain 'operator'
// signatures. In those cases, the operator handler will incorrectly match on the
// operator text. Since the 'special handlers' perform more specific checks, it is
// safe to do those first.
@@ -464,7 +460,7 @@ public class GnuDemanglerParser {
if (DECLTYPE_RETURN_TYPE_PATTERN.matcher(returnType).matches()) {
// Not sure yet if there is any information we wish to recover from this pattern.
// Sample: decltype (functionName({parm#1}, (float)[42c80000]))
// Sample: decltype (functionName({parm#1}, (float)[42c80000]))
return;
}
@@ -523,10 +519,10 @@ public class GnuDemanglerParser {
}
/**
* Removes spaces from unwanted places. For example, all spaces internal to templates and
* Removes spaces from unwanted places. For example, all spaces internal to templates and
* parameter lists will be removed. Also, other special cases may be handled, such as when
* the 'unnamed type' construct is found.
*
*
* @param text the text to fix
* @return the fixed text
*/
@@ -735,7 +731,7 @@ public class GnuDemanglerParser {
// lambda function
// e.g., {lambda(NS1::Class1 const&, int, int)#1} const&
// {lambda(auto:1&&)#1}<NS1::NS2>>&&
//
//
LambdaName lambdaName = getLambdaName(datatype);
@@ -898,30 +894,30 @@ public class GnuDemanglerParser {
private boolean isDataTypeNameCharacter(char ch) {
/*
Note: really, this should just be checking a list of known disallowed characters,
Note: really, this should just be checking a list of known disallowed characters,
which is something like:
<,>,(,),&,*,[,]
It seems like the current code below is unnecessarily restrictive
*/
//@formatter:off
return Character.isLetter(ch) ||
Character.isDigit(ch) ||
ch == ':' ||
return Character.isLetter(ch) ||
Character.isDigit(ch) ||
ch == ':' ||
ch == '_' ||
ch == '$';
//@formatter:on
}
/**
* Scans the given string from the given offset looking for a balanced {@code close}
* character. This algorithm will not report a match for the end character until the
* Scans the given string from the given offset looking for a balanced {@code close}
* character. This algorithm will not report a match for the end character until the
* {@code open} character has first been found. This allows clients to scan from anywhere
* in a string to find an open and start character combination, including at or before the
* desired opening character.
*
*
* @param string the input string
* @param start the start position within the string
* @param open the open character (e.g, '(' or '<')
@@ -952,12 +948,12 @@ public class GnuDemanglerParser {
}
/**
* Scans the given string from the given offset looking for a balanced {@code open}
* character. This algorithm will not report a match for the open character until the
* Scans the given string from the given offset looking for a balanced {@code open}
* character. This algorithm will not report a match for the open character until the
* {@code end} character has first been found. This allows clients to scan from anywhere
* in a string to find an open and start character combination, including at or before the
* desired opening character.
*
*
* @param string the input string
* @param start the start position within the string
* @param open the open character (e.g, '(' or '<')
@@ -998,11 +994,11 @@ public class GnuDemanglerParser {
/**
* Walks backward from the given start position to find the next namespace separator. This
* allows clients to determine if a given position is inside of a namespace.
*
*
* @param text the text to search
* @param start the start position
* @param stop the stop position
* @return the start index of the namespace entry containing the current {@code start}
* @return the start index of the namespace entry containing the current {@code start}
* index; -1 if no namespace start is found
*/
private int findNamespaceStart(String text, int start, int stop) {
@@ -1191,9 +1187,9 @@ public class GnuDemanglerParser {
/*
Examples:
NS1::Function<>()::StructureName::StructureConstructor()
*/
String nameString = removeBadSpaces(demangled).trim();
@@ -1208,10 +1204,10 @@ public class GnuDemanglerParser {
* Given names = { "A", "B", "C" }, which represents "A::B::C".
* The following will be created {@literal "Namespace{A}->Namespace{B}->Namespace{C}"}
* and Namespace{C} will be returned.
*
*
* <p>This method will also escape spaces separators inside of templates
* (see {@link #removeBadSpaces(String)}).
*
*
* @param names the names to convert
* @return the newly created type
*/
@@ -1357,7 +1353,7 @@ public class GnuDemanglerParser {
DemangledObject doBuild(Demangled namespace) {
DemangledString demangledString = new DemangledString(mangledSource, demangledSource,
"typeinfo-name", type, -1/*unknown length*/, false);
demangledString.setSpecialPrefix("typeinfo name for ");
demangledString.setSpecialPrefix(TYPEINFO_NAME_FOR);
String namespaceString = removeBadSpaces(type);
setNamespace(demangledString, namespaceString);
return demangledString;
@@ -1374,15 +1370,15 @@ public class GnuDemanglerParser {
/*
Samples:
prefix: construction vtable for
prefix: construction vtable for
name: construction-vtable
prefix: vtable for
prefix: vtable for
name: vtable
prefix: typeinfo name for
prefix: typeinfo name for
name: typeinfo-name
prefix: covariant return thunk
name: covariant-return
*/
@@ -1439,9 +1435,9 @@ public class GnuDemanglerParser {
int end = matcher.end(2); // operator chars start
//
// The 'operator' functions have symbols that confuse our default function parsing.
// Specifically, operators that use shift symbols (<, <<, >, >>) will cause our
// template parsing to fail. To defeat the failure, we will install a temporary
// The 'operator' functions have symbols that confuse our default function parsing.
// Specifically, operators that use shift symbols (<, <<, >, >>) will cause our
// template parsing to fail. To defeat the failure, we will install a temporary
// function name here and then restore it after parsing is finished.
//
@@ -1722,7 +1718,7 @@ public class GnuDemanglerParser {
}
/**
* An object that will parse a function signature string into parts: return type, name,
* An object that will parse a function signature string into parts: return type, name,
* and parameters. {@link #isValidFunction()} can be called to check if the given sting is
* indeed a function signature.
*/
@@ -1791,8 +1787,8 @@ public class GnuDemanglerParser {
* remove bad spaces, which is all whitespace that is not needed to separate distinct objects
* inside of a demangled string.
*
* <p>Generally, this class removes spaces within templates and parameter lists. It will
* remove some spaces, while converting some to underscores.
* <p>Generally, this class removes spaces within templates and parameter lists. It will
* remove some spaces, while converting some to underscores.
*/
private class CondensedString {
@@ -1862,7 +1858,7 @@ public class GnuDemanglerParser {
}
/**
* Returns the original string value that has been 'condensed', which means to remove
* Returns the original string value that has been 'condensed', which means to remove
* internal spaces
* @return the condensed string
*/
@@ -22,9 +22,11 @@ import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import docking.options.editor.BooleanEditor;
import ghidra.app.cmd.label.AddLabelCmd;
import ghidra.app.util.demangler.gnu.GnuDemanglerOptions;
import ghidra.app.util.demangler.gnu.GnuDemanglerFormat;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.EnumEditor;
import ghidra.framework.options.Options;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
@@ -34,7 +36,6 @@ import ghidra.program.model.symbol.*;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
import ghidra.test.ToyProgramBuilder;
import ghidra.util.Msg;
import ghidra.util.StringUtilities;
import ghidra.util.task.TaskMonitor;
public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationTest {
@@ -99,6 +100,7 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
Address addr = addr("0x110");
createSymbol(addr, mangled);
setFormat(GnuDemanglerFormat.AUTO);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER, true);
analyze();
@@ -117,7 +119,7 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
Address addr = addr("0x110");
createSymbol(addr, mangled);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_PARAMETERS, "-s rust");
setFormat(GnuDemanglerFormat.RUST);
analyze();
@@ -135,7 +137,7 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
Address addr = addr("0x110");
createSymbol(addr, mangled);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_PARAMETERS, "-s dlang");
setFormat(GnuDemanglerFormat.DLANG);
analyze();
@@ -143,104 +145,22 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
}
@Test
public void testMangledString_WithArguments_Invalid() {
public void testUseDeprecatedOptionUpdatesAvailableFormats() {
//
// The below demangles to std::io::Read::read_to_end
//
String mangled = "_ZN3std2io4Read11read_to_end17hb85a0f6802e14499E";
setOption_UseDeprecatedDemangler(false);
assertFormatAvailable(GnuDemanglerFormat.RUST, true);
Address addr = addr("0x110");
createSymbol(addr, mangled);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_PARAMETERS, "-s badformatname");
analyze();
assertNotDemangled(addr, "read_to_end");
assertMessageLogLine("java.io.IOException: Error starting demangler with command");
assertMessageLogLine("Invalid options", GnuDemanglerOptions.GNU_DEMANGLER_V2_33_1);
}
@Test
public void testDeprecatedMangledString_WithArguments_Invalid() {
//
// The below demangles to std::io::Read::read_to_end
//
String mangled = "_ZN3std2io4Read11read_to_end17hb85a0f6802e14499E";
Address addr = addr("0x110");
createSymbol(addr, mangled);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER, true);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_PARAMETERS, "-s badformatname");
analyze();
assertNotDemangled(addr, "read_to_end");
assertMessageLogLine("java.io.IOException: Error starting demangler with command");
assertMessageLogLine("Invalid options", GnuDemanglerOptions.GNU_DEMANGLER_V2_33_1);
assertMessageLogLine("Invalid options", GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
}
@Test
public void testDeprecatedMangledString_WithArguments_InvalidModernArguments_ValidDeprecatedArguments() {
//
// The below demangles to std::io::Read::read_to_end
//
String mangled = "_ZN3std2io4Read11read_to_end17hb85a0f6802e14499E";
Address addr = addr("0x110");
createSymbol(addr, mangled);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER, true);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_PARAMETERS, "-s arm");
analyze();
assertNotDemangled(addr, "read_to_end");
assertMessageLogLine("java.io.IOException: Error starting demangler with command");
assertMessageLogLine("Invalid options", GnuDemanglerOptions.GNU_DEMANGLER_V2_33_1);
assertMessageNotInLogLine("Invalid options", GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
setOption_UseDeprecatedDemangler(true);
assertFormatAvailable(GnuDemanglerFormat.RUST, false);
}
// things missed:
// -demangle error case in base class...this is OK
// -error case in applyTo method in base class
// -use deprecated demangler case in validateOptions
//==================================================================================================
// Private Methods
//==================================================================================================
private void assertMessageLogLine(String... expected) {
String allMessages = log.toString();
String[] logLines = allMessages.split("\n");
for (String line : logLines) {
if (StringUtilities.containsAllIgnoreCase(line, expected)) {
return;
}
}
fail("The folllowing source text did not have a line containing:\n" +
Arrays.toString(expected) + "\n\nActual Text:\n" + allMessages);
}
private void assertMessageNotInLogLine(String... expected) {
String allMessages = log.toString();
String[] logLines = allMessages.split("\n");
for (String line : logLines) {
if (StringUtilities.containsAllIgnoreCase(line, expected)) {
fail("The folllowing source text unexpectedly has a line containing:\n" +
Arrays.toString(expected) + "\n\nActual Text:\n" + allMessages);
}
}
}
//==================================================================================================
private void analyze() {
tx(program, () -> analyzer.added(program, program.getMemory(), TaskMonitor.DUMMY, log));
@@ -270,6 +190,32 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
fail("Unable to find demangled symbol '" + name + "'");
}
private void assertFormatAvailable(GnuDemanglerFormat format, boolean isAvailable) {
Options options = program.getOptions("Analyzers");
Options analyzerOptions = options.getOptions(analyzer.getName());
EnumEditor enumEditor =
(EnumEditor) runSwing(() -> analyzerOptions.getPropertyEditor("Demangler Format"));
assertNotNull(enumEditor);
Enum<?>[] values = enumEditor.getEnums();
for (Enum<?> enum1 : values) {
if (format.equals(enum1)) {
if (isAvailable) {
return;
}
fail("Found bad enum in list of choices: " + format + ".\nFound: " +
Arrays.toString(values));
}
}
if (isAvailable) {
fail("Did not find enum in list of choices: " + format + ".\nInstead found: " +
Arrays.toString(values));
}
}
private void setOption(String optionName, boolean doUse) {
String fullOptionName = analyzer.getName() + Options.DELIMITER_STRING + optionName;
@@ -288,14 +234,27 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
fail("Could not find option '" + optionName + "'");
}
private void setOption(String optionName, String value) {
private void setOption_UseDeprecatedDemangler(boolean use) {
Options options = program.getOptions("Analyzers");
Options analyzerOptions = options.getOptions(analyzer.getName());
BooleanEditor enumEditor = (BooleanEditor) runSwing(
() -> analyzerOptions.getPropertyEditor("Use Deprecated Demangler"));
assertNotNull(enumEditor);
runSwing(() -> enumEditor.setValue(use));
}
private void setFormat(GnuDemanglerFormat format) {
String optionName = GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_FORMAT;
String fullOptionName = analyzer.getName() + Options.DELIMITER_STRING + optionName;
Options options = program.getOptions("Analyzers");
for (String name : options.getOptionNames()) {
if (name.equals(fullOptionName)) {
tx(program, () -> options.setString(optionName, value));
tx(program, () -> options.setEnum(optionName, format));
// we must call this manually, since we are not using a tool
analyzer.optionsChanged(options, program);
@@ -32,8 +32,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
@Before
public void setUp() throws Exception {
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess(
GnuDemanglerOptions.GNU_DEMANGLER_V2_33_1);
process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_33_1);
parser = new GnuDemanglerParser();
}
@@ -111,8 +111,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testFunctionPointers() throws Exception {
String mangled = "__t6XpsMap2ZlZP14CORBA_TypeCodePFRCl_UlUlUlf";
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess(
GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled);
@@ -564,8 +564,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String mangled = "CalcPortExposedRect__13LScrollerViewCFR4Rectb";
// use an older demangler; the current demangler cannot handle this string
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess(
GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled);
@@ -589,8 +589,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String mangled = "__dt__Q26MsoDAL9VertFrameFv";
// use an older demangler; the current demangler cannot handle this string
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess(
GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled);
@@ -630,8 +630,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String mangled = "GetColWidths__13CDataRendererCFRA7_s";
// use an older demangler; the current demangler cannot handle this string
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess(
GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled);
@@ -655,8 +655,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String mangled = "GetColWidths__13CDataRendererCFPA7_s";
// use an older demangler; the current demangler cannot handle this string
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess(
GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled);
@@ -709,13 +709,13 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// This is testing a bug where we were 'off by one' when the array pointer syntax was
// followed by another parameter.
//
// The below demangles to _gmStage2(SECTION_INFO *, int *, int (*)[12], int, short const *)
// The below demangles to _gmStage2(SECTION_INFO *, int *, int (*)[12], int, short const *)
//
String mangled = "_gmStage2__FP12SECTION_INFOPiPA12_iiPCs";
// use an older demangler; the current demangler cannot handle this string
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess(
GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled);
@@ -749,8 +749,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String mangled = "__ct__Q24CStr6BufferFR4CStrUl";
// use an older demangler; the current demangler cannot handle this string
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess(
GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled);
@@ -887,16 +887,14 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
@Test
public void testOverloadedShiftOperatorTemplated_LeftShift() {
String raw =
"std::basic_ostream<char, std::char_traits<char> >& " +
"std::operator<< <std::char_traits<char> >" +
"(std::basic_ostream<char, std::char_traits<char> >&, char const*)";
String raw = "std::basic_ostream<char, std::char_traits<char> >& " +
"std::operator<< <std::char_traits<char> >" +
"(std::basic_ostream<char, std::char_traits<char> >&, char const*)";
String formatted = "std::basic_ostream<char,std::char_traits<char>> & " +
"std::operator<<<std::char_traits<char>>" +
"(std::basic_ostream<char,std::char_traits<char>> &,char const *)";
DemangledObject object = parser.parse(
"_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc",
raw);
DemangledObject object =
parser.parse("_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc", raw);
String name = object.getName();
assertEquals("operator<<", name);
assertEquals(formatted, object.getSignature());
@@ -928,15 +926,15 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String demangled = process.demangle(mangled);
/*
typeinfo for
typeinfo for
std::__ndk1::__function::__func<
dummy::it::other::Namespace::function(float)::$_2::operator()(dummy::it::other::Namespace*) const::{lambda(dummy::it::other::Namespace*)#1},
std::__ndk1::allocator<{lambda(dummy::it::other::Namespace*)#1}>,
int (dummy::it::other::Namespace*)
>
'__func' has 3 template parameters, the operator and the allocator
*/
String dummyNs = "dummy::it::other::Namespace";
@@ -985,7 +983,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testOperatorCastTo() throws Exception {
//
// Mangled: _ZNKSt17integral_constantIbLb0EEcvbEv
//
//
// Demangled: std::integral_constant<bool, false>::operator bool() const
String mangled = "_ZNKSt17integral_constantIbLb0EEcvbEv";
@@ -1005,11 +1003,11 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
//
// Converts the object upon which it is overridden to the given value.
//
//
// Format: operator std::string() const { return "bob"; }
//
//
//
//
//
// Mangled: _ZNK6Magick5ColorcvSsEv
//
@@ -1031,7 +1029,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
@Test
public void testConversionOperatorWithConst() throws Exception {
//
//
//
// Mangled: _ZN12_GLOBAL__N_120decode_charset_iconvEPKc
//
@@ -1040,7 +1038,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
//
// Converts the object upon which it is overridden to the given value.
//
//
// Format: operator std::string() const { return "bob"; }
//
//
@@ -1064,7 +1062,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
//
// Converts the object upon which it is overridden to the given value.
//
//
// Format: operator delete(void*)
//
@@ -1084,7 +1082,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
//
// Converts the object upon which it is overridden to the given value.
//
//
// Format: operator delete[](void*)
//
@@ -1100,7 +1098,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
//
// Converts the object upon which it is overridden to the given value.
//
//
// Format: operator new(unsigned long)
//
@@ -1217,7 +1215,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// Mangled: _ZN2Dr15ClipboardHelper17FTransferGvmlDataERN3Art11TransactionERKN3Ofc13TReferringPtrINS_10DrawingE2oEEEbNS4_7TCntPtrI11IDataObjectEERNS_18IClientDataCreatorERNS4_7TVectorINS4_8TWeakPtrINS_14DrawingElementEEELj0ELj4294967295EEERNS1_6Rect64E
//
// Demangled: Dr::ClipboardHelper::FTransferGvmlData(Art::Transaction&, Ofc::TReferringPtr<Dr::DrawingE2o> const&, bool, Ofc::TCntPtr<IDataObject>, Dr::IClientDataCreator&, Ofc::TVector<Ofc::TWeakPtr<Dr::DrawingElement>, 0u, 4294967295u>&, Art::Rect64&)
//
//
String mangled =
"_ZN2Dr15ClipboardHelper17FTransferGvmlDataERN3Art11TransactionERKN3Ofc13TReferringPtrINS_10DrawingE2oEEEbNS4_7TCntPtrI11IDataObjectEERNS_18IClientDataCreatorERNS4_7TVectorINS4_8TWeakPtrINS_14DrawingElementEEELj0ELj4294967295EEERNS1_6Rect64E";
@@ -1235,11 +1233,11 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
@Test
public void testTemplatedParametersWithCast_OldStyleDemangle() throws Exception {
//
// This demangled string has appeared at some point in the past. It no longer looks like
// This demangled string has appeared at some point in the past. It no longer looks like
// this (note the odd syntax of '<(int)2085>&)')
//
// Ofc::TSimpleTypeHelper<Art::Percentage>::ToString(Art::Percentage const&, Ofc::TFixedVarStr<(int)2085>&)
//
//
String demangled =
"Ofc::TSimpleTypeHelper<Art::Percentage>::ToString(Art::Percentage const&, Ofc::TFixedVarStr<(int)2085>&)";
DemangledObject object = parser.parse("nomangled", demangled);
@@ -1257,7 +1255,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// Mangled: _ZN4Core9AsyncFile7performEON3WTF1FIFNS2_IFvRNS_10FileClientEEEERNS_4FileEEEE
//
// Demangled: Core::AsyncFile::perform(WTF::F<WTF::F<void (Core::FileClient&)> (Core::File&)>&&)
//
//
String mangled =
"_ZN4Core9AsyncFile7performEON3WTF1FIFNS2_IFvRNS_10FileClientEEEERNS_4FileEEEE";
@@ -1287,7 +1285,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testFunctionInsideOfTemplates_NoArguments_NoPointerParens() throws Exception {
//
// Mangled: _ZN15LogLevelMonitor27registerKeysChangedCallbackERKN5boost8functionIFvvEEE
//
//
// Demangled: LogLevelMonitor::registerKeysChangedCallback(boost::function<void ()> const&)
String mangled =
@@ -1320,7 +1318,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testFunctionInsideOfTemplates_WithArguments_NoPointerParens() throws Exception {
//
// Mangled: _ZN9DnsThread32set_mutate_ares_options_callbackERKN5boost8functionIFvP12ares_optionsPiEEE
//
//
// Demangled: DnsThread::set_mutate_ares_options_callback(boost::function<void (ares_options*, int*)> const&)
String mangled =
@@ -1354,7 +1352,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testTemplatesThatContainFunctionSignatures() throws Exception {
//
// Mangled: _ZNSt6vectorIN5boost8functionIFvvEEESaIS3_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS3_S5_EERKS3_
//
//
// Demangled: std::vector<boost::function<void ()>, std::allocator<boost::function<void ()> > >::_M_insert_aux(__gnu_cxx::__normal_iterator<boost::function<void ()>*, std::vector<boost::function<void ()>, std::allocator<boost::function<void ()> > > >, boost::function<void ()> const&)
String mangled =
@@ -1405,7 +1403,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testVtableParsingError_NoSpaceBeforeTrailingDigits() throws Exception {
//
// Mangled: _ZTCN6Crypto10HmacSha256E0_NS_3MacE
//
//
// Demangled: construction vtable for Crypto::Mac-in-Crypto::HmacSha256
//
@@ -1425,7 +1423,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testVarArgs() throws Exception {
//
// Mangled: _Z11testVarArgsiz
//
//
// Demangled: testVarArgs(int, ...)
//
@@ -1449,7 +1447,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testMultidimensionalArrayFunctionParameter() throws Exception {
//
// Mangled: _ZN12uavcan_stm329CanDriverC1ILj64EEERA2_AT__NS_9CanRxItemE
//
//
// Demangled: uavcan_stm32::CanDriver::CanDriver<64u>(uavcan_stm32::CanRxItem (&) [2][64u])
//
@@ -1473,12 +1471,11 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// This is a function name that the native demangler tries to demangle, but should not:
// Input: uv__dup
// Incorrect Native Output: uv(double, *__restrict)
//
//
String mangled = "uv__dup";
GnuDemangler demangler = new GnuDemangler();
DemangledObject res = demangler.demangle(mangled);
assertNull(res);
DemangledObject demangled = demangler.demangle(mangled);
assertNull(demangled);
}
@Test
@@ -1486,7 +1483,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
//
// Mangled: _ZZN9__gnu_cxx6__stoaIlicJiEEET0_PFT_PKT1_PPS3_DpT2_EPKcS5_PmS9_EN11_Save_errnoC2Ev
//
//
// Demangled: __gnu_cxx
// ::
// __stoa<long, int, char, int>(long (*)(char const*, char**, int), char const*, char const*, unsigned long*, int)
@@ -1497,7 +1494,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
//
// This is _Save_errno struct's constructor inside of the stoa templated function, in the
// __gnu_cxx namespace.
//
//
String mangled =
"_ZZN9__gnu_cxx6__stoaIlicJiEEET0_PFT_PKT1_PPS3_DpT2_EPKcS5_PmS9_EN11_Save_errnoC2Ev";
@@ -1518,7 +1515,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
//
// Mangled: _ZNK2cc14ScrollSnapTypeneERKS0_
//
//
// Demangled: cc::ScrollSnapType::operator!=(cc::ScrollSnapType const&) const
//
@@ -1548,8 +1545,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String name =
"for_each_args<WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1},brigand::type_<std::__1::integral_constant<long,0l>>,WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1}<std::__1<long,1l>>,WebCore::JSConverter<WebCore::IDLUnion<WebCore::IDLNull,WebCore::IDLDOMString,WebCore::IDLUnrestrictedDouble>>::convert(JSC::ExecState&,WebCore::JSDOMGlobalObject&,WTF::Variant<decltype(nullptr),WTF::String,double>const&)::{lambda(auto:1&&)#1}<std::__1<long,2l>>>";
assertName(object, name,
"brigand");
assertName(object, name, "brigand");
String signature = object.getSignature(false);
assertEquals(
@@ -1568,8 +1564,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
//
// WebCore::FontSelectionAlgorithm::filterCapability
// (
// bool*,
// WebCore::FontSelectionAlgorithm::DistanceResult (WebCore::FontSelectionAlgorithm::*)(WebCore::FontSelectionCapabilities) const,
// bool*,
// WebCore::FontSelectionAlgorithm::DistanceResult (WebCore::FontSelectionAlgorithm::*)(WebCore::FontSelectionCapabilities) const,
// WebCore::FontSelectionRange WebCore::FontSelectionCapabilities::*
// )
//
@@ -1601,10 +1597,10 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
//
// Mangled: __ZN7WebCore12TextCodecICU14registerCodecsEPFvPKcON3WTF8FunctionIFNSt3__110unique_ptrINS_9TextCodecENS5_14default_deleteIS7_EEEEvEEEE
//
// Demangled: undefined WebCore::TextCodecICU::registerCodecs(void ()(char const *,WTF::Function<std::__1::unique_ptr<WebCore::TextCodec,std::__1::default_delete<WebCore::TextCodec>> ()> &&))
// Demangled: undefined WebCore::TextCodecICU::registerCodecs(void ()(char const *,WTF::Function<std::__1::unique_ptr<WebCore::TextCodec,std::__1::default_delete<WebCore::TextCodec>> ()> &&))
//
// The regression tested here revolves around this parameter:
//
//
// void ()(char const *,WTF::Function<std::__1::unique_ptr<WebCore::TextCodec,std::__1::default_delete<WebCore::TextCodec>> ()> &&
//
// (note the trailing '()' chars)
@@ -1638,7 +1634,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
//
// where the above is a parameter to function, where the params look like:
// (
// WTF::Visitor<WTF::TextBreakIterator::following(unsigned int) const::{lambda(auto:1 const&)#1}>&,
// WTF::Visitor<WTF::TextBreakIterator::following(unsigned int) const::{lambda(auto:1 const&)#1}>&,
// (WTF::__multi_visitor_return_type&&)...
// )
//
@@ -1670,8 +1666,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertNotNull(object);
assertType(object, DemangledFunction.class);
String name =
"operator=";
String name = "operator=";
assertName(object, name, "WTF", "Function<void()>");
String signature = object.getSignature(false);
@@ -1706,18 +1701,18 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testFunctionWithLambdaParameter() throws Exception {
//
// Mangled: _ZN3JSC9Structure3addILNS0_9ShouldPinE1EZNS_8JSObject35prepareToPutDirectWithoutTransitionERNS_2VMENS_12PropertyNameEjjPS0_EUlRKNS_24GCSafeConcurrentJSLockerEiiE_EEiS5_S6_jRKT0_
// Mangled: _ZN3JSC9Structure3addILNS0_9ShouldPinE1EZNS_8JSObject35prepareToPutDirectWithoutTransitionERNS_2VMENS_12PropertyNameEjjPS0_EUlRKNS_24GCSafeConcurrentJSLockerEiiE_EEiS5_S6_jRKT0_
//
// Demangled: int
// Demangled: int
// JSC::Structure::add<
// (JSC::Structure::ShouldPin)1,
// (JSC::Structure::ShouldPin)1,
// JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&, JSC::PropertyName, unsigned int, unsigned int, JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1}
// >(
// JSC::VM&, JSC::PropertyName,
// unsigned int,
// JSC::VM&, JSC::PropertyName,
// unsigned int,
// JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&, JSC::PropertyName, unsigned int, unsigned int, JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1} const&
// )
//
//
//
DemangledObject object = parser.parse(
@@ -1740,7 +1735,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testFunctionInLambdaNamespace() throws Exception {
//
// Mangled: _ZZN12GrGLFunctionIFPKhjEEC1IZN13skia_bindings28CreateGLES2InterfaceBindingsEPN3gpu5gles214GLES2InterfaceEPNS6_14ContextSupportEE3$_0EET_ENUlPKvjE_8__invokeESF_j
// Mangled: _ZZN12GrGLFunctionIFPKhjEEC1IZN13skia_bindings28CreateGLES2InterfaceBindingsEPN3gpu5gles214GLES2InterfaceEPNS6_14ContextSupportEE3$_0EET_ENUlPKvjE_8__invokeESF_j
//
// Demangled: GrGLFunction<unsigned char const* (unsigned int)>
// ::
@@ -1771,7 +1766,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testFunctionWithLamba_WithUnnamedType() throws Exception {
//
// Mangled: _ZN13SoloGimbalEKFUt_C2Ev
// Mangled: _ZN13SoloGimbalEKFUt_C2Ev
//
// Demangled: SoloGimbalEKF::{unnamed type#1}::SoloGimbalEKF()
//
@@ -1791,7 +1786,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
//
// Mangled: _Z11wrap_360_cdIiEDTcl8wrap_360fp_Lf42c80000EEET_
//
//
// Demangled: decltype (wrap_360({parm#1}, (float)[42c80000])) wrap_360_cd<int>(int)
//
// 'wrap_360_cd<int>(int)' is a function that takes an int and then passes that int along
@@ -0,0 +1,160 @@
/* ###
* 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.gnu;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
import org.junit.Test;
import static ghidra.app.util.demangler.gnu.GnuDemanglerFormat.*;
import java.io.IOException;
public class GnuDemanglerOptionsTest extends AbstractGhidraHeadlessIntegrationTest {
@Test
public void testAuto_withDeprecated() throws IOException {
GnuDemanglerOptions options = new GnuDemanglerOptions(AUTO, true);
getNativeProcess(options);
}
@Test
public void testAuto_withModern() throws IOException {
GnuDemanglerOptions options = new GnuDemanglerOptions(AUTO, false);
getNativeProcess(options);
}
@Test
public void testGnu_withDeprecated() throws IOException {
GnuDemanglerOptions options = new GnuDemanglerOptions(GNU, true);
getNativeProcess(options);
}
@Test(expected = IllegalArgumentException.class)
public void testGnu_withModern() {
new GnuDemanglerOptions(GNU, false);
}
@Test
public void testLucid_withDeprecated() throws IOException {
GnuDemanglerOptions options = new GnuDemanglerOptions(LUCID, true);
getNativeProcess(options);
}
@Test(expected = IllegalArgumentException.class)
public void testLucid_withModern() {
new GnuDemanglerOptions(LUCID, false);
}
@Test
public void testArm_withDeprecated() throws IOException {
GnuDemanglerOptions options = new GnuDemanglerOptions(ARM, true);
getNativeProcess(options);
}
@Test(expected = IllegalArgumentException.class)
public void testArm_withModern() {
new GnuDemanglerOptions(ARM, false);
}
@Test
public void testHp_withDeprecated() throws IOException {
GnuDemanglerOptions options = new GnuDemanglerOptions(HP, true);
getNativeProcess(options);
}
@Test(expected = IllegalArgumentException.class)
public void testHp_withModern() {
new GnuDemanglerOptions(HP, false);
}
@Test
public void testEdg_withDeprecated() throws IOException {
GnuDemanglerOptions options = new GnuDemanglerOptions(EDG, true);
getNativeProcess(options);
}
@Test(expected = IllegalArgumentException.class)
public void testEdg_withModern() {
new GnuDemanglerOptions(EDG, false);
}
@Test
public void testGnuV3_withDeprecated() throws IOException {
GnuDemanglerOptions options = new GnuDemanglerOptions(GNUV3, true);
getNativeProcess(options);
}
@Test
public void testGnuV3_withModern() throws IOException {
GnuDemanglerOptions options = new GnuDemanglerOptions(GNUV3, false);
getNativeProcess(options);
}
@Test
public void testJava_withDeprecated() throws IOException {
GnuDemanglerOptions options = new GnuDemanglerOptions(JAVA, true);
getNativeProcess(options);
}
@Test
public void testJava_withModern() throws IOException {
GnuDemanglerOptions options = new GnuDemanglerOptions(JAVA, false);
getNativeProcess(options);
}
@Test
public void testGnat_withDeprecated() throws IOException {
GnuDemanglerOptions options = new GnuDemanglerOptions(GNAT, true);
getNativeProcess(options);
}
@Test
public void testGnat_withModern() throws IOException {
GnuDemanglerOptions options = new GnuDemanglerOptions(GNAT, false);
getNativeProcess(options);
}
@Test(expected = IllegalArgumentException.class)
public void testDlang_withDeprecated() {
new GnuDemanglerOptions(DLANG, true);
}
@Test
public void testDlang_withModern() throws IOException {
GnuDemanglerOptions options = new GnuDemanglerOptions(DLANG, false);
getNativeProcess(options);
}
@Test(expected = IllegalArgumentException.class)
public void testRust_withDeprecated() {
new GnuDemanglerOptions(RUST, true);
}
@Test
public void testRust_withModern() throws IOException {
GnuDemanglerOptions options = new GnuDemanglerOptions(RUST, false);
getNativeProcess(options);
}
private static GnuDemanglerNativeProcess getNativeProcess(GnuDemanglerOptions options)
throws IOException {
String demanglerName = options.getDemanglerName();
String applicationOptions = options.getDemanglerApplicationArguments();
return GnuDemanglerNativeProcess.getDemanglerNativeProcess(demanglerName,
applicationOptions);
}
}
@@ -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.
@@ -55,7 +55,12 @@ public class GnuDemanglerTest extends AbstractGenericTest {
demangler.canDemangle(program);// this perform initialization
// this throws an exception with the bug in place
demangler.demangle(mangled);
try {
demangler.demangle(mangled);
}
catch (DemangledException e) {
assertTrue(e.isInvalidMangledName());
}
}
@Test
@@ -157,33 +162,16 @@ public class GnuDemanglerTest extends AbstractGenericTest {
assertEquals("ABC", d.getValue());
}
@Test
public void testDemangler_Format_EDG_DemangleOnlyKnownPatterns_False()
throws DemangledException {
String mangled = "_$_10MyFunction";
GnuDemangler demangler = new GnuDemangler();
demangler.canDemangle(program);// this perform initialization
GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(false);
options.setDemanglerName(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
DemangledObject result = demangler.demangle(mangled, options);
assertNotNull(result);
assertEquals("undefined MyFunction::~MyFunction(void)", result.getSignature(false));
}
@Test
public void testDemangler_Format_EDG_DemangleOnlyKnownPatterns_True()
throws DemangledException {
/*
Note:
This test is less of a requirement and more of an observation. This symbol was
This test is less of a requirement and more of an observation. This symbol was
seen in the wild and is claimed to be of the Edison Design Group (EDG) format.
It fails our parsing due to its resemblance to non-mangled text (see
the test testNonMangledSymbol()). If we update the code that checks for this
the test testNonMangledSymbol()). If we update the code that checks for this
noise, then this test and it's parter should be consolidated.
*/
@@ -192,16 +180,31 @@ public class GnuDemanglerTest extends AbstractGenericTest {
GnuDemangler demangler = new GnuDemangler();
demangler.canDemangle(program);// this perform initialization
GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(true); // do not try
options.setDemanglerName(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
GnuDemanglerOptions options = new GnuDemanglerOptions(GnuDemanglerFormat.EDG);
DemangledObject result = demangler.demangle(mangled, options);
assertNull(result);
}
@Test
public void testDemangler_Format_CodeWarrior_MacOS8or9() throws DemangledException {
public void testDemangler_Format_EDG_DemangleOnlyKnownPatterns_False()
throws DemangledException {
String mangled = "_$_10MyFunction";
GnuDemangler demangler = new GnuDemangler();
demangler.canDemangle(program);// this perform initialization
GnuDemanglerOptions options = new GnuDemanglerOptions(GnuDemanglerFormat.AUTO, true);
options.setDemangleOnlyKnownPatterns(false);
DemangledObject result = demangler.demangle(mangled, options);
assertNotNull(result);
assertEquals("undefined MyFunction::~MyFunction(void)", result.getSignature(false));
}
@Test
public void testDemangler_Format_CodeWarrior_MacOS8or9() throws DemangledException {
// NOTE: mangled CodeWarrior format symbols with templates will fail
// This is because the GNU demangler does not support CodeWarrior
// .scroll__10TTextPanelFUcsi
String mangled = ".scroll__10TTextPanelFUcsi";
@@ -209,9 +212,8 @@ public class GnuDemanglerTest extends AbstractGenericTest {
GnuDemangler demangler = new GnuDemangler();
demangler.canDemangle(program);// this perform initialization
GnuDemanglerOptions options = new GnuDemanglerOptions();
GnuDemanglerOptions options = new GnuDemanglerOptions(GnuDemanglerFormat.AUTO, true);
options.setDemangleOnlyKnownPatterns(false);
options.setDemanglerName(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
DemangledObject result = demangler.demangle(mangled, options);
assertNotNull(result);
assertEquals("undefined TTextPanel::scroll(unsigned char,short,int)",
@@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,38 +15,26 @@
*/
package ghidra.framework.options;
import ghidra.util.Msg;
import java.beans.PropertyEditorSupport;
import java.lang.reflect.Method;
import java.util.HashSet;
import ghidra.util.Msg;
public class EnumEditor extends PropertyEditorSupport {
private Enum<?> value;
/**
*
* @see java.beans.PropertyEditor#setValue(java.lang.Object)
*/
@Override
public void setValue(Object o) {
value = (Enum<?>) o;
}
/**
*
* @see java.beans.PropertyEditor#getValue()
*/
@Override
public Object getValue() {
return value;
}
/**
*
* @see java.beans.PropertyEditor#getTags()
*/
@Override
public String[] getTags() {
@@ -85,28 +72,20 @@ public class EnumEditor extends PropertyEditorSupport {
return new Enum<?>[] { value };
}
/**
*
* @see java.beans.PropertyEditor#getAsText()
*/
@Override
public String getAsText() {
return value.toString();
}
/**
*
* @see java.beans.PropertyEditor#setAsText(java.lang.String)
*/
@Override
public void setAsText(String s) {
try {
Method m = value.getClass().getMethod("values");
Enum<?>[] enums = (Enum<?>[]) m.invoke(null);
for (int i = 0; i < enums.length; i++) {
if (s.equals(enums[i].toString())) {
value = enums[i];
for (Enum<?> enum1 : enums) {
if (s.equals(enum1.toString())) {
value = enum1;
break;
}
}
@@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,19 +16,19 @@
package ghidra.framework.options;
// Support for PropertyEditors that use tags.
import java.awt.event.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.*;
import javax.swing.*;
import javax.swing.JComboBox;
/**
* An implementation of a PropertyComponent that is represented as a
* combo box.
*/
public class PropertySelector extends JComboBox implements ItemListener {
public class PropertySelector extends JComboBox<String> implements ItemListener {
private PropertyEditor editor;
private PropertyEditor propertyEditor;
private boolean notifyEditorOfChanges = true;
/**
@@ -38,22 +37,23 @@ public class PropertySelector extends JComboBox implements ItemListener {
* changes in the combo box
*/
public PropertySelector(PropertyEditor pe) {
editor = pe;
String tags[] = editor.getTags();
for (int i = 0; i < tags.length; i++) {
addItem(tags[i]);
propertyEditor = pe;
String tags[] = propertyEditor.getTags();
for (String tag : tags) {
addItem(tag);
}
setSelectedIndex(0);
// This is a no-op if the getAsText is not a tag that we set from getTags() above
setSelectedItem(editor.getAsText());
setSelectedItem(propertyEditor.getAsText());
addItemListener(this);
invalidate();
editor.addPropertyChangeListener(new PropertyChangeListener() {
propertyEditor.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String value = editor.getAsText();
String value = propertyEditor.getAsText();
if (!value.equals(getSelectedItem())) {
notifyEditorOfChanges = false;
try {
@@ -67,14 +67,15 @@ public class PropertySelector extends JComboBox implements ItemListener {
});
}
/*
* (non-Javadoc)
* @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
*/
@Override
public void itemStateChanged(ItemEvent evt) {
if (notifyEditorOfChanges) {
String s = (String) getSelectedItem();
editor.setAsText(s);
if (!notifyEditorOfChanges) {
return;
}
String s = (String) getSelectedItem();
if (s != null) {
propertyEditor.setAsText(s);
}
}
}
@@ -61,7 +61,7 @@ public class GnuDemanglerIntegrationTest extends AbstractGhidraHeadlessIntegrati
GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(false);
options = options.withDeprecatedDemangler();
options = options.withDemanglerFormat(GnuDemanglerFormat.AUTO, true);
DemangledObject result = demangler.demangle(mangled, options);
assertNotNull(result);
assertEquals("undefined MyNamespace::MyFunction($ParamNamespace::paramName *)",
@@ -86,7 +86,7 @@ public class GnuDemanglerIntegrationTest extends AbstractGhidraHeadlessIntegrati
GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(false);
options = options.withDeprecatedDemangler();
options = options.withDemanglerFormat(GnuDemanglerFormat.AUTO, true);
DemangledObject result = demangler.demangle(mangled, options);
assertNotNull(result);
assertEquals("undefined SoloGimbalEKF::{unnamed_type#1}::SoloGimbalEKF(void)",
@@ -116,7 +116,7 @@ public class GnuDemanglerIntegrationTest extends AbstractGhidraHeadlessIntegrati
GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(false);
options = options.withDeprecatedDemangler();
options = options.withDemanglerFormat(GnuDemanglerFormat.AUTO, true);
DemangledObject result = demangler.demangle(mangled, options);
assertNotNull(result);
assertEquals(