mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-29 00:15:49 +08:00
Custom GnuDemanglerAnalyzer format editor
This commit is contained in:
+102
-15
@@ -15,13 +15,19 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.analysis;
|
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.*;
|
||||||
import ghidra.app.util.demangler.gnu.*;
|
import ghidra.app.util.demangler.gnu.*;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
|
import docking.options.editor.BooleanEditor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A version of the demangler analyzer to handle GNU GCC symbols
|
* A version of the demangler analyzer to handle GNU GCC symbols
|
||||||
*/
|
*/
|
||||||
@@ -70,20 +76,23 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerOptions(Options options, Program program) {
|
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");
|
HelpLocation help = new HelpLocation("AutoAnalysisPlugin", "Demangler_Analyzer");
|
||||||
options.registerOption(OPTION_NAME_APPLY_SIGNATURE, doSignatureEnabled, help,
|
options.registerOption(OPTION_NAME_APPLY_SIGNATURE, doSignatureEnabled, help,
|
||||||
OPTION_DESCRIPTION_APPLY_SIGNATURE);
|
OPTION_DESCRIPTION_APPLY_SIGNATURE);
|
||||||
|
|
||||||
options.registerOption(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns,
|
options.registerOption(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns,
|
||||||
help,
|
help, OPTION_DESCRIPTION_USE_KNOWN_PATTERNS);
|
||||||
OPTION_DESCRIPTION_USE_KNOWN_PATTERNS);
|
|
||||||
|
|
||||||
options.registerOption(OPTION_NAME_DEMANGLER_FORMAT, demanglerFormat, help,
|
|
||||||
OPTION_DESCRIPTION_DEMANGLER_FORMAT);
|
|
||||||
|
|
||||||
options.registerOption(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler, help,
|
options.registerOption(OPTION_NAME_USE_DEPRECATED_DEMANGLER, OptionType.BOOLEAN_TYPE,
|
||||||
OPTION_DESCRIPTION_DEPRECATED_DEMANGLER);
|
useDeprecatedDemangler, help, OPTION_DESCRIPTION_DEPRECATED_DEMANGLER, editor);
|
||||||
|
|
||||||
|
options.registerOption(OPTION_NAME_DEMANGLER_FORMAT, OptionType.ENUM_TYPE,
|
||||||
|
demanglerFormat, help, OPTION_DESCRIPTION_DEMANGLER_FORMAT, formatEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -92,18 +101,14 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||||||
demangleOnlyKnownPatterns =
|
demangleOnlyKnownPatterns =
|
||||||
options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns);
|
options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns);
|
||||||
demanglerFormat = options.getEnum(OPTION_NAME_DEMANGLER_FORMAT, GnuDemanglerFormat.AUTO);
|
demanglerFormat = options.getEnum(OPTION_NAME_DEMANGLER_FORMAT, GnuDemanglerFormat.AUTO);
|
||||||
if (demanglerFormat.isDeprecatedFormat() && demanglerFormat.isModernFormat()) {
|
useDeprecatedDemangler =
|
||||||
useDeprecatedDemangler =
|
|
||||||
options.getBoolean(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler);
|
options.getBoolean(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler);
|
||||||
} else {
|
|
||||||
useDeprecatedDemangler = demanglerFormat.isDeprecatedFormat();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DemanglerOptions getOptions() {
|
protected DemanglerOptions getOptions() {
|
||||||
|
GnuDemanglerOptions options =
|
||||||
GnuDemanglerOptions options = new GnuDemanglerOptions(demanglerFormat, useDeprecatedDemangler);
|
new GnuDemanglerOptions(demanglerFormat, useDeprecatedDemangler);
|
||||||
options.setDoDisassembly(true);
|
options.setDoDisassembly(true);
|
||||||
options.setApplySignature(doSignatureEnabled);
|
options.setApplySignature(doSignatureEnabled);
|
||||||
options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
|
options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
|
||||||
@@ -115,4 +120,86 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||||||
MessageLog log) throws DemangledException {
|
MessageLog log) throws DemangledException {
|
||||||
return demangler.demangle(mangled, (GnuDemanglerOptions) demanglerOtions);
|
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() {
|
public boolean isModernFormat() {
|
||||||
return version >= 0;
|
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
|
* 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();
|
this.isDeprecated = !format.isModernFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GnuDemanglerOptions(GnuDemanglerFormat format, boolean deprecated) {
|
public GnuDemanglerOptions(GnuDemanglerFormat format, boolean isDeprecated) {
|
||||||
this.format = format;
|
this.format = format;
|
||||||
this.isDeprecated = deprecated;
|
this.isDeprecated = isDeprecated;
|
||||||
if (!isValidFormat(format, deprecated)) {
|
if (!format.isAvailable(isDeprecated)) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
format.name() + " is not available in the "+getDemanglerName());
|
format.name() + " is not available in the "+getDemanglerName());
|
||||||
}
|
}
|
||||||
@@ -109,23 +109,13 @@ public class GnuDemanglerOptions extends DemanglerOptions {
|
|||||||
if (this.format == format && this.isDeprecated == isDeprecated) {
|
if (this.format == format && this.isDeprecated == isDeprecated) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
if (isValidFormat(format, isDeprecated)) {
|
if (format.isAvailable(isDeprecated)) {
|
||||||
return new GnuDemanglerOptions(this, format, isDeprecated);
|
return new GnuDemanglerOptions(this, format, isDeprecated);
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
format.name() + " is not available in the "+getDemanglerName());
|
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
|
* Returns the current arguments to be passed to the external demangler executable
|
||||||
* @return the arguments
|
* @return the arguments
|
||||||
|
|||||||
+5
-2
@@ -1477,8 +1477,11 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
|||||||
String mangled = "uv__dup";
|
String mangled = "uv__dup";
|
||||||
|
|
||||||
GnuDemangler demangler = new GnuDemangler();
|
GnuDemangler demangler = new GnuDemangler();
|
||||||
DemangledObject res = demangler.demangle(mangled);
|
try {
|
||||||
assertNull(res);
|
demangler.demangle(mangled);
|
||||||
|
} catch (DemangledException e) {
|
||||||
|
assertTrue(e.isInvalidMangledName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
+5
-1
@@ -55,7 +55,11 @@ public class GnuDemanglerTest extends AbstractGenericTest {
|
|||||||
demangler.canDemangle(program);// this perform initialization
|
demangler.canDemangle(program);// this perform initialization
|
||||||
|
|
||||||
// this throws an exception with the bug in place
|
// this throws an exception with the bug in place
|
||||||
demangler.demangle(mangled);
|
try {
|
||||||
|
demangler.demangle(mangled);
|
||||||
|
} catch (DemangledException e) {
|
||||||
|
assertTrue(e.isInvalidMangledName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user