mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
Added GnuDemanglerFormat, changed analyzer options
All available demangler formats have been added to GnuDemanglerFormat. The options in GnuDemanglerAnalyzer now only reflect the available formats to remove any user error when specifying a format. This also prevents a format from being used on a demangler which doesn't support it.
This commit is contained in:
parent
ce78b860be
commit
0fcab24073
9 changed files with 454 additions and 365 deletions
|
@ -388,32 +388,15 @@
|
|||
that Ghidra contains (<B>version 2.33.1</B> as of this writing). Turning this
|
||||
option on will also invoke the now deprecated previous version of the demangler
|
||||
(<B>version 2.24</B>) if the preferred demangler cannot demangle a given symbol.
|
||||
This option only has an effect when the demangler format is available in both
|
||||
the deprecated and modern demanglers.
|
||||
</P>
|
||||
<P>
|
||||
Support for older demangling styles was removed in <CODE>c++filt (v2.32)</CODE>.
|
||||
Specifically, the following formats are no longer supported:
|
||||
<CODE>Lucid, ARM, HP, and EDG</CODE>. To use these formats, you must enable
|
||||
usage of the deprecated demangler, which is <B>version 2.24</B>. Further, you
|
||||
may have to pass the required external demangler options using the Ghidra
|
||||
option below.
|
||||
<CODE>Lucid, ARM, HP, GNU, and EDG</CODE>. For these formats, the deprecated
|
||||
demangler, which is <B>version 2.24</B>, will automatically be used.
|
||||
</P>
|
||||
<P>
|
||||
|
||||
<U><B>Use External Demangler Options</B></U> -
|
||||
|
||||
This allows users to pass settings to the demangler. As an example, you can enter
|
||||
in this Ghidra option text field the following text to use the <CODE>rust</CODE>
|
||||
format: <CODE>-s rust</CODE>. This is not needed for
|
||||
normal operation. To see a full list of supported options, query each demangler
|
||||
directly using the <CODE>--help</CODE> switch.
|
||||
</P>
|
||||
<P>
|
||||
The GNU demanglers can be found at:
|
||||
<CODE CLASS="path">
|
||||
<GHIDRA_INSTALL_DIR>/GPL/DemanglerGnu/build/os/<OS>/
|
||||
</CODE><BR>
|
||||
</P>
|
||||
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>
|
||||
|
|
|
@ -15,10 +15,6 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.analysis;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.util.demangler.*;
|
||||
import ghidra.app.util.demangler.gnu.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
|
@ -51,15 +47,14 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||
"Signals to use the deprecated demangler when the modern demangler cannot demangle a " +
|
||||
"given string";
|
||||
|
||||
static final String OPTION_NAME_DEMANGLER_PARAMETERS =
|
||||
"Use External Demangler Options";
|
||||
private static final String OPTION_DESCRIPTION_DEMANGLER_PARAMETERS =
|
||||
"Signals to use pass the given parameters to the demangler program";
|
||||
static final String OPTION_NAME_DEMANGLER_FORMAT = "Demangler Format";
|
||||
private static final String OPTION_DESCRIPTION_DEMANGLER_FORMAT =
|
||||
"The demangling format to use";
|
||||
|
||||
private boolean doSignatureEnabled = true;
|
||||
private boolean demangleOnlyKnownPatterns = false;
|
||||
private GnuDemanglerFormat demanglerFormat = GnuDemanglerFormat.AUTO;
|
||||
private boolean useDeprecatedDemangler = false;
|
||||
private String demanglerParameters = "";
|
||||
|
||||
private GnuDemangler demangler = new GnuDemangler();
|
||||
|
||||
|
@ -84,11 +79,11 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||
help,
|
||||
OPTION_DESCRIPTION_USE_KNOWN_PATTERNS);
|
||||
|
||||
options.registerOption(OPTION_NAME_DEMANGLER_FORMAT, demanglerFormat, help,
|
||||
OPTION_DESCRIPTION_DEMANGLER_FORMAT);
|
||||
|
||||
options.registerOption(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler, help,
|
||||
OPTION_DESCRIPTION_DEPRECATED_DEMANGLER);
|
||||
|
||||
options.registerOption(OPTION_NAME_DEMANGLER_PARAMETERS, demanglerParameters, help,
|
||||
OPTION_DESCRIPTION_DEMANGLER_PARAMETERS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -96,94 +91,28 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
|||
doSignatureEnabled = options.getBoolean(OPTION_NAME_APPLY_SIGNATURE, doSignatureEnabled);
|
||||
demangleOnlyKnownPatterns =
|
||||
options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns);
|
||||
|
||||
useDeprecatedDemangler =
|
||||
options.getBoolean(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler);
|
||||
|
||||
demanglerParameters =
|
||||
options.getString(OPTION_NAME_DEMANGLER_PARAMETERS, demanglerParameters);
|
||||
demanglerFormat = options.getEnum(OPTION_NAME_DEMANGLER_FORMAT, GnuDemanglerFormat.AUTO);
|
||||
if (demanglerFormat.isDeprecatedFormat() && demanglerFormat.isModernFormat()) {
|
||||
useDeprecatedDemangler =
|
||||
options.getBoolean(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler);
|
||||
} else {
|
||||
useDeprecatedDemangler = demanglerFormat.isDeprecatedFormat();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DemanglerOptions getOptions() {
|
||||
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions();
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(demanglerFormat, useDeprecatedDemangler);
|
||||
options.setDoDisassembly(true);
|
||||
options.setApplySignature(doSignatureEnabled);
|
||||
options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
|
||||
options.setDemanglerApplicationArguments(demanglerParameters);
|
||||
return options;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateOptions(DemanglerOptions demanglerOtions, MessageLog log) {
|
||||
|
||||
GnuDemanglerOptions options = (GnuDemanglerOptions) demanglerOtions;
|
||||
String applicationArguments = options.getDemanglerApplicationArguments();
|
||||
if (StringUtils.isBlank(applicationArguments)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check that the supplied arguments will work with at least one of the requested
|
||||
// demanglers. (Different versions of the GNU demangler support different arguments.)
|
||||
String demanglerName = options.getDemanglerName();
|
||||
try {
|
||||
GnuDemanglerNativeProcess.getDemanglerNativeProcess(demanglerName,
|
||||
applicationArguments);
|
||||
return true;
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(getName(), "Invalid options for GNU dangler '" + demanglerName +
|
||||
"': " + applicationArguments);
|
||||
log.appendException(e);
|
||||
}
|
||||
|
||||
if (useDeprecatedDemangler) {
|
||||
// see if the options work in the deprecated demangler
|
||||
GnuDemanglerOptions deprecatedOptions = options.withDeprecatedDemangler();
|
||||
String deprecatedName = deprecatedOptions.getDemanglerName();
|
||||
try {
|
||||
GnuDemanglerNativeProcess.getDemanglerNativeProcess(deprecatedName,
|
||||
applicationArguments);
|
||||
return true;
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.appendMsg(getName(),
|
||||
"Invalid options for GNU dangler '" + deprecatedName + "': " +
|
||||
applicationArguments);
|
||||
log.appendException(e);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DemangledObject doDemangle(String mangled, DemanglerOptions demanglerOtions,
|
||||
MessageLog log)
|
||||
throws DemangledException {
|
||||
|
||||
GnuDemanglerOptions options = (GnuDemanglerOptions) demanglerOtions;
|
||||
DemangledObject demangled = null;
|
||||
try {
|
||||
demangled = demangler.demangle(mangled, options);
|
||||
}
|
||||
catch (DemangledException e) {
|
||||
if (!useDeprecatedDemangler) {
|
||||
throw e; // let our parent handle this
|
||||
}
|
||||
}
|
||||
|
||||
if (demangled != null) {
|
||||
return demangled;
|
||||
}
|
||||
|
||||
if (useDeprecatedDemangler) {
|
||||
GnuDemanglerOptions newOptions = options.withDeprecatedDemangler();
|
||||
demangled = demangler.demangle(mangled, newOptions);
|
||||
}
|
||||
|
||||
return demangled;
|
||||
MessageLog log) throws DemangledException {
|
||||
return demangler.demangle(mangled, (GnuDemanglerOptions) demanglerOtions);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,11 +72,11 @@ public class GnuDemangler implements Demangler {
|
|||
public DemangledObject demangle(String mangled, DemanglerOptions demanglerOtions)
|
||||
throws DemangledException {
|
||||
|
||||
if (skip(mangled, demanglerOtions)) {
|
||||
GnuDemanglerOptions options = getGnuOptions(demanglerOtions);
|
||||
if (skip(mangled, options)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
GnuDemanglerOptions options = getGnuOptions(demanglerOtions);
|
||||
String originalMangled = mangled;
|
||||
String globalPrefix = null;
|
||||
if (mangled.startsWith(GLOBAL_PREFIX)) {
|
||||
|
@ -163,7 +163,7 @@ public class GnuDemangler implements Demangler {
|
|||
applicationOptions);
|
||||
}
|
||||
|
||||
private boolean skip(String mangled, DemanglerOptions options) {
|
||||
private boolean skip(String mangled, GnuDemanglerOptions options) {
|
||||
|
||||
// Ignore versioned symbols which are generally duplicated at the same address
|
||||
if (mangled.indexOf("@") > 0) { // do not demangle versioned symbols
|
||||
|
@ -179,21 +179,28 @@ public class GnuDemangler implements Demangler {
|
|||
return false; // let it go through
|
||||
}
|
||||
|
||||
// add to this list if we find any other known GNU start patterns
|
||||
if (mangled.startsWith("_Z")) {
|
||||
// TODO provide some checks specific to the other formats
|
||||
GnuDemanglerFormat format = options.getDemanglerFormat();
|
||||
if (format == GnuDemanglerFormat.AUTO) {
|
||||
return false;
|
||||
}
|
||||
else if (mangled.startsWith("__Z")) {
|
||||
return false;
|
||||
}
|
||||
else if (mangled.startsWith("h__")) {
|
||||
return false; // not sure about this one
|
||||
}
|
||||
else if (mangled.startsWith("?")) {
|
||||
return false; // not sure about this one
|
||||
}
|
||||
else if (isGnu2Or3Pattern(mangled)) {
|
||||
return false;
|
||||
if (format == GnuDemanglerFormat.GNUV3) {
|
||||
// add to this list if we find any other known GNU start patterns
|
||||
if (mangled.startsWith("_Z")) {
|
||||
return false;
|
||||
}
|
||||
if (mangled.startsWith("__Z")) {
|
||||
return false;
|
||||
}
|
||||
if (mangled.startsWith("h__")) {
|
||||
return false; // not sure about this one
|
||||
}
|
||||
if (mangled.startsWith("?")) {
|
||||
return false; // not sure about this one
|
||||
}
|
||||
if (isGnu2Or3Pattern(mangled)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.demangler.gnu;
|
||||
|
||||
/**
|
||||
* Enum representation of the available GnuDemangler formats
|
||||
*/
|
||||
public enum GnuDemanglerFormat {
|
||||
// OLD: none,auto,gnu,lucid,arm,hp,edg,gnu-v3,java,gnat
|
||||
// NEW: none,auto,gnu-v3,java,gnat,dlang,rust
|
||||
/** Automatic mangling format detection */
|
||||
AUTO("", 0),
|
||||
/** GNUv2 mangling format */
|
||||
GNU("gnu", -1),
|
||||
/** lucid mangling format */
|
||||
LUCID("lucid", -1),
|
||||
/** arm mangling format */
|
||||
ARM("arm", -1),
|
||||
/** hp mangling format */
|
||||
HP("hp", -1),
|
||||
/** mangling format used by the Edison Design Group (EDG) compiler */
|
||||
EDG("edg", -1),
|
||||
/** GNUv3 mangling format */
|
||||
GNUV3("gnu-v3", 0),
|
||||
/** Java mangling format */
|
||||
JAVA("java", 0),
|
||||
/** GNAT Ada compiler mangling format */
|
||||
GNAT("gnat", 0),
|
||||
/** D mangling format */
|
||||
DLANG("dlang", 1),
|
||||
/** Rust mangling format */
|
||||
RUST("rust", 1);
|
||||
|
||||
/** the format option string */
|
||||
private final String format;
|
||||
/** private sentinal. deprecated = -1, both = 0, new = 1 */
|
||||
private final byte version;
|
||||
|
||||
private GnuDemanglerFormat(String format, int version) {
|
||||
this.format = format;
|
||||
this.version = (byte) version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this format is available in the deprecated gnu demangler
|
||||
* @return true if this format is available in the deprecated gnu demangler
|
||||
*/
|
||||
public boolean isDeprecatedFormat() {
|
||||
return version <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this format is available in a modern version of the gnu demangler
|
||||
* @return true if this format is available in a modern version of the gnu demangler.
|
||||
*/
|
||||
public boolean isModernFormat() {
|
||||
return version >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the format option to be passed to the demangler via the <code>-s</code> option
|
||||
* @return the format option to be passed to the demangler
|
||||
*/
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
}
|
|
@ -43,11 +43,27 @@ public class GnuDemanglerOptions extends DemanglerOptions {
|
|||
*/
|
||||
public static final String GNU_DEMANGLER_DEFAULT = GNU_DEMANGLER_V2_33_1;
|
||||
|
||||
private String demanglerName = GNU_DEMANGLER_DEFAULT;
|
||||
private String demanglerApplicationArguments;
|
||||
private final GnuDemanglerFormat format;
|
||||
private final boolean isDeprecated;
|
||||
|
||||
public GnuDemanglerOptions() {
|
||||
// use default values
|
||||
this(GnuDemanglerFormat.AUTO);
|
||||
}
|
||||
|
||||
public GnuDemanglerOptions(GnuDemanglerFormat format) {
|
||||
this.format = format;
|
||||
// default to the "new" demangler if the format is available in both
|
||||
this.isDeprecated = !format.isModernFormat();
|
||||
}
|
||||
|
||||
public GnuDemanglerOptions(GnuDemanglerFormat format, boolean deprecated) {
|
||||
this.format = format;
|
||||
this.isDeprecated = deprecated;
|
||||
if (!isValidFormat(format, deprecated)) {
|
||||
throw new IllegalArgumentException(
|
||||
format.name() + " is not available in the "+getDemanglerName());
|
||||
}
|
||||
}
|
||||
|
||||
public GnuDemanglerOptions(DemanglerOptions copy) {
|
||||
|
@ -55,26 +71,59 @@ public class GnuDemanglerOptions extends DemanglerOptions {
|
|||
|
||||
if (copy instanceof GnuDemanglerOptions) {
|
||||
GnuDemanglerOptions gCopy = (GnuDemanglerOptions) copy;
|
||||
demanglerName = gCopy.demanglerName;
|
||||
demanglerApplicationArguments = gCopy.demanglerApplicationArguments;
|
||||
format = gCopy.format;
|
||||
isDeprecated = gCopy.isDeprecated;
|
||||
} else {
|
||||
format = GnuDemanglerFormat.AUTO;
|
||||
isDeprecated = false;
|
||||
}
|
||||
}
|
||||
|
||||
private GnuDemanglerOptions(GnuDemanglerOptions copy, GnuDemanglerFormat format,
|
||||
boolean deprecated) {
|
||||
super(copy);
|
||||
this.format = format;
|
||||
this.isDeprecated = deprecated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the external demangler executable name to be used for demangling. The
|
||||
* default value is {@link #GNU_DEMANGLER_DEFAULT}.
|
||||
* @return the name
|
||||
*/
|
||||
public String getDemanglerName() {
|
||||
return demanglerName;
|
||||
return isDeprecated ? GNU_DEMANGLER_V2_24 : GNU_DEMANGLER_V2_33_1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the external demangler executable name to be used for demangling
|
||||
* @param name the name
|
||||
* A convenience method to copy the state of this options object, changing the
|
||||
* demangler executable name and demangler format to the specified values.
|
||||
* @param format the demangling format to use
|
||||
* @param isDeprecated true to use the deprecated gnu demangler, else false
|
||||
* @return the new options
|
||||
* @throws IllegalArgumentException if the current format is not available in the
|
||||
* selected demangler.
|
||||
*/
|
||||
public void setDemanglerName(String name) {
|
||||
this.demanglerName = name;
|
||||
public GnuDemanglerOptions withDemanglerFormat(GnuDemanglerFormat format, boolean isDeprecated)
|
||||
throws IllegalArgumentException {
|
||||
if (this.format == format && this.isDeprecated == isDeprecated) {
|
||||
return this;
|
||||
}
|
||||
if (isValidFormat(format, isDeprecated)) {
|
||||
return new GnuDemanglerOptions(this, format, isDeprecated);
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
format.name() + " is not available in the "+getDemanglerName());
|
||||
}
|
||||
|
||||
private static boolean isValidFormat(GnuDemanglerFormat format, boolean isDeprecated) {
|
||||
if (isDeprecated && format.isDeprecatedFormat()) {
|
||||
return true;
|
||||
}
|
||||
if (!isDeprecated && format.isModernFormat()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,26 +131,19 @@ public class GnuDemanglerOptions extends DemanglerOptions {
|
|||
* @return the arguments
|
||||
*/
|
||||
public String getDemanglerApplicationArguments() {
|
||||
return demanglerApplicationArguments;
|
||||
if (format == GnuDemanglerFormat.AUTO) {
|
||||
// no format argument
|
||||
return "";
|
||||
}
|
||||
return "-s " + format.getFormat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the arguments to be passed to the external demangler executable
|
||||
* @param args the arguments
|
||||
* Gets the current demangler format
|
||||
* @return the demangler format
|
||||
*/
|
||||
public void setDemanglerApplicationArguments(String args) {
|
||||
this.demanglerApplicationArguments = args;
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method to copy the state of this options object, changing the
|
||||
* demangler executable name to the deprecated demangler
|
||||
* @return the new options
|
||||
*/
|
||||
public GnuDemanglerOptions withDeprecatedDemangler() {
|
||||
GnuDemanglerOptions newOptions = new GnuDemanglerOptions(this);
|
||||
newOptions.setDemanglerName(GNU_DEMANGLER_V2_24);
|
||||
return newOptions;
|
||||
public GnuDemanglerFormat getDemanglerFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,8 +153,8 @@ public class GnuDemanglerOptions extends DemanglerOptions {
|
|||
"\tdoDisassembly: " + doDisassembly() + ",\n" +
|
||||
"\tapplySignature: " + applySignature() + ",\n" +
|
||||
"\tdemangleOnlyKnownPatterns: " + demangleOnlyKnownPatterns() + ",\n" +
|
||||
"\tdemanglerName: " + demanglerName + ",\n" +
|
||||
"\tdemanglerApplicationArguments: " + demanglerApplicationArguments + ",\n" +
|
||||
"\tdemanglerName: " + getDemanglerName() + ",\n" +
|
||||
"\tdemanglerApplicationArguments: " + getDemanglerApplicationArguments() + ",\n" +
|
||||
"}";
|
||||
//@formatter:on
|
||||
}
|
||||
|
|
|
@ -43,12 +43,8 @@ public class GnuDemanglerParser {
|
|||
private static final String TYPEINFO_FOR = "typeinfo for ";
|
||||
private static final String COVARIANT_RETURN_THUNK = "covariant return thunk";
|
||||
|
||||
private static final Set<String> ADDRESS_TABLE_PREFIXES = Set.of(
|
||||
CONSTRUCTION_VTABLE_FOR,
|
||||
VTT_FOR,
|
||||
VTABLE_FOR,
|
||||
TYPEINFO_FN_FOR,
|
||||
TYPEINFO_FOR);
|
||||
private static final Set<String> ADDRESS_TABLE_PREFIXES =
|
||||
Set.of(CONSTRUCTION_VTABLE_FOR, VTT_FOR, VTABLE_FOR, TYPEINFO_FN_FOR, TYPEINFO_FOR);
|
||||
|
||||
private static final String OPERATOR = "operator";
|
||||
private static final String LAMBDA = "lambda";
|
||||
|
|
|
@ -17,13 +17,11 @@ package ghidra.app.plugin.core.analysis;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.app.cmd.label.AddLabelCmd;
|
||||
import ghidra.app.util.demangler.gnu.GnuDemanglerOptions;
|
||||
import ghidra.app.util.demangler.gnu.GnuDemanglerFormat;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
|
@ -34,7 +32,6 @@ import ghidra.program.model.symbol.*;
|
|||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||
import ghidra.test.ToyProgramBuilder;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.StringUtilities;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
|
@ -99,6 +96,7 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
|
|||
Address addr = addr("0x110");
|
||||
createSymbol(addr, mangled);
|
||||
|
||||
setFormat(GnuDemanglerFormat.AUTO);
|
||||
setOption(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER, true);
|
||||
|
||||
analyze();
|
||||
|
@ -106,24 +104,6 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
|
|||
assertDemangled(addr, "__dt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMangledString_WithArguments_Valid() {
|
||||
|
||||
//
|
||||
// The below demangles to std::io::Read::read_to_end
|
||||
//
|
||||
String mangled = "_ZN3std2io4Read11read_to_end17hb85a0f6802e14499E";
|
||||
|
||||
Address addr = addr("0x110");
|
||||
createSymbol(addr, mangled);
|
||||
|
||||
setOption(GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_PARAMETERS, "-s rust");
|
||||
|
||||
analyze();
|
||||
|
||||
assertDemangled(addr, "read_to_end");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMangledString_WithArguments_ValidButWrongFormat() {
|
||||
|
||||
|
@ -135,7 +115,7 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
|
|||
Address addr = addr("0x110");
|
||||
createSymbol(addr, mangled);
|
||||
|
||||
setOption(GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_PARAMETERS, "-s dlang");
|
||||
setFormat(GnuDemanglerFormat.DLANG);
|
||||
|
||||
analyze();
|
||||
|
||||
|
@ -143,105 +123,36 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testMangledString_WithArguments_Invalid() {
|
||||
|
||||
//
|
||||
// The below demangles to std::io::Read::read_to_end
|
||||
//
|
||||
String mangled = "_ZN3std2io4Read11read_to_end17hb85a0f6802e14499E";
|
||||
|
||||
Address addr = addr("0x110");
|
||||
createSymbol(addr, mangled);
|
||||
|
||||
setOption(GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_PARAMETERS, "-s badformatname");
|
||||
|
||||
analyze();
|
||||
|
||||
assertNotDemangled(addr, "read_to_end");
|
||||
assertMessageLogLine("java.io.IOException: Error starting demangler with command");
|
||||
assertMessageLogLine("Invalid options", GnuDemanglerOptions.GNU_DEMANGLER_V2_33_1);
|
||||
public void testUseDeprecatedOptionRemoval_WithDeprecatedFormat() {
|
||||
setFormat(GnuDemanglerFormat.GNU);
|
||||
Options options = program.getOptions("Analyzers");
|
||||
assertFalse(options.contains(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeprecatedMangledString_WithArguments_Invalid() {
|
||||
|
||||
//
|
||||
// The below demangles to std::io::Read::read_to_end
|
||||
//
|
||||
String mangled = "_ZN3std2io4Read11read_to_end17hb85a0f6802e14499E";
|
||||
|
||||
Address addr = addr("0x110");
|
||||
createSymbol(addr, mangled);
|
||||
|
||||
setOption(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER, true);
|
||||
setOption(GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_PARAMETERS, "-s badformatname");
|
||||
|
||||
analyze();
|
||||
|
||||
assertNotDemangled(addr, "read_to_end");
|
||||
assertMessageLogLine("java.io.IOException: Error starting demangler with command");
|
||||
assertMessageLogLine("Invalid options", GnuDemanglerOptions.GNU_DEMANGLER_V2_33_1);
|
||||
assertMessageLogLine("Invalid options", GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
|
||||
public void testUseDeprecatedOptionRemoval_WithRecentFormat() {
|
||||
setFormat(GnuDemanglerFormat.RUST);
|
||||
Options options = program.getOptions("Analyzers");
|
||||
assertFalse(options.contains(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeprecatedMangledString_WithArguments_InvalidModernArguments_ValidDeprecatedArguments() {
|
||||
|
||||
//
|
||||
// The below demangles to std::io::Read::read_to_end
|
||||
//
|
||||
String mangled = "_ZN3std2io4Read11read_to_end17hb85a0f6802e14499E";
|
||||
|
||||
Address addr = addr("0x110");
|
||||
createSymbol(addr, mangled);
|
||||
|
||||
setOption(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER, true);
|
||||
setOption(GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_PARAMETERS, "-s arm");
|
||||
|
||||
analyze();
|
||||
|
||||
assertNotDemangled(addr, "read_to_end");
|
||||
assertMessageLogLine("java.io.IOException: Error starting demangler with command");
|
||||
assertMessageLogLine("Invalid options", GnuDemanglerOptions.GNU_DEMANGLER_V2_33_1);
|
||||
assertMessageNotInLogLine("Invalid options", GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
|
||||
public void testUseDeprecatedOptionAddition() {
|
||||
// remove it first
|
||||
testUseDeprecatedOptionRemoval_WithDeprecatedFormat();
|
||||
setFormat(GnuDemanglerFormat.AUTO);
|
||||
Options options = program.getOptions("Analyzers");
|
||||
assertTrue(options.contains(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER));
|
||||
}
|
||||
|
||||
// things missed:
|
||||
// -demangle error case in base class...this is OK
|
||||
// -error case in applyTo method in base class
|
||||
|
||||
// -use deprecated demangler case in validateOptions
|
||||
|
||||
//==================================================================================================
|
||||
// Private Methods
|
||||
//==================================================================================================
|
||||
|
||||
private void assertMessageLogLine(String... expected) {
|
||||
|
||||
String allMessages = log.toString();
|
||||
String[] logLines = allMessages.split("\n");
|
||||
for (String line : logLines) {
|
||||
if (StringUtilities.containsAllIgnoreCase(line, expected)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fail("The folllowing source text did not have a line containing:\n" +
|
||||
Arrays.toString(expected) + "\n\nActual Text:\n" + allMessages);
|
||||
}
|
||||
|
||||
private void assertMessageNotInLogLine(String... expected) {
|
||||
|
||||
String allMessages = log.toString();
|
||||
String[] logLines = allMessages.split("\n");
|
||||
for (String line : logLines) {
|
||||
if (StringUtilities.containsAllIgnoreCase(line, expected)) {
|
||||
fail("The folllowing source text unexpectedly has a line containing:\n" +
|
||||
Arrays.toString(expected) + "\n\nActual Text:\n" + allMessages);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void analyze() {
|
||||
tx(program, () -> analyzer.added(program, program.getMemory(), TaskMonitor.DUMMY, log));
|
||||
}
|
||||
|
@ -288,14 +199,15 @@ public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationT
|
|||
fail("Could not find option '" + optionName + "'");
|
||||
}
|
||||
|
||||
private void setOption(String optionName, String value) {
|
||||
private void setFormat(GnuDemanglerFormat format) {
|
||||
|
||||
String optionName = GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_FORMAT;
|
||||
String fullOptionName = analyzer.getName() + Options.DELIMITER_STRING + optionName;
|
||||
Options options = program.getOptions("Analyzers");
|
||||
|
||||
for (String name : options.getOptionNames()) {
|
||||
if (name.equals(fullOptionName)) {
|
||||
tx(program, () -> options.setString(optionName, value));
|
||||
tx(program, () -> options.setEnum(optionName, format));
|
||||
|
||||
// we must call this manually, since we are not using a tool
|
||||
analyzer.optionsChanged(options, program);
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.demangler.gnu;
|
||||
|
||||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static ghidra.app.util.demangler.gnu.GnuDemanglerFormat.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class GnuDemanglerOptionsTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void testAuto_withDeprecated() throws IOException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(AUTO, true);
|
||||
getNativeProcess(options);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuto_withModern() throws IOException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(AUTO, false);
|
||||
getNativeProcess(options);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGnu_withDeprecated() throws IOException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(GNU, true);
|
||||
getNativeProcess(options);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testGnu_withModern() {
|
||||
new GnuDemanglerOptions(GNU, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLucid_withDeprecated() throws IOException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(LUCID, true);
|
||||
getNativeProcess(options);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testLucid_withModern() {
|
||||
new GnuDemanglerOptions(LUCID, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArm_withDeprecated() throws IOException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(ARM, true);
|
||||
getNativeProcess(options);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testArm_withModern() {
|
||||
new GnuDemanglerOptions(ARM, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHp_withDeprecated() throws IOException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(HP, true);
|
||||
getNativeProcess(options);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testHp_withModern() {
|
||||
new GnuDemanglerOptions(HP, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEdg_withDeprecated() throws IOException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(EDG, true);
|
||||
getNativeProcess(options);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testEdg_withModern() {
|
||||
new GnuDemanglerOptions(EDG, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGnuV3_withDeprecated() throws IOException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(GNUV3, true);
|
||||
getNativeProcess(options);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGnuV3_withModern() throws IOException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(GNUV3, false);
|
||||
getNativeProcess(options);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJava_withDeprecated() throws IOException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(JAVA, true);
|
||||
getNativeProcess(options);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJava_withModern() throws IOException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(JAVA, false);
|
||||
getNativeProcess(options);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGnat_withDeprecated() throws IOException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(GNAT, true);
|
||||
getNativeProcess(options);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGnat_withModern() throws IOException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(GNAT, false);
|
||||
getNativeProcess(options);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testDlang_withDeprecated() {
|
||||
new GnuDemanglerOptions(DLANG, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDlang_withModern() throws IOException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(DLANG, false);
|
||||
getNativeProcess(options);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testRust_withDeprecated() {
|
||||
new GnuDemanglerOptions(RUST, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRust_withModern() throws IOException {
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(RUST, false);
|
||||
getNativeProcess(options);
|
||||
}
|
||||
|
||||
private static GnuDemanglerNativeProcess getNativeProcess(GnuDemanglerOptions options)
|
||||
throws IOException {
|
||||
String demanglerName = options.getDemanglerName();
|
||||
String applicationOptions = options.getDemanglerApplicationArguments();
|
||||
return GnuDemanglerNativeProcess.getDemanglerNativeProcess(demanglerName,
|
||||
applicationOptions);
|
||||
}
|
||||
}
|
|
@ -157,23 +157,6 @@ public class GnuDemanglerTest extends AbstractGenericTest {
|
|||
assertEquals("ABC", d.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDemangler_Format_EDG_DemangleOnlyKnownPatterns_False()
|
||||
throws DemangledException {
|
||||
|
||||
String mangled = "_$_10MyFunction";
|
||||
|
||||
GnuDemangler demangler = new GnuDemangler();
|
||||
demangler.canDemangle(program);// this perform initialization
|
||||
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions();
|
||||
options.setDemangleOnlyKnownPatterns(false);
|
||||
options.setDemanglerName(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
|
||||
DemangledObject result = demangler.demangle(mangled, options);
|
||||
assertNotNull(result);
|
||||
assertEquals("undefined MyFunction::~MyFunction(void)", result.getSignature(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDemangler_Format_EDG_DemangleOnlyKnownPatterns_True()
|
||||
throws DemangledException {
|
||||
|
@ -192,16 +175,15 @@ public class GnuDemanglerTest extends AbstractGenericTest {
|
|||
GnuDemangler demangler = new GnuDemangler();
|
||||
demangler.canDemangle(program);// this perform initialization
|
||||
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions();
|
||||
options.setDemangleOnlyKnownPatterns(true); // do not try
|
||||
options.setDemanglerName(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(GnuDemanglerFormat.EDG);
|
||||
DemangledObject result = demangler.demangle(mangled, options);
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDemangler_Format_CodeWarrior_MacOS8or9() throws DemangledException {
|
||||
|
||||
// NOTE: mangled CodeWarrior format symbols with templates will fail
|
||||
// This is because the GNU demangler does not support CodeWarrior
|
||||
// .scroll__10TTextPanelFUcsi
|
||||
|
||||
String mangled = ".scroll__10TTextPanelFUcsi";
|
||||
|
@ -209,9 +191,7 @@ public class GnuDemanglerTest extends AbstractGenericTest {
|
|||
GnuDemangler demangler = new GnuDemangler();
|
||||
demangler.canDemangle(program);// this perform initialization
|
||||
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions();
|
||||
options.setDemangleOnlyKnownPatterns(false);
|
||||
options.setDemanglerName(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
|
||||
GnuDemanglerOptions options = new GnuDemanglerOptions(GnuDemanglerFormat.AUTO, true);
|
||||
DemangledObject result = demangler.demangle(mangled, options);
|
||||
assertNotNull(result);
|
||||
assertEquals("undefined TTextPanel::scroll(unsigned char,short,int)",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue