mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-30 01:50:16 +08:00
Merge remote-tracking branch 'origin/GP-4901_ghizard_MDMang_output_options--SQUASHED'
This commit is contained in:
@@ -422,7 +422,7 @@
|
|||||||
</TD>
|
</TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD>Only Demangle Known Mangled Symbols
|
<TD>Demangle Only Known Mangled Symbols
|
||||||
</TD>
|
</TD>
|
||||||
<TD>
|
<TD>
|
||||||
Only demangle symbols that follow known compiler mangling patterns.
|
Only demangle symbols that follow known compiler mangling patterns.
|
||||||
@@ -509,7 +509,7 @@
|
|||||||
<BR>
|
<BR>
|
||||||
<BR>
|
<BR>
|
||||||
<P><A name="Microsoft_Demangler_Options">
|
<P><A name="Microsoft_Demangler_Options">
|
||||||
<B>The Microsoft Demangler</B></H4> adds the following analysis option:
|
<B>The Microsoft Demangler</B></H4> adds the following analysis options:
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<P>
|
<P>
|
||||||
@@ -536,6 +536,33 @@
|
|||||||
</P>
|
</P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>
|
||||||
|
<U><B>Use Encoded Anonymous Namespace</B></U> -
|
||||||
|
This output option is used to create a more unique namespace node from the
|
||||||
|
standard output for anonymous namespaces, thus helping to prevent collisions
|
||||||
|
between multiple types of the same name, but each in their own unique anonymous
|
||||||
|
namespace. When turned on, variations of the standard namespace
|
||||||
|
<B>`anonymous namespace'</B> will be replaced with a more specific namespace of
|
||||||
|
the form <B>_anon_ABCD1234</B> where the hexadecimal number comes from a number
|
||||||
|
encoded in the mangled string. The trade-off is that when this option is turned on,
|
||||||
|
the resultant namespace will not match non-mangled names that have the standard,
|
||||||
|
non-specific anonymous namespace.
|
||||||
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>
|
||||||
|
<U><B>Apply Argument UDT Tags</B></U> -
|
||||||
|
This output option controls whether user-defined type tags (e.g., class, enum,
|
||||||
|
struct, union) are placed in front of the named type when the type is used as a
|
||||||
|
template or function argument. When turned on, the demangled string matches the
|
||||||
|
common demangler standard. When turned off, the standard demangled strings of
|
||||||
|
<B>struct AAA<class BBB></B> and <B>struct AAA<struct BBB></B> would
|
||||||
|
both be reduced to <B>struct AAA<BBB></B>.
|
||||||
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -15,15 +15,17 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.util.demangler;
|
package ghidra.app.util.demangler;
|
||||||
|
|
||||||
|
import generic.json.Json;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple class to contain the various settings for demangling
|
* A simple class to contain the various settings for demangling
|
||||||
*/
|
*/
|
||||||
public class DemanglerOptions {
|
public class DemanglerOptions {
|
||||||
|
|
||||||
private boolean applyCallingConvention = true;
|
protected boolean applyCallingConvention = true;
|
||||||
private boolean applySignature = true;
|
protected boolean applySignature = true;
|
||||||
private boolean doDisassembly = true;
|
protected boolean doDisassembly = true;
|
||||||
private boolean demangleOnlyKnownPatterns = true;
|
protected boolean demangleOnlyKnownPatterns = true;
|
||||||
|
|
||||||
public DemanglerOptions() {
|
public DemanglerOptions() {
|
||||||
// use default values
|
// use default values
|
||||||
@@ -118,12 +120,6 @@ public class DemanglerOptions {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
//@formatter:off
|
return Json.toString(this);
|
||||||
return "{\n" +
|
|
||||||
"\tdoDisassembly: " + doDisassembly + ",\n" +
|
|
||||||
"\tapplySignature: " + applySignature + ",\n" +
|
|
||||||
"\tdemangleOnlyKnownPatterns: " + demangleOnlyKnownPatterns + ",\n" +
|
|
||||||
"}";
|
|
||||||
//@formatter:on
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-25
@@ -17,7 +17,9 @@ package ghidra.app.plugin.core.analysis;
|
|||||||
|
|
||||||
import ghidra.app.util.demangler.*;
|
import ghidra.app.util.demangler.*;
|
||||||
import ghidra.app.util.demangler.microsoft.*;
|
import ghidra.app.util.demangler.microsoft.*;
|
||||||
|
import ghidra.app.util.demangler.microsoft.options.*;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
|
import ghidra.framework.options.OptionType;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
@@ -58,6 +60,12 @@ public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||||||
private boolean demangleOnlyKnownPatterns = false;
|
private boolean demangleOnlyKnownPatterns = false;
|
||||||
private MsCInterpretation interpretation = MsCInterpretation.FUNCTION_IF_EXISTS;
|
private MsCInterpretation interpretation = MsCInterpretation.FUNCTION_IF_EXISTS;
|
||||||
|
|
||||||
|
private static final String APPLY_OPTIONS_LABEL = "msdApplyOptions";
|
||||||
|
private static final String OUTPUT_OPTIONS_LABEL = "msdOutputOptions";
|
||||||
|
|
||||||
|
private MsdApplyOption applyOption;
|
||||||
|
private MsdOutputOption outputOption;
|
||||||
|
|
||||||
public MicrosoftDemanglerAnalyzer() {
|
public MicrosoftDemanglerAnalyzer() {
|
||||||
super(NAME, DESCRIPTION);
|
super(NAME, DESCRIPTION);
|
||||||
demangler = new MicrosoftDemangler();
|
demangler = new MicrosoftDemangler();
|
||||||
@@ -71,43 +79,36 @@ public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerOptions(Options options, Program program) {
|
public void registerOptions(Options options, Program program) {
|
||||||
|
|
||||||
HelpLocation help = new HelpLocation("AutoAnalysisPlugin", "Demangler_Analyzer");
|
HelpLocation help = new HelpLocation("AutoAnalysisPlugin", "Demangler_Analyzer");
|
||||||
|
|
||||||
options.registerOption(OPTION_NAME_APPLY_SIGNATURE, applyFunctionSignature, help,
|
options.registerOption(APPLY_OPTIONS_LABEL, OptionType.CUSTOM_TYPE,
|
||||||
OPTION_DESCRIPTION_APPLY_SIGNATURE);
|
new MsdApplyOption(), help, "Configures how demangling is applied",
|
||||||
|
() -> new MsdApplyOptionsEditor());
|
||||||
|
applyOption =
|
||||||
|
(MsdApplyOption) options.getCustomOption(APPLY_OPTIONS_LABEL, null);
|
||||||
|
|
||||||
options.registerOption(OPTION_NAME_APPLY_CALLING_CONVENTION, applyCallingConvention, help,
|
options.registerOption(OUTPUT_OPTIONS_LABEL, OptionType.CUSTOM_TYPE,
|
||||||
OPTION_DESCRIPTION_APPLY_CALLING_CONVENTION);
|
new MsdOutputOption(), help, "Controls demangled output",
|
||||||
|
() -> new MsdOutputOptionsEditor());
|
||||||
options.registerOption(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns,
|
outputOption = (MsdOutputOption) options.getCustomOption(OUTPUT_OPTIONS_LABEL, null);
|
||||||
help, OPTION_DESCRIPTION_USE_KNOWN_PATTERNS);
|
|
||||||
|
|
||||||
options.registerOption(OPTION_NAME_MS_C_INTERPRETATION, interpretation, help,
|
|
||||||
OPTION_DESCRIPTION_MS_C_INTERPRETATION);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void optionsChanged(Options options, Program program) {
|
public void optionsChanged(Options options, Program program) {
|
||||||
applyFunctionSignature =
|
applyOption = (MsdApplyOption) options.getCustomOption(APPLY_OPTIONS_LABEL, applyOption);
|
||||||
options.getBoolean(OPTION_NAME_APPLY_SIGNATURE, applyFunctionSignature);
|
outputOption =
|
||||||
|
(MsdOutputOption) options.getCustomOption(OUTPUT_OPTIONS_LABEL, outputOption);
|
||||||
applyCallingConvention =
|
|
||||||
options.getBoolean(OPTION_NAME_APPLY_CALLING_CONVENTION, applyCallingConvention);
|
|
||||||
|
|
||||||
demangleOnlyKnownPatterns =
|
|
||||||
options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns);
|
|
||||||
|
|
||||||
interpretation = options.getEnum(OPTION_NAME_MS_C_INTERPRETATION, interpretation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DemanglerOptions getOptions() {
|
protected DemanglerOptions getOptions() {
|
||||||
MicrosoftDemanglerOptions options = new MicrosoftDemanglerOptions();
|
MicrosoftDemanglerOptions options = new MicrosoftDemanglerOptions();
|
||||||
options.setApplySignature(applyFunctionSignature);
|
options.setApplySignature(applyOption.applySignature());
|
||||||
options.setApplyCallingConvention(applyCallingConvention);
|
options.setApplyCallingConvention(applyOption.applyCallingConvention());
|
||||||
options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
|
options.setDemangleOnlyKnownPatterns(applyOption.demangleOnlyKnownPatterns());
|
||||||
options.setInterpretation(interpretation);
|
options.setInterpretation(applyOption.getInterpretation());
|
||||||
|
options.setUseEncodedAnonymousNamespace(outputOption.getUseEncodedAnonymousNamespace());
|
||||||
|
options.setApplyUdtArgumentTypeTag(outputOption.getApplyUdtArgumentTypeTag());
|
||||||
options.setErrorOnRemainingChars(true);
|
options.setErrorOnRemainingChars(true);
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-2
@@ -64,13 +64,24 @@ public class MicrosoftDemangler implements Demangler {
|
|||||||
demangler.setDemangleOnlyKnownPatterns(options.demangleOnlyKnownPatterns());
|
demangler.setDemangleOnlyKnownPatterns(options.demangleOnlyKnownPatterns());
|
||||||
demangler.setArchitectureSize(mContext.getArchitectureSize());
|
demangler.setArchitectureSize(mContext.getArchitectureSize());
|
||||||
demangler.setIsFunction(mContext.shouldInterpretAsFunction());
|
demangler.setIsFunction(mContext.shouldInterpretAsFunction());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
item = demangler.demangle();
|
item = demangler.demangle();
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// The item.toString() method is influenced by the demangler output options, so we get
|
||||||
|
// the originalDemangled string before we change the output options to what we desire
|
||||||
|
// for Ghidra processing.
|
||||||
String originalDemangled = item.toString();
|
String originalDemangled = item.toString();
|
||||||
demangler.getOutputOptions().setUseEncodedAnonymousNamespace(true);
|
// Now we set the particular output options that we didt't want to affect what was
|
||||||
|
// in the originalDemangled string above. Once set, then when
|
||||||
|
// MicrosoftDemanglerUtil.convertToDemangledObject() method is called, the newly
|
||||||
|
// set output options affect the object result.
|
||||||
|
demangler.getOutputOptions()
|
||||||
|
.setUseEncodedAnonymousNamespace(options.getUseEncodedAnonymousNamespace());
|
||||||
|
demangler.getOutputOptions()
|
||||||
|
.setApplyUdtArgumentTypeTag(options.getApplyUdtArgumentTypeTag());
|
||||||
object =
|
object =
|
||||||
MicrosoftDemanglerUtil.convertToDemangledObject(item, mangled, originalDemangled);
|
MicrosoftDemanglerUtil.convertToDemangledObject(item, mangled, originalDemangled);
|
||||||
if (object != null) {
|
if (object != null) {
|
||||||
@@ -112,8 +123,18 @@ public class MicrosoftDemangler implements Demangler {
|
|||||||
if (mdType == null) {
|
if (mdType == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// The item.toString() method is influenced by the demangler output options, so we get
|
||||||
|
// the originalDemangled string before we change the output options to what we desire
|
||||||
|
// for Ghidra processing.
|
||||||
String originalDemangled = mdType.toString();
|
String originalDemangled = mdType.toString();
|
||||||
demangler.getOutputOptions().setUseEncodedAnonymousNamespace(true);
|
// Now we set the particular output options that we didt't want to affect what was
|
||||||
|
// in the originalDemangled string above. Once set, then when
|
||||||
|
// MicrosoftDemanglerUtil.convertToDemangledObject() method is called, the newly
|
||||||
|
// set output options affect the object result.
|
||||||
|
demangler.getOutputOptions()
|
||||||
|
.setUseEncodedAnonymousNamespace(options.getUseEncodedAnonymousNamespace());
|
||||||
|
demangler.getOutputOptions()
|
||||||
|
.setApplyUdtArgumentTypeTag(options.getApplyUdtArgumentTypeTag());
|
||||||
dataType = MicrosoftDemanglerUtil.convertToDemangledDataType(mdType, mangled,
|
dataType = MicrosoftDemanglerUtil.convertToDemangledDataType(mdType, mangled,
|
||||||
originalDemangled);
|
originalDemangled);
|
||||||
if (dataType != null) {
|
if (dataType != null) {
|
||||||
|
|||||||
+65
-22
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.util.demangler.microsoft;
|
package ghidra.app.util.demangler.microsoft;
|
||||||
|
|
||||||
|
import generic.json.Json;
|
||||||
import ghidra.app.util.demangler.DemanglerOptions;
|
import ghidra.app.util.demangler.DemanglerOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,24 +23,29 @@ import ghidra.app.util.demangler.DemanglerOptions;
|
|||||||
*/
|
*/
|
||||||
public class MicrosoftDemanglerOptions extends DemanglerOptions {
|
public class MicrosoftDemanglerOptions extends DemanglerOptions {
|
||||||
|
|
||||||
|
// Processing options
|
||||||
private boolean errorOnRemainingChars;
|
private boolean errorOnRemainingChars;
|
||||||
private MsCInterpretation interpretation;
|
private MsCInterpretation interpretation;
|
||||||
|
|
||||||
|
// Output options:
|
||||||
|
private boolean useEncodedAnonymousNamespace;
|
||||||
|
private boolean applyUdtArgumentTypeTag; // specific to MS for now
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for MicrosoftDemanglerOptions
|
||||||
|
* @param errorOnRemainingCharsArg {@code true} to error on remaining characters
|
||||||
|
*/
|
||||||
|
public MicrosoftDemanglerOptions(boolean errorOnRemainingCharsArg) {
|
||||||
|
this();
|
||||||
|
errorOnRemainingChars = errorOnRemainingCharsArg; // override defaultInits()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor for MicrosoftDemanglerOptions
|
* Default constructor for MicrosoftDemanglerOptions
|
||||||
*/
|
*/
|
||||||
public MicrosoftDemanglerOptions() {
|
public MicrosoftDemanglerOptions() {
|
||||||
this(true);
|
|
||||||
interpretation = MsCInterpretation.FUNCTION_IF_EXISTS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for MicrosoftDemanglerOptions
|
|
||||||
* @param errorOnRemainingChars {@code true} to error on remaining characters
|
|
||||||
*/
|
|
||||||
public MicrosoftDemanglerOptions(boolean errorOnRemainingChars) {
|
|
||||||
super();
|
super();
|
||||||
this.errorOnRemainingChars = errorOnRemainingChars;
|
defaultInits();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,17 +54,24 @@ public class MicrosoftDemanglerOptions extends DemanglerOptions {
|
|||||||
*/
|
*/
|
||||||
public MicrosoftDemanglerOptions(DemanglerOptions copy) {
|
public MicrosoftDemanglerOptions(DemanglerOptions copy) {
|
||||||
super(copy);
|
super(copy);
|
||||||
|
|
||||||
if (copy instanceof MicrosoftDemanglerOptions mCopy) {
|
if (copy instanceof MicrosoftDemanglerOptions mCopy) {
|
||||||
errorOnRemainingChars = mCopy.errorOnRemainingChars;
|
errorOnRemainingChars = mCopy.errorOnRemainingChars;
|
||||||
interpretation = mCopy.interpretation;
|
interpretation = mCopy.interpretation;
|
||||||
|
useEncodedAnonymousNamespace = mCopy.useEncodedAnonymousNamespace;
|
||||||
|
applyUdtArgumentTypeTag = mCopy.applyUdtArgumentTypeTag;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
errorOnRemainingChars = true;
|
defaultInits();
|
||||||
interpretation = MsCInterpretation.FUNCTION_IF_EXISTS;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void defaultInits() {
|
||||||
|
errorOnRemainingChars = true;
|
||||||
|
interpretation = MsCInterpretation.FUNCTION_IF_EXISTS;
|
||||||
|
useEncodedAnonymousNamespace = true;
|
||||||
|
applyUdtArgumentTypeTag = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the control for erroring on remaining characters at demangler completion
|
* Sets the control for erroring on remaining characters at demangler completion
|
||||||
* @param errorOnRemainingCharsArg {@code true} to error when remaining characters exist
|
* @param errorOnRemainingCharsArg {@code true} to error when remaining characters exist
|
||||||
@@ -94,16 +107,46 @@ public class MicrosoftDemanglerOptions extends DemanglerOptions {
|
|||||||
return interpretation;
|
return interpretation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the output flag to use an anonymous namespace's encoded number to craft a namespace
|
||||||
|
* containing this number instead of using the generic "`anonymous namespace'" name. Default
|
||||||
|
* is true (to create a namespace containing the encoded number)
|
||||||
|
* @param useEncodedAnonymousNamespaceArg {@code true} to use
|
||||||
|
*/
|
||||||
|
public void setUseEncodedAnonymousNamespace(boolean useEncodedAnonymousNamespaceArg) {
|
||||||
|
useEncodedAnonymousNamespace = useEncodedAnonymousNamespaceArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if the output flag is set to use an anonymous namespace's encoded
|
||||||
|
* number to craft a namespace containing the number instead of using the generic
|
||||||
|
* "`anonymous namespace'" name.
|
||||||
|
* @return {@code true} if encoded number is used to craft a namespace
|
||||||
|
*/
|
||||||
|
public boolean getUseEncodedAnonymousNamespace() {
|
||||||
|
return useEncodedAnonymousNamespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the output flag for applying user-defined tags (e.g., class, struct, union, enum)
|
||||||
|
* within template and function arguments. Default is {@code true} (to apply)
|
||||||
|
* @param applyUdtArgumentTypeTagArg {@code true} to apply the tags
|
||||||
|
*/
|
||||||
|
public void setApplyUdtArgumentTypeTag(boolean applyUdtArgumentTypeTagArg) {
|
||||||
|
applyUdtArgumentTypeTag = applyUdtArgumentTypeTagArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if the output interpretation is set to apply user-defined type
|
||||||
|
* tags (e.g., class, struct, union, enum) within template and function arguments.
|
||||||
|
* @return {@code true} if applying the tags
|
||||||
|
*/
|
||||||
|
public boolean getApplyUdtArgumentTypeTag() {
|
||||||
|
return applyUdtArgumentTypeTag;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
//@formatter:off
|
return Json.toString(this);
|
||||||
return "{\n" +
|
|
||||||
"\tdoDisassembly: " + doDisassembly() + ",\n" +
|
|
||||||
"\tapplySignature: " + applySignature() + ",\n" +
|
|
||||||
"\terrorOnRemainingChars: " + errorOnRemainingChars + ",\n" +
|
|
||||||
"\tinterpretation: " + interpretation + ",\n" +
|
|
||||||
"\tdemangleOnlyKnownPatterns: " + demangleOnlyKnownPatterns() + ",\n" +
|
|
||||||
"}";
|
|
||||||
//@formatter:on
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
@@ -37,6 +37,15 @@ public class MicrosoftMangledContext extends MangledContext {
|
|||||||
super(program, options, mangled, address);
|
super(program, options, mangled, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the demangler options
|
||||||
|
* @return the options
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public MicrosoftDemanglerOptions getOptions() {
|
||||||
|
return (MicrosoftDemanglerOptions) options;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the program architecture size
|
* Returns the program architecture size
|
||||||
* @return the architecture size or zero if not known (program is null)
|
* @return the architecture size or zero if not known (program is null)
|
||||||
|
|||||||
+118
@@ -0,0 +1,118 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.microsoft.options;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import ghidra.app.plugin.core.analysis.MicrosoftDemanglerAnalyzer;
|
||||||
|
import ghidra.app.util.demangler.DemanglerOptions;
|
||||||
|
import ghidra.app.util.demangler.microsoft.MicrosoftDemanglerOptions;
|
||||||
|
import ghidra.app.util.demangler.microsoft.MsCInterpretation;
|
||||||
|
import ghidra.framework.options.CustomOption;
|
||||||
|
import ghidra.framework.options.GProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Option class that is paired with the {@link MsdApplyOptionsEditor} so that we can have a
|
||||||
|
* custom editor for an "Apply" option panel for the {@link MicrosoftDemanglerAnalyzer}.
|
||||||
|
* Also see {@link MsdOutputOption}, which is another panel.
|
||||||
|
* The results of both get pushed into the {@link MicrosoftDemanglerOptions} to control the
|
||||||
|
* analyzer and underlying demangler.
|
||||||
|
*/
|
||||||
|
public class MsdApplyOption extends DemanglerOptions implements CustomOption {
|
||||||
|
|
||||||
|
private static final String DEMANGLE_USE_KNOWN_PATTERNS = "demangleOnlyKnownMangledSymbols";
|
||||||
|
private static final String APPLY_SIGNATURE = "applyFunctionSignatures";
|
||||||
|
private static final String APPLY_CALLING_CONVENTION = "applyFunctionCallingConventions";
|
||||||
|
private static final String MS_C_INTERPRETATION = "C-StyleSymbolInterpretation";
|
||||||
|
|
||||||
|
private static boolean DEFAULT_DEMANGLE_USE_KNOWN_PATTERNS = false;
|
||||||
|
private static boolean DEFAULT_APPLY_SIGNATURE = true;
|
||||||
|
private static boolean DEFAULT_APPLY_CALLING_CONVENTION = true;
|
||||||
|
private static MsCInterpretation DEFAULT_MS_C_INTERPRETATION =
|
||||||
|
MsCInterpretation.FUNCTION_IF_EXISTS;
|
||||||
|
|
||||||
|
private MsCInterpretation interpretation;
|
||||||
|
|
||||||
|
public MsdApplyOption() {
|
||||||
|
// required for persistence, but also using for overriding initializations of parent
|
||||||
|
setDemangleOnlyKnownPatterns(DEFAULT_DEMANGLE_USE_KNOWN_PATTERNS);
|
||||||
|
setApplySignature(DEFAULT_APPLY_SIGNATURE);
|
||||||
|
setApplyCallingConvention(DEFAULT_APPLY_CALLING_CONVENTION);
|
||||||
|
interpretation = DEFAULT_MS_C_INTERPRETATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the interpretation for processing a C-style mangled symbol if there could be multiple
|
||||||
|
* interpretations
|
||||||
|
* @param interpretationArg the interpretation to use
|
||||||
|
*/
|
||||||
|
public void setInterpretation(MsCInterpretation interpretationArg) {
|
||||||
|
interpretation = interpretationArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the interpretation for processing a C-style mangled symbol if there could be multiple
|
||||||
|
* interpretations
|
||||||
|
* @return the interpretation used
|
||||||
|
*/
|
||||||
|
public MsCInterpretation getInterpretation() {
|
||||||
|
return interpretation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (!(obj instanceof MsdApplyOption other)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return demangleOnlyKnownPatterns == other.demangleOnlyKnownPatterns &&
|
||||||
|
applyCallingConvention == other.applyCallingConvention &&
|
||||||
|
applySignature == other.applySignature &&
|
||||||
|
interpretation == other.interpretation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(demangleOnlyKnownPatterns, applyCallingConvention,
|
||||||
|
applySignature, interpretation);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Persistence
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readState(GProperties properties) {
|
||||||
|
demangleOnlyKnownPatterns =
|
||||||
|
properties.getBoolean(DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns);
|
||||||
|
applySignature = properties.getBoolean(APPLY_SIGNATURE, applySignature);
|
||||||
|
applyCallingConvention =
|
||||||
|
properties.getBoolean(APPLY_CALLING_CONVENTION, applyCallingConvention);
|
||||||
|
interpretation = properties.getEnum(MS_C_INTERPRETATION, interpretation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeState(GProperties properties) {
|
||||||
|
properties.putBoolean(DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns);
|
||||||
|
properties.putBoolean(APPLY_SIGNATURE, applySignature);
|
||||||
|
properties.putBoolean(APPLY_CALLING_CONVENTION, applyCallingConvention);
|
||||||
|
properties.putEnum(MS_C_INTERPRETATION, interpretation);
|
||||||
|
}
|
||||||
|
}
|
||||||
+282
@@ -0,0 +1,282 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.microsoft.options;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.beans.PropertyEditorSupport;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.border.Border;
|
||||||
|
import javax.swing.border.TitledBorder;
|
||||||
|
|
||||||
|
import docking.options.editor.OptionsEditorAlignable;
|
||||||
|
import docking.widgets.checkbox.GCheckBox;
|
||||||
|
import docking.widgets.combobox.GComboBox;
|
||||||
|
import ghidra.app.util.demangler.microsoft.MsCInterpretation;
|
||||||
|
import ghidra.framework.options.CustomOptionsEditor;
|
||||||
|
import ghidra.util.HTMLUtilities;
|
||||||
|
import ghidra.util.layout.PairLayout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Editor used presenting and receiving GUI changes to {@link MsdApplyOption}
|
||||||
|
*/
|
||||||
|
public class MsdApplyOptionsEditor extends PropertyEditorSupport
|
||||||
|
implements CustomOptionsEditor {
|
||||||
|
|
||||||
|
private static final String USE_KNOWN_PATTERNS_LABEL = "Demangle Only Known Mangled Symbols";
|
||||||
|
public static final String APPLY_SIGNATURE_LABEL = "Apply Function Signatures";
|
||||||
|
public static final String APPLY_CALLING_CONVENTION_LABEL =
|
||||||
|
"Apply Function Calling Conventions";
|
||||||
|
|
||||||
|
public static final String MS_C_INTERPRETATION_LABEL = "C-Style Symbol Interpretation";
|
||||||
|
|
||||||
|
private static final String[] NAMES = { USE_KNOWN_PATTERNS_LABEL, APPLY_SIGNATURE_LABEL,
|
||||||
|
APPLY_CALLING_CONVENTION_LABEL, MS_C_INTERPRETATION_LABEL };
|
||||||
|
|
||||||
|
// help tooltips
|
||||||
|
private static final String USE_KNOWN_PATTERNS_TOOLTIP = HTMLUtilities.toWrappedHTML(
|
||||||
|
"Only demangle symbols that follow known compiler mangling patterns. " +
|
||||||
|
"Leaving this option off may cause non-mangled symbols to get demangled.",
|
||||||
|
75);
|
||||||
|
private static final String APPLY_SIGNATURE_TOOLTIP = HTMLUtilities.toWrappedHTML(
|
||||||
|
"Apply any recovered function signature, in addition to the function name",
|
||||||
|
75);
|
||||||
|
private static final String APPLY_CALLING_CONVENTION_TOOLTIP = HTMLUtilities.toWrappedHTML(
|
||||||
|
"Apply any recovered function signature calling convention",
|
||||||
|
75);
|
||||||
|
private static final String MS_C_INTERPRETATION_TOOLTIP = HTMLUtilities.toWrappedHTML(
|
||||||
|
"When ambiguous, treat C-Style mangled symbol as: function, variable," +
|
||||||
|
" or function if a function exists",
|
||||||
|
75);
|
||||||
|
|
||||||
|
private static final String[] DESCRIPTIONS = { USE_KNOWN_PATTERNS_TOOLTIP,
|
||||||
|
APPLY_SIGNATURE_TOOLTIP, APPLY_CALLING_CONVENTION_TOOLTIP, MS_C_INTERPRETATION_TOOLTIP };
|
||||||
|
|
||||||
|
private MsdApplyOption applyOption;
|
||||||
|
|
||||||
|
private Component editorComponent;
|
||||||
|
|
||||||
|
private JLabel interpretationLabel;
|
||||||
|
private JLabel callingConventionLabel;
|
||||||
|
private JLabel signatureLabel;
|
||||||
|
private JLabel knownPatternsLabel;
|
||||||
|
|
||||||
|
private JCheckBox knownPatternsCb;
|
||||||
|
private JCheckBox signatureCb;
|
||||||
|
private JCheckBox callingConventionCb;
|
||||||
|
private JComboBox<MsCInterpretation> interpretationComboBox;
|
||||||
|
|
||||||
|
public MsdApplyOptionsEditor() {
|
||||||
|
editorComponent = buildEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Component buildEditor() {
|
||||||
|
// we want to have a panel with our options so that we may group them together
|
||||||
|
JPanel panel = new JPanel(new PairLayout(0, 6));
|
||||||
|
|
||||||
|
knownPatternsCb = new GCheckBox();
|
||||||
|
knownPatternsCb.setSelected(false);
|
||||||
|
knownPatternsCb.setToolTipText(USE_KNOWN_PATTERNS_TOOLTIP);
|
||||||
|
knownPatternsLabel = new JLabel(USE_KNOWN_PATTERNS_LABEL, SwingConstants.RIGHT);
|
||||||
|
knownPatternsLabel.setLabelFor(knownPatternsCb);
|
||||||
|
knownPatternsLabel.setToolTipText(USE_KNOWN_PATTERNS_TOOLTIP);
|
||||||
|
panel.add(knownPatternsLabel);
|
||||||
|
panel.add(knownPatternsCb);
|
||||||
|
|
||||||
|
signatureCb = new GCheckBox();
|
||||||
|
signatureCb.setSelected(false);
|
||||||
|
signatureCb.setToolTipText(APPLY_SIGNATURE_TOOLTIP);
|
||||||
|
signatureLabel = new JLabel(APPLY_SIGNATURE_LABEL, SwingConstants.RIGHT);
|
||||||
|
signatureLabel.setLabelFor(signatureCb);
|
||||||
|
signatureLabel.setToolTipText(APPLY_SIGNATURE_TOOLTIP);
|
||||||
|
panel.add(signatureLabel);
|
||||||
|
panel.add(signatureCb);
|
||||||
|
|
||||||
|
callingConventionCb = new GCheckBox();
|
||||||
|
callingConventionCb.setSelected(false);
|
||||||
|
callingConventionCb.setToolTipText(APPLY_CALLING_CONVENTION_TOOLTIP);
|
||||||
|
callingConventionLabel = new JLabel(APPLY_CALLING_CONVENTION_LABEL, SwingConstants.RIGHT);
|
||||||
|
callingConventionLabel.setLabelFor(callingConventionCb);
|
||||||
|
callingConventionLabel.setToolTipText(APPLY_CALLING_CONVENTION_TOOLTIP);
|
||||||
|
panel.add(callingConventionLabel);
|
||||||
|
panel.add(callingConventionCb);
|
||||||
|
|
||||||
|
interpretationComboBox = new GComboBox<>(MsCInterpretation.values());
|
||||||
|
interpretationComboBox.setSelectedItem(false);
|
||||||
|
interpretationComboBox.setToolTipText(MS_C_INTERPRETATION_TOOLTIP);
|
||||||
|
interpretationLabel = new JLabel(MS_C_INTERPRETATION_LABEL, SwingConstants.RIGHT);
|
||||||
|
interpretationLabel.setLabelFor(interpretationComboBox);
|
||||||
|
interpretationLabel.setToolTipText(MS_C_INTERPRETATION_TOOLTIP);
|
||||||
|
panel.add(interpretationLabel);
|
||||||
|
panel.add(interpretationComboBox);
|
||||||
|
|
||||||
|
knownPatternsCb.addItemListener(e -> firePropertyChange());
|
||||||
|
signatureCb.addItemListener(e -> {
|
||||||
|
signatureChangeListener();
|
||||||
|
firePropertyChange();
|
||||||
|
});
|
||||||
|
callingConventionCb.addItemListener(e -> firePropertyChange());
|
||||||
|
interpretationComboBox.addItemListener(e -> firePropertyChange());
|
||||||
|
|
||||||
|
Border emptyBorder = BorderFactory.createEmptyBorder(0, 0, 0, 0);
|
||||||
|
TitledBorder titledNoLineBorder = BorderFactory.createTitledBorder(
|
||||||
|
emptyBorder, // The invisible base border
|
||||||
|
"Apply Options", // The title text
|
||||||
|
TitledBorder.LEADING, // Title justification (e.g., LEADING, CENTER, TRAILING)
|
||||||
|
TitledBorder.TOP, // Title position (e.g., TOP, BOTTOM)
|
||||||
|
null, // Optional: Font
|
||||||
|
null // Optional: Title color
|
||||||
|
);
|
||||||
|
|
||||||
|
// Use an outer panel so we can offset the main panel
|
||||||
|
JPanel outerPanel = new AlignablePanel(new BorderLayout());
|
||||||
|
|
||||||
|
panel.setBorder(BorderFactory.createEmptyBorder(5, 20, 0, 0));
|
||||||
|
|
||||||
|
outerPanel.add(panel, BorderLayout.CENTER);
|
||||||
|
outerPanel.setBorder(BorderFactory.createCompoundBorder(
|
||||||
|
BorderFactory.createEmptyBorder(10, 0, 10, 0), titledNoLineBorder));
|
||||||
|
|
||||||
|
return outerPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setValue(Object value) {
|
||||||
|
if (!(value instanceof MsdApplyOption option)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
applyOption = option;
|
||||||
|
setLocalValues(applyOption);
|
||||||
|
firePropertyChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLocalValues(MsdApplyOption applyOptions) {
|
||||||
|
boolean knownPatterns = applyOptions.demangleOnlyKnownPatterns();
|
||||||
|
if (knownPatterns != knownPatternsCb.isSelected()) {
|
||||||
|
knownPatternsCb.setSelected(knownPatterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean applySignature = applyOptions.applySignature();
|
||||||
|
if (applySignature != signatureCb.isSelected()) {
|
||||||
|
signatureCb.setSelected(applySignature);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean applyCc = applyOptions.applyCallingConvention();
|
||||||
|
if (applyCc != callingConventionCb.isSelected()) {
|
||||||
|
callingConventionCb.setSelected(applyCc);
|
||||||
|
}
|
||||||
|
|
||||||
|
MsCInterpretation interpretation = applyOptions.getInterpretation();
|
||||||
|
if (interpretation != interpretationComboBox.getSelectedItem()) {
|
||||||
|
interpretationComboBox.setSelectedItem(interpretation);
|
||||||
|
}
|
||||||
|
|
||||||
|
signatureChangeListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void signatureChangeListener() {
|
||||||
|
// Calling convention enabled only if signature is selected
|
||||||
|
boolean signatureEnabled = signatureCb.isSelected();
|
||||||
|
callingConventionCb.setEnabled(signatureEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MsdApplyOption cloneNamespaceValues() {
|
||||||
|
MsdApplyOption newOptions = new MsdApplyOption();
|
||||||
|
newOptions.setApplySignature(signatureCb.isSelected());
|
||||||
|
newOptions.setApplyCallingConvention(callingConventionCb.isSelected());
|
||||||
|
newOptions.setDemangleOnlyKnownPatterns(knownPatternsCb.isSelected());
|
||||||
|
newOptions.setInterpretation((MsCInterpretation) interpretationComboBox.getSelectedItem());
|
||||||
|
return newOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getOptionDescriptions() {
|
||||||
|
return DESCRIPTIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getOptionNames() {
|
||||||
|
return NAMES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValue() {
|
||||||
|
return cloneNamespaceValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getCustomEditor() {
|
||||||
|
return editorComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsCustomEditor() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allows us to mimic the alignment of the normal options for this custom editor and any other
|
||||||
|
// custom editor in the same view as us
|
||||||
|
private class AlignablePanel extends JPanel implements OptionsEditorAlignable {
|
||||||
|
|
||||||
|
AlignablePanel(LayoutManager layout) {
|
||||||
|
super(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredAlignmentSize() {
|
||||||
|
//
|
||||||
|
// Use all labels and components to find the overall preferred size.
|
||||||
|
//
|
||||||
|
int maxWidth = 0;
|
||||||
|
int maxHeight = 0;
|
||||||
|
Dimension size = getPairDimension(knownPatternsLabel, knownPatternsCb);
|
||||||
|
maxWidth = Math.max(size.width, maxWidth);
|
||||||
|
maxHeight = Math.max(size.height, maxHeight);
|
||||||
|
|
||||||
|
size = getPairDimension(signatureLabel, signatureCb);
|
||||||
|
maxWidth = Math.max(size.width, maxWidth);
|
||||||
|
maxHeight = Math.max(size.height, maxHeight);
|
||||||
|
|
||||||
|
size = getPairDimension(callingConventionLabel, callingConventionCb);
|
||||||
|
maxWidth = Math.max(size.width, maxWidth);
|
||||||
|
maxHeight = Math.max(size.height, maxHeight);
|
||||||
|
|
||||||
|
size = getPairDimension(interpretationLabel, interpretationComboBox);
|
||||||
|
maxWidth = Math.max(size.width, maxWidth);
|
||||||
|
maxHeight = Math.max(size.height, maxHeight);
|
||||||
|
|
||||||
|
return new Dimension(maxWidth, maxHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dimension getPairDimension(JLabel label, JComponent c) {
|
||||||
|
// Note: this code is taken from DefaultOptionComponent
|
||||||
|
Dimension dimension = label.getPreferredSize();
|
||||||
|
int labelWidth = dimension.width;
|
||||||
|
int labelHeight = dimension.height;
|
||||||
|
int maxHeight = Math.max(labelHeight, c.getPreferredSize().height);
|
||||||
|
return new Dimension(labelWidth, maxHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPreferredAlignmentSize(Dimension size) {
|
||||||
|
// This is called after all preferred sizes have been retrieved and combined
|
||||||
|
knownPatternsLabel.setPreferredSize(size);
|
||||||
|
signatureLabel.setPreferredSize(size);
|
||||||
|
callingConventionLabel.setPreferredSize(size);
|
||||||
|
interpretationLabel.setPreferredSize(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+120
@@ -0,0 +1,120 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.microsoft.options;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import ghidra.app.plugin.core.analysis.MicrosoftDemanglerAnalyzer;
|
||||||
|
import ghidra.framework.options.CustomOption;
|
||||||
|
import ghidra.framework.options.GProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options class that is paired with the {@link MsdOutputOptionsEditor} so that we can have a
|
||||||
|
* custom editor for an "Output" options panel for the {@link MicrosoftDemanglerAnalyzer}.
|
||||||
|
* Also see {@link MsdApplyOption}, which is another panel.
|
||||||
|
* The results of both get pushed into the {@link MicrosoftDemanglerOptions} to control the
|
||||||
|
* analyzer and underlying demangler.
|
||||||
|
*/
|
||||||
|
public class MsdOutputOption implements CustomOption {
|
||||||
|
|
||||||
|
private static final String USE_ENCODED_ANONYMOUS_NAMESPACE = "useEncodedAnonymousNamespace";
|
||||||
|
private static final String APPLY_TEMPLATE_ARG_TAGS = "applyTagsTemplateArgumentTags";
|
||||||
|
|
||||||
|
private static boolean DEFAULT_USE_ENCODED_ANONYMOUS_NAMESPACE = true;
|
||||||
|
private static boolean DEFAULT_APPLY_TEMPLATE_ARG_TAGS = true;
|
||||||
|
|
||||||
|
private boolean useEncodedAnonymousNamespace = DEFAULT_USE_ENCODED_ANONYMOUS_NAMESPACE;
|
||||||
|
private boolean applyUdtArgumentTypeTag = DEFAULT_APPLY_TEMPLATE_ARG_TAGS;
|
||||||
|
|
||||||
|
public MsdOutputOption() {
|
||||||
|
// required for persistence
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the output flag to use an anonymous namespace's encoded number to craft a namespace
|
||||||
|
* containing this number instead of using the generic "`anonymous namespace'" name. Default
|
||||||
|
* is true (to create a namespace containing the encoded number)
|
||||||
|
* @param useEncodedAnonymousNamespaceArg {@code true} to use
|
||||||
|
*/
|
||||||
|
public void setUseEncodedAnonymousNamespace(boolean useEncodedAnonymousNamespaceArg) {
|
||||||
|
useEncodedAnonymousNamespace = useEncodedAnonymousNamespaceArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if the output flag is set to use an anonymous namespace's encoded
|
||||||
|
* number to craft a namespace containing the number instead of using the generic
|
||||||
|
* "`anonymous namespace'" name.
|
||||||
|
* @return {@code true} if encoded number is used to craft a namespace
|
||||||
|
*/
|
||||||
|
public boolean getUseEncodedAnonymousNamespace() {
|
||||||
|
return useEncodedAnonymousNamespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the output flag for applying user-defined tags (e.g., class, struct, union, enum)
|
||||||
|
* within template and function arguments. Default is {@code true} (to apply)
|
||||||
|
* @param applyUdtArgumentTypeTagArg {@code true} to apply the tags
|
||||||
|
*/
|
||||||
|
public void setApplyUdtArgumentTypeTag(boolean applyUdtArgumentTypeTagArg) {
|
||||||
|
applyUdtArgumentTypeTag = applyUdtArgumentTypeTagArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if the output interpretation is set to apply user-defined type
|
||||||
|
* tags (e.g., class, struct, union, enum) within template and function arguments.
|
||||||
|
* @return {@code true} if applying the tags
|
||||||
|
*/
|
||||||
|
public boolean getApplyUdtArgumentTypeTag() {
|
||||||
|
return applyUdtArgumentTypeTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (!(obj instanceof MsdOutputOption other)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return useEncodedAnonymousNamespace == other.useEncodedAnonymousNamespace &&
|
||||||
|
applyUdtArgumentTypeTag == other.applyUdtArgumentTypeTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(applyUdtArgumentTypeTag, useEncodedAnonymousNamespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Persistence
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readState(GProperties properties) {
|
||||||
|
useEncodedAnonymousNamespace =
|
||||||
|
properties.getBoolean(USE_ENCODED_ANONYMOUS_NAMESPACE, useEncodedAnonymousNamespace);
|
||||||
|
applyUdtArgumentTypeTag =
|
||||||
|
properties.getBoolean(APPLY_TEMPLATE_ARG_TAGS, applyUdtArgumentTypeTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeState(GProperties properties) {
|
||||||
|
properties.putBoolean(USE_ENCODED_ANONYMOUS_NAMESPACE, useEncodedAnonymousNamespace);
|
||||||
|
properties.putBoolean(APPLY_TEMPLATE_ARG_TAGS, applyUdtArgumentTypeTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
+211
@@ -0,0 +1,211 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.microsoft.options;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.beans.PropertyEditorSupport;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.border.Border;
|
||||||
|
import javax.swing.border.TitledBorder;
|
||||||
|
|
||||||
|
import docking.options.editor.OptionsEditorAlignable;
|
||||||
|
import docking.widgets.checkbox.GCheckBox;
|
||||||
|
import ghidra.framework.options.CustomOptionsEditor;
|
||||||
|
import ghidra.util.HTMLUtilities;
|
||||||
|
import ghidra.util.layout.PairLayout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Editor used presenting and receiving GUI changes to {@link MsdOutputOption}
|
||||||
|
*/
|
||||||
|
public class MsdOutputOptionsEditor extends PropertyEditorSupport implements CustomOptionsEditor {
|
||||||
|
|
||||||
|
private static final String USE_ENCODED_ANON_NS_LABEL = "Use Encoded Anonymous Namespace";
|
||||||
|
private static final String APPLY_UDT_ARG_TAGS_LABEL = "Apply UDT Argument Type Tags";
|
||||||
|
|
||||||
|
private static final String[] NAMES = { USE_ENCODED_ANON_NS_LABEL, APPLY_UDT_ARG_TAGS_LABEL };
|
||||||
|
|
||||||
|
// help tooltips
|
||||||
|
private static final String USE_ENCODED_ANON_NS_TOOLTIP =
|
||||||
|
HTMLUtilities.toWrappedHTML(
|
||||||
|
"Instead of a variation of <B>Anonymous Namespace</B>, uses the encoded numeric " +
|
||||||
|
"identifier to output an <B>_anon_ABCD1234</B> name form.",
|
||||||
|
75);
|
||||||
|
|
||||||
|
private static final String APPLY_UDT_ARG_TAGS_TOOLTIP = HTMLUtilities.toWrappedHTML(
|
||||||
|
"Applies a user-defined type's (UDT) class/enum/struct/union tag when the UDT is a " +
|
||||||
|
"template or function argument.",
|
||||||
|
75);
|
||||||
|
|
||||||
|
private static final String[] DESCRIPTIONS = { USE_ENCODED_ANON_NS_TOOLTIP,
|
||||||
|
APPLY_UDT_ARG_TAGS_TOOLTIP };
|
||||||
|
|
||||||
|
private MsdOutputOption msOutputOption;
|
||||||
|
|
||||||
|
private Component editorComponent;
|
||||||
|
|
||||||
|
private JCheckBox useEncodedAnonNsCb;
|
||||||
|
private JCheckBox useUdtTagsCb;
|
||||||
|
private JLabel useEncodedAnonNsLabel;
|
||||||
|
private JLabel useUdtTagsLabel;
|
||||||
|
|
||||||
|
public MsdOutputOptionsEditor() {
|
||||||
|
editorComponent = buildEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Component buildEditor() {
|
||||||
|
// we want to have a panel with our options so that we may group them together
|
||||||
|
JPanel panel = new JPanel(new PairLayout(0, 6));
|
||||||
|
|
||||||
|
useEncodedAnonNsCb = new GCheckBox();
|
||||||
|
useEncodedAnonNsCb.setSelected(true);
|
||||||
|
useEncodedAnonNsCb.setToolTipText(USE_ENCODED_ANON_NS_TOOLTIP);
|
||||||
|
useEncodedAnonNsLabel = new JLabel(USE_ENCODED_ANON_NS_LABEL, SwingConstants.RIGHT);
|
||||||
|
useEncodedAnonNsLabel.setLabelFor(useEncodedAnonNsCb);
|
||||||
|
useEncodedAnonNsLabel.setToolTipText(USE_ENCODED_ANON_NS_TOOLTIP);
|
||||||
|
panel.add(useEncodedAnonNsLabel);
|
||||||
|
panel.add(useEncodedAnonNsCb);
|
||||||
|
|
||||||
|
useUdtTagsCb = new GCheckBox();
|
||||||
|
useUdtTagsCb.setSelected(false);
|
||||||
|
useUdtTagsCb.setToolTipText(APPLY_UDT_ARG_TAGS_TOOLTIP);
|
||||||
|
useUdtTagsLabel = new JLabel(APPLY_UDT_ARG_TAGS_LABEL, SwingConstants.RIGHT);
|
||||||
|
useUdtTagsLabel.setLabelFor(useUdtTagsCb);
|
||||||
|
useUdtTagsLabel.setToolTipText(APPLY_UDT_ARG_TAGS_TOOLTIP);
|
||||||
|
panel.add(useUdtTagsLabel);
|
||||||
|
panel.add(useUdtTagsCb);
|
||||||
|
|
||||||
|
useEncodedAnonNsCb.addItemListener(e -> firePropertyChange());
|
||||||
|
useUdtTagsCb.addItemListener(e -> firePropertyChange());
|
||||||
|
|
||||||
|
Border emptyBorder = BorderFactory.createEmptyBorder(0, 0, 0, 0);
|
||||||
|
TitledBorder titledNoLineBorder = BorderFactory.createTitledBorder(
|
||||||
|
emptyBorder, // The invisible base border
|
||||||
|
"Output Options", // The title text
|
||||||
|
TitledBorder.LEADING, // Title justification (e.g., LEADING, CENTER, TRAILING)
|
||||||
|
TitledBorder.TOP, // Title position (e.g., TOP, BOTTOM)
|
||||||
|
null, // Optional: Font
|
||||||
|
null // Optional: Title color
|
||||||
|
);
|
||||||
|
|
||||||
|
// Use an outer panel so we can offset the main panel
|
||||||
|
JPanel outerPanel = new AlignablePanel(new BorderLayout());
|
||||||
|
|
||||||
|
panel.setBorder(BorderFactory.createEmptyBorder(5, 20, 0, 0));
|
||||||
|
|
||||||
|
outerPanel.add(panel, BorderLayout.CENTER);
|
||||||
|
outerPanel.setBorder(BorderFactory.createCompoundBorder(
|
||||||
|
BorderFactory.createEmptyBorder(10, 0, 10, 0), titledNoLineBorder));
|
||||||
|
|
||||||
|
return outerPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setValue(Object value) {
|
||||||
|
if (!(value instanceof MsdOutputOption option)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
msOutputOption = option;
|
||||||
|
setLocalValues(msOutputOption);
|
||||||
|
firePropertyChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLocalValues(MsdOutputOption outputOptions) {
|
||||||
|
boolean useEncoded = outputOptions.getUseEncodedAnonymousNamespace();
|
||||||
|
if (useEncoded != useEncodedAnonNsCb.isSelected()) {
|
||||||
|
useEncodedAnonNsCb.setSelected(useEncoded);
|
||||||
|
}
|
||||||
|
boolean applyComplexTag = outputOptions.getApplyUdtArgumentTypeTag();
|
||||||
|
if (applyComplexTag != useUdtTagsCb.isSelected()) {
|
||||||
|
useUdtTagsCb.setSelected(applyComplexTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MsdOutputOption cloneNamespaceValues() {
|
||||||
|
MsdOutputOption newOption = new MsdOutputOption();
|
||||||
|
newOption.setUseEncodedAnonymousNamespace(useEncodedAnonNsCb.isSelected());
|
||||||
|
newOption.setApplyUdtArgumentTypeTag(useUdtTagsCb.isSelected());
|
||||||
|
return newOption;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getOptionDescriptions() {
|
||||||
|
return DESCRIPTIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getOptionNames() {
|
||||||
|
return NAMES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValue() {
|
||||||
|
return cloneNamespaceValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getCustomEditor() {
|
||||||
|
return editorComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsCustomEditor() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allows us to mimic the alignment of the normal options for this custom editor and any other
|
||||||
|
// custom editor in the same view as us
|
||||||
|
private class AlignablePanel extends JPanel implements OptionsEditorAlignable {
|
||||||
|
|
||||||
|
AlignablePanel(LayoutManager layout) {
|
||||||
|
super(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredAlignmentSize() {
|
||||||
|
//
|
||||||
|
// Use all labels and components to find the overall preferred size.
|
||||||
|
//
|
||||||
|
int maxWidth = 0;
|
||||||
|
int maxHeight = 0;
|
||||||
|
Dimension size = getPairDimension(useEncodedAnonNsLabel, useEncodedAnonNsCb);
|
||||||
|
maxWidth = Math.max(size.width, maxWidth);
|
||||||
|
maxHeight = Math.max(size.height, maxHeight);
|
||||||
|
|
||||||
|
size = getPairDimension(useUdtTagsLabel, useUdtTagsCb);
|
||||||
|
maxWidth = Math.max(size.width, maxWidth);
|
||||||
|
maxHeight = Math.max(size.height, maxHeight);
|
||||||
|
|
||||||
|
return new Dimension(maxWidth, maxHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dimension getPairDimension(JLabel label, JComponent c) {
|
||||||
|
// Note: this code is taken from DefaultOptionComponent
|
||||||
|
Dimension dimension = label.getPreferredSize();
|
||||||
|
int labelWidth = dimension.width;
|
||||||
|
int labelHeight = dimension.height;
|
||||||
|
int maxHeight = Math.max(labelHeight, c.getPreferredSize().height);
|
||||||
|
return new Dimension(labelWidth, maxHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPreferredAlignmentSize(Dimension size) {
|
||||||
|
// This is called after all preferred sizes have been retrieved and combined
|
||||||
|
useEncodedAnonNsLabel.setPreferredSize(size);
|
||||||
|
useUdtTagsLabel.setPreferredSize(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+135
@@ -0,0 +1,135 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FilenameUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import docking.widgets.values.GValuesMap;
|
||||||
|
import ghidra.app.script.GhidraScript;
|
||||||
|
import ghidra.app.util.SymbolPath;
|
||||||
|
import ghidra.features.base.values.GhidraValuesMap;
|
||||||
|
import ghidra.util.MessageType;
|
||||||
|
import ghidra.util.StatusListener;
|
||||||
|
import mdemangler.*;
|
||||||
|
import utilities.util.FileUtilities;
|
||||||
|
|
||||||
|
public class MDMangDeveloperDemangleNamesScript extends GhidraScript {
|
||||||
|
|
||||||
|
private static final String TITLE = "Demangle Names";
|
||||||
|
private static final String INPUT_PROMPT = "Choose an input file";
|
||||||
|
private static final String OUTPUT_PROMPT = "Choose an output file";
|
||||||
|
|
||||||
|
private static boolean validateInputFile(GValuesMap valueMap, StatusListener status) {
|
||||||
|
File file = valueMap.getFile(INPUT_PROMPT);
|
||||||
|
if (file == null) {
|
||||||
|
status.setStatusText("Input file must be selected.", MessageType.ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!file.exists()) {
|
||||||
|
status.setStatusText(file.getAbsolutePath() + " is not a valid file.",
|
||||||
|
MessageType.ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean validateOutputFile(GValuesMap valueMap, StatusListener status) {
|
||||||
|
File fileIn = valueMap.getFile(INPUT_PROMPT);
|
||||||
|
File fileOut = valueMap.getFile(OUTPUT_PROMPT);
|
||||||
|
String fileNameIn = fileIn.getAbsolutePath();
|
||||||
|
String fileNameOut = fileOut.getAbsolutePath();
|
||||||
|
if (fileNameOut.equals(fileNameIn)) {
|
||||||
|
status.setStatusText("Output file cannot be same as input file '" + fileNameOut + "').",
|
||||||
|
MessageType.ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void run() throws Exception {
|
||||||
|
|
||||||
|
GhidraValuesMap values = new GhidraValuesMap();
|
||||||
|
|
||||||
|
values.defineFile(INPUT_PROMPT, null);
|
||||||
|
values.setValidator((valueMap, status) -> {
|
||||||
|
return validateInputFile(valueMap, status);
|
||||||
|
});
|
||||||
|
values = askValues(TITLE, null, values);
|
||||||
|
File inputFile = values.getFile(INPUT_PROMPT);
|
||||||
|
String inputFileName = inputFile.getAbsolutePath();
|
||||||
|
|
||||||
|
// creating a default output and asking again, to include output file query
|
||||||
|
String outputFileName = FilenameUtils.removeExtension(inputFileName) + ".out." +
|
||||||
|
FilenameUtils.getExtension(inputFileName);
|
||||||
|
values.defineFile(OUTPUT_PROMPT, new File(outputFileName));
|
||||||
|
values.setValidator((valueMap, status) -> {
|
||||||
|
return validateInputFile(valueMap, status) && validateOutputFile(valueMap, status);
|
||||||
|
});
|
||||||
|
setReusePreviousChoices(false); // false for second pass... want our default output
|
||||||
|
values = askValues(TITLE, null, values);
|
||||||
|
inputFile = values.getFile(INPUT_PROMPT); // might have changed
|
||||||
|
inputFileName = inputFile.getAbsolutePath(); // might have changed
|
||||||
|
File outputFile = values.getFile(OUTPUT_PROMPT);
|
||||||
|
|
||||||
|
if (outputFile.exists()) {
|
||||||
|
if (!askYesNo("Confirm Overwrite", "Overwrite file: " + outputFile.getName())) {
|
||||||
|
println("Operation canceled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileWriter fileWriter = new FileWriter(outputFile);
|
||||||
|
try (BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) {
|
||||||
|
String message = "Processing " + inputFileName;
|
||||||
|
monitor.setMessage(message);
|
||||||
|
println(message);
|
||||||
|
List<String> lines = FileUtilities.getLines(inputFile);
|
||||||
|
for (String name : lines) {
|
||||||
|
monitor.checkCancelled();
|
||||||
|
String output = getProcessedName(name);
|
||||||
|
bufferedWriter.append(output);
|
||||||
|
bufferedWriter.append("\n");
|
||||||
|
}
|
||||||
|
message = "Results located in: " + outputFile.getAbsolutePath();
|
||||||
|
monitor.setMessage(message);
|
||||||
|
println(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getProcessedName(String name) {
|
||||||
|
if (StringUtils.containsWhitespace(name)) {
|
||||||
|
return getError(name, "contains white space");
|
||||||
|
}
|
||||||
|
MDMang demangler = new MDMang();
|
||||||
|
demangler.setMangledSymbol(name);
|
||||||
|
try {
|
||||||
|
MDParsableItem item = demangler.demangle();
|
||||||
|
SymbolPath sp = MDMangUtils.getSymbolPath(item);
|
||||||
|
return sp.toString();
|
||||||
|
}
|
||||||
|
catch (MDException e) {
|
||||||
|
return getError(name, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getError(String name, String reason) {
|
||||||
|
return "!Failed(" + reason + "): " + name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -21,7 +21,9 @@ package mdemangler;
|
|||||||
*/
|
*/
|
||||||
public class MDOutputOptions {
|
public class MDOutputOptions {
|
||||||
|
|
||||||
private boolean useEncodedAnonymousNamespaceNumber;
|
// These defaults match standard output
|
||||||
|
private boolean useEncodedAnonymousNamespaceNumber = false;
|
||||||
|
private boolean applyUdtArgumentTypeTag = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@@ -48,4 +50,23 @@ public class MDOutputOptions {
|
|||||||
return useEncodedAnonymousNamespaceNumber;
|
return useEncodedAnonymousNamespaceNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the option for whether to apply user-defined type tags when found as template
|
||||||
|
* or function arguments
|
||||||
|
* @param applyUdtArgumentTypeTag {@code true} to apply the tag on a complex type when
|
||||||
|
* used as a template or function argument
|
||||||
|
*/
|
||||||
|
public void setApplyUdtArgumentTypeTag(boolean applyUdtArgumentTypeTag) {
|
||||||
|
this.applyUdtArgumentTypeTag = applyUdtArgumentTypeTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if the demangler will apply user-defined type tags when found as
|
||||||
|
* template or function arguments, such as the "struct" in "templateName<struct A,int>"
|
||||||
|
* @return {@code true} if the flag is set to apply
|
||||||
|
*/
|
||||||
|
public boolean applyUdtArgumentTypeTag() {
|
||||||
|
return applyUdtArgumentTypeTag;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-2
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -64,4 +64,13 @@ public class MDComplexType extends MDDataType {
|
|||||||
qualifiedName.insert(builder);
|
qualifiedName.insert(builder);
|
||||||
super.insert(builder);
|
super.insert(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void insertWithoutComplexTag(StringBuilder builder) {
|
||||||
|
// TODO: look at what needs to be done to get rid of this?
|
||||||
|
if ((builder.length() != 0) && (builder.charAt(0) != ' ')) {
|
||||||
|
dmang.insertString(builder, " ");
|
||||||
|
}
|
||||||
|
qualifiedName.insert(builder);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-3
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -119,7 +119,13 @@ public class MDArgumentsList extends MDParsableItem {
|
|||||||
}
|
}
|
||||||
firstArgDone = true;
|
firstArgDone = true;
|
||||||
StringBuilder argBuilder = new StringBuilder();
|
StringBuilder argBuilder = new StringBuilder();
|
||||||
arg.insert(argBuilder);
|
if (arg instanceof MDComplexType ct &&
|
||||||
|
!dmang.getOutputOptions().applyUdtArgumentTypeTag()) {
|
||||||
|
ct.insertWithoutComplexTag(argBuilder);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
arg.insert(argBuilder);
|
||||||
|
}
|
||||||
dmang.appendString(builder, argBuilder.toString().trim());
|
dmang.appendString(builder, argBuilder.toString().trim());
|
||||||
// doing toString() allows the Based5 "bug" to be cleaned per parameter.
|
// doing toString() allows the Based5 "bug" to be cleaned per parameter.
|
||||||
// possible: dmang.appendString(builder, arg.toString().trim());
|
// possible: dmang.appendString(builder, arg.toString().trim());
|
||||||
|
|||||||
+2
-1
@@ -137,7 +137,7 @@ public class MDFunctionType extends MDType {
|
|||||||
// output on underscore-based access-level types (from MDTypeInfoParser '_' prefix),
|
// output on underscore-based access-level types (from MDTypeInfoParser '_' prefix),
|
||||||
// specifically based5 variants. This could possibly be put into the MDMangVS2015
|
// specifically based5 variants. This could possibly be put into the MDMangVS2015
|
||||||
// demangler, but then we would probably need to describe the standard MDMang output
|
// demangler, but then we would probably need to describe the standard MDMang output
|
||||||
// as "invalid," as based-on-basedptr is supposed to be invalid.
|
// as "invalid," as based-on-basedptr is supposed to be invalid.
|
||||||
StringBuilder conventionBuilder = new StringBuilder();
|
StringBuilder conventionBuilder = new StringBuilder();
|
||||||
convention.insert(conventionBuilder);
|
convention.insert(conventionBuilder);
|
||||||
if (based != null) {
|
if (based != null) {
|
||||||
@@ -179,6 +179,7 @@ public class MDFunctionType extends MDType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ package mdemangler.naming;
|
|||||||
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import mdemangler.*;
|
import mdemangler.*;
|
||||||
|
import mdemangler.datatype.MDDataType;
|
||||||
import mdemangler.object.MDObjectCPP;
|
import mdemangler.object.MDObjectCPP;
|
||||||
import mdemangler.template.MDTemplateNameAndArguments;
|
import mdemangler.template.MDTemplateNameAndArguments;
|
||||||
|
|
||||||
@@ -131,6 +132,20 @@ public class MDBasicName extends MDParsableItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setXtorQual(MDQualifier qual) {
|
||||||
|
// We should only get a call for setName() due to a contructor or destructor,
|
||||||
|
// which come from MDSpecialName or from MDTemplateNameAndArguments.
|
||||||
|
if (specialName != null) {
|
||||||
|
specialName.setXtorQual(qual);
|
||||||
|
}
|
||||||
|
else if (templateNameAndArguments != null) {
|
||||||
|
templateNameAndArguments.setXtorQual(qual);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Msg.warn(this, "name cannot be set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This needs to be separate from nameModifier. The contrived example that follows
|
// This needs to be separate from nameModifier. The contrived example that follows
|
||||||
// shows that both a nameModifier as well as a castTypeString should be considered
|
// shows that both a nameModifier as well as a castTypeString should be considered
|
||||||
// separately, as both can exist. Trying to manage multiple calls to
|
// separately, as both can exist. Trying to manage multiple calls to
|
||||||
@@ -150,6 +165,18 @@ public class MDBasicName extends MDParsableItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCastType(MDDataType castType) {
|
||||||
|
if (specialName != null) {
|
||||||
|
specialName.setCastType(castType);
|
||||||
|
}
|
||||||
|
else if (templateNameAndArguments != null) {
|
||||||
|
templateNameAndArguments.setCastType(castType);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Msg.warn(this, "castType cannot be set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void insert(StringBuilder builder) {
|
public void insert(StringBuilder builder) {
|
||||||
if (reusableName != null) {
|
if (reusableName != null) {
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -94,6 +94,13 @@ public class MDQualification extends MDParsableItem implements Iterable<MDQualif
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MDQualifier getHead() {
|
||||||
|
if (quals.size() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return quals.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void parseInternal() throws MDException {
|
protected void parseInternal() throws MDException {
|
||||||
// TODO: consider a do-while loop so we do not need this initial test for an empty
|
// TODO: consider a do-while loop so we do not need this initial test for an empty
|
||||||
|
|||||||
+9
@@ -16,6 +16,7 @@
|
|||||||
package mdemangler.naming;
|
package mdemangler.naming;
|
||||||
|
|
||||||
import mdemangler.*;
|
import mdemangler.*;
|
||||||
|
import mdemangler.datatype.MDDataType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents a qualified name (wiki page parlance) within a name of a
|
* This class represents a qualified name (wiki page parlance) within a name of a
|
||||||
@@ -85,6 +86,10 @@ public class MDQualifiedBasicName extends MDParsableItem {
|
|||||||
basicName.setCastTypeString(castTypeString);
|
basicName.setCastTypeString(castTypeString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCastType(MDDataType castType) {
|
||||||
|
basicName.setCastType(castType);
|
||||||
|
}
|
||||||
|
|
||||||
public MDBasicName getBasicName() {
|
public MDBasicName getBasicName() {
|
||||||
return basicName;
|
return basicName;
|
||||||
}
|
}
|
||||||
@@ -105,12 +110,16 @@ public class MDQualifiedBasicName extends MDParsableItem {
|
|||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
qualification.insertHeadQualifier(builder);
|
qualification.insertHeadQualifier(builder);
|
||||||
basicName.setName(builder.toString());
|
basicName.setName(builder.toString());
|
||||||
|
MDQualifier head = qualification.getHead();
|
||||||
|
basicName.setXtorQual(head);
|
||||||
}
|
}
|
||||||
else if (basicName.isDestructor()) {
|
else if (basicName.isDestructor()) {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
qualification.insertHeadQualifier(builder);
|
qualification.insertHeadQualifier(builder);
|
||||||
dmang.insertString(builder, "~");
|
dmang.insertString(builder, "~");
|
||||||
basicName.setName(builder.toString());
|
basicName.setName(builder.toString());
|
||||||
|
MDQualifier head = qualification.getHead();
|
||||||
|
basicName.setXtorQual(head);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,71 +25,110 @@ public class MDQualifier extends MDParsableItem {
|
|||||||
private static final String ANONYMOUS_NAMESPACE = "`anonymous namespace'";
|
private static final String ANONYMOUS_NAMESPACE = "`anonymous namespace'";
|
||||||
private static final String UNKNOWN_NAMESPACE = "MDMANG_UNK_QUALIFICATION";
|
private static final String UNKNOWN_NAMESPACE = "MDMANG_UNK_QUALIFICATION";
|
||||||
private MDReusableName name;
|
private MDReusableName name;
|
||||||
|
private MDReusableName templateName;
|
||||||
private MDReusableName nameAnonymous;
|
private MDReusableName nameAnonymous;
|
||||||
private MDReusableName nameInterface;
|
private MDReusableName nameInterface;
|
||||||
private MDNestedName nameNested;
|
private MDNestedName nameNested;
|
||||||
private MDNumberedNamespace nameNumbered;
|
private MDNumberedNamespace nameNumbered;
|
||||||
private String nameQ;
|
private MDQualification nameQ;
|
||||||
private String nameC; // Windows 10 stuff
|
private MDFragmentName nameC; // Windows 10 stuff
|
||||||
|
|
||||||
public MDQualifier(MDMang dmang) {
|
public MDQualifier(MDMang dmang) {
|
||||||
super(dmang);
|
super(dmang);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isInterface() {
|
//====
|
||||||
return (nameInterface != null);
|
|
||||||
|
public boolean isName() {
|
||||||
|
return name != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNested() {
|
public boolean isTemplate() {
|
||||||
return (nameNested != null);
|
return templateName != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAnon() {
|
public boolean isAnon() {
|
||||||
return (nameAnonymous != null);
|
return nameAnonymous != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isInterface() {
|
||||||
|
return nameInterface != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNested() {
|
||||||
|
return nameNested != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// possibly delete this one and use isNameNumbered() instead; TODO
|
||||||
public boolean isLocalNamespace() {
|
public boolean isLocalNamespace() {
|
||||||
return (nameNumbered != null);
|
return nameNumbered != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNameC() {
|
public boolean isNameNumbered() {
|
||||||
return (nameC != null);
|
return nameNumbered != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNameQ() {
|
public boolean isNameQ() {
|
||||||
return (nameQ != null);
|
return nameQ != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MDNestedName getNested() {
|
public boolean isNameC() {
|
||||||
return nameNested;
|
return nameC != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//====
|
||||||
|
|
||||||
|
public MDReusableName getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MDReusableName getTemplate() {
|
||||||
|
return templateName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAnonymousName() {
|
public String getAnonymousName() {
|
||||||
return nameAnonymous.getName();
|
return nameAnonymous.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MDReusableName getInterface() {
|
||||||
|
return nameInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MDNestedName getNested() {
|
||||||
|
return nameNested;
|
||||||
|
}
|
||||||
|
|
||||||
|
// possibly delete this one and use getNameNumbered() instead; TODO
|
||||||
public String getLocalNamespace() {
|
public String getLocalNamespace() {
|
||||||
return nameNumbered.getName();
|
return nameNumbered.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// possibly delete this one and use getNameNumbered() instead; TODO
|
||||||
public String getLocalNamespaceNumber() {
|
public String getLocalNamespaceNumber() {
|
||||||
return nameNumbered.getNumber().toString();
|
return nameNumbered.getNumber().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNameC() {
|
public MDNumberedNamespace getNameNumbered() {
|
||||||
return nameC;
|
return nameNumbered;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNameQ() {
|
public MDQualification getNameQ() {
|
||||||
return nameQ;
|
return nameQ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MDFragmentName getNameC() {
|
||||||
|
return nameC;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void insert(StringBuilder builder) {
|
public void insert(StringBuilder builder) {
|
||||||
// Only one of these will hit.
|
// Only one of these will hit.
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
name.insert(builder);
|
name.insert(builder);
|
||||||
}
|
}
|
||||||
|
else if (templateName != null) {
|
||||||
|
templateName.insert(builder);
|
||||||
|
}
|
||||||
else if (nameAnonymous != null) {
|
else if (nameAnonymous != null) {
|
||||||
if (dmang.getOutputOptions().useEncodedAnonymousNamespace()) {
|
if (dmang.getOutputOptions().useEncodedAnonymousNamespace()) {
|
||||||
dmang.insertString(builder,
|
dmang.insertString(builder,
|
||||||
@@ -109,10 +148,21 @@ public class MDQualifier extends MDParsableItem {
|
|||||||
nameNumbered.insert(builder);
|
nameNumbered.insert(builder);
|
||||||
}
|
}
|
||||||
else if (nameQ != null) {
|
else if (nameQ != null) {
|
||||||
dmang.insertString(builder, nameQ);
|
// Could create a new object for this type and modify its insert method (and getName
|
||||||
|
// method) to return the right things. As it is, the above access getNameQ method
|
||||||
|
// will return an MDQualification that has no concept of the brackets here. But
|
||||||
|
// it could be remedied with the separate object. Similarly (but no bracket issue),
|
||||||
|
// the "nameC" could also get its own type to represent its object, but we don't
|
||||||
|
// quite know what that is at this time.
|
||||||
|
StringBuilder nameQBuilder = new StringBuilder();
|
||||||
|
nameQ.insert(nameQBuilder);
|
||||||
|
dmang.insertString(nameQBuilder, "[");
|
||||||
|
dmang.appendString(nameQBuilder, "]");
|
||||||
|
String str = nameQBuilder.toString();
|
||||||
|
dmang.insertString(builder, str);
|
||||||
}
|
}
|
||||||
else if (nameC != null) {
|
else if (nameC != null) {
|
||||||
dmang.insertString(builder, nameC);
|
nameC.insert(builder);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dmang.insertString(builder, UNKNOWN_NAMESPACE);
|
dmang.insertString(builder, UNKNOWN_NAMESPACE);
|
||||||
@@ -129,8 +179,8 @@ public class MDQualifier extends MDParsableItem {
|
|||||||
break;
|
break;
|
||||||
case '$':
|
case '$':
|
||||||
// This is a template, but it will get processed through MDReusableName.
|
// This is a template, but it will get processed through MDReusableName.
|
||||||
name = new MDReusableName(dmang);
|
templateName = new MDReusableName(dmang);
|
||||||
name.parse();
|
templateName.parse();
|
||||||
break;
|
break;
|
||||||
case 'A': // Anonymous namespace
|
case 'A': // Anonymous namespace
|
||||||
// 20140522 found that we should Keep the 'A' as part of the name
|
// 20140522 found that we should Keep the 'A' as part of the name
|
||||||
@@ -165,7 +215,7 @@ public class MDQualifier extends MDParsableItem {
|
|||||||
MDFragmentName fragName = new MDFragmentName(dmang);
|
MDFragmentName fragName = new MDFragmentName(dmang);
|
||||||
fragName.keepTerminator(); // keeps the terminating '@'
|
fragName.keepTerminator(); // keeps the terminating '@'
|
||||||
fragName.parse();
|
fragName.parse();
|
||||||
nameC = fragName.toString();
|
nameC = fragName;
|
||||||
dmang.parseInfoPop();
|
dmang.parseInfoPop();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -214,11 +264,7 @@ public class MDQualifier extends MDParsableItem {
|
|||||||
dmang.increment(); // skip the 'Q'
|
dmang.increment(); // skip the 'Q'
|
||||||
MDQualification qualName = new MDQualification(dmang);
|
MDQualification qualName = new MDQualification(dmang);
|
||||||
qualName.parse();
|
qualName.parse();
|
||||||
StringBuilder nameQBuilder = new StringBuilder();
|
nameQ = qualName;
|
||||||
qualName.insert(nameQBuilder);
|
|
||||||
dmang.insertString(nameQBuilder, "[");
|
|
||||||
dmang.appendString(nameQBuilder, "]");
|
|
||||||
nameQ = nameQBuilder.toString();
|
|
||||||
dmang.parseInfoPop();
|
dmang.parseInfoPop();
|
||||||
break;
|
break;
|
||||||
default: // special name
|
default: // special name
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -32,6 +32,58 @@ public class MDReusableName extends MDParsableItem {
|
|||||||
super(dmang);
|
super(dmang);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the name is a fragment name. Note that there can still be a special name
|
||||||
|
* interpretation of a fragment, so both can be true
|
||||||
|
* @return {@code true} if is a fragment name
|
||||||
|
*/
|
||||||
|
public boolean isFragment() {
|
||||||
|
return fragment != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the name is a template name with arguments. This is exclusive; if
|
||||||
|
* {@code true} the other two tests on name will be {@code false}
|
||||||
|
* @return {@code true} if is a template with arguments
|
||||||
|
*/
|
||||||
|
public boolean isTemplate() {
|
||||||
|
return templateName != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the name has a special name representation. This is the interpretation
|
||||||
|
* of a fragment name, so if {@code true} then {@code isFragment} is also {@code true}
|
||||||
|
* @return {@code true} if the name is a fragment with a special interpretation
|
||||||
|
*/
|
||||||
|
public boolean isSpecialName() {
|
||||||
|
return specialName != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the MDFragmentName
|
||||||
|
* @return the fragment name or {@code null} if the name is not a fragment name
|
||||||
|
*/
|
||||||
|
public MDFragmentName getFragmentName() {
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Template Name And Arguments
|
||||||
|
* @return the template information or {@code null} if the name is not a template with arguments
|
||||||
|
*/
|
||||||
|
public MDTemplateNameAndArguments getTemplateName() {
|
||||||
|
return templateName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the special name interpretation of a fragment name
|
||||||
|
* @return the special name or {@code null} if there is no fragment name or no special
|
||||||
|
* interpretation of it
|
||||||
|
*/
|
||||||
|
public String getSpecialName() {
|
||||||
|
return specialName;
|
||||||
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
if (specialName != null) {
|
if (specialName != null) {
|
||||||
return specialName;
|
return specialName;
|
||||||
@@ -57,9 +109,10 @@ public class MDReusableName extends MDParsableItem {
|
|||||||
// else if (qualifiedName != null) { //TODO: do we need this 20140520
|
// else if (qualifiedName != null) { //TODO: do we need this 20140520
|
||||||
// qualifiedName.setName(name);
|
// qualifiedName.setName(name);
|
||||||
// }
|
// }
|
||||||
else if (templateName != null) {
|
// else if (templateName != null) {
|
||||||
templateName.setName(name);
|
// // eliminating this call... think it existed for ctor/dtor reason; refactoring
|
||||||
}
|
// templateName.setName(name);
|
||||||
|
// }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
package mdemangler.naming;
|
package mdemangler.naming;
|
||||||
|
|
||||||
import mdemangler.*;
|
import mdemangler.*;
|
||||||
|
import mdemangler.datatype.MDDataType;
|
||||||
import mdemangler.datatype.MDDataTypeParser;
|
import mdemangler.datatype.MDDataTypeParser;
|
||||||
import mdemangler.object.MDObjectCPP;
|
import mdemangler.object.MDObjectCPP;
|
||||||
|
|
||||||
@@ -53,6 +54,8 @@ public class MDSpecialName extends MDParsableItem {
|
|||||||
private int rttiNumber = -1;
|
private int rttiNumber = -1;
|
||||||
private MDString mstring;
|
private MDString mstring;
|
||||||
private String castTypeString;
|
private String castTypeString;
|
||||||
|
private MDQualifier xtorQual;
|
||||||
|
private MDDataType castType;
|
||||||
|
|
||||||
public MDSpecialName(MDMang dmang, int startIndexOffset) {
|
public MDSpecialName(MDMang dmang, int startIndexOffset) {
|
||||||
super(dmang, startIndexOffset);
|
super(dmang, startIndexOffset);
|
||||||
@@ -66,10 +69,18 @@ public class MDSpecialName extends MDParsableItem {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setXtorQual(MDQualifier xtorQual) {
|
||||||
|
this.xtorQual = xtorQual;
|
||||||
|
}
|
||||||
|
|
||||||
public void setCastTypeString(String castTypeString) {
|
public void setCastTypeString(String castTypeString) {
|
||||||
this.castTypeString = castTypeString;
|
this.castTypeString = castTypeString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCastType(MDDataType castType) {
|
||||||
|
this.castType = castType;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isConstructor() {
|
public boolean isConstructor() {
|
||||||
return isConstructor;
|
return isConstructor;
|
||||||
}
|
}
|
||||||
@@ -108,10 +119,36 @@ public class MDSpecialName extends MDParsableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void insert(StringBuilder builder) {
|
public void insert(StringBuilder builder) {
|
||||||
dmang.insertString(builder, name);
|
if (isConstructor) {
|
||||||
if (isTypeCast && castTypeString != null) {
|
if (xtorQual != null) {
|
||||||
dmang.appendString(builder, " ");
|
xtorQual.insert(builder);
|
||||||
dmang.appendString(builder, castTypeString);
|
}
|
||||||
|
else {
|
||||||
|
dmang.insertString(builder, "ctor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isDestructor) {
|
||||||
|
if (xtorQual != null) {
|
||||||
|
xtorQual.insert(builder);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dmang.insertString(builder, "dtor");
|
||||||
|
}
|
||||||
|
dmang.insertString(builder, "~");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dmang.insertString(builder, name);
|
||||||
|
}
|
||||||
|
if (isTypeCast) {
|
||||||
|
if (castType != null) {
|
||||||
|
dmang.appendString(builder, " ");
|
||||||
|
castType.insert(builder);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (castTypeString != null) {
|
||||||
|
dmang.appendString(builder, " ");
|
||||||
|
dmang.appendString(builder, castTypeString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-3
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -208,7 +208,13 @@ public class MDTemplateArgumentsList extends MDParsableItem {
|
|||||||
}
|
}
|
||||||
// firstArgDone = true;
|
// firstArgDone = true;
|
||||||
StringBuilder argBuilder = new StringBuilder();
|
StringBuilder argBuilder = new StringBuilder();
|
||||||
arg.insert(argBuilder);
|
if (arg instanceof MDComplexType ct &&
|
||||||
|
!dmang.getOutputOptions().applyUdtArgumentTypeTag()) {
|
||||||
|
ct.insertWithoutComplexTag(argBuilder);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
arg.insert(argBuilder);
|
||||||
|
}
|
||||||
dmang.appendString(builder, argBuilder.toString());
|
dmang.appendString(builder, argBuilder.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-2
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -16,7 +16,9 @@
|
|||||||
package mdemangler.template;
|
package mdemangler.template;
|
||||||
|
|
||||||
import mdemangler.*;
|
import mdemangler.*;
|
||||||
|
import mdemangler.datatype.MDDataType;
|
||||||
import mdemangler.naming.MDBasicName;
|
import mdemangler.naming.MDBasicName;
|
||||||
|
import mdemangler.naming.MDQualifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents the template name and arguments list portion of a
|
* This class represents the template name and arguments list portion of a
|
||||||
@@ -46,6 +48,10 @@ public class MDTemplateNameAndArguments extends MDParsableItem {
|
|||||||
templateName.setName(name);
|
templateName.setName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setXtorQual(MDQualifier qual) {
|
||||||
|
templateName.setXtorQual(qual);
|
||||||
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return templateName.getName();
|
return templateName.getName();
|
||||||
}
|
}
|
||||||
@@ -57,6 +63,13 @@ public class MDTemplateNameAndArguments extends MDParsableItem {
|
|||||||
templateName.setCastTypeString(castTypeString);
|
templateName.setCastTypeString(castTypeString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCastType(MDDataType castType) {
|
||||||
|
if (templateName == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
templateName.setCastType(castType);
|
||||||
|
}
|
||||||
|
|
||||||
public MDTemplateArgumentsList getArgumentsList() {
|
public MDTemplateArgumentsList getArgumentsList() {
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,6 +137,69 @@ public class MDMangExtraTest extends AbstractGenericTest {
|
|||||||
assertEquals("_anon_FEDCBA98::a", qualifications.get(1).toString());
|
assertEquals("_anon_FEDCBA98::a", qualifications.get(1).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Eliminate complex tag in template arguments
|
||||||
|
@Test
|
||||||
|
public void testDemangleNameWithComplexTagInTemplateArgumentsWithBackRef() throws Exception {
|
||||||
|
String mangled = "?Ti@@3V?$Tc@V?$Tb@H@@0@@A";
|
||||||
|
String truth = "class Tc<class Tb<int>,class Tb<int> > Ti";
|
||||||
|
String truth2 = "class Tc<Tb<int>,Tb<int> > Ti";
|
||||||
|
|
||||||
|
MDMangGhidra demangler = new MDMangGhidra();
|
||||||
|
demangler.setMangledSymbol(mangled);
|
||||||
|
demangler.setErrorOnRemainingChars(true);
|
||||||
|
demangler.setDemangleOnlyKnownPatterns(true);
|
||||||
|
MDParsableItem item = demangler.demangle();
|
||||||
|
|
||||||
|
String demangled = item.toString();
|
||||||
|
assertEquals(truth, demangled);
|
||||||
|
|
||||||
|
demangler.getOutputOptions().setApplyUdtArgumentTypeTag(false);
|
||||||
|
demangled = item.toString();
|
||||||
|
assertEquals(truth2, demangled);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eliminate complex tag in template arguments
|
||||||
|
@Test
|
||||||
|
public void testDemangleTypeWithComplexTagInTemplateArguments() throws Exception {
|
||||||
|
String mangled = ".?AV?$name0@Uname1@@Uname2@@@@";
|
||||||
|
String truth = "class name0<struct name1,struct name2>";
|
||||||
|
String truth2 = "class name0<name1,name2>";
|
||||||
|
|
||||||
|
MDMangGhidra demangler = new MDMangGhidra();
|
||||||
|
demangler.setMangledSymbol(mangled);
|
||||||
|
demangler.setErrorOnRemainingChars(true);
|
||||||
|
MDParsableItem item = demangler.demangleType(); // note demangleType()
|
||||||
|
|
||||||
|
String demangled = item.toString();
|
||||||
|
assertEquals(truth, demangled);
|
||||||
|
|
||||||
|
demangler.getOutputOptions().setApplyUdtArgumentTypeTag(false);
|
||||||
|
demangled = item.toString();
|
||||||
|
assertEquals(truth2, demangled);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eliminate complex tag in template arguments
|
||||||
|
@Test
|
||||||
|
public void testDemangleTemplateConstructorWithTagInTemplateAndFunctionArguments()
|
||||||
|
throws Exception {
|
||||||
|
String mangled = "??0?$AAA@VBBB@@@ANS@@QAE@VBBB@@@Z";
|
||||||
|
String truth = "public: __thiscall ANS::AAA<class BBB>::AAA<class BBB>(class BBB)";
|
||||||
|
String truth2 = "public: __thiscall ANS::AAA<BBB>::AAA<BBB>(BBB)";
|
||||||
|
|
||||||
|
MDMangGhidra demangler = new MDMangGhidra();
|
||||||
|
demangler.setMangledSymbol(mangled);
|
||||||
|
demangler.setErrorOnRemainingChars(true);
|
||||||
|
demangler.setDemangleOnlyKnownPatterns(true);
|
||||||
|
MDParsableItem item = demangler.demangle();
|
||||||
|
|
||||||
|
String demangled = item.toString();
|
||||||
|
assertEquals(truth, demangled);
|
||||||
|
|
||||||
|
demangler.getOutputOptions().setApplyUdtArgumentTypeTag(false);
|
||||||
|
demangled = item.toString();
|
||||||
|
assertEquals(truth2, demangled);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSimpleDemangleType() throws Exception {
|
public void testSimpleDemangleType() throws Exception {
|
||||||
String mangled = ".?AUname0@name1@@";
|
String mangled = ".?AUname0@name1@@";
|
||||||
|
|||||||
+20
-3
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package docking.options.editor;
|
package docking.options.editor;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
|
|
||||||
import ghidra.framework.options.EditorState;
|
import ghidra.framework.options.EditorState;
|
||||||
@@ -26,17 +27,33 @@ import ghidra.util.layout.HorizontalLayout;
|
|||||||
*/
|
*/
|
||||||
public class CustomOptionComponent extends GenericOptionsComponent {
|
public class CustomOptionComponent extends GenericOptionsComponent {
|
||||||
|
|
||||||
|
private Component editorComponent;
|
||||||
|
|
||||||
protected CustomOptionComponent(EditorState editorState) {
|
protected CustomOptionComponent(EditorState editorState) {
|
||||||
|
|
||||||
// this layout allows us to easily left-align the single component in this container
|
// this layout allows us to easily left-align the single component in this container
|
||||||
setLayout(new HorizontalLayout(0));
|
setLayout(new HorizontalLayout(0));
|
||||||
|
|
||||||
// this class is designed to let the editor component handle the display and editing
|
// this class is designed to let the editor component handle the display and editing
|
||||||
add(editorState.getEditorComponent());
|
editorComponent = editorState.getEditorComponent();
|
||||||
|
add(editorComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Dimension getPreferredAlignmentSize() {
|
protected Dimension getPreferredAlignmentSize() {
|
||||||
|
if (editorComponent instanceof OptionsEditorAlignable alignable) {
|
||||||
|
return alignable.getPreferredAlignmentSize();
|
||||||
|
}
|
||||||
return new Dimension(0, 0);
|
return new Dimension(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setPreferredAlignmentSize(Dimension dimension) {
|
||||||
|
if (editorComponent instanceof OptionsEditorAlignable alignable) {
|
||||||
|
alignable.setPreferredAlignmentSize(dimension);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.setPreferredAlignmentSize(dimension);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-4
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -78,8 +78,10 @@ public class DefaultOptionComponent extends GenericOptionsComponent {
|
|||||||
@Override // overridden to get the size based upon this class's two components
|
@Override // overridden to get the size based upon this class's two components
|
||||||
protected Dimension getPreferredAlignmentSize() {
|
protected Dimension getPreferredAlignmentSize() {
|
||||||
Dimension dimension = label.getPreferredSize();
|
Dimension dimension = label.getPreferredSize();
|
||||||
int maxHeight = Math.max(dimension.height, component.getPreferredSize().height);
|
int labelWidth = dimension.width;
|
||||||
return new Dimension(dimension.width, maxHeight);
|
int labelHeight = dimension.height;
|
||||||
|
int maxHeight = Math.max(labelHeight, component.getPreferredSize().height);
|
||||||
|
return new Dimension(labelWidth, maxHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLabelText() {
|
public String getLabelText() {
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
/* ###
|
||||||
|
* 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 docking.options.editor;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.beans.PropertyEditor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple interface for options {@link PropertyEditor}s to signal that they provide a custom
|
||||||
|
* option editor that would like to be aligned with other options in the same view.
|
||||||
|
*/
|
||||||
|
public interface OptionsEditorAlignable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return Gets the preferred alignment size of this class.}
|
||||||
|
*/
|
||||||
|
public Dimension getPreferredAlignmentSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the final preferred alignment size after merging all preferred sizes from all options
|
||||||
|
* components in the view.
|
||||||
|
* @param size the size
|
||||||
|
*/
|
||||||
|
public void setPreferredAlignmentSize(Dimension size);
|
||||||
|
}
|
||||||
+4
-4
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -88,12 +88,11 @@ public class OptionsEditorPanel extends JPanel {
|
|||||||
editorPropertyChangeListener);
|
editorPropertyChangeListener);
|
||||||
editorInfoList.add(editorState);
|
editorInfoList.add(editorState);
|
||||||
|
|
||||||
HelpLocation helpLoc = options.getHelpLocation(optionName);
|
|
||||||
|
|
||||||
GenericOptionsComponent component =
|
GenericOptionsComponent component =
|
||||||
GenericOptionsComponent.createOptionComponent(editorState);
|
GenericOptionsComponent.createOptionComponent(editorState);
|
||||||
add(component);
|
add(component);
|
||||||
|
|
||||||
|
HelpLocation helpLoc = options.getHelpLocation(optionName);
|
||||||
if (helpLoc == null) {
|
if (helpLoc == null) {
|
||||||
help.excludeFromHelp(component);
|
help.excludeFromHelp(component);
|
||||||
}
|
}
|
||||||
@@ -119,6 +118,7 @@ public class OptionsEditorPanel extends JPanel {
|
|||||||
state.applyValue();
|
state.applyValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOptionsPropertyChangeListener(PropertyChangeListener listener) {
|
public void setOptionsPropertyChangeListener(PropertyChangeListener listener) {
|
||||||
this.propertyChangeListener = listener;
|
this.propertyChangeListener = listener;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user