mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-22 05:43:05 +08:00
Custom GnuDemanglerAnalyzer format editor
This commit is contained in:
+102
-15
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+9
@@ -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
|
||||
|
||||
+4
-14
@@ -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
|
||||
|
||||
+5
-2
@@ -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
|
||||
|
||||
+5
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user