mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-22 10:02:49 +08:00
Merge remote-tracking branch
'origin/GP-94_dragonmacher_PR-2214_astrelsky_GnuDemangler' (fixes #2214)
This commit is contained in:
+10
-25
@@ -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">
|
||||
<GHIDRA_INSTALL_DIR>/GPL/DemanglerGnu/build/os/<OS>/
|
||||
</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">
|
||||
<GHIDRA_INSTALL_DIR>/GPL/DemanglerGnu/os/<OS>/
|
||||
</CODE><CODE>demangler_gnu_v2_33_1</CODE></LI>
|
||||
<LI><CODE CLASS="path">
|
||||
<GHIDRA_INSTALL_DIR>/GPL/DemanglerGnu/os/<OS>/
|
||||
</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
|
||||
|
||||
+27
-22
@@ -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);
|
||||
|
||||
+95
-81
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+27
-16
@@ -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)
|
||||
|
||||
+92
@@ -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
|
||||
}
|
||||
}
|
||||
+82
-29
@@ -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
|
||||
}
|
||||
|
||||
+75
-79
@@ -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
|
||||
*/
|
||||
|
||||
+53
-94
@@ -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);
|
||||
|
||||
+65
-70
@@ -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
|
||||
|
||||
+160
@@ -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);
|
||||
}
|
||||
}
|
||||
+30
-28
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+21
-20
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user