GP-94 - Gnu Demangler - review fixes

Closes #2214
This commit is contained in:
dragonmacher 2021-02-12 16:05:26 -05:00
parent 443e398bb4
commit 8f1dc3f476
14 changed files with 386 additions and 319 deletions

View file

@ -386,10 +386,7 @@
<U><B>Use Deprecated Demangler</B></U> - <U><B>Use Deprecated Demangler</B></U> -
By default, GCC symbols will be demangled using the most up-to-date demangler 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 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 option on will invoke the now deprecated version of the demangler (<B>version 2.24</B>).
(<B>version 2.24</B>) if the preferred demangler cannot demangle a given symbol.
This option only has an effect when the demangler format is available in both
the deprecated and modern demanglers.
</P> </P>
<P> <P>
Support for older demangling styles was removed in <CODE>c++filt (v2.32)</CODE>. Support for older demangling styles was removed in <CODE>c++filt (v2.32)</CODE>.
@ -402,10 +399,15 @@
<P> <P>
The available programs are: The available programs are:
<UL> <UL>
<LI><CODE>demangler_gnu_v2_33_1</CODE></LI> <LI><CODE CLASS="path">
<LI><CODE>demangler_gnu_v2_24</CODE></LI> &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> </UL>
</P> </P>
<P style="background-color: #FFF0E0;"> <P style="background-color: #FFF0E0;">
<IMG SRC="../../shared/warning.png" />When using an external GNU demangler, <IMG SRC="../../shared/warning.png" />When using an external GNU demangler,
please understand the risks associated with using that version of the please understand the risks associated with using that version of the

View file

@ -16,7 +16,7 @@
package ghidra.app.util.demangler; 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 { public class DemanglerOptions {
@ -35,47 +35,47 @@ public class DemanglerOptions {
} }
/** /**
* Checks if the apply signature option is currently set. * Checks if the apply signature option is currently set
* *
* @return true if set to apply function signatures that are demangled. * @return true if set to apply function signatures that are demangled
*/ */
public boolean applySignature() { public boolean applySignature() {
return applySignature; return applySignature;
} }
/** /**
* Set the option 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. * @param applySignature true to apply function signatures that are demangled
*/ */
public void setApplySignature(boolean applySignature) { public void setApplySignature(boolean applySignature) {
this.applySignature = applySignature; this.applySignature = applySignature;
} }
/** /**
* Checks if the option to perform disassembly for known data structures (like functions) when * Checks if the option to perform disassembly for known data structures (like functions) when
* demangling is set. * demangling is set
* *
* @return true if the option is set. * @return true if the option is set
*/ */
public boolean doDisassembly() { public boolean doDisassembly() {
return doDisassembly; return doDisassembly;
} }
/** /**
* Sets the option to perform disassembly for known data structures (like functions) when * Sets the option to perform disassembly for known data structures (like functions) when
* demangling. * demangling
* *
* @param doDisassembly true to perform disassembly when demangling. * @param doDisassembly true to perform disassembly when demangling
*/ */
public void setDoDisassembly(boolean doDisassembly) { public void setDoDisassembly(boolean doDisassembly) {
this.doDisassembly = doDisassembly; this.doDisassembly = doDisassembly;
} }
/** /**
* Checks if the option to only demangle known mangled patterns is set. * Checks if the option to only demangle known mangled patterns is set
* *
* @return true if only known mangled patterns will be demangled. * @return true if only known mangled patterns will be demangled
*/ */
public boolean demangleOnlyKnownPatterns() { public boolean demangleOnlyKnownPatterns() {
return demangleOnlyKnownPatterns; return demangleOnlyKnownPatterns;
@ -83,10 +83,15 @@ public class DemanglerOptions {
/** /**
* Sets the option to only demangle known mangled patterns. Setting this to false causes * 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 * most symbols to be demangled, which may result in some symbols getting demangled that were
* actually mangled symbols. * not actually mangled symbols.
* *
* @param demangleOnlyKnownPatterns true to only demangle known mangled patterns. * <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) { public void setDemangleOnlyKnownPatterns(boolean demangleOnlyKnownPatterns) {
this.demangleOnlyKnownPatterns = demangleOnlyKnownPatterns; this.demangleOnlyKnownPatterns = demangleOnlyKnownPatterns;

View file

@ -21,8 +21,7 @@
//@category Examples.Demangler //@category Examples.Demangler
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledObject; import ghidra.app.util.demangler.DemangledObject;
import ghidra.app.util.demangler.gnu.GnuDemangler; import ghidra.app.util.demangler.gnu.*;
import ghidra.app.util.demangler.gnu.GnuDemanglerOptions;
import ghidra.program.model.symbol.Symbol; import ghidra.program.model.symbol.Symbol;
public class DemangleElfWithOptionScript extends GhidraScript { public class DemangleElfWithOptionScript extends GhidraScript {
@ -33,8 +32,8 @@ public class DemangleElfWithOptionScript extends GhidraScript {
GnuDemangler demangler = new GnuDemangler(); GnuDemangler demangler = new GnuDemangler();
if (!demangler.canDemangle(currentProgram)) { if (!demangler.canDemangle(currentProgram)) {
String executableFormat = currentProgram.getExecutableFormat(); String executableFormat = currentProgram.getExecutableFormat();
println("Cannot use the elf demangling options for executable format: " + println(
executableFormat); "Cannot use the elf demangling options for executable format: " + executableFormat);
return; return;
} }
@ -49,14 +48,12 @@ public class DemangleElfWithOptionScript extends GhidraScript {
String mangled = symbol.getName(); String mangled = symbol.getName();
GnuDemanglerOptions options = new GnuDemanglerOptions(); GnuDemanglerOptions options = new GnuDemanglerOptions(GnuDemanglerFormat.AUTO, false);
options.setDoDisassembly(false); options.setDoDisassembly(false);
options.setDemanglerApplicationArguments("-s auto");
/* /*
// for older formats use the deprecated demangler // for older formats use the deprecated demangler
options.setDemanglerName(GnuDemanglerOptions.GNU_DEMANGLER_V2_24); options = options.withDemanglerFormat(GnuDemanglerFormat.ARM, true);
options.setDemanglerApplicationArguments("-s arm");
*/ */
DemangledObject demangledObject = demangler.demangle(mangled, options); DemangledObject demangledObject = demangler.demangle(mangled, options);

View file

@ -19,6 +19,7 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.Arrays; import java.util.Arrays;
import docking.options.editor.BooleanEditor;
import ghidra.app.util.demangler.*; import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.gnu.*; import ghidra.app.util.demangler.gnu.*;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
@ -26,10 +27,8 @@ import ghidra.framework.options.*;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
import docking.options.editor.BooleanEditor;
/** /**
* 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 { public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
@ -87,12 +86,12 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
options.registerOption(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns, 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, OptionType.BOOLEAN_TYPE, options.registerOption(OPTION_NAME_USE_DEPRECATED_DEMANGLER, OptionType.BOOLEAN_TYPE,
useDeprecatedDemangler, help, OPTION_DESCRIPTION_DEPRECATED_DEMANGLER, editor); useDeprecatedDemangler, help, OPTION_DESCRIPTION_DEPRECATED_DEMANGLER, editor);
options.registerOption(OPTION_NAME_DEMANGLER_FORMAT, OptionType.ENUM_TYPE, options.registerOption(OPTION_NAME_DEMANGLER_FORMAT, OptionType.ENUM_TYPE, demanglerFormat,
demanglerFormat, help, OPTION_DESCRIPTION_DEMANGLER_FORMAT, formatEditor); help, OPTION_DESCRIPTION_DEMANGLER_FORMAT, formatEditor);
} }
@Override @Override
@ -102,7 +101,7 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns); options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns);
demanglerFormat = options.getEnum(OPTION_NAME_DEMANGLER_FORMAT, GnuDemanglerFormat.AUTO); demanglerFormat = options.getEnum(OPTION_NAME_DEMANGLER_FORMAT, GnuDemanglerFormat.AUTO);
useDeprecatedDemangler = useDeprecatedDemangler =
options.getBoolean(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler); options.getBoolean(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler);
} }
@Override @Override
@ -118,7 +117,7 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
@Override @Override
protected DemangledObject doDemangle(String mangled, DemanglerOptions demanglerOtions, protected DemangledObject doDemangle(String mangled, DemanglerOptions demanglerOtions,
MessageLog log) throws DemangledException { MessageLog log) throws DemangledException {
return demangler.demangle(mangled, (GnuDemanglerOptions) demanglerOtions); return demangler.demangle(mangled, demanglerOtions);
} }
private static class FormatEditor extends EnumEditor implements PropertyChangeListener { private static class FormatEditor extends EnumEditor implements PropertyChangeListener {
@ -145,16 +144,16 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
@Override @Override
public GnuDemanglerFormat[] getEnums() { public GnuDemanglerFormat[] getEnums() {
return Arrays.stream(GnuDemanglerFormat.values()) return Arrays.stream(GnuDemanglerFormat.values())
.filter(this::filter) .filter(this::filter)
.toArray(GnuDemanglerFormat[]::new); .toArray(GnuDemanglerFormat[]::new);
} }
@Override @Override
public String[] getTags() { public String[] getTags() {
return Arrays.stream(GnuDemanglerFormat.values()) return Arrays.stream(GnuDemanglerFormat.values())
.filter(this::filter) .filter(this::filter)
.map(GnuDemanglerFormat::name) .map(GnuDemanglerFormat::name)
.toArray(String[]::new); .toArray(String[]::new);
} }
@Override @Override
@ -164,7 +163,8 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
if (format.isAvailable(isDeprecatedDemangler())) { if (format.isAvailable(isDeprecatedDemangler())) {
setValue(format); setValue(format);
selector.setFormat(format); selector.setFormat(format);
} else { }
else {
setValue(GnuDemanglerFormat.AUTO); setValue(GnuDemanglerFormat.AUTO);
} }
} }
@ -178,18 +178,16 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
} }
} }
@SuppressWarnings("serial")
private static class FormatSelector extends PropertySelector { private static class FormatSelector extends PropertySelector {
public FormatSelector(FormatEditor fe) { public FormatSelector(FormatEditor fe) {
super(fe); super(fe);
} }
@SuppressWarnings("unchecked")
void reset(String[] tags) { void reset(String[] tags) {
removeAllItems(); removeAllItems();
for (int i = 0; i < tags.length; i++) { for (String tag : tags) {
addItem(tags[i]); addItem(tag);
} }
} }
@ -200,6 +198,6 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
void setFormat(GnuDemanglerFormat format) { void setFormat(GnuDemanglerFormat format) {
setSelectedItem(format.name()); setSelectedItem(format.name());
} }
} }
} }

View file

@ -106,16 +106,14 @@ public class GnuDemangler implements Demangler {
} }
boolean onlyKnownPatterns = options.demangleOnlyKnownPatterns(); boolean onlyKnownPatterns = options.demangleOnlyKnownPatterns();
DemangledObject demangledObject = DemangledObject demangledObject = parse(mangled, process, demangled, onlyKnownPatterns);
parse(mangled, process, demangled, onlyKnownPatterns);
if (demangledObject == null) { if (demangledObject == null) {
return demangledObject; return demangledObject;
} }
if (globalPrefix != null) { if (globalPrefix != null) {
DemangledFunction dfunc = DemangledFunction dfunc = new DemangledFunction(originalMangled, demangled,
new DemangledFunction(originalMangled, demangled, globalPrefix + demangledObject.getName());
globalPrefix + demangledObject.getName());
dfunc.setNamespace(demangledObject.getNamespace()); dfunc.setNamespace(demangledObject.getNamespace());
demangledObject = dfunc; demangledObject = dfunc;
} }
@ -163,6 +161,19 @@ public class GnuDemangler implements Demangler {
applicationOptions); applicationOptions);
} }
/**
* 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) { private boolean skip(String mangled, GnuDemanglerOptions options) {
// Ignore versioned symbols which are generally duplicated at the same address // Ignore versioned symbols which are generally duplicated at the same address
@ -179,36 +190,29 @@ public class GnuDemangler implements Demangler {
return false; // let it go through return false; // let it go through
} }
// TODO provide some checks specific to the other formats // This is the current list of known demangler start patterns. Add to this list if we
GnuDemanglerFormat format = options.getDemanglerFormat(); // find any other known GNU start patterns.
if (format == GnuDemanglerFormat.AUTO) { if (mangled.startsWith("_Z")) {
return false; return false;
} }
if (format == GnuDemanglerFormat.GNUV3) { if (mangled.startsWith("__Z")) {
// add to this list if we find any other known GNU start patterns return false;
if (mangled.startsWith("_Z")) { }
return false; if (mangled.startsWith("h__")) {
} return false; // not sure about this one
if (mangled.startsWith("__Z")) { }
return false; if (mangled.startsWith("?")) {
} return false; // not sure about this one
if (mangled.startsWith("h__")) { }
return false; // not sure about this one if (isGnu2Or3Pattern(mangled)) {
} return false;
if (mangled.startsWith("?")) {
return false; // not sure about this one
}
if (isGnu2Or3Pattern(mangled)) {
return false;
}
} }
return true; return true;
} }
private DemangledObject parse(String mangled, GnuDemanglerNativeProcess process, private DemangledObject parse(String mangled, GnuDemanglerNativeProcess process,
String demangled, String demangled, boolean demangleOnlyKnownPatterns) {
boolean demangleOnlyKnownPatterns) {
if (demangleOnlyKnownPatterns && !isKnownMangledString(mangled, demangled)) { if (demangleOnlyKnownPatterns && !isKnownMangledString(mangled, demangled)) {
return null; return null;
@ -224,7 +228,7 @@ public class GnuDemangler implements Demangler {
// We get requests to demangle strings that are not mangled. For newer mangled strings // 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 // 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 // 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) // check for the case where good strings have '__' in them (which is valid GNU2 mangling)

View file

@ -19,71 +19,74 @@ package ghidra.app.util.demangler.gnu;
* Enum representation of the available GnuDemangler formats * Enum representation of the available GnuDemangler formats
*/ */
public enum GnuDemanglerFormat { public enum GnuDemanglerFormat {
// OLD: none,auto,gnu,lucid,arm,hp,edg,gnu-v3,java,gnat // OLD: none,auto,gnu,lucid,arm,hp,edg,gnu-v3,java,gnat
// NEW: none,auto,gnu-v3,java,gnat,dlang,rust // NEW: none,auto,gnu-v3,java,gnat,dlang,rust
/** Automatic mangling format detection */ /** Automatic mangling format detection */
AUTO("", 0), AUTO("", Version.ALL),
/** GNUv2 mangling format */ /** GNUv2 mangling format */
GNU("gnu", -1), GNU("gnu", Version.DEPRECATED),
/** lucid mangling format */ /** lucid mangling format */
LUCID("lucid", -1), LUCID("lucid", Version.DEPRECATED),
/** arm mangling format */ /** arm mangling format */
ARM("arm", -1), ARM("arm", Version.DEPRECATED),
/** hp mangling format */ /** hp mangling format */
HP("hp", -1), HP("hp", Version.DEPRECATED),
/** mangling format used by the Edison Design Group (EDG) compiler */ /** mangling format used by the Edison Design Group (EDG) compiler */
EDG("edg", -1), EDG("edg", Version.DEPRECATED),
/** GNUv3 mangling format */ /** GNUv3 mangling format */
GNUV3("gnu-v3", 0), GNUV3("gnu-v3", Version.ALL),
/** Java mangling format */ /** Java mangling format */
JAVA("java", 0), JAVA("java", Version.ALL),
/** GNAT Ada compiler mangling format */ /** GNAT Ada compiler mangling format */
GNAT("gnat", 0), GNAT("gnat", Version.ALL),
/** D mangling format */ /** D mangling format */
DLANG("dlang", 1), DLANG("dlang", Version.MODERN),
/** Rust mangling format */ /** Rust mangling format */
RUST("rust", 1); RUST("rust", Version.MODERN);
/** the format option string */ /** the format option string used by the native demangler */
private final String format; private final String format;
/** private sentinal. deprecated = -1, both = 0, new = 1 */ private final Version version;
private final byte version;
private GnuDemanglerFormat(String format, int version) { private GnuDemanglerFormat(String format, Version version) {
this.format = format; this.format = format;
this.version = (byte) version; this.version = version;
} }
/** /**
* Checks if this format is available in the deprecated gnu demangler * Checks if this format is available in the deprecated gnu demangler
* @return true 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() { public boolean isDeprecatedFormat() {
return version <= 0; return version == Version.DEPRECATED || version == Version.ALL;
} }
/** /**
* Checks if this format is available in a modern version of the gnu demangler * 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. * @return true if this format is available in a modern version of the gnu demangler
*/ */
public boolean isModernFormat() { public boolean isModernFormat() {
return version >= 0; 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 * Checks if this format is available for the specified demangler
* @return the format option to be passed to the demangler * @param isDeprecated true for the deprecated demangler, false for the modern demangler
*/ * @return true if the format is available
public String getFormat() { */
return format; 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
}
} }

View file

@ -46,26 +46,45 @@ public class GnuDemanglerOptions extends DemanglerOptions {
private final GnuDemanglerFormat format; private final GnuDemanglerFormat format;
private final boolean isDeprecated; 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() { public GnuDemanglerOptions() {
// use default values
this(GnuDemanglerFormat.AUTO); this(GnuDemanglerFormat.AUTO);
} }
/**
* Constructor to specify a particular format
*
* @param format signals to use the given format
*/
public GnuDemanglerOptions(GnuDemanglerFormat format) { public GnuDemanglerOptions(GnuDemanglerFormat format) {
this.format = format; this(format, !format.isModernFormat());
// default to the "new" demangler if the format is available in both
this.isDeprecated = !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) { public GnuDemanglerOptions(GnuDemanglerFormat format, boolean isDeprecated) {
this.format = format; this.format = format;
this.isDeprecated = isDeprecated; this.isDeprecated = isDeprecated;
if (!format.isAvailable(isDeprecated)) { if (!format.isAvailable(isDeprecated)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
format.name() + " is not available in the "+getDemanglerName()); 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) { public GnuDemanglerOptions(DemanglerOptions copy) {
super(copy); super(copy);
@ -73,7 +92,8 @@ public class GnuDemanglerOptions extends DemanglerOptions {
GnuDemanglerOptions gCopy = (GnuDemanglerOptions) copy; GnuDemanglerOptions gCopy = (GnuDemanglerOptions) copy;
format = gCopy.format; format = gCopy.format;
isDeprecated = gCopy.isDeprecated; isDeprecated = gCopy.isDeprecated;
} else { }
else {
format = GnuDemanglerFormat.AUTO; format = GnuDemanglerFormat.AUTO;
isDeprecated = false; isDeprecated = false;
} }
@ -87,7 +107,7 @@ public class GnuDemanglerOptions extends DemanglerOptions {
} }
/** /**
* 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}. * default value is {@link #GNU_DEMANGLER_DEFAULT}.
* @return the name * @return the name
*/ */
@ -96,24 +116,25 @@ public class GnuDemanglerOptions extends DemanglerOptions {
} }
/** /**
* A convenience method to copy the state of this options object, changing the * A convenience method to copy the state of this options object, changing the
* demangler executable name and demangler format to the specified values. * demangler executable name and demangler format to the specified values
* @param format the demangling format to use *
* @param isDeprecated true to use the deprecated gnu demangler, else false * @param demanglerFormat the demangling format to use
* @param useDeprecated true to use the deprecated gnu demangler, else false
* @return the new options * @return the new options
* @throws IllegalArgumentException if the current format is not available in the * @throws IllegalArgumentException if the current format is not available in the
* selected demangler. * selected demangler.
*/ */
public GnuDemanglerOptions withDemanglerFormat(GnuDemanglerFormat format, boolean isDeprecated) public GnuDemanglerOptions withDemanglerFormat(GnuDemanglerFormat demanglerFormat,
throws IllegalArgumentException { boolean useDeprecated) throws IllegalArgumentException {
if (this.format == format && this.isDeprecated == isDeprecated) { if (this.format == demanglerFormat && this.isDeprecated == useDeprecated) {
return this; return this;
} }
if (format.isAvailable(isDeprecated)) { if (demanglerFormat.isAvailable(useDeprecated)) {
return new GnuDemanglerOptions(this, format, isDeprecated); return new GnuDemanglerOptions(this, demanglerFormat, useDeprecated);
} }
throw new IllegalArgumentException( throw new IllegalArgumentException(
format.name() + " is not available in the "+getDemanglerName()); demanglerFormat.name() + " is not available in the " + getDemanglerName());
} }
/** /**

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -896,9 +896,9 @@ public class GnuDemanglerParser {
/* /*
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: which is something like:
<,>,(,),&,*,[,] <,>,(,),&,*,[,]
It seems like the current code below is unnecessarily restrictive It seems like the current code below is unnecessarily restrictive
*/ */
@ -1187,9 +1187,9 @@ public class GnuDemanglerParser {
/* /*
Examples: Examples:
NS1::Function<>()::StructureName::StructureConstructor() NS1::Function<>()::StructureName::StructureConstructor()
*/ */
String nameString = removeBadSpaces(demangled).trim(); String nameString = removeBadSpaces(demangled).trim();
@ -1353,7 +1353,7 @@ public class GnuDemanglerParser {
DemangledObject doBuild(Demangled namespace) { DemangledObject doBuild(Demangled namespace) {
DemangledString demangledString = new DemangledString(mangledSource, demangledSource, DemangledString demangledString = new DemangledString(mangledSource, demangledSource,
"typeinfo-name", type, -1/*unknown length*/, false); "typeinfo-name", type, -1/*unknown length*/, false);
demangledString.setSpecialPrefix("typeinfo name for "); demangledString.setSpecialPrefix(TYPEINFO_NAME_FOR);
String namespaceString = removeBadSpaces(type); String namespaceString = removeBadSpaces(type);
setNamespace(demangledString, namespaceString); setNamespace(demangledString, namespaceString);
return demangledString; return demangledString;
@ -1372,13 +1372,13 @@ public class GnuDemanglerParser {
Samples: Samples:
prefix: construction vtable for prefix: construction vtable for
name: construction-vtable name: construction-vtable
prefix: vtable for prefix: vtable for
name: vtable name: vtable
prefix: typeinfo name for prefix: typeinfo name for
name: typeinfo-name name: typeinfo-name
prefix: covariant return thunk prefix: covariant return thunk
name: covariant-return name: covariant-return
*/ */

View file

@ -17,12 +17,16 @@ package ghidra.app.plugin.core.analysis;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.util.Arrays;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import docking.options.editor.BooleanEditor;
import ghidra.app.cmd.label.AddLabelCmd; import ghidra.app.cmd.label.AddLabelCmd;
import ghidra.app.util.demangler.gnu.GnuDemanglerFormat; import ghidra.app.util.demangler.gnu.GnuDemanglerFormat;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.EnumEditor;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramDB;
@ -104,6 +108,24 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
assertDemangled(addr, "__dt"); assertDemangled(addr, "__dt");
} }
@Test
public void testMangledString_WithArguments_Valid() {
//
// The below demangles to std::io::Read::read_to_end
//
String mangled = "_ZN3std2io4Read11read_to_end17hb85a0f6802e14499E";
Address addr = addr("0x110");
createSymbol(addr, mangled);
setFormat(GnuDemanglerFormat.RUST);
analyze();
assertDemangled(addr, "read_to_end");
}
@Test @Test
public void testMangledString_WithArguments_ValidButWrongFormat() { public void testMangledString_WithArguments_ValidButWrongFormat() {
@ -123,26 +145,13 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
} }
@Test @Test
public void testUseDeprecatedOptionRemoval_WithDeprecatedFormat() { public void testUseDeprecatedOptionUpdatesAvailableFormats() {
setFormat(GnuDemanglerFormat.GNU);
Options options = program.getOptions("Analyzers");
assertFalse(options.contains(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER));
}
@Test setOption_UseDeprecatedDemangler(false);
public void testUseDeprecatedOptionRemoval_WithRecentFormat() { assertFormatAvailable(GnuDemanglerFormat.RUST, true);
setFormat(GnuDemanglerFormat.RUST);
Options options = program.getOptions("Analyzers");
assertFalse(options.contains(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER));
}
@Test setOption_UseDeprecatedDemangler(true);
public void testUseDeprecatedOptionAddition() { assertFormatAvailable(GnuDemanglerFormat.RUST, false);
// remove it first
testUseDeprecatedOptionRemoval_WithDeprecatedFormat();
setFormat(GnuDemanglerFormat.AUTO);
Options options = program.getOptions("Analyzers");
assertTrue(options.contains(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER));
} }
// things missed: // things missed:
@ -151,7 +160,7 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
//================================================================================================== //==================================================================================================
// Private Methods // Private Methods
//================================================================================================== //==================================================================================================
private void analyze() { private void analyze() {
tx(program, () -> analyzer.added(program, program.getMemory(), TaskMonitor.DUMMY, log)); tx(program, () -> analyzer.added(program, program.getMemory(), TaskMonitor.DUMMY, log));
@ -181,6 +190,32 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
fail("Unable to find demangled symbol '" + name + "'"); 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) { private void setOption(String optionName, boolean doUse) {
String fullOptionName = analyzer.getName() + Options.DELIMITER_STRING + optionName; String fullOptionName = analyzer.getName() + Options.DELIMITER_STRING + optionName;
@ -199,6 +234,18 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
fail("Could not find option '" + optionName + "'"); fail("Could not find option '" + optionName + "'");
} }
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) { private void setFormat(GnuDemanglerFormat format) {
String optionName = GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_FORMAT; String optionName = GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_FORMAT;

View file

@ -32,8 +32,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess( process = GnuDemanglerNativeProcess
GnuDemanglerOptions.GNU_DEMANGLER_V2_33_1); .getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_33_1);
parser = new GnuDemanglerParser(); parser = new GnuDemanglerParser();
} }
@ -111,8 +111,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testFunctionPointers() throws Exception { public void testFunctionPointers() throws Exception {
String mangled = "__t6XpsMap2ZlZP14CORBA_TypeCodePFRCl_UlUlUlf"; String mangled = "__t6XpsMap2ZlZP14CORBA_TypeCodePFRCl_UlUlUlf";
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess( process = GnuDemanglerNativeProcess
GnuDemanglerOptions.GNU_DEMANGLER_V2_24); .getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
@ -564,8 +564,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String mangled = "CalcPortExposedRect__13LScrollerViewCFR4Rectb"; String mangled = "CalcPortExposedRect__13LScrollerViewCFR4Rectb";
// use an older demangler; the current demangler cannot handle this string // use an older demangler; the current demangler cannot handle this string
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess( process = GnuDemanglerNativeProcess
GnuDemanglerOptions.GNU_DEMANGLER_V2_24); .getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
@ -589,8 +589,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String mangled = "__dt__Q26MsoDAL9VertFrameFv"; String mangled = "__dt__Q26MsoDAL9VertFrameFv";
// use an older demangler; the current demangler cannot handle this string // use an older demangler; the current demangler cannot handle this string
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess( process = GnuDemanglerNativeProcess
GnuDemanglerOptions.GNU_DEMANGLER_V2_24); .getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
@ -630,8 +630,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String mangled = "GetColWidths__13CDataRendererCFRA7_s"; String mangled = "GetColWidths__13CDataRendererCFRA7_s";
// use an older demangler; the current demangler cannot handle this string // use an older demangler; the current demangler cannot handle this string
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess( process = GnuDemanglerNativeProcess
GnuDemanglerOptions.GNU_DEMANGLER_V2_24); .getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
@ -655,8 +655,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String mangled = "GetColWidths__13CDataRendererCFPA7_s"; String mangled = "GetColWidths__13CDataRendererCFPA7_s";
// use an older demangler; the current demangler cannot handle this string // use an older demangler; the current demangler cannot handle this string
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess( process = GnuDemanglerNativeProcess
GnuDemanglerOptions.GNU_DEMANGLER_V2_24); .getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled); 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 // This is testing a bug where we were 'off by one' when the array pointer syntax was
// followed by another parameter. // 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"; String mangled = "_gmStage2__FP12SECTION_INFOPiPA12_iiPCs";
// use an older demangler; the current demangler cannot handle this string // use an older demangler; the current demangler cannot handle this string
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess( process = GnuDemanglerNativeProcess
GnuDemanglerOptions.GNU_DEMANGLER_V2_24); .getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
@ -749,8 +749,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String mangled = "__ct__Q24CStr6BufferFR4CStrUl"; String mangled = "__ct__Q24CStr6BufferFR4CStrUl";
// use an older demangler; the current demangler cannot handle this string // use an older demangler; the current demangler cannot handle this string
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess( process = GnuDemanglerNativeProcess
GnuDemanglerOptions.GNU_DEMANGLER_V2_24); .getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
@ -887,16 +887,14 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
@Test @Test
public void testOverloadedShiftOperatorTemplated_LeftShift() { public void testOverloadedShiftOperatorTemplated_LeftShift() {
String raw = String raw = "std::basic_ostream<char, std::char_traits<char> >& " +
"std::basic_ostream<char, std::char_traits<char> >& " + "std::operator<< <std::char_traits<char> >" +
"std::operator<< <std::char_traits<char> >" + "(std::basic_ostream<char, std::char_traits<char> >&, char const*)";
"(std::basic_ostream<char, std::char_traits<char> >&, char const*)";
String formatted = "std::basic_ostream<char,std::char_traits<char>> & " + String formatted = "std::basic_ostream<char,std::char_traits<char>> & " +
"std::operator<<<std::char_traits<char>>" + "std::operator<<<std::char_traits<char>>" +
"(std::basic_ostream<char,std::char_traits<char>> &,char const *)"; "(std::basic_ostream<char,std::char_traits<char>> &,char const *)";
DemangledObject object = parser.parse( DemangledObject object =
"_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc", parser.parse("_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc", raw);
raw);
String name = object.getName(); String name = object.getName();
assertEquals("operator<<", name); assertEquals("operator<<", name);
assertEquals(formatted, object.getSignature()); assertEquals(formatted, object.getSignature());
@ -928,15 +926,15 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
/* /*
typeinfo for typeinfo for
std::__ndk1::__function::__func< std::__ndk1::__function::__func<
dummy::it::other::Namespace::function(float)::$_2::operator()(dummy::it::other::Namespace*) const::{lambda(dummy::it::other::Namespace*)#1}, 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}>, std::__ndk1::allocator<{lambda(dummy::it::other::Namespace*)#1}>,
int (dummy::it::other::Namespace*) int (dummy::it::other::Namespace*)
> >
'__func' has 3 template parameters, the operator and the allocator '__func' has 3 template parameters, the operator and the allocator
*/ */
String dummyNs = "dummy::it::other::Namespace"; String dummyNs = "dummy::it::other::Namespace";
@ -985,7 +983,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testOperatorCastTo() throws Exception { public void testOperatorCastTo() throws Exception {
// //
// Mangled: _ZNKSt17integral_constantIbLb0EEcvbEv // Mangled: _ZNKSt17integral_constantIbLb0EEcvbEv
// //
// Demangled: std::integral_constant<bool, false>::operator bool() const // Demangled: std::integral_constant<bool, false>::operator bool() const
String mangled = "_ZNKSt17integral_constantIbLb0EEcvbEv"; 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. // Converts the object upon which it is overridden to the given value.
// //
// Format: operator std::string() const { return "bob"; } // Format: operator std::string() const { return "bob"; }
// //
// //
// //
// //
// Mangled: _ZNK6Magick5ColorcvSsEv // Mangled: _ZNK6Magick5ColorcvSsEv
// //
@ -1031,7 +1029,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
@Test @Test
public void testConversionOperatorWithConst() throws Exception { public void testConversionOperatorWithConst() throws Exception {
// //
// //
// Mangled: _ZN12_GLOBAL__N_120decode_charset_iconvEPKc // 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. // Converts the object upon which it is overridden to the given value.
// //
// Format: operator std::string() const { return "bob"; } // 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. // Converts the object upon which it is overridden to the given value.
// //
// Format: operator delete(void*) // 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. // Converts the object upon which it is overridden to the given value.
// //
// Format: operator delete[](void*) // 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. // Converts the object upon which it is overridden to the given value.
// //
// Format: operator new(unsigned long) // Format: operator new(unsigned long)
// //
@ -1217,7 +1215,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// Mangled: _ZN2Dr15ClipboardHelper17FTransferGvmlDataERN3Art11TransactionERKN3Ofc13TReferringPtrINS_10DrawingE2oEEEbNS4_7TCntPtrI11IDataObjectEERNS_18IClientDataCreatorERNS4_7TVectorINS4_8TWeakPtrINS_14DrawingElementEEELj0ELj4294967295EEERNS1_6Rect64E // 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&) // 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 = String mangled =
"_ZN2Dr15ClipboardHelper17FTransferGvmlDataERN3Art11TransactionERKN3Ofc13TReferringPtrINS_10DrawingE2oEEEbNS4_7TCntPtrI11IDataObjectEERNS_18IClientDataCreatorERNS4_7TVectorINS4_8TWeakPtrINS_14DrawingElementEEELj0ELj4294967295EEERNS1_6Rect64E"; "_ZN2Dr15ClipboardHelper17FTransferGvmlDataERN3Art11TransactionERKN3Ofc13TReferringPtrINS_10DrawingE2oEEEbNS4_7TCntPtrI11IDataObjectEERNS_18IClientDataCreatorERNS4_7TVectorINS4_8TWeakPtrINS_14DrawingElementEEELj0ELj4294967295EEERNS1_6Rect64E";
@ -1235,11 +1233,11 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
@Test @Test
public void testTemplatedParametersWithCast_OldStyleDemangle() throws Exception { 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>&)') // this (note the odd syntax of '<(int)2085>&)')
// //
// Ofc::TSimpleTypeHelper<Art::Percentage>::ToString(Art::Percentage const&, Ofc::TFixedVarStr<(int)2085>&) // Ofc::TSimpleTypeHelper<Art::Percentage>::ToString(Art::Percentage const&, Ofc::TFixedVarStr<(int)2085>&)
// //
String demangled = String demangled =
"Ofc::TSimpleTypeHelper<Art::Percentage>::ToString(Art::Percentage const&, Ofc::TFixedVarStr<(int)2085>&)"; "Ofc::TSimpleTypeHelper<Art::Percentage>::ToString(Art::Percentage const&, Ofc::TFixedVarStr<(int)2085>&)";
DemangledObject object = parser.parse("nomangled", demangled); DemangledObject object = parser.parse("nomangled", demangled);
@ -1257,7 +1255,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// Mangled: _ZN4Core9AsyncFile7performEON3WTF1FIFNS2_IFvRNS_10FileClientEEEERNS_4FileEEEE // Mangled: _ZN4Core9AsyncFile7performEON3WTF1FIFNS2_IFvRNS_10FileClientEEEERNS_4FileEEEE
// //
// Demangled: Core::AsyncFile::perform(WTF::F<WTF::F<void (Core::FileClient&)> (Core::File&)>&&) // Demangled: Core::AsyncFile::perform(WTF::F<WTF::F<void (Core::FileClient&)> (Core::File&)>&&)
// //
String mangled = String mangled =
"_ZN4Core9AsyncFile7performEON3WTF1FIFNS2_IFvRNS_10FileClientEEEERNS_4FileEEEE"; "_ZN4Core9AsyncFile7performEON3WTF1FIFNS2_IFvRNS_10FileClientEEEERNS_4FileEEEE";
@ -1287,7 +1285,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testFunctionInsideOfTemplates_NoArguments_NoPointerParens() throws Exception { public void testFunctionInsideOfTemplates_NoArguments_NoPointerParens() throws Exception {
// //
// Mangled: _ZN15LogLevelMonitor27registerKeysChangedCallbackERKN5boost8functionIFvvEEE // Mangled: _ZN15LogLevelMonitor27registerKeysChangedCallbackERKN5boost8functionIFvvEEE
// //
// Demangled: LogLevelMonitor::registerKeysChangedCallback(boost::function<void ()> const&) // Demangled: LogLevelMonitor::registerKeysChangedCallback(boost::function<void ()> const&)
String mangled = String mangled =
@ -1320,7 +1318,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testFunctionInsideOfTemplates_WithArguments_NoPointerParens() throws Exception { public void testFunctionInsideOfTemplates_WithArguments_NoPointerParens() throws Exception {
// //
// Mangled: _ZN9DnsThread32set_mutate_ares_options_callbackERKN5boost8functionIFvP12ares_optionsPiEEE // Mangled: _ZN9DnsThread32set_mutate_ares_options_callbackERKN5boost8functionIFvP12ares_optionsPiEEE
// //
// Demangled: DnsThread::set_mutate_ares_options_callback(boost::function<void (ares_options*, int*)> const&) // Demangled: DnsThread::set_mutate_ares_options_callback(boost::function<void (ares_options*, int*)> const&)
String mangled = String mangled =
@ -1354,7 +1352,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testTemplatesThatContainFunctionSignatures() throws Exception { public void testTemplatesThatContainFunctionSignatures() throws Exception {
// //
// Mangled: _ZNSt6vectorIN5boost8functionIFvvEEESaIS3_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS3_S5_EERKS3_ // 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&) // 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 = String mangled =
@ -1405,7 +1403,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testVtableParsingError_NoSpaceBeforeTrailingDigits() throws Exception { public void testVtableParsingError_NoSpaceBeforeTrailingDigits() throws Exception {
// //
// Mangled: _ZTCN6Crypto10HmacSha256E0_NS_3MacE // Mangled: _ZTCN6Crypto10HmacSha256E0_NS_3MacE
// //
// Demangled: construction vtable for Crypto::Mac-in-Crypto::HmacSha256 // Demangled: construction vtable for Crypto::Mac-in-Crypto::HmacSha256
// //
@ -1425,7 +1423,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testVarArgs() throws Exception { public void testVarArgs() throws Exception {
// //
// Mangled: _Z11testVarArgsiz // Mangled: _Z11testVarArgsiz
// //
// Demangled: testVarArgs(int, ...) // Demangled: testVarArgs(int, ...)
// //
@ -1449,7 +1447,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testMultidimensionalArrayFunctionParameter() throws Exception { public void testMultidimensionalArrayFunctionParameter() throws Exception {
// //
// Mangled: _ZN12uavcan_stm329CanDriverC1ILj64EEERA2_AT__NS_9CanRxItemE // Mangled: _ZN12uavcan_stm329CanDriverC1ILj64EEERA2_AT__NS_9CanRxItemE
// //
// Demangled: uavcan_stm32::CanDriver::CanDriver<64u>(uavcan_stm32::CanRxItem (&) [2][64u]) // Demangled: uavcan_stm32::CanDriver::CanDriver<64u>(uavcan_stm32::CanRxItem (&) [2][64u])
// //
@ -1473,15 +1471,11 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// This is a function name that the native demangler tries to demangle, but should not: // This is a function name that the native demangler tries to demangle, but should not:
// Input: uv__dup // Input: uv__dup
// Incorrect Native Output: uv(double, *__restrict) // Incorrect Native Output: uv(double, *__restrict)
// //
String mangled = "uv__dup"; String mangled = "uv__dup";
GnuDemangler demangler = new GnuDemangler(); GnuDemangler demangler = new GnuDemangler();
try { DemangledObject demangled = demangler.demangle(mangled);
demangler.demangle(mangled); assertNull(demangled);
} catch (DemangledException e) {
assertTrue(e.isInvalidMangledName());
}
} }
@Test @Test
@ -1489,7 +1483,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// //
// Mangled: _ZZN9__gnu_cxx6__stoaIlicJiEEET0_PFT_PKT1_PPS3_DpT2_EPKcS5_PmS9_EN11_Save_errnoC2Ev // Mangled: _ZZN9__gnu_cxx6__stoaIlicJiEEET0_PFT_PKT1_PPS3_DpT2_EPKcS5_PmS9_EN11_Save_errnoC2Ev
// //
// Demangled: __gnu_cxx // Demangled: __gnu_cxx
// :: // ::
// __stoa<long, int, char, int>(long (*)(char const*, char**, int), char const*, char const*, unsigned long*, int) // __stoa<long, int, char, int>(long (*)(char const*, char**, int), char const*, char const*, unsigned long*, int)
@ -1500,7 +1494,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// //
// This is _Save_errno struct's constructor inside of the stoa templated function, in the // This is _Save_errno struct's constructor inside of the stoa templated function, in the
// __gnu_cxx namespace. // __gnu_cxx namespace.
// //
String mangled = String mangled =
"_ZZN9__gnu_cxx6__stoaIlicJiEEET0_PFT_PKT1_PPS3_DpT2_EPKcS5_PmS9_EN11_Save_errnoC2Ev"; "_ZZN9__gnu_cxx6__stoaIlicJiEEET0_PFT_PKT1_PPS3_DpT2_EPKcS5_PmS9_EN11_Save_errnoC2Ev";
@ -1521,7 +1515,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// //
// Mangled: _ZNK2cc14ScrollSnapTypeneERKS0_ // Mangled: _ZNK2cc14ScrollSnapTypeneERKS0_
// //
// Demangled: cc::ScrollSnapType::operator!=(cc::ScrollSnapType const&) const // Demangled: cc::ScrollSnapType::operator!=(cc::ScrollSnapType const&) const
// //
@ -1551,8 +1545,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String name = 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>>>"; "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, assertName(object, name, "brigand");
"brigand");
String signature = object.getSignature(false); String signature = object.getSignature(false);
assertEquals( assertEquals(
@ -1571,8 +1564,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// //
// WebCore::FontSelectionAlgorithm::filterCapability // WebCore::FontSelectionAlgorithm::filterCapability
// ( // (
// bool*, // bool*,
// WebCore::FontSelectionAlgorithm::DistanceResult (WebCore::FontSelectionAlgorithm::*)(WebCore::FontSelectionCapabilities) const, // WebCore::FontSelectionAlgorithm::DistanceResult (WebCore::FontSelectionAlgorithm::*)(WebCore::FontSelectionCapabilities) const,
// WebCore::FontSelectionRange WebCore::FontSelectionCapabilities::* // WebCore::FontSelectionRange WebCore::FontSelectionCapabilities::*
// ) // )
// //
@ -1604,10 +1597,10 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// //
// Mangled: __ZN7WebCore12TextCodecICU14registerCodecsEPFvPKcON3WTF8FunctionIFNSt3__110unique_ptrINS_9TextCodecENS5_14default_deleteIS7_EEEEvEEEE // 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: // 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>> ()> && // void ()(char const *,WTF::Function<std::__1::unique_ptr<WebCore::TextCodec,std::__1::default_delete<WebCore::TextCodec>> ()> &&
// //
// (note the trailing '()' chars) // (note the trailing '()' chars)
@ -1641,7 +1634,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// //
// where the above is a parameter to function, where the params look like: // 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&&)... // (WTF::__multi_visitor_return_type&&)...
// ) // )
// //
@ -1673,8 +1666,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertNotNull(object); assertNotNull(object);
assertType(object, DemangledFunction.class); assertType(object, DemangledFunction.class);
String name = String name = "operator=";
"operator=";
assertName(object, name, "WTF", "Function<void()>"); assertName(object, name, "WTF", "Function<void()>");
String signature = object.getSignature(false); String signature = object.getSignature(false);
@ -1709,18 +1701,18 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testFunctionWithLambdaParameter() throws Exception { 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::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::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&, JSC::PropertyName, unsigned int, unsigned int, JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1}
// >( // >(
// JSC::VM&, JSC::PropertyName, // JSC::VM&, JSC::PropertyName,
// unsigned int, // unsigned int,
// JSC::JSObject::prepareToPutDirectWithoutTransition(JSC::VM&, JSC::PropertyName, unsigned int, unsigned int, JSC::Structure*)::{lambda(JSC::GCSafeConcurrentJSLocker const&, int, int)#1} const& // 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( DemangledObject object = parser.parse(
@ -1743,7 +1735,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testFunctionInLambdaNamespace() throws Exception { 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)> // Demangled: GrGLFunction<unsigned char const* (unsigned int)>
// :: // ::
@ -1774,7 +1766,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testFunctionWithLamba_WithUnnamedType() throws Exception { public void testFunctionWithLamba_WithUnnamedType() throws Exception {
// //
// Mangled: _ZN13SoloGimbalEKFUt_C2Ev // Mangled: _ZN13SoloGimbalEKFUt_C2Ev
// //
// Demangled: SoloGimbalEKF::{unnamed type#1}::SoloGimbalEKF() // Demangled: SoloGimbalEKF::{unnamed type#1}::SoloGimbalEKF()
// //
@ -1794,7 +1786,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// //
// Mangled: _Z11wrap_360_cdIiEDTcl8wrap_360fp_Lf42c80000EEET_ // Mangled: _Z11wrap_360_cdIiEDTcl8wrap_360fp_Lf42c80000EEET_
// //
// Demangled: decltype (wrap_360({parm#1}, (float)[42c80000])) wrap_360_cd<int>(int) // 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 // 'wrap_360_cd<int>(int)' is a function that takes an int and then passes that int along

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -57,7 +57,8 @@ public class GnuDemanglerTest extends AbstractGenericTest {
// this throws an exception with the bug in place // this throws an exception with the bug in place
try { try {
demangler.demangle(mangled); demangler.demangle(mangled);
} catch (DemangledException e) { }
catch (DemangledException e) {
assertTrue(e.isInvalidMangledName()); assertTrue(e.isInvalidMangledName());
} }
} }
@ -167,10 +168,10 @@ public class GnuDemanglerTest extends AbstractGenericTest {
/* /*
Note: 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. 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 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. noise, then this test and it's parter should be consolidated.
*/ */
@ -184,6 +185,22 @@ public class GnuDemanglerTest extends AbstractGenericTest {
assertNull(result); assertNull(result);
} }
@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(GnuDemanglerFormat.AUTO, true);
options.setDemangleOnlyKnownPatterns(false);
DemangledObject result = demangler.demangle(mangled, options);
assertNotNull(result);
assertEquals("undefined MyFunction::~MyFunction(void)", result.getSignature(false));
}
@Test @Test
public void testDemangler_Format_CodeWarrior_MacOS8or9() throws DemangledException { public void testDemangler_Format_CodeWarrior_MacOS8or9() throws DemangledException {
// NOTE: mangled CodeWarrior format symbols with templates will fail // NOTE: mangled CodeWarrior format symbols with templates will fail
@ -196,6 +213,7 @@ public class GnuDemanglerTest extends AbstractGenericTest {
demangler.canDemangle(program);// this perform initialization demangler.canDemangle(program);// this perform initialization
GnuDemanglerOptions options = new GnuDemanglerOptions(GnuDemanglerFormat.AUTO, true); GnuDemanglerOptions options = new GnuDemanglerOptions(GnuDemanglerFormat.AUTO, true);
options.setDemangleOnlyKnownPatterns(false);
DemangledObject result = demangler.demangle(mangled, options); DemangledObject result = demangler.demangle(mangled, options);
assertNotNull(result); assertNotNull(result);
assertEquals("undefined TTextPanel::scroll(unsigned char,short,int)", assertEquals("undefined TTextPanel::scroll(unsigned char,short,int)",

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,38 +15,26 @@
*/ */
package ghidra.framework.options; package ghidra.framework.options;
import ghidra.util.Msg;
import java.beans.PropertyEditorSupport; import java.beans.PropertyEditorSupport;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashSet; import java.util.HashSet;
import ghidra.util.Msg;
public class EnumEditor extends PropertyEditorSupport { public class EnumEditor extends PropertyEditorSupport {
private Enum<?> value; private Enum<?> value;
/**
*
* @see java.beans.PropertyEditor#setValue(java.lang.Object)
*/
@Override @Override
public void setValue(Object o) { public void setValue(Object o) {
value = (Enum<?>) o; value = (Enum<?>) o;
} }
/**
*
* @see java.beans.PropertyEditor#getValue()
*/
@Override @Override
public Object getValue() { public Object getValue() {
return value; return value;
} }
/**
*
* @see java.beans.PropertyEditor#getTags()
*/
@Override @Override
public String[] getTags() { public String[] getTags() {
@ -85,28 +72,20 @@ public class EnumEditor extends PropertyEditorSupport {
return new Enum<?>[] { value }; return new Enum<?>[] { value };
} }
/**
*
* @see java.beans.PropertyEditor#getAsText()
*/
@Override @Override
public String getAsText() { public String getAsText() {
return value.toString(); return value.toString();
} }
/**
*
* @see java.beans.PropertyEditor#setAsText(java.lang.String)
*/
@Override @Override
public void setAsText(String s) { public void setAsText(String s) {
try { try {
Method m = value.getClass().getMethod("values"); Method m = value.getClass().getMethod("values");
Enum<?>[] enums = (Enum<?>[]) m.invoke(null); Enum<?>[] enums = (Enum<?>[]) m.invoke(null);
for (int i = 0; i < enums.length; i++) { for (Enum<?> enum1 : enums) {
if (s.equals(enums[i].toString())) { if (s.equals(enum1.toString())) {
value = enums[i]; value = enum1;
break; break;
} }
} }

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,19 +16,19 @@
package ghidra.framework.options; package ghidra.framework.options;
// Support for PropertyEditors that use tags. // Support for PropertyEditors that use tags.
import java.awt.event.ItemEvent;
import java.awt.event.*; import java.awt.event.ItemListener;
import java.beans.*; import java.beans.*;
import javax.swing.*; import javax.swing.JComboBox;
/** /**
* An implementation of a PropertyComponent that is represented as a * An implementation of a PropertyComponent that is represented as a
* combo box. * 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; private boolean notifyEditorOfChanges = true;
/** /**
@ -38,22 +37,23 @@ public class PropertySelector extends JComboBox implements ItemListener {
* changes in the combo box * changes in the combo box
*/ */
public PropertySelector(PropertyEditor pe) { public PropertySelector(PropertyEditor pe) {
editor = pe; propertyEditor = pe;
String tags[] = editor.getTags(); String tags[] = propertyEditor.getTags();
for (int i = 0; i < tags.length; i++) { for (String tag : tags) {
addItem(tags[i]); addItem(tag);
} }
setSelectedIndex(0); setSelectedIndex(0);
// This is a no-op if the getAsText is not a tag that we set from getTags() above // 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); addItemListener(this);
invalidate(); invalidate();
editor.addPropertyChangeListener(new PropertyChangeListener() { propertyEditor.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
String value = editor.getAsText(); String value = propertyEditor.getAsText();
if (!value.equals(getSelectedItem())) { if (!value.equals(getSelectedItem())) {
notifyEditorOfChanges = false; notifyEditorOfChanges = false;
try { try {
@ -67,14 +67,15 @@ public class PropertySelector extends JComboBox implements ItemListener {
}); });
} }
/* @Override
* (non-Javadoc)
* @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
*/
public void itemStateChanged(ItemEvent evt) { public void itemStateChanged(ItemEvent evt) {
if (notifyEditorOfChanges) { if (!notifyEditorOfChanges) {
String s = (String) getSelectedItem(); return;
editor.setAsText(s); }
String s = (String) getSelectedItem();
if (s != null) {
propertyEditor.setAsText(s);
} }
} }
} }

View file

@ -61,7 +61,7 @@ public class GnuDemanglerIntegrationTest extends AbstractGhidraHeadlessIntegrati
GnuDemanglerOptions options = new GnuDemanglerOptions(); GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(false); options.setDemangleOnlyKnownPatterns(false);
options = options.withDeprecatedDemangler(); options = options.withDemanglerFormat(GnuDemanglerFormat.AUTO, true);
DemangledObject result = demangler.demangle(mangled, options); DemangledObject result = demangler.demangle(mangled, options);
assertNotNull(result); assertNotNull(result);
assertEquals("undefined MyNamespace::MyFunction($ParamNamespace::paramName *)", assertEquals("undefined MyNamespace::MyFunction($ParamNamespace::paramName *)",
@ -86,7 +86,7 @@ public class GnuDemanglerIntegrationTest extends AbstractGhidraHeadlessIntegrati
GnuDemanglerOptions options = new GnuDemanglerOptions(); GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(false); options.setDemangleOnlyKnownPatterns(false);
options = options.withDeprecatedDemangler(); options = options.withDemanglerFormat(GnuDemanglerFormat.AUTO, true);
DemangledObject result = demangler.demangle(mangled, options); DemangledObject result = demangler.demangle(mangled, options);
assertNotNull(result); assertNotNull(result);
assertEquals("undefined SoloGimbalEKF::{unnamed_type#1}::SoloGimbalEKF(void)", assertEquals("undefined SoloGimbalEKF::{unnamed_type#1}::SoloGimbalEKF(void)",
@ -116,7 +116,7 @@ public class GnuDemanglerIntegrationTest extends AbstractGhidraHeadlessIntegrati
GnuDemanglerOptions options = new GnuDemanglerOptions(); GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(false); options.setDemangleOnlyKnownPatterns(false);
options = options.withDeprecatedDemangler(); options = options.withDemanglerFormat(GnuDemanglerFormat.AUTO, true);
DemangledObject result = demangler.demangle(mangled, options); DemangledObject result = demangler.demangle(mangled, options);
assertNotNull(result); assertNotNull(result);
assertEquals( assertEquals(