Custom GnuDemanglerAnalyzer format editor

This commit is contained in:
astrelsky
2020-08-20 17:55:27 -04:00
committed by dragonmacher
parent 0fcab24073
commit 443e398bb4
5 changed files with 125 additions and 32 deletions
@@ -15,13 +15,19 @@
*/
package ghidra.app.plugin.core.analysis;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
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;
import docking.options.editor.BooleanEditor;
/**
* A version of the demangler analyzer to handle GNU GCC symbols
*/
@@ -70,20 +76,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);
options.registerOption(OPTION_NAME_DEMANGLER_FORMAT, demanglerFormat, help,
OPTION_DESCRIPTION_DEMANGLER_FORMAT);
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_FORMAT, OptionType.ENUM_TYPE,
demanglerFormat, help, OPTION_DESCRIPTION_DEMANGLER_FORMAT, formatEditor);
}
@Override
@@ -92,18 +101,14 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
demangleOnlyKnownPatterns =
options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns);
demanglerFormat = options.getEnum(OPTION_NAME_DEMANGLER_FORMAT, GnuDemanglerFormat.AUTO);
if (demanglerFormat.isDeprecatedFormat() && demanglerFormat.isModernFormat()) {
useDeprecatedDemangler =
useDeprecatedDemangler =
options.getBoolean(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler);
} else {
useDeprecatedDemangler = demanglerFormat.isDeprecatedFormat();
}
}
@Override
protected DemanglerOptions getOptions() {
GnuDemanglerOptions options = new GnuDemanglerOptions(demanglerFormat, useDeprecatedDemangler);
GnuDemanglerOptions options =
new GnuDemanglerOptions(demanglerFormat, useDeprecatedDemangler);
options.setDoDisassembly(true);
options.setApplySignature(doSignatureEnabled);
options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
@@ -115,4 +120,86 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
MessageLog log) throws DemangledException {
return demangler.demangle(mangled, (GnuDemanglerOptions) demanglerOtions);
}
private static class FormatEditor extends EnumEditor implements PropertyChangeListener {
private final FormatSelector selector;
private final BooleanEditor isDeprecated;
FormatEditor(GnuDemanglerFormat value, BooleanEditor isDeprecated) {
setValue(value);
this.isDeprecated = isDeprecated;
this.selector = new FormatSelector(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);
}
}
private boolean isDeprecatedDemangler() {
return (Boolean) isDeprecated.getValue();
}
private boolean filter(GnuDemanglerFormat f) {
return f.isAvailable(isDeprecatedDemangler());
}
}
@SuppressWarnings("serial")
private static class FormatSelector extends PropertySelector {
public FormatSelector(FormatEditor fe) {
super(fe);
}
@SuppressWarnings("unchecked")
void reset(String[] tags) {
removeAllItems();
for (int i = 0; i < tags.length; i++) {
addItem(tags[i]);
}
}
GnuDemanglerFormat getFormat() {
return GnuDemanglerFormat.valueOf((String) getSelectedItem());
}
void setFormat(GnuDemanglerFormat format) {
setSelectedItem(format.name());
}
}
}
@@ -69,6 +69,15 @@ public enum GnuDemanglerFormat {
public boolean isModernFormat() {
return version >= 0;
}
/**
* 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
@@ -57,10 +57,10 @@ public class GnuDemanglerOptions extends DemanglerOptions {
this.isDeprecated = !format.isModernFormat();
}
public GnuDemanglerOptions(GnuDemanglerFormat format, boolean deprecated) {
public GnuDemanglerOptions(GnuDemanglerFormat format, boolean isDeprecated) {
this.format = format;
this.isDeprecated = deprecated;
if (!isValidFormat(format, deprecated)) {
this.isDeprecated = isDeprecated;
if (!format.isAvailable(isDeprecated)) {
throw new IllegalArgumentException(
format.name() + " is not available in the "+getDemanglerName());
}
@@ -109,23 +109,13 @@ public class GnuDemanglerOptions extends DemanglerOptions {
if (this.format == format && this.isDeprecated == isDeprecated) {
return this;
}
if (isValidFormat(format, isDeprecated)) {
if (format.isAvailable(isDeprecated)) {
return new GnuDemanglerOptions(this, format, isDeprecated);
}
throw new IllegalArgumentException(
format.name() + " is not available in the "+getDemanglerName());
}
private static boolean isValidFormat(GnuDemanglerFormat format, boolean isDeprecated) {
if (isDeprecated && format.isDeprecatedFormat()) {
return true;
}
if (!isDeprecated && format.isModernFormat()) {
return true;
}
return false;
}
/**
* Returns the current arguments to be passed to the external demangler executable
* @return the arguments
@@ -1477,8 +1477,11 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String mangled = "uv__dup";
GnuDemangler demangler = new GnuDemangler();
DemangledObject res = demangler.demangle(mangled);
assertNull(res);
try {
demangler.demangle(mangled);
} catch (DemangledException e) {
assertTrue(e.isInvalidMangledName());
}
}
@Test
@@ -55,7 +55,11 @@ 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