Merge remote-tracking branch

'origin/GP-4898_ghizard_MDMang_process_C_style_mangled_function_symbols--SQUASHED'
(Closes #1514)
This commit is contained in:
Ryan Kurtz
2024-09-19 09:45:47 -04:00
53 changed files with 3016 additions and 1460 deletions
@@ -498,6 +498,38 @@
</BLOCKQUOTE>
<P STYLE="margin-top: 30px;"><U>Started By:</U> New defined functions</P>
<BR>
<BR>
<P><A name="Microsoft_Demangler_Options">
<B>The Microsoft Demangler</B></H4> adds the following analysis option:
<BLOCKQUOTE>
<P>
<U><B>C-Style Symbol Interpretation</B></U> -
This option is used to help direct processing of certain C-style symbols that
could have C-style interpretations. The Microsoft C-Style mangling scheme
permits a simple encoding of some functions, to include calling convention
and number of bytes in the arguments list. This is mainly for 32-bit programs,
but the convention is also used for at least one calling convention for 64-bit
programs. When a symbol can be interpreted as both a C-style function and as
some other C++-style object, this option controls which is chosen.
<P> The choices are:
<UL>
<LI><B>FUNCTION</B>: the C-style function type is produced</LI>
<LI><B>NON_FUNCTION</B>: the C++-style object is produced</LI>
<LI><B>FUNCTION_IF_EXISTS</B>: the C-style function type is produced if
a function already exists at the program address</LI>
</UL>
</P>
<P><IMG alt="" src="help/shared/warning.png"> The user should generally not change this
option except for trying to debug the results of this new scheme. This option may
be removed in a future release.
</P>
</P>
</BLOCKQUOTE>
</BLOCKQUOTE>
<H3><A name="Auto_Analysis_Option_Byte"></A>Entry Point Analyzer</H3>
@@ -4,9 +4,9 @@
* 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.
@@ -70,8 +70,10 @@ public class DemanglerCmd extends BackgroundCommand<Program> {
private boolean doDemangle(Demangler demangler, Program program, TaskMonitor monitor) {
MangledContext mangledContext =
demangler.createMangledContext(mangled, options, program, addr);
try {
demangledObject = demangler.demangle(mangled, options);
demangledObject = demangler.demangle(mangledContext);
}
catch (DemangledException e) {
if (e.isInvalidMangledName()) {
@@ -85,13 +87,13 @@ public class DemanglerCmd extends BackgroundCommand<Program> {
return false; // error
// This produces too many messages for non-demangled symbols. If we could
// figure out a way to tell which symbol are those which are mangled and
// failing, then we should print those. The problem is not knowing how to
// figure out a way to tell which symbol are those which are mangled and
// failing, then we should print those. The problem is not knowing how to
// tell a mangled from a non-mangled symbol.
// Msg.debug(this, "Unable to demangle name: " + mangled);
}
catch (Exception e) {
// Demangler IndexOutOfBoundsException that we're not sure how to fix
// Demangler IndexOutOfBoundsException that we're not sure how to fix
setStatusMsg("Unable to demangle symbol: " + mangled + " at " + addr + ". Message: " +
e.getMessage());
return false;
@@ -4,9 +4,9 @@
* 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.
@@ -37,7 +37,7 @@ import ghidra.util.task.TaskMonitor;
* the analyzer UI.
*
* <P>This analyzer will call each implementation's
* {@link #doDemangle(String, DemanglerOptions, MessageLog)} method for each symbol.
* {@link #doDemangle(MangledContext, MessageLog)} method for each symbol.
* See the various protected methods of this class for points at which behavior can be overridden.
*
*/
@@ -46,6 +46,8 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
private static final AddressSetView EXTERNAL_SET = new AddressSet(
AddressSpace.EXTERNAL_SPACE.getMinAddress(), AddressSpace.EXTERNAL_SPACE.getMaxAddress());
protected Demangler demangler;
public AbstractDemanglerAnalyzer(String name, String description) {
super(name, description, AnalyzerType.BYTE_ANALYZER);
setPriority(AnalysisPriority.DATA_TYPE_PROPOGATION.before().before().before());
@@ -102,6 +104,23 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
return true;
}
/**
* Creates a mangled context
* @param program the program
* @param options the demangler options
* @param symbol the symbol to demangle
* @return the mangled context
*/
private MangledContext createMangledContext(Program program, DemanglerOptions options,
Symbol symbol) {
Address address = symbol.getAddress();
String mangled = cleanSymbol(address, symbol.getName());
return demangler.createMangledContext(mangled, options, program, address);
}
/**
* Demangles and applies the program's symbols
*/
private int demangleSymbols(Program program, AddressSetView set, int initialCount,
DemanglerOptions options, MessageLog log, TaskMonitor monitor)
throws CancelledException {
@@ -124,10 +143,10 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
}
Address address = symbol.getAddress();
String mangled = cleanSymbol(address, symbol.getName());
DemangledObject demangled = demangle(mangled, address, options, log);
MangledContext mangledContext = createMangledContext(program, options, symbol);
DemangledObject demangled = demangle(mangledContext, log);
if (demangled != null) {
apply(program, address, demangled, options, log, monitor);
apply(mangledContext, demangled, log, monitor);
continue;
}
@@ -141,10 +160,10 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
if (altSym.isPrimary() || skipSymbol(altSym)) {
continue;
}
mangled = cleanSymbol(address, altSym.getName());
demangled = demangle(mangled, address, options, log);
mangledContext = createMangledContext(program, options, altSym);
demangled = demangle(mangledContext, log);
if (demangled != null) {
apply(program, address, demangled, options, log, monitor);
apply(mangledContext, demangled, log, monitor);
break;
}
}
@@ -156,14 +175,13 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
/**
* The implementation-specific demangling callback
*
* @param mangled the mangled string
* @param options the demangler options
* @param mangledContext the demangler context
* @param log the error log
* @return the demangled object; null if demangling was unsuccessful
* @throws DemangledException if there is a problem demangling or building the result
*/
protected abstract DemangledObject doDemangle(String mangled, DemanglerOptions options,
MessageLog log) throws DemangledException;
protected abstract DemangledObject doDemangle(MangledContext mangledContext, MessageLog log)
throws DemangledException;
/**
* Called before each analysis request to ensure that the current options (which may have
@@ -233,21 +251,18 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
}
/**
* This calss's default demangle method. This may be overridden to change how errors are
* This class's default demangle method. This may be overridden to change how errors are
* handled.
*
* @param mangled the mangled string
* @param address the symbol address
* @param options the demangler options
* @param mangledContext the mangled context
* @param log the error log
* @return the demangled object; null if unsuccessful
*/
protected DemangledObject demangle(String mangled, Address address, DemanglerOptions options,
MessageLog log) {
protected DemangledObject demangle(MangledContext mangledContext, MessageLog log) {
DemangledObject demangled = null;
try {
demangled = doDemangle(mangled, options, log);
demangled = doDemangle(mangledContext, log);
}
catch (Throwable e) {
@@ -258,8 +273,8 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
}
}
log.appendMsg(getName(), "Unable to demangle symbol: " + mangled + " at " + address +
". Message: " + e.getMessage());
log.appendMsg(getName(), "Unable to demangle symbol: " + mangledContext.getMangled() +
" at " + mangledContext.getAddress() + ". Message: " + e.getMessage());
return null;
}
@@ -269,24 +284,24 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
/**
* Applies the given demangled object to the program
*
* @param program the program
* @param address the apply address
* @param mangledContext the mangled context
* @param demangled the demangled object
* @param options the options used during the apply
* @param log the error log
* @param monitor the task monitor
*/
protected void apply(Program program, Address address, DemangledObject demangled,
DemanglerOptions options, MessageLog log, TaskMonitor monitor) {
protected void apply(MangledContext mangledContext, DemangledObject demangled, MessageLog log,
TaskMonitor monitor) {
try {
if (demangled.applyTo(program, address, options, monitor)) {
if (demangled.applyTo(mangledContext.getProgram(), mangledContext.getAddress(),
mangledContext.getOptions(), monitor)) {
return;
}
String errorString = demangled.getErrorMessage();
logApplyErrorMessage(log, demangled, address, null, errorString);
logApplyErrorMessage(log, demangled, mangledContext.getAddress(), null,
errorString);
}
catch (Exception e) {
logApplyErrorMessage(log, demangled, address, e, null);
logApplyErrorMessage(log, demangled, mangledContext.getAddress(), e, null);
}
}
@@ -4,9 +4,9 @@
* 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.
@@ -25,7 +25,6 @@ import ghidra.app.services.AnalysisPriority;
import ghidra.app.util.demangler.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
import ghidra.util.SystemUtilities;
@@ -64,10 +63,9 @@ public class RustDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
private RustDemanglerFormat demanglerFormat = RustDemanglerFormat.AUTO;
private boolean useDeprecatedDemangler = false;
private RustDemangler demangler = new RustDemangler();
public RustDemanglerAnalyzer() {
super(NAME, DESCRIPTION);
demangler = new RustDemangler();
// Set priority to one before the default AbstractDemanglerAnalyzer priority
setPriority(AnalysisPriority.DATA_TYPE_PROPOGATION.before().before().before().before());
setDefaultEnablement(true);
@@ -121,17 +119,18 @@ public class RustDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
}
@Override
protected DemangledObject doDemangle(String mangled, DemanglerOptions demanglerOptions,
MessageLog log) throws DemangledException {
return demangler.demangle(mangled, demanglerOptions);
protected DemangledObject doDemangle(MangledContext mangledContext, MessageLog log)
throws DemangledException {
return demangler.demangle(mangledContext);
}
@Override
protected void apply(Program program, Address address, DemangledObject demangled,
DemanglerOptions options, MessageLog log, TaskMonitor monitor) {
protected void apply(MangledContext mangledContext, DemangledObject demangled, MessageLog log,
TaskMonitor monitor) {
try {
if (demangled instanceof DemangledFunction defunc) {
defunc.applyTo(program, address, options, monitor);
defunc.applyTo(mangledContext.getProgram(), mangledContext.getAddress(),
mangledContext.getOptions(), monitor);
}
}
catch (Exception e) {
@@ -148,7 +147,7 @@ public class RustDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
DemangledVariable demangledVariable = new DemangledVariable(mangled, original, name);
demangledVariable.setNamespace(namespace);
super.apply(program, address, demangledVariable, options, log, monitor);
super.apply(mangledContext, demangledVariable, log, monitor);
}
//==================================================================================================
@@ -4,9 +4,9 @@
* 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.
@@ -40,16 +40,18 @@ public class RustDemangler implements Demangler {
}
@Override
@Deprecated(since = "9.2", forRemoval = true)
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
throws DemangledException {
return null;
@Deprecated(since = "11.3", forRemoval = true)
public DemangledObject demangle(String mangled, DemanglerOptions options) {
MangledContext mangledContext = createMangledContext(mangled, options, null, null);
return demangle(mangledContext);
}
@Override
public DemangledObject demangle(String mangled, DemanglerOptions options) {
public DemangledObject demangle(MangledContext context) {
DemanglerOptions options = context.getOptions();
RustDemanglerOptions rustOptions = getRustOptions(options);
String mangled = context.getMangled();
if (skip(mangled, rustOptions)) {
return null;
}
@@ -74,6 +76,7 @@ public class RustDemangler implements Demangler {
demangledFunction.setCallingConvention(CompilerSpec.CALLING_CONVENTION_rustcall);
}
demangledObject.setMangledContext(context);
return demangledObject;
}
@@ -88,7 +91,7 @@ public class RustDemangler implements Demangler {
/**
* Determines if the given mangled string should not be demangled, on the basis
* of if it has a known start pattern
*
*
* @param mangled the mangled string
* @param options the options
* @return true if the string should not be demangled
@@ -106,7 +109,7 @@ public class RustDemangler implements Demangler {
/**
* Return true if the string is a mangled rust string in a rust program
*
*
* @param mangled potential mangled string
* @return true if the string could be a mangled string in a rust program
*/
@@ -4,9 +4,9 @@
* 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.
@@ -17,8 +17,8 @@ package ghidra.app.util.demangler;
/**
* A unifying top-level interface for all {@link DemangledObject}s and {@link DemangledType}s
*
* <p>This class and its children have many overlapping concepts that we wish to refine at a
*
* <p>This class and its children have many overlapping concepts that we wish to refine at a
* future date. Below is a listing of known uses:
* <TABLE>
* <TR>
@@ -26,6 +26,22 @@ package ghidra.app.util.demangler;
* </TR>
* <TR>
* <TD>
* {@link #setMangledContext(MangledContext)}
* </TD>
* <TD>
* Sets the mangled context in use since version 11.3.
* </TD>
* </TR>
* <TR>
* <TD>
* {@link #getMangledContext()}
* </TD>
* <TD>
* The mangled context in use since version 11.3.
* </TD>
* </TR>
* <TR>
* <TD>
* {@link #getName()}
* </TD>
* <TD>
@@ -38,7 +54,7 @@ package ghidra.app.util.demangler;
* {@link #getDemangledName()}
* </TD>
* <TD>
* The unmodified <b>name</b> that was set upon this object.
* The unmodified <b>name</b> that was set upon this object.
* </TD>
* </TR>
* <TR>
@@ -46,7 +62,7 @@ package ghidra.app.util.demangler;
* {@link #getNamespaceName()}
* </TD>
* <TD>
* The 'safe' name of this object when it is used as a namespace name. This usually has
* The 'safe' name of this object when it is used as a namespace name. This usually has
* parameter and template information. Further, some characters within templates and
* function signatures are replaced, such as spaces and namespace separators.
* <P>
@@ -59,9 +75,9 @@ package ghidra.app.util.demangler;
* {@link #getNamespaceString()}
* </TD>
* <TD>
* This returns the unmodified name of this item, along with any unmodified parent
* namespace names, all separated by a namespace delimiter. Unlike
* {@link #getNamespaceName()}, the spaces and internal namespace tokens will not be
* This returns the unmodified name of this item, along with any unmodified parent
* namespace names, all separated by a namespace delimiter. Unlike
* {@link #getNamespaceName()}, the spaces and internal namespace tokens will not be
* replaced.
* <P>
* Given this full demangled string: {@code Foo::Bar::Baz<int>}, this method will return
@@ -73,8 +89,8 @@ package ghidra.app.util.demangler;
* {@link #getSignature()}
* </TD>
* <TD>
* Returns the complete string form of this object, with most known attributes. For
* functions, this will be a complete signature.
* Returns the complete string form of this object, with most known attributes. For
* functions, this will be a complete signature.
* </TD>
* </TR>
* <TR>
@@ -90,6 +106,35 @@ package ghidra.app.util.demangler;
*/
public interface Demangled {
/**
* Sets the mangled context
* <p>
* This method currently has a {@code default} implementation so not to break existing
* class implementations. However, at some point the {@code default} tag and implementation,
* which is empty, will be removed. Thus, all implementers need to implement this method
* before the removal of the {@code default}
* @param mangledContextArg the mangled context
* @since 11.3
*/
public default void setMangledContext(MangledContext mangledContextArg) {
// currently this does nothing; implementers must override this even though marked as
// default... the default implementation will be removed in a future release
}
/**
* Returns the mangled context
* <p>
* This method currently has a {@code default} implementation so not to break existing
* class implementations. However, at some point the {@code default} tag and implementation,
* which returns null, will be removed. Thus, all implementers need to implement this method
* before the removal of the {@code default}
* @return the context or null if no context
* @since 11.3
*/
public default MangledContext getMangledContext() {
return null;
}
/**
* Returns the original mangled string
* @return the string
@@ -102,7 +147,7 @@ public interface Demangled {
*/
public String getOriginalDemangled();
/**
/**
* Returns the demangled name of this object.
* NOTE: unsupported symbol characters, like whitespace, will be converted to an underscore.
* @return name of this DemangledObject with unsupported characters converted to underscore
@@ -116,9 +161,9 @@ public interface Demangled {
*/
public void setName(String name);
/**
* Returns the unmodified demangled name of this object. This name may contain whitespace
* and other characters not supported for symbol or data type creation. See {@link #getName()}
/**
* Returns the unmodified demangled name of this object. This name may contain whitespace
* and other characters not supported for symbol or data type creation. See {@link #getName()}
* for the same name modified for use within Ghidra.
* @return name of this DemangledObject
*/
@@ -137,7 +182,7 @@ public interface Demangled {
public void setNamespace(Demangled ns);
/**
* Returns a representation of this object as fully-qualified namespace. The
* Returns a representation of this object as fully-qualified namespace. The
* value returned here may have had some special characters replaced, such as ' ' replaced
* with '_' and '::' replaced with '--'.
* @return the full namespace
@@ -145,17 +190,17 @@ public interface Demangled {
public String getNamespaceString();
/**
* Returns this object's namespace name without the fully-qualified parent path. The
* Returns this object's namespace name without the fully-qualified parent path. The
* value returned here may have had some special characters replaced, such as ' ' replaced
* with '_' and '::' replaced with '--'.
*
*
* @return the name
*/
public String getNamespaceName();
/**
* Generates a complete representation of this object to include all know attributes of this
* object
* object
* @return the signature
*/
public String getSignature();
@@ -44,37 +44,38 @@ public abstract class DemangledObject implements Demangled {
/*
The following names probably need to be refactored. Until then, this is how the following
fields are used.
mangled -
Source: The original mangled string as seen in the program
Usage: Can be used to see if a program symbol has already been demangled
originalDemangled -
Source: The raw demangled string returned from the demangler
Usage: for display
demangledName -
Source: The name as created by the parser which may transform or even replace the
string returned from the demangler
Usage: for display
name -
Source: This is derived from the 'demangledName' This is updated to be suitable
for use as a symbol name. This may be null while building, but is
expected to be non-null when applyTo() is called
Usage: The name that will be applied when applyTo() is called.
Future: These variables should be refactored and renamed to be clearer and more cohesive,
something like:
mangled
rawDemangled
escapedDemangled
symbolName
*/
protected MangledContext mangledContext; // the mangled context, which includes mangled string
protected final String mangled; // original mangled string
protected String originalDemangled; // raw demangled string
private String demangledName; // updated demangled string
@@ -110,11 +111,29 @@ public abstract class DemangledObject implements Demangled {
private boolean demangledNameSucceeded = false;
private String errorMessage = null;
/**
* Constructor. This is the older constructor that does not take a mangled context
* @param mangled the mangled string
* @param originalDemangled the raw demangled string; usually what comes from the upstream
* demangler process, if there is one
*/
DemangledObject(String mangled, String originalDemangled) {
this.mangled = mangled;
this.originalDemangled = originalDemangled;
}
/**
* Constructor.
* @param mangledContext the context, which includes the mangled string
* @param originalDemangled the raw demangled string; usually what comes from the upstream
* demangler process, if there is one
*/
DemangledObject(MangledContext mangledContext, String originalDemangled) {
this.mangledContext = mangledContext;
this.mangled = mangledContext.getMangled();
this.originalDemangled = originalDemangled;
}
@Override
public String getDemangledName() {
return demangledName;
@@ -230,6 +249,16 @@ public abstract class DemangledObject implements Demangled {
return demangledNameSucceeded;
}
@Override
public void setMangledContext(MangledContext mangledContextArg) {
mangledContext = mangledContextArg;
}
@Override
public MangledContext getMangledContext() {
return mangledContext;
}
@Override
public String getMangledString() {
return mangled;
@@ -378,7 +407,7 @@ public abstract class DemangledObject implements Demangled {
* Apply this demangled object detail to the specified program.
* <br>
* NOTE: An open Program transaction must be established prior to invoking this method.
*
*
* @param program program to which demangled data should be applied.
* @param address address which corresponds to this demangled object
* @param options options which control how demangled data is applied
@@ -391,6 +420,25 @@ public abstract class DemangledObject implements Demangled {
return applyPlateCommentOnly(program, address);
}
/**
* Apply this demangled object detail to the specified program. This method only works
* if the {@link MangledContext} was set with the appropriate constructor or with the
* {@link #setMangledContext(MangledContext)} method
* <br>
* NOTE: An open Program transaction must be established prior to invoking this method.
*
* @param monitor task monitor
* @return true if successfully applied, else false
* @throws Exception if an error occurs during the apply operation or if the context is null
*/
public boolean applyUsingContext(TaskMonitor monitor) throws Exception {
if (mangledContext == null) {
throw new DemangledException("Null context found for: " + mangled);
}
return applyTo(mangledContext.getProgram(), mangledContext.getAddress(),
mangledContext.getOptions(), monitor);
}
/**
* @param program The program for which to apply the comment
* @param address The address for the comment
@@ -4,9 +4,9 @@
* 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.
@@ -15,6 +15,7 @@
*/
package ghidra.app.util.demangler;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.util.classfinder.ExtensionPoint;
@@ -24,46 +25,53 @@ import ghidra.util.classfinder.ExtensionPoint;
*/
public interface Demangler extends ExtensionPoint {
// Note: Consider deprecating this method and creating one that takes the MangledContext.
// Another option might be to find a smarter utility method that contains the complete
// knowledge of when a particular demangler is appropriate.. but that would have to consider
// demanglers written by others.
public boolean canDemangle(Program program);
/**
* Deprecated. Use {@link #demangle(String)} or
* {@link #demangle(String, DemanglerOptions)}.
* Attempts to demangle the given string using a context
* ({@link #createMangledContext(String, DemanglerOptions, Program, Address)} with
* default options ({@link #createDefaultOptions()}.
*
* @param mangled the mangled string
* @param demangleOnlyKnownPatterns true signals to avoid demangling strings that do
* not fit known demangled patterns for this demangler
* @return the result
* @throws DemangledException if the string cannot be demangled
* @deprecated see above
*/
@Deprecated(since = "9.2", forRemoval = true)
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
throws DemangledException;
/**
* Attempts to demangle the given string using the default options
* ({@link #createDefaultOptions()}
*
* @param mangled the mangled string
* @return the result
* @throws DemangledException if the string cannot be demangled
*/
public default DemangledObject demangle(String mangled) throws DemangledException {
return demangle(mangled, createDefaultOptions());
MangledContext mangledContext = createMangledContext(mangled, null, null, null);
return demangle(mangledContext);
}
/**
* Deprecated. Use {@link #demangle(String)} or
* {@link #demangle(MangledContext)}.
*
* Attempts to demangle the given string using the given options
*
*
* @param mangled the mangled string
* @param options the options
* @return the result
* @throws DemangledException if the string cannot be demangled
* @deprecated see above
*/
@Deprecated(since = "11.3", forRemoval = true)
public DemangledObject demangle(String mangled, DemanglerOptions options)
throws DemangledException;
/**
* Attempts to demangle the string of the mangled context
*
* @param context the mangled context
* @return the result
* @throws DemangledException if the string cannot be demangled
*/
public default DemangledObject demangle(MangledContext context) throws DemangledException {
return demangle(context.getMangled(), context.getOptions());
}
/**
* Creates default options for this particular demangler
* @return the options
@@ -71,4 +79,21 @@ public interface Demangler extends ExtensionPoint {
public default DemanglerOptions createDefaultOptions() {
return new DemanglerOptions();
}
/**
* Creates a mangled context
* @param mangled the mangled name
* @param options the demangler options; if null, the default options are created
* @param program the program; can be null
* @param address the address for the name in the program; can be null
* @return the mangled context
*/
public default MangledContext createMangledContext(String mangled, DemanglerOptions options,
Program program, Address address) {
if (options == null) {
options = createDefaultOptions();
}
return new MangledContext(program, options, mangled, address);
}
}
@@ -4,9 +4,9 @@
* 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.
@@ -15,39 +15,59 @@
*/
package ghidra.app.util.demangler;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.util.classfinder.ClassSearcher;
/**
* Demangler Utility class. For version 11.3, we have migrated to a new Demangler API that
* requires a {@link MangledContext} be passed to the demangler. This provides more information
* for properly demangling symbols.
* <p>
* Two methods below have been deprecated, as they do not provide enough information to produce
* the {@link MangledContext}. A new method @link demangle(Program, String, Address) is provided
* to permit proper operation using a completed context. Moreover, this new method returns all
* results instead of the first one found, as is how the deprecated methods work.
*/
public class DemanglerUtil {
//
// Patterns used to remove superfluous spaces within parameter list.
// Patterns used to remove superfluous spaces within parameter list.
//
private static final Pattern LEADING_PARAMETER_SPACE_PATTERN =
Pattern.compile(" ([\\*\\&\\)])");
private static final Pattern TRAILING_PARAMETER_SPACE_PATTERN = Pattern.compile("([\\(\\,]) ");
/**
* Deprecated. Use {@link #demangle(Program, String, Address)}. See class header for more
* details.
*
* Locates all available demanglers, then it attempts to demangle. This method will
* query all demanglers regardless of architecture.
*
* <p>This method will use only the default options for demangling. If you need to
* query all demanglers regardless of architecture.
*
* <p>This method will use only the default options for demangling. If you need to
* specify options, then you will have to call each specific demangler directly, creating
* the options specifically needed for each demangler. See
* the options and mangled context specifically needed for each demangler. See
* {@link Demangler#createMangledContext(String, DemanglerOptions, Program, Address)} and
* {@link Demangler#createDefaultOptions()}.
*
*
* @param mangled the mangled name
* @return the demangled object or null
* @deprecated see above
*/
@Deprecated(since = "11.3", forRemoval = true)
public static DemangledObject demangle(String mangled) {
List<Demangler> demanglers = getDemanglers();
for (Demangler demangler : demanglers) {
try {
DemangledObject demangledObject = demangler.demangle(mangled);
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, null, null);
DemangledObject demangledObject = demangler.demangle(mangledContext);
if (demangledObject != null) {
return demangledObject;
}
@@ -60,18 +80,24 @@ public class DemanglerUtil {
}
/**
* Locates all available demanglers and checks to see if the supplied program is
* Deprecated. Use {@link #demangle(Program, String, Address)}. See class header for more
* details.
*
* Locates all available demanglers and checks to see if the supplied program is
* supported, then it attempts to demangle.
*
* <p>This method will use only the default options for demangling. If you need to
*
* <p>This method will use only the default options for demangling. If you need to
* specify options, then you will have to call each specific demangler directly, creating
* the options specifically needed for each demangler. See
* the options and mangled context specifically needed for each demangler. See
* {@link Demangler#createMangledContext(String, DemanglerOptions, Program, Address)} and
* {@link Demangler#createDefaultOptions()}.
*
*
* @param program the program containing the mangled name
* @param mangled the mangled name
* @return the demangled object or null
* @deprecated see above
*/
@Deprecated(since = "11.3", forRemoval = true)
public static DemangledObject demangle(Program program, String mangled) {
List<Demangler> demanglers = getDemanglers();
for (Demangler demangler : demanglers) {
@@ -80,7 +106,9 @@ public class DemanglerUtil {
continue;
}
DemangledObject demangledObject = demangler.demangle(mangled);
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, null, null);
DemangledObject demangledObject = demangler.demangle(mangledContext);
if (demangledObject != null) {
return demangledObject;
}
@@ -92,9 +120,48 @@ public class DemanglerUtil {
return null;
}
/**
* Locates all available demanglers and checks to see if the supplied program is
* supported, then it attempts to demangle. Returns a list of {@link DemangledObject} of
* successful demanglings
*
* <p>This method will use only the default options for demangling. If you need to
* specify options, then you will have to call each specific demangler directly, creating
* the options and mangled context specifically needed for each demangler. See
* {@link Demangler#createMangledContext(String, DemanglerOptions, Program, Address)} and
* {@link Demangler#createDefaultOptions()}.
*
* @param program the program containing the mangled name
* @param mangled the mangled name
* @param address the address of the mangled name
* @return the list of {@link DemangledObject}
*/
public static List<DemangledObject> demangle(Program program, String mangled, Address address) {
List<DemangledObject> results = new ArrayList<>();
List<Demangler> demanglers = getDemanglers();
for (Demangler demangler : demanglers) {
try {
if (!demangler.canDemangle(program)) {
continue;
}
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, address);
DemangledObject demangledObject = demangler.demangle(mangledContext);
if (demangledObject != null) {
results.add(demangledObject);
}
}
catch (DemangledException e) {
// ignore
}
}
return results;
}
/**
* Dynamically locates all available demangler implementations.
*
*
* @return a list of all demanglers
*/
private static List<Demangler> getDemanglers() {
@@ -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;
import java.util.Objects;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
/**
* A simple class to contain the context of a mangled symbol for demangling
*/
public class MangledContext {
protected Program program;
protected DemanglerOptions options;
protected String mangled;
protected Address address;
/**
* Constructor for mangled context
* @param program the program; can be null
* @param options the demangler options
* @param mangled the mangled string
* @param address the address; can be null
*/
public MangledContext(Program program, DemanglerOptions options, String mangled,
Address address) {
this.program = program;
this.options = Objects.requireNonNull(options, "Options cannot be null");
this.mangled = Objects.requireNonNull(mangled, "Mangled cannot be null");
this.address = address;
}
/**
* Returns the program
* @return the program; can be null
*/
public Program getProgram() {
return program;
}
/**
* Returns the demangler options
* @return the options
*/
public DemanglerOptions getOptions() {
return options;
}
/**
* Returns the mangled string
* @return the mangled string
*/
public String getMangled() {
return mangled;
}
/**
* Returns the address
* @return the address; can be null
*/
public Address getAddress() {
return address;
}
}
@@ -4,9 +4,9 @@
* 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.
@@ -259,15 +259,21 @@ abstract class AbstractPeDebugLoader extends AbstractOrdinalSupportLoader {
}
private void demangle(Address address, String name, Program program) {
DemangledObject demangledObj = null;
StringBuilder builder = new StringBuilder();
try {
demangledObj = DemanglerUtil.demangle(program, name);
List<DemangledObject> demangledObjects = DemanglerUtil.demangle(program, name, address);
for (DemangledObject demangledObj : demangledObjects) {
if (builder.length() > 0) {
builder.append("\t");
}
builder.append(demangledObj.getSignature(true));
}
}
catch (Exception e) {
//log.appendMsg("Unable to demangle: "+name);
}
if (demangledObj != null) {
setComment(CodeUnit.PLATE_COMMENT, address, demangledObj.getSignature(true));
if (builder.length() > 0) {
setComment(CodeUnit.PLATE_COMMENT, address, builder.toString());
}
}
@@ -426,7 +432,7 @@ abstract class AbstractPeDebugLoader extends AbstractOrdinalSupportLoader {
Symbol newSymbol =
program.getSymbolTable().createLabel(address, sym, SourceType.IMPORTED);
// Force non-section symbols to be primary. We never want section symbols (.text,
// Force non-section symbols to be primary. We never want section symbols (.text,
// .text$func_name) to be primary because we don't want to use them for function names
// or demangling.
if (!sym.equals(section.getName()) && !sym.startsWith(section.getName() + "$")) {
@@ -4,9 +4,9 @@
* 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.
@@ -21,6 +21,7 @@
//@category Examples.Demangler
import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledObject;
import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.gnu.*;
import ghidra.program.model.symbol.Symbol;
@@ -56,7 +57,9 @@ public class DemangleElfWithOptionScript extends GhidraScript {
options = options.withDemanglerFormat(GnuDemanglerFormat.ARM, true);
*/
DemangledObject demangledObject = demangler.demangle(mangled, options);
MangledContext mangledContext =
demangler.createMangledContext(mangled, options, currentProgram, currentAddress);
DemangledObject demangledObject = demangler.demangle(mangledContext);
if (demangledObject == null) {
println("Could not demangle: " + mangled);
return;
@@ -4,9 +4,9 @@
* 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.
@@ -53,6 +53,7 @@ import java.util.List;
import ghidra.app.cmd.label.DemanglerCmd;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.program.model.address.Address;
import ghidra.program.model.mem.Memory;
@@ -143,7 +144,9 @@ public class VxWorksSymTab_5_4 extends GhidraScript {
String symDemangledName = null;
try {
// if successful, symDemangledName will be non-NULL
symDemangledName = demangler.demangle(symName).getSignature(false);
MangledContext mangledContext = demangler.createMangledContext(symDemangledName,
null, currentProgram, symNameAddr);
symDemangledName = demangler.demangle(mangledContext).getSignature(false);
}
catch (DemangledException e) {
// if symName wasn't a mangled name, silently continue
@@ -4,9 +4,9 @@
* 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.
@@ -51,6 +51,7 @@ import java.util.List;
import ghidra.app.cmd.label.DemanglerCmd;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.program.model.address.Address;
import ghidra.program.model.mem.Memory;
@@ -139,7 +140,9 @@ public class VxWorksSymTab_6_1 extends GhidraScript {
String symDemangledName = null;
try {
// if successful, symDemangledName will be non-NULL
symDemangledName = demangler.demangle(symName).getSignature(false);
MangledContext mangledContext = demangler.createMangledContext(symDemangledName,
null, currentProgram, symNameAddr);
symDemangledName = demangler.demangle(mangledContext).getSignature(false);
}
catch (DemangledException e) {
// if symName wasn't a mangled name, silently continue
@@ -4,9 +4,9 @@
* 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.
@@ -49,6 +49,7 @@ import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.script.GhidraScript;
import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
@@ -604,7 +605,7 @@ public class VxWorksSymTab_Finder extends GhidraScript {
/**
* Look before/after the table to see if there is a size value there and mark it if it agrees with TableLen
*
*
* @param symTbl
* @param vxSymbol
* @param tableLen
@@ -784,7 +785,9 @@ public class VxWorksSymTab_Finder extends GhidraScript {
// Demangle symName
String symDemangledName = null;
try {
symDemangledName = demangler.demangle(symName).getSignature(false);
MangledContext mangledContext =
demangler.createMangledContext(symName, null, currentProgram, symNameAddr);
symDemangledName = demangler.demangle(mangledContext).getSignature(false);
}
catch (DemangledException e) { // report demangling error
if (!e.isInvalidMangledName()) {
@@ -73,10 +73,9 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
private GnuDemanglerFormat demanglerFormat = GnuDemanglerFormat.AUTO;
private boolean useDeprecatedDemangler = false;
private GnuDemangler demangler = new GnuDemangler();
public GnuDemanglerAnalyzer() {
super(NAME, DESCRIPTION);
demangler = new GnuDemangler();
setDefaultEnablement(true);
}
@@ -142,9 +141,9 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
}
@Override
protected DemangledObject doDemangle(String mangled, DemanglerOptions demanglerOtions,
MessageLog log) throws DemangledException {
return demangler.demangle(mangled, demanglerOtions);
protected DemangledObject doDemangle(MangledContext mangledContext, MessageLog log)
throws DemangledException {
return demangler.demangle(mangledContext);
}
//==================================================================================================
@@ -66,19 +66,27 @@ public class GnuDemangler implements Demangler {
}
@Override
@Deprecated(since = "9.2", forRemoval = true)
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
@Deprecated(since = "11.3", forRemoval = true)
public DemangledObject demangle(String mangled, DemanglerOptions demanglerOptions)
throws DemangledException {
GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
return demangle(mangled, options);
MangledContext mangledContext = createMangledContext(mangled, demanglerOptions, null, null);
return demangle(mangledContext);
}
@Override
public DemangledObject demangle(String mangled, DemanglerOptions demanglerOtions)
public DemangledObject demangle(MangledContext mangledContext)
throws DemangledException {
DemangledObject demangled = demangleInternal(mangledContext);
demangled.setMangledContext(mangledContext);
return demangled;
}
private DemangledObject demangleInternal(MangledContext mangledContext)
throws DemangledException {
GnuDemanglerOptions options = getGnuOptions(demanglerOtions);
DemanglerOptions demanglerOptions = mangledContext.getOptions();
String mangled = mangledContext.getMangled();
GnuDemanglerOptions options = getGnuOptions(demanglerOptions);
if (skip(mangled, options)) {
return null;
}
@@ -4,9 +4,9 @@
* 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.
@@ -22,6 +22,6 @@ apply plugin: 'eclipse'
eclipse.project.name = 'Features MicrosoftCodeAnalyzer'
dependencies {
api project(":MicrosoftDmang")
api project(":MicrosoftDemangler")
api project(":Base")
}
@@ -4,9 +4,9 @@
* 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.
@@ -19,6 +19,7 @@ import ghidra.app.cmd.data.rtti.RttiUtil;
import ghidra.app.util.datatype.microsoft.DataValidationOptions;
import ghidra.app.util.datatype.microsoft.MSDataTypeUtils;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.microsoft.MicrosoftDemangler;
import ghidra.docking.settings.SettingsImpl;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
@@ -33,8 +34,6 @@ import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import mdemangler.MDException;
import mdemangler.MDMangGhidra;
/**
* Model for the TypeDescriptor data type.
@@ -446,7 +445,8 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
Object value = terminatedStringDt.getValue(nameMemBuffer, SettingsImpl.NO_SETTINGS, 1);
if (value instanceof String) {
originalTypeName = (String) value;
demangledDataType = getDemangledDataType(originalTypeName); // Can be null
// The returned demangledDataType an be null
demangledDataType = getDemangledDataType(originalTypeName, program, nameAddress);
}
hasProcessedName = true;
return originalTypeName;
@@ -597,20 +597,22 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
/**
* Gets a DemangledDataType for the indicated mangled string
* @param mangledString the mangled string to be demangled
* @param program the program
* @param address address of the mangled string
* @return the DemangledDataType or null if couldn't demangle or is not a class type
*/
private static DemangledDataType getDemangledDataType(String mangledString) {
MDMangGhidra demangler = new MDMangGhidra();
private static DemangledDataType getDemangledDataType(String mangledString, Program program,
Address address) {
MicrosoftDemangler demangler = new MicrosoftDemangler();
try {
// Note that we could play with the return value, but it is not needed; instead, we
// get the DemangledDataType by calling the appropriate method
demangler.demangleType(mangledString, true);
DemangledDataType demangledType = demangler.getDataType();
MangledContext mangledContext =
demangler.createMangledContext(mangledString, null, program, address);
DemangledDataType demangledType = demangler.demangleType(mangledContext);
if (isPermittedType(demangledType)) {
return demangledType;
}
}
catch (MDException e) {
catch (DemangledException e) {
// Couldn't demangle.
}
return null;
@@ -4,9 +4,9 @@
* 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.
@@ -17,6 +17,7 @@
//@category Symbol
import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledObject;
import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.microsoft.MicrosoftDemangler;
public class MicrosoftDemanglerScript extends GhidraScript {
@@ -33,7 +34,7 @@ public class MicrosoftDemanglerScript extends GhidraScript {
demangle("??$?0G@?$allocator@U_Container_proxy@std@@@std@@QAE@ABV?$allocator@G@1@@Z");
/*
demangle("??0__non_rtti_object@@QAE@PBD@Z");
demangle("??0bad_cast@@AAE@PBQBD@Z");
demangle("??0bad_cast@@QAE@ABQBD@Z");
@@ -94,7 +95,11 @@ public class MicrosoftDemanglerScript extends GhidraScript {
}
private void demangle(String mangled) throws Exception {
DemangledObject demangled = demangler.demangle(mangled);
printf("magled %s\ndemangled %s", mangled, demangled);
// Using a null address instead of currentAddress because we are not demangling a symbol
// at the address... just a symbol to dump to the output
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, currentProgram, null);
DemangledObject demangled = demangler.demangle(mangledContext);
printf("mangled %s\ndemangled %s", mangled, demangled);
}
}
@@ -4,9 +4,9 @@
* 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.
@@ -16,10 +16,11 @@
package ghidra.app.plugin.core.analysis;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.microsoft.MicrosoftDemangler;
import ghidra.app.util.demangler.microsoft.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
/**
* A version of the demangler analyzer to handle microsoft symbols
@@ -40,12 +41,26 @@ public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
private static final String OPTION_DESCRIPTION_APPLY_CALLING_CONVENTION =
"Apply any recovered function signature calling convention";
private static final String OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS =
"Demangle Only Known Mangled Symbols";
private static final String OPTION_DESCRIPTION_USE_KNOWN_PATTERNS =
"Only demangle symbols that follow known compiler mangling patterns. " +
"Leaving this option off may cause non-mangled symbols to get demangled.";
public static final String OPTION_NAME_MS_C_INTERPRETATION =
"C-Style Symbol Interpretation";
private static final String OPTION_DESCRIPTION_MS_C_INTERPRETATION =
"When ambiguous, treat C-Style mangled symbol as: function, variable," +
" or function if a function exists";
private boolean applyFunctionSignature = true;
private boolean applyCallingConvention = true;
private MicrosoftDemangler demangler = new MicrosoftDemangler();
private boolean demangleOnlyKnownPatterns = false;
private MsCInterpretation interpretation = MsCInterpretation.FUNCTION_IF_EXISTS;
public MicrosoftDemanglerAnalyzer() {
super(NAME, DESCRIPTION);
demangler = new MicrosoftDemangler();
setDefaultEnablement(true);
}
@@ -56,11 +71,20 @@ public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
@Override
public void registerOptions(Options options, Program program) {
options.registerOption(OPTION_NAME_APPLY_SIGNATURE, applyFunctionSignature, null,
HelpLocation help = new HelpLocation("AutoAnalysisPlugin", "Demangler_Analyzer");
options.registerOption(OPTION_NAME_APPLY_SIGNATURE, applyFunctionSignature, help,
OPTION_DESCRIPTION_APPLY_SIGNATURE);
options.registerOption(OPTION_NAME_APPLY_CALLING_CONVENTION, applyCallingConvention, null,
options.registerOption(OPTION_NAME_APPLY_CALLING_CONVENTION, applyCallingConvention, help,
OPTION_DESCRIPTION_APPLY_CALLING_CONVENTION);
options.registerOption(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns,
help, OPTION_DESCRIPTION_USE_KNOWN_PATTERNS);
options.registerOption(OPTION_NAME_MS_C_INTERPRETATION, interpretation, help,
OPTION_DESCRIPTION_MS_C_INTERPRETATION);
}
@Override
@@ -70,20 +94,28 @@ public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
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
protected DemanglerOptions getOptions() {
DemanglerOptions options = new DemanglerOptions();
MicrosoftDemanglerOptions options = new MicrosoftDemanglerOptions();
options.setApplySignature(applyFunctionSignature);
options.setApplyCallingConvention(applyCallingConvention);
options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
options.setInterpretation(interpretation);
options.setErrorOnRemainingChars(true);
return options;
}
@Override
protected DemangledObject doDemangle(String mangled, DemanglerOptions options, MessageLog log)
protected DemangledObject doDemangle(MangledContext context, MessageLog log)
throws DemangledException {
DemangledObject demangled = demangler.demangle(mangled, options);
DemangledObject demangled = demangler.demangle(context);
return demangled;
}
}
@@ -4,9 +4,9 @@
* 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.
@@ -18,18 +18,29 @@ package ghidra.app.util.demangler.microsoft;
import ghidra.app.util.demangler.*;
import ghidra.app.util.opinion.MSCoffLoader;
import ghidra.app.util.opinion.PeLoader;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import mdemangler.MDException;
import mdemangler.MDMangGhidra;
import mdemangler.*;
import mdemangler.datatype.MDDataType;
/**
* A class for demangling debug symbols created using Microsoft Visual Studio.
*/
public class MicrosoftDemangler implements Demangler {
private MDMangGhidra demangler;
private MDParsableItem item;
private DemangledObject object;
private MDDataType mdType;
private DemangledDataType dataType;
public MicrosoftDemangler() {
}
// Note: Consider deprecating this method and creating one that takes the MangledContext.
// Another option might be to find a smarter, utility method that contains the complete
// knowledge of when a particular demangler is appropriate.. but that would have to consider
// demanglers written by others.
@Override
public boolean canDemangle(Program program) {
String executableFormat = program.getExecutableFormat();
@@ -38,47 +49,128 @@ public class MicrosoftDemangler implements Demangler {
}
@Override
@Deprecated(since = "9.2", forRemoval = true)
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
@Deprecated(since = "11.3", forRemoval = true)
public DemangledObject demangle(String mangled, DemanglerOptions options)
throws DemangledException {
try {
DemangledObject demangled = demangleMS(mangled, demangleOnlyKnownPatterns);
return demangled;
}
catch (DemangledException e) {
throw new DemangledException(true);
}
MangledContext mangledContext = new MangledContext(null, options, mangled, null);
return demangle(mangledContext);
}
@Override
public DemangledObject demangle(String mangled, DemanglerOptions options)
throws DemangledException {
public DemangledObject demangle(MangledContext context) throws DemangledException {
if (!(context instanceof MicrosoftMangledContext mContext)) {
throw new DemangledException("Wrong context type");
}
if (!(context.getOptions() instanceof MicrosoftDemanglerOptions options)) {
throw new DemangledException("MicrosoftDemanglerOptions expected");
}
String mangled = context.getMangled();
demangler = new MDMangGhidra();
demangler.setMangledSymbol(mangled);
demangler.setErrorOnRemainingChars(options.errorOnRemainingChars());
demangler.setDemangleOnlyKnownPatterns(options.demangleOnlyKnownPatterns());
demangler.setArchitectureSize(mContext.getArchitectureSize());
demangler.setIsFunction(mContext.shouldInterpretAsFunction());
try {
DemangledObject demangled = demangleMS(mangled, options.demangleOnlyKnownPatterns());
return demangled;
}
catch (DemangledException e) {
throw new DemangledException(true);
}
}
private DemangledObject demangleMS(String mangled, boolean demangleOnlyKnownPatterns)
throws DemangledException {
if (mangled == null || mangled.length() == 0) {
throw new DemangledException(true);
}
MDMangGhidra demangler = new MDMangGhidra();
try {
demangler.demangle(mangled, true, demangleOnlyKnownPatterns);
DemangledObject object = demangler.getObject();
item = demangler.demangle();
object = MicrosoftDemanglerUtil.convertToDemangledObject(item, mangled);
if (object != null) {
object.setMangledContext(context);
}
return object;
}
catch (MDException e) {
DemangledException de = new DemangledException("Unable to demangle symbol: " + mangled);
DemangledException de = new DemangledException(true);
de.initCause(e);
throw de;
}
}
/**
* Attempts to demangle the type string of the mangled context into a type
*
* @param context the mangled context
* @return the result
* @throws DemangledException if the string cannot be demangled
*/
public DemangledDataType demangleType(MangledContext context) throws DemangledException {
if (!(context instanceof MicrosoftMangledContext mContext)) {
throw new DemangledException("Wrong context type");
}
if (!(context.getOptions() instanceof MicrosoftDemanglerOptions options)) {
throw new DemangledException("MicrosoftDemanglerOptions expected");
}
String mangled = context.getMangled();
demangler = new MDMangGhidra();
demangler.setMangledSymbol(mangled);
demangler.setErrorOnRemainingChars(options.errorOnRemainingChars());
demangler.setDemangleOnlyKnownPatterns(options.demangleOnlyKnownPatterns());
demangler.setArchitectureSize(mContext.getArchitectureSize());
demangler.setIsFunction(mContext.shouldInterpretAsFunction());
try {
mdType = demangler.demangleType();
dataType = MicrosoftDemanglerUtil.convertToDemangledDataType(mdType, mangled);
if (dataType != null) {
dataType.setMangledContext(context);
}
return dataType;
}
catch (MDException e) {
DemangledException de = new DemangledException(true);
de.initCause(e);
throw de;
}
}
/**
* Returns the {@link MDParsableItem} used in demangling to a {@link DemangledObject}
* @return the item; can be null if item wasn't demangled
*/
public MDParsableItem getMdItem() {
return item;
}
/**
* Returns the {@link MDDataType} used in demangling to a @link DemangledDataType}
* @return the type; can be null if type wasn't demangled
*/
public MDDataType getMdType() {
return mdType;
}
/**
* Creates default options for microsoft demangler
* @return the options
*/
@Override
public MicrosoftDemanglerOptions createDefaultOptions() {
return new MicrosoftDemanglerOptions();
}
/**
* Creates a microsoft mangled context
* @param mangled the mangled name
* @param options the demangler options; if null, the default options are created
* @param program the program; can be null
* @param address the address for the name in the program; can be null
* @return the mangled context
*/
@Override
public MicrosoftMangledContext createMangledContext(String mangled, DemanglerOptions options,
Program program, Address address) {
return new MicrosoftMangledContext(program, getMicrosoftOptions(options), mangled, address);
}
private MicrosoftDemanglerOptions getMicrosoftOptions(DemanglerOptions options) {
if (options instanceof MicrosoftDemanglerOptions mOptions) {
return mOptions;
}
if (options == null) {
return createDefaultOptions();
}
return new MicrosoftDemanglerOptions(options);
}
}
@@ -0,0 +1,109 @@
/* ###
* 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;
import ghidra.app.util.demangler.DemanglerOptions;
/**
* Microsoft demangler options
*/
public class MicrosoftDemanglerOptions extends DemanglerOptions {
private boolean errorOnRemainingChars;
private MsCInterpretation interpretation;
/**
* Default constructor for 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();
this.errorOnRemainingChars = errorOnRemainingChars;
}
/**
* Copy constructor to create a version of this class from a more generic set of options
* @param copy the options to copy
*/
public MicrosoftDemanglerOptions(DemanglerOptions copy) {
super(copy);
if (copy instanceof MicrosoftDemanglerOptions mCopy) {
errorOnRemainingChars = mCopy.errorOnRemainingChars;
interpretation = mCopy.interpretation;
}
else {
errorOnRemainingChars = true;
interpretation = MsCInterpretation.FUNCTION_IF_EXISTS;
}
}
/**
* Sets the control for erroring on remaining characters at demangler completion
* @param errorOnRemainingCharsArg {@code true} to error when remaining characters exist
*/
public void setErrorOnRemainingChars(boolean errorOnRemainingCharsArg) {
errorOnRemainingChars = errorOnRemainingCharsArg;
}
/**
* Returns {@code true} if the process will error when remaining characters exist at the end
* of processing
* @return {@code true} if will error
*/
public boolean errorOnRemainingChars() {
return errorOnRemainingChars;
}
/**
* 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 String toString() {
//@formatter:off
return "{\n" +
"\tdoDisassembly: " + doDisassembly() + ",\n" +
"\tapplySignature: " + applySignature() + ",\n" +
"\terrorOnRemainingChars: " + errorOnRemainingChars + ",\n" +
"\tinterpretation: " + interpretation + ",\n" +
"\tdemangleOnlyKnownPatterns: " + demangleOnlyKnownPatterns() + ",\n" +
"}";
//@formatter:on
}
}
@@ -0,0 +1,77 @@
/* ###
* 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;
import ghidra.app.util.demangler.MangledContext;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
/**
* A simple class to contain the context of a mangled symbol for demangling
*/
public class MicrosoftMangledContext extends MangledContext {
/**
* Constructor for mangled context
* @param program the program; can be null
* @param options the demangler options
* @param mangled the mangled string
* @param address the address; can be null
*/
public MicrosoftMangledContext(Program program, MicrosoftDemanglerOptions options,
String mangled, Address address) {
super(program, options, mangled, address);
}
/**
* Returns the program architecture size
* @return the architecture size or zero if not known (program is null)
*/
public int getArchitectureSize() {
if (program == null) {
return 0;
}
return program.getAddressFactory().getDefaultAddressSpace().getSize();
}
/**
* Returns whether the symbol should be interpreted as a function
* @return {@code true} if should be interpreted as a function
*/
boolean shouldInterpretAsFunction() {
MsCInterpretation control =
((MicrosoftDemanglerOptions) options).getInterpretation();
return switch (control) {
case FUNCTION -> true;
case NON_FUNCTION -> false;
case FUNCTION_IF_EXISTS -> getExistingFunction() != null;
default -> throw new AssertionError("Invalid case");
};
}
/**
* Returns the function at the context address
* @return the function or null if program or address is null
*/
private Function getExistingFunction() {
if (program == null || address == null) {
return null;
}
return program.getFunctionManager().getFunctionAt(address);
}
}
@@ -0,0 +1,37 @@
/* ###
* 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;
/**
* Class to control whether a symbol should be demangled as a function symbols or a some other
* (e.g., variable) symbol
*/
public enum MsCInterpretation {
/**
* Forces processing as a function symbol if there are multiple symbol interpretations
*/
FUNCTION,
/**
* Forces processing as a non-function (e.g., variable) if there are multiple symbol
* interpretations
*/
NON_FUNCTION,
/**
* If there are multiple symbol interpretations, forces processing as a function only if
* there is already a function at the address
*/
FUNCTION_IF_EXISTS
}
@@ -0,0 +1,428 @@
/* ###
* 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;
import static org.junit.Assert.*;
import org.junit.*;
import generic.test.AbstractGenericTest;
import ghidra.app.util.demangler.*;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.VoidDataType;
import mdemangler.MDMangBaseTest;
import mdemangler.object.MDObjectC;
/**
* This class performs extra demangler testing for special cases that do not fit
* the testing pattern found in {@link MDMangBaseTest} and {@link MicrosoftDemanglerTest}
*/
public class MicrosoftDemanglerExtraTest extends AbstractGenericTest {
ProgramBuilder builder32;
ProgramBuilder builder64;
private ProgramDB program32;
private ProgramDB program64;
private Address address32;
private Address functionAddress32;
private Address address64;
private Address functionAddress64;
@Before
public void setUp() throws Exception {
String blockAddress = "0x01001000";
String nonFunctionAddress = "0x01001000";
String functionAddress = "0x01001010";
builder32 = new ProgramBuilder("test32", "x86:LE:32:default");
builder32.createMemory(".text", blockAddress, 0x100);
builder32.createEmptyFunction("function", functionAddress, 1, VoidDataType.dataType);
program32 = builder32.getProgram();
address32 = program32.getAddressFactory().getAddress(nonFunctionAddress);
functionAddress32 = program32.getAddressFactory().getAddress(functionAddress);
builder64 = new ProgramBuilder("test64", "x86:LE:64:default");
builder64.createMemory(".text", blockAddress, 0x100);
builder64.createEmptyFunction("function", functionAddress, 1, VoidDataType.dataType);
program64 = builder64.getProgram();
address64 = program64.getAddressFactory().getAddress(nonFunctionAddress);
functionAddress64 = program64.getAddressFactory().getAddress(functionAddress);
}
@After
public void tearDown() throws Exception {
builder32.dispose();
builder64.dispose();
}
//==============================================================================================
// Helpers
private void processWith32Function(String mangled, String expectDemangled,
String expectedFunction, String expectedConvention, int expectedNumBytes)
throws DemangledException {
MicrosoftDemangler demangler = new MicrosoftDemangler();
MicrosoftMangledContext context =
demangler.createMangledContext(mangled, null, program32, functionAddress32);
// We do not need to do this here: options.setErrorOnRemainingChars(false);
// Testing Demangled hierarchy
DemangledFunction demangledFunction = (DemangledFunction) demangler.demangle(context);
assertEquals(expectedFunction,
demangledFunction == null ? null : demangledFunction.toString());
// Testing MDMang hierarchy
MDObjectC objc = (MDObjectC) demangler.getMdItem();
String convention = objc.getCallingConvention();
int numParameterBytes = objc.getNumParameterBytes();
assertEquals(expectedConvention, convention);
assertEquals(expectedNumBytes, numParameterBytes);
assertEquals(expectDemangled, objc.toString());
}
private void processWith32NonFunction(String mangled, String expectDemangled)
throws DemangledException {
MicrosoftDemangler demangler = new MicrosoftDemangler();
MicrosoftMangledContext context =
demangler.createMangledContext(mangled, null, program32, address32);
MicrosoftDemanglerOptions options = (MicrosoftDemanglerOptions) context.getOptions();
// Important to set to false to standardize our test results to simple expected
// results. When the C-style symbols do not create function results either because
// there is not a function at the address or because of the architecture, we might end
// up with remaining charactes because the demangler sets its index back tot he start.
options.setErrorOnRemainingChars(false);
// Testing Demangled hierarchy
DemangledFunction demangledFunction = (DemangledFunction) demangler.demangle(context);
assertEquals(null, demangledFunction);
// Testing MDMang hierarchy
MDObjectC objc = (MDObjectC) demangler.getMdItem();
String convention = objc.getCallingConvention();
int numParameterBytes = objc.getNumParameterBytes();
assertEquals(null, convention);
assertEquals(0, numParameterBytes);
assertEquals(expectDemangled, objc.toString());
}
private void processWith64Function(String mangled, String expectDemangled,
String expectedFunction, String expectedConvention, int expectedNumBytes)
throws DemangledException {
MicrosoftDemangler demangler = new MicrosoftDemangler();
MicrosoftMangledContext context =
demangler.createMangledContext(mangled, null, program64, functionAddress64);
MicrosoftDemanglerOptions options = (MicrosoftDemanglerOptions) context.getOptions();
// Important to set to false to standardize our test results to simple expected
// results. When the C-style symbols do not create function results either because
// there is not a function at the address or because of the architecture, we might end
// up with remaining charactes because the demangler sets its index back tot he start.
options.setErrorOnRemainingChars(false);
// Testing Demangled hierarchy
DemangledFunction demangledFunction = (DemangledFunction) demangler.demangle(context);
assertEquals(expectedFunction,
demangledFunction == null ? null : demangledFunction.toString());
// Testing MDMang hierarchy
MDObjectC objc = (MDObjectC) demangler.getMdItem();
String convention = objc.getCallingConvention();
int numParameterBytes = objc.getNumParameterBytes();
assertEquals(expectedConvention, convention);
assertEquals(expectedNumBytes, numParameterBytes);
assertEquals(expectDemangled, objc.toString());
}
private void processWith64NonFunction(String mangled, String expectDemangled)
throws DemangledException {
MicrosoftDemangler demangler = new MicrosoftDemangler();
MicrosoftMangledContext context =
demangler.createMangledContext(mangled, null, program64, address64);
MicrosoftDemanglerOptions options = (MicrosoftDemanglerOptions) context.getOptions();
// Important to set to false to standardize our test results to simple expected
// results. When the C-style symbols do not create function results either because
// there is not a function at the address or because of the architecture, we might end
// up with remaining charactes because the demangler sets its index back tot he start.
options.setErrorOnRemainingChars(false);
// Testing Demangled hierarchy
DemangledFunction demangledFunction = (DemangledFunction) demangler.demangle(context);
assertEquals(null, demangledFunction);
// Testing MDMang hierarchy
MDObjectC objc = (MDObjectC) demangler.getMdItem();
String convention = objc.getCallingConvention();
int numParameterBytes = objc.getNumParameterBytes();
assertEquals(null, convention);
assertEquals(0, numParameterBytes);
assertEquals(expectDemangled, objc.toString());
}
//==============================================================================================
@Test
//This test checks that we can provide a mangled string for a function namespace.
// The return String from getOriginalMangled() is not null only for this special
// circumstance. So, in normal processing, we should check it for non-null to
// determine that we have a result of this form.
// The symbol here is from our cn3.cpp source target.
public void testFunctionNamespace() throws Exception {
String mangled = "?fn3@?2??Bar3@Foo2b@@SAHXZ@4HA";
String wholeTruth = "int `public: static int __cdecl Foo2b::Bar3(void)'::`3'::fn3";
String functionNamespaceMangledTruth = "?Bar3@Foo2b@@SAHXZ";
String functionNamespaceTruth = "public: static int __cdecl Foo2b::Bar3(void)";
MicrosoftDemangler demangler = new MicrosoftDemangler();
MicrosoftMangledContext context =
demangler.createMangledContext(mangled, null, program32, address32);
DemangledObject obj = demangler.demangle(context);
String demangled = demangler.getMdItem().toString();
assertEquals(wholeTruth, demangled);
String mangledFunctionNS = obj.getNamespace().getNamespace().getMangledString();
assertEquals(functionNamespaceMangledTruth, mangledFunctionNS);
context = demangler.createMangledContext(mangledFunctionNS, null, program32, address32);
demangler.demangle(context);
demangled = demangler.getMdItem().toString();
assertEquals(functionNamespaceTruth, demangled);
}
//==============================================================================================
/*
* Follow are C-style mangling scheme under 32-bit model; __vectorcall also valid for 64-bit
* __cdecl: '_' prefix; no suffix; example "_name"
* __stdcall: '_' prefix; "@<decimal_digits>" suffix; example "_name@12"
* __fastcall: '@' prefix; "@<decimal_digits>" suffix; example "@name@12"
* __vectorcall: no prefix; "@@<decimal_digits>" suffix; example "name@@12"
*/
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: cdecl; Architecture size: 32; Function present: yes
// Result: cdecl function (stripped '_'); 0 bytes
public void testCStyleCdeclWith32Function() throws Exception {
String mangled = "_func_cdecl";
String expectedDemangled = "func_cdecl";
String expectedFunction = "__cdecl func_cdecl(void)";
String expectedConvention = "__cdecl";
int expectedNumBytes = 0;
processWith32Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: cdecl; Architecture size: 32; Function present: no
// Result: no function; 0 bytes
public void testCStyleCdeclWith32NoFunction() throws Exception {
String mangled = "_func_cdecl";
String expectedDemangled = "_func_cdecl";
processWith32NonFunction(mangled, expectedDemangled);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: cdecl; Architecture size: 64; Function present: yes
// Result: no function; 0 bytes
public void testCStyleCdeclWith64Function() throws Exception {
String mangled = "_func_cdecl";
String expectedDemangled = "_func_cdecl";
String expectedFunction = null;
String expectedConvention = null;
int expectedNumBytes = 0;
processWith64Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: cdecl; Architecture size: 64; Function present: no
// Result: no function; 0 bytes
public void testCStyleCdeclWith64NoFunction() throws Exception {
String mangled = "_func_cdecl";
String expectedDemangled = "_func_cdecl";
processWith64NonFunction(mangled, expectedDemangled);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: stdcall; Architecture size: 32; Function present: yes
// Result: stdcall function; 12 bytes
public void testCStyleStdcallWith32Function() throws Exception {
String mangled = "_func_stdcall@12";
String expectedDemangled = "func_stdcall";
String expectedFunction = "__stdcall func_stdcall(undefined4,undefined4,undefined4)";
String expectedConvention = "__stdcall";
int expectedNumBytes = 12;
processWith32Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: stdcall; Architecture size: 32; Function present: no
// Result: no function; 0 bytes
public void testCStyleStdcallWith32NoFunction() throws Exception {
String mangled = "_func_stdcall@12";
String expectedDemangled = "_func_stdcall";
processWith32NonFunction(mangled, expectedDemangled);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: stdcall; Architecture size: 64; Function present: yes
// Result: no function; 0 bytes
public void testCStyleStdcallWith64Function() throws Exception {
String mangled = "_func_stdcall@12";
String expectedDemangled = "_func_stdcall";
String expectedFunction = null;
String expectedConvention = null;
int expectedNumBytes = 0;
processWith64Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: stdcall; Architecture size: 64; Function present: no
// Result: no function; 0 bytes
public void testCStyleStdcallWith64NoFunction() throws Exception {
String mangled = "_func_stdcall@12";
String expectedDemangled = "_func_stdcall";
processWith64NonFunction(mangled, expectedDemangled);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: fastcall; Architecture size: 32; Function present: yes
// Result: fastcall function (stripped '@'); 12 bytes
public void testCStyleFastcallWith32Function() throws Exception {
String mangled = "@func_fastcall@12";
String expectedDemangled = "func_fastcall";
String expectedFunction = "__fastcall func_fastcall(undefined4,undefined4,undefined4)";
String expectedConvention = "__fastcall";
int expectedNumBytes = 12;
processWith32Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: fastcall; Architecture size: 32; Function present: no
// Result: no function; 12 bytes
public void testCStyleFastcallWith32NoFunction() throws Exception {
String mangled = "@func_fastcall@12";
String expectedDemangled = ""; // empty because the prefix '@' causes an empty name
processWith32NonFunction(mangled, expectedDemangled);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: fastcall; Architecture size: 64; Function present: yes
// Result: no function; 12 bytes
public void testCStyleFastcallWith64Function() throws Exception {
String mangled = "@func_fastcall@12";
String expectedDemangled = ""; // empty because the prefix '@' causes an empty name
String expectedFunction = null;
String expectedConvention = null;
int expectedNumBytes = 0;
processWith64Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: fastcall; Architecture size: 64; Function present: no
// Result: fastcall function; 12 bytes
public void testCStyleFastcallWith64NoFunction() throws Exception {
String mangled = "@func_fastcall@12";
String expectedDemangled = ""; // empty because the prefix '@' causes an empty name
processWith64NonFunction(mangled, expectedDemangled);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: vectorcall; Architecture size: 32; Function present: yes
// Result: vectorcall function; 12 bytes
public void testCStyleVectorcallWith32Function() throws Exception {
String mangled = "func_vectorcall@@12";
String expectedDemangled = "func_vectorcall";
String expectedFunction = "__vectorcall func_vectorcall(undefined4,undefined4,undefined4)";
String expectedConvention = "__vectorcall";
int expectedNumBytes = 12;
processWith32Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: vectorcall; Architecture size: 32; Function present: no
// Result: no function; 0 bytes
public void testCStyleVectorcallWith32NoFunction() throws Exception {
String mangled = "func_vectorcall@@12";
String expectedDemangled = "func_vectorcall";
processWith32NonFunction(mangled, expectedDemangled);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: vectorcall; Architecture size: 32; Function present: yes
// Result: vectorcall function; 12 bytes
public void testCStyleVectorcallWith64Function() throws Exception {
String mangled = "func_vectorcall@@12";
String expectedDemangled = "func_vectorcall";
String expectedFunction = "__vectorcall func_vectorcall(undefined4,undefined4,undefined4)";
String expectedConvention = "__vectorcall";
int expectedNumBytes = 12;
processWith64Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: vectorcall; Architecture size: 64; Function present: no
// Result: no function; 0 bytes
public void testCStyleVectorcallWith64NoFunction() throws Exception {
String mangled = "func_vectorcall@@12";
String expectedDemangled = "func_vectorcall";
processWith64NonFunction(mangled, expectedDemangled);
}
}
@@ -4,9 +4,9 @@
* 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.
@@ -45,21 +45,24 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
public void testUnsignedShortParameter() throws Exception {
String mangled = "?InvokeHelperV@COleDispatchDriver@@QAEXJGGPAXPBEPAD@Z";
Address address = addr("01001000");
MicrosoftDemangler demangler = new MicrosoftDemangler();
DemangledObject demangledObject = demangler.demangle(mangled);
DemanglerOptions options = new MicrosoftDemanglerOptions();
MangledContext mangledContext =
demangler.createMangledContext(mangled, options, program, address);
DemangledObject demangledObject = demangler.demangle(mangledContext);
int txID = program.startTransaction("Test");
SymbolTable st = program.getSymbolTable();
st.createLabel(addr("01001000"), mangled, SourceType.ANALYSIS);
st.createLabel(address, mangled, SourceType.ANALYSIS);
demangledObject.applyTo(program, address, options, TaskMonitor.DUMMY);
DemanglerOptions options = new DemanglerOptions();
demangledObject.applyTo(program, addr("01001000"), options, TaskMonitor.DUMMY);
program.endTransaction(txID, true);
FunctionManager fm = program.getFunctionManager();
Function function = fm.getFunctionAt(addr("01001000"));
Function function = fm.getFunctionAt(address);
Parameter[] parameters = function.getParameters();
// this was broken at one point, returning 'unsigned_short'
@@ -69,17 +72,19 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
@Test
public void testArrayVariable() throws Exception { // NullPointerException
String mangled = "?Te@NS1@BobsStuff@@0QAY0BAA@$$CBIA";
Address address = addr("01001000");
MicrosoftDemangler demangler = new MicrosoftDemangler();
DemangledObject demangledObject = demangler.demangle(mangled);
DemanglerOptions options = new MicrosoftDemanglerOptions();
MangledContext mangledContext =
demangler.createMangledContext(mangled, options, program, address);
DemangledObject demangledObject = demangler.demangle(mangledContext);
int txID = program.startTransaction("Test");
SymbolTable st = program.getSymbolTable();
st.createLabel(addr("01001000"), mangled, SourceType.ANALYSIS);
st.createLabel(address, mangled, SourceType.ANALYSIS);
DemanglerOptions options = new DemanglerOptions();
demangledObject.applyTo(program, addr("01001000"), options, TaskMonitor.DUMMY);
demangledObject.applyTo(program, address, options, TaskMonitor.DUMMY);
program.endTransaction(txID, false);
}
@@ -203,8 +208,11 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
String mangled = "?BobsStuffIO@344GPAUHINSTANCE__@@U_COMMPROP@@+W";
MicrosoftDemangler demangler = new MicrosoftDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, null);
try {
demangler.demangle(mangled);
demangler.demangle(mangledContext);
}
catch (DemangledException e) {
// Expected
@@ -218,8 +226,10 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
String mangled = "?BobsStuffIO@344GPAUHINSTANCE__@@U_COMMPROP@@/W";
MicrosoftDemangler demangler = new MicrosoftDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, null);
try {
demangler.demangle(mangled);
demangler.demangle(mangledContext);
}
catch (DemangledException e) {
// Expected
@@ -4,9 +4,9 @@
* 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.
@@ -93,8 +93,9 @@ public class DeveloperDumpMDMangParseInfoScript extends GhidraScript {
StringBuilder builder = new StringBuilder();
builder.append("\nName: " + name + "\n");
MDMangParseInfo demangler = new MDMangParseInfo();
demangler.setMangledSymbol(name);
try {
demangler.demangle(name, false);
demangler.demangle();
String parseInfo = demangler.getParseInfoIncremental();
builder.append(parseInfo);
builder.append("Num remaining chars:" + demangler.getNumCharsRemaining() + "\n");
@@ -4,9 +4,9 @@
* 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.
@@ -125,8 +125,9 @@ public class MDMangDeveloperGenericizeMangledNamesScript extends GhidraScript {
return getError(name, "contains white space");
}
MDMangGenericize demangler = new MDMangGenericize();
demangler.setMangledSymbol(name);
try {
demangler.demangle(name, false);
demangler.demangle();
}
catch (MDException e) {
return getError(name, e.getMessage());
@@ -4,9 +4,9 @@
* 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.
@@ -17,13 +17,13 @@ package mdemangler;
/**
* A class for bidirectional iteration over a string.
*
*
* Iterators maintain a current character index, whose valid range is from
* 0 to string.length()-1.
*
*
* The current index can be retrieved by calling getIndex() and set directly
* by calling setIndex().
*
*
* The methods previous() and next() are used for iteration. They return DONE if
* they would move outside the range from 0 to string.length()-1.
*/
@@ -71,13 +71,13 @@ public class MDCharacterIterator {
}
/**
* Sets the position to the specified position in the text.
* @param index the position within the text.
* @return the character at the specified position
* @throws IllegalArgumentException if index is not in range from 0 to string.length()-1
* Sets the position to the specified position in the text. Can set index to just beyond
* the text to represent the iterator being at the end of the text
* @param index the position within the text.
* @throws IllegalArgumentException if index is not in range from 0 to string.length()
*/
public void setIndex(int index) {
if (index < 0 || index > string.length() - 1) {
if (index < 0 || index > string.length()) {
throw new IllegalArgumentException();
}
this.index = index;
@@ -92,7 +92,7 @@ public class MDCharacterIterator {
}
/**
* Returns the next character without incrementing the current index.
* Returns the next character without incrementing the current index.
* @return the next character without incrementing the current index
*/
public char peek() {
@@ -137,7 +137,7 @@ public class MDCharacterIterator {
}
/**
* Returns the character at the current index and then increments the index by one.
* Returns the character at the current index and then increments the index by one.
* If the resulting index is greater or equal
* to the end index, the current index is reset to the end index and
* a value of DONE is returned.
@@ -154,7 +154,7 @@ public class MDCharacterIterator {
}
/**
* Increments the index by one.
* Increments the index by one.
* Does no testing for whether the index surpasses the length of the string.
*/
public void increment() {
@@ -162,7 +162,7 @@ public class MDCharacterIterator {
}
/**
* Increments the index by the amount of count.
* Increments the index by the amount of count.
* Does no testing for whether the index surpasses the length of the string.
*/
public void increment(int count) {
@@ -4,9 +4,9 @@
* 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.
@@ -59,7 +59,10 @@ public class MDDotSeparatedItem extends MDParsableItem {
try {
Constructor<? extends MDMang> ctor = dmang.getClass().getDeclaredConstructor();
MDMang subDmang = ctor.newInstance();
subItem = subDmang.demangle(sub, false);
subDmang.setArchitectureSize(dmang.getArchitectureSize());
subDmang.setIsFunction(dmang.isFunction);
subDmang.setMangledSymbol(sub);
subItem = subDmang.demangle();
}
// might want to handle these separately for now... later can possibly group all
// together
@@ -4,9 +4,9 @@
* 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.
@@ -19,6 +19,8 @@ import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import mdemangler.MDContext.MDContextType;
import mdemangler.datatype.MDDataType;
import mdemangler.datatype.MDDataTypeParser;
@@ -38,6 +40,9 @@ import mdemangler.template.MDTemplateArgumentsList;
public class MDMang {
public static final char DONE = MDCharacterIterator.DONE;
protected int architectureSize = 32;
protected boolean isFunction = false;
protected String mangled;
protected MDCharacterIterator iter;
protected String errorMessage;
@@ -45,12 +50,147 @@ public class MDMang {
protected List<MDContext> contextStack;
protected boolean errorOnRemainingChars = false;
public enum ProcessingMode {
DEFAULT_STANDARD, LLVM
}
private ProcessingMode processingMode;
//==============================================================================================
// Mangled Context
/**
* Sets the mangled string to be demangled
* @param mangledIn the string to be demangled
*/
public void setMangledSymbol(String mangledIn) {
this.mangled = mangledIn;
}
/**
* Gets the mangled string being demangled
* @return the string being demangled
*/
public String getMangledSymbol() {
return mangled;
}
/**
* Sets the architecture size. Default is 64 bits
* @param size the architecture size
*/
public void setArchitectureSize(int size) {
architectureSize = size;
}
/**
* Returns the architecture size (bits)
* @return the architecture size
*/
public int getArchitectureSize() {
return architectureSize;
}
/**
* Sets whether the symbol is known to be for a function
* @param isFunction {@code true} if known to be a symbol for a function
*/
public void setIsFunction(boolean isFunction) {
this.isFunction = isFunction;
}
/**
* Returns whether the symbol is known to be for a function
* @return {@code true} if known to be a symbol for a function
*/
public boolean isFunction() {
return isFunction;
}
//==============================================================================================
// Control
/**
* Controls whether an exception is thrown if there are remaining characters after demangling.
* Default is {@code false}
* @param errorOnRemainingCharsArg {@code true} to error if characters remaining
*/
public void setErrorOnRemainingChars(boolean errorOnRemainingCharsArg) {
errorOnRemainingChars = errorOnRemainingCharsArg;
}
/**
* Returns {@code true} if the process will throw an exception if characters remain after
* demangling
* @return {@code true} if errors will occur on remaining characters
*/
public boolean errorOnRemainingChars() {
return errorOnRemainingChars;
}
/**
* Returns the error message when demangle() returns null.
* @return the error message for the demangle() call.
*/
public String getErrorMessage() {
return errorMessage;
}
/**
* Returns the number of unprocessed mangled characters. Note that
* demangle() has a flag controlling whether remaining characters causes an
* error
* @return the integer number of characters that remain
*/
public int getNumCharsRemaining() {
return iter.getLength() - iter.getIndex();
}
//==============================================================================================
// Processing
/**
* Demangles the string already stored and returns a parsed item
* @return item detected and parsed
* @throws MDException upon error parsing item
*/
public MDParsableItem demangle() throws MDException {
initState();
item = MDMangObjectParser.determineItemAndParse(this);
if (item instanceof MDObjectCPP) {
// MDMANG SPECIALIZATION USED.
item = getEmbeddedObject((MDObjectCPP) item);
}
int numCharsRemaining = getNumCharsRemaining();
if (errorOnRemainingChars && (numCharsRemaining > 0)) {
throw new MDException(
"MDMang: characters remain after demangling: " + numCharsRemaining + ".");
}
return item;
}
/**
* Demangles the mangled "type" name already stored and returns a parsed MDDataType
* @return the parsed MDDataType
* @throws MDException upon parsing error
*/
public MDDataType demangleType() throws MDException {
initState();
MDDataType mdDataType = MDDataTypeParser.determineAndParseDataType(this, false);
item = mdDataType;
int numCharsRemaining = getNumCharsRemaining();
if (errorOnRemainingChars && (numCharsRemaining > 0)) {
throw new MDException(
"MDMang: characters remain after demangling: " + numCharsRemaining + ".");
}
return mdDataType;
}
//==============================================================================================
// Internal processing control
public void setProcessingMode(ProcessingMode processingMode) {
this.processingMode = processingMode;
}
@@ -67,33 +207,13 @@ public class MDMang {
return processingMode == ProcessingMode.LLVM;
}
/**
* Demangles the string passed in and returns a parsed item.
*
* @param mangledIn
* the string to be demangled.
* @param errorOnRemainingChars
* boolean flag indicating whether remaining characters causes an
* error.
* @return the item that has been parsed.
* @throws MDException upon parsing error
*/
public MDParsableItem demangle(String mangledIn, boolean errorOnRemainingChars)
throws MDException {
if (mangledIn == null || mangledIn.isEmpty()) {
throw new MDException("Invalid mangled symbol.");
}
setMangledSymbol(mangledIn);
return demangle(errorOnRemainingChars);
}
/**
* Variables that get set at the very beginning.
* @throws MDException if mangled name is not set
*/
protected void initState() throws MDException {
if (mangled == null) {
throw new MDException("MDMang: Mangled string is null.");
if (StringUtils.isBlank(mangled)) {
throw new MDException("MDMang: Mangled string is null or blank.");
}
errorMessage = "";
processingMode = ProcessingMode.DEFAULT_STANDARD;
@@ -109,108 +229,7 @@ public class MDMang {
setIndex(0);
}
/**
* Demangles the string already stored and returns a parsed item.
*
* @param errorOnRemainingChars
* boolean flag indicating whether remaining characters causes an
* error.
* @return item detected and parsed
* @throws MDException upon error parsing item
*/
public MDParsableItem demangle(boolean errorOnRemainingChars) throws MDException {
initState();
item = MDMangObjectParser.determineItemAndParse(this);
if (item instanceof MDObjectCPP) {
// MDMANG SPECIALIZATION USED.
item = getEmbeddedObject((MDObjectCPP) item);
}
int numCharsRemaining = getNumCharsRemaining();
if (errorOnRemainingChars && (numCharsRemaining > 0)) {
throw new MDException(
"MDMang: characters remain after demangling: " + numCharsRemaining + ".");
}
return item;
}
/**
* Demangles the mangled "type" name and returns a parsed MDDataType
*
* @param mangledIn the mangled "type" string to be demangled
* @param errorOnRemainingChars
* boolean flag indicating whether remaining characters causes an
* error
* @return the parsed MDDataType
* @throws MDException upon parsing error
*/
public MDDataType demangleType(String mangledIn, boolean errorOnRemainingChars)
throws MDException {
if (mangledIn == null || mangledIn.isEmpty()) {
throw new MDException("Invalid mangled symbol.");
}
setMangledSymbol(mangledIn);
return demangleType(errorOnRemainingChars);
}
/**
* Demangles the mangled "type" name already stored and returns a parsed MDDataType
*
* @param errorOnRemainingChars
* boolean flag indicating whether remaining characters causes an
* error
* @return the parsed MDDataType
* @throws MDException upon parsing error
*/
public MDDataType demangleType(boolean errorOnRemainingChars) throws MDException {
initState();
MDDataType mdDataType = MDDataTypeParser.determineAndParseDataType(this, false);
item = mdDataType;
int numCharsRemaining = getNumCharsRemaining();
if (errorOnRemainingChars && (numCharsRemaining > 0)) {
throw new MDException(
"MDMang: characters remain after demangling: " + numCharsRemaining + ".");
}
return mdDataType;
}
/**
* Sets the mangled string to be demangled.
*
* @param mangledIn
* the string to be demangled.
*/
public void setMangledSymbol(String mangledIn) {
this.mangled = mangledIn;
}
/**
* Gets the mangled string being demangled.
*
* @return the string being demangled.
*/
public String getMangledSymbol() {
return mangled;
}
/**
* Returns the error message when demangle() returns null.
*
* @return the error message for the demangle() call.
*/
public String getErrorMessage() {
return errorMessage;
}
/**
* Returns the number of unprocessed mangled characters. Note that
* demangle() has a flag controlling whether remaining characters causes an
* error.
*
* @return the integer number of characters that remain.
*/
public int getNumCharsRemaining() {
return iter.getLength() - iter.getIndex();
}
//==============================================================================================
/******************************************************************************/
/******************************************************************************/
@@ -252,9 +271,10 @@ public class MDMang {
}
/**
* Sets the current index.
* @param index the position to set.
* @throws IllegalArgumentException if index is not in range from 0 to string.length()-1
* Sets the current index. Can set index to just beyond the text to represent the iterator
* being at the end of the text
* @param index the position to set
* @throws IllegalArgumentException if index is not in range from 0 to string.length()
*/
public void setIndex(int index) {
iter.setIndex(index);
@@ -4,9 +4,9 @@
* 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.
@@ -67,7 +67,7 @@ public class MDMangGenericize extends MDMang {
// return item;
// }
@Override
public MDParsableItem demangle(boolean errorOnRemainingChars) throws MDException {
public MDParsableItem demangle() throws MDException {
// ignoring the 'errorOnRemainingChars' parameter (for now)
initState();
item = MDMangObjectParser.determineItemAndParse(this);
File diff suppressed because it is too large Load Diff
@@ -28,9 +28,8 @@ import mdemangler.template.MDTemplateArgumentsList;
public class MDMangVS2015 extends MDMang {
@Override
public MDParsableItem demangle(String mangledIn, boolean errorOnRemainingChars)
throws MDException {
MDParsableItem returnedItem = super.demangle(mangledIn, errorOnRemainingChars);
public MDParsableItem demangle() throws MDException {
MDParsableItem returnedItem = super.demangle();
//VS2015 does not understand all of the object types that we made up. These all fall
// under MDObjectReserved; but it does understand MDObjectBracket objects.
if (returnedItem instanceof MDObjectBracket) {
@@ -4,9 +4,9 @@
* 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.
@@ -25,21 +25,131 @@ import mdemangler.naming.MDFragmentName;
*/
public class MDObjectC extends MDObject {
protected MDFragmentName name;
int conventionIndex;
int numParameterBytes;
private final String callingConvention[] =
{ "__cdecl", "__stdcall", "__fastcall", "__vectorcall" };
public MDObjectC(MDMang dmang) {
super(dmang);
conventionIndex = -1;
numParameterBytes = 0;
name = new MDFragmentName(dmang);
}
/**
* Returns the name
* @return the name
*/
public String getName() {
if (name == null) {
return null;
}
return name.getName();
}
/**
* Returns a calling convention string if the C object is determined to be a function with
* a specified convention
* @return the convention or {@code null} if not determined to be a function with convention
*/
public String getCallingConvention() {
if (conventionIndex == -1) {
return null;
}
return callingConvention[conventionIndex];
}
/**
* Returns the number of parameter bytes if the C object is determined to be a function with
* a specified convention
* @return the number of bytes; will always be zero for __cdecl
*/
public int getNumParameterBytes() {
return numParameterBytes;
}
@Override
public void insert(StringBuilder builder) {
// We've come up with the demangling output for the function format ourselves. This
// format does not output anything for __cdecl (default) convention
if (conventionIndex >= 1 && conventionIndex <= 3) {
builder.append(callingConvention[conventionIndex]);
builder.append(' ');
}
builder.append(name);
if (conventionIndex >= 1 && conventionIndex <= 3) {
builder.append(',');
builder.append(numParameterBytes);
}
}
/*
* Follow are C-style mangling scheme under 32-bit model; __vectorcall also valid for 64-bit
* __cdecl: '_' prefix; no suffix; example "_name"
* __stdcall: '_' prefix; "@<decimal_digits>" suffix; example "_name@12"
* __fastcall: '@' prefix; "@<decimal_digits>" suffix; example "@name@12"
* __vectorcall: no prefix; "@@<decimal_digits>" suffix; example "name@@12"
*/
@Override
protected void parseInternal() throws MDException {
name.parse();
if (!dmang.isFunction()) {
name.parse();
return;
}
int index = dmang.getIndex();
char c = dmang.peek();
if (c == '@') {
conventionIndex = 2;
dmang.next();
}
else if (c == '_') {
conventionIndex = 0; // will be 0 or 1
dmang.next();
}
else {
conventionIndex = 3;
}
name.parse(); // This strips a trailing '@' if it exists
c = dmang.peek();
if (c == '@') {
if (conventionIndex != 3) {
throw new MDException("Error parsing C Object calling convention");
}
dmang.next(); // skip the '@'
}
else if (conventionIndex == 0 &&
dmang.getMangledSymbol().charAt(dmang.getIndex() - 1) == '@') {
conventionIndex = 1;
}
if (dmang.getArchitectureSize() != 32 && conventionIndex != 3) {
conventionIndex = -1;
dmang.setIndex(index); // reset iterator back to original location
name.parse();
return;
}
if (conventionIndex != 0) {
numParameterBytes = parseNumParameterBytes();
}
}
private int parseNumParameterBytes() throws MDException {
int loc = dmang.getIndex();
String str = dmang.getMangledSymbol().substring(loc);
dmang.setIndex(loc + dmang.getNumCharsRemaining());
try {
return Integer.parseInt(str);
}
catch (NumberFormatException e) {
throw new MDException("Error parsing C Object calling convention");
}
}
}
/******************************************************************************/
@@ -4,9 +4,9 @@
* 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.
@@ -56,6 +56,14 @@ public class MDObjectCPP extends MDObject {
return this;
}
/**
* Returns whether the object was a hashed object
* @return {@code true} if was a hashed object
*/
public boolean isHashObject() {
return hashedObjectFlag;
}
/**
* Returns the name of the symbol, minus any namespace component.
* @return the name.
@@ -4,9 +4,9 @@
* 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.
@@ -44,6 +44,7 @@ public class MDBaseTestConfiguration {
// Internal variables
protected String mangled;
protected MDParsableItem demangItem;
protected boolean isFunction = false;
protected String demangled;
protected String truth;
@@ -61,6 +62,10 @@ public class MDBaseTestConfiguration {
}
}
public void setIsFunction(boolean isFunctionArg) {
isFunction = isFunctionArg;
}
/**
* Runs through the process of creating a demangler, demangling a symbol string,
* testing the output, and performing other ancillary outputs and tests.
@@ -85,6 +90,7 @@ public class MDBaseTestConfiguration {
outputInfo.append(getTestHeader());
}
mdm.setIsFunction(isFunction);
// Meant to be overridden, as needed by extended classes
demangItem = doDemangleSymbol(mdm, mangled);
demangled = (demangItem == null) ? "" : demangItem.toString();
@@ -123,6 +129,7 @@ public class MDBaseTestConfiguration {
}
}
// Need to do a better job here
private boolean isMangled(String s) {
if (s.charAt(0) == '?') {
return true;
@@ -130,9 +137,9 @@ public class MDBaseTestConfiguration {
else if (s.startsWith("__")) {
return true;
}
else if ((s.charAt(0) == '_') || Character.isUpperCase(s.charAt(1))) {
return true;
}
// else if ((s.charAt(0) == '_') || Character.isUpperCase(s.charAt(1))) {
// return true;
// }
return false;
}
@@ -193,8 +200,10 @@ public class MDBaseTestConfiguration {
// Meant to be overridden, as needed by extended classes
protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception {
mdmIn.setMangledSymbol(mangledIn);
mdmIn.setErrorOnRemainingChars(true);
try {
return mdmIn.demangle(mangledIn, true);
return mdmIn.demangle();
}
catch (MDException e) {
return null;
@@ -4,9 +4,9 @@
* 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.
@@ -15,8 +15,6 @@
*/
package mdemangler;
import ghidra.app.util.demangler.DemangledObject;
/**
* This class is a derivation of MDBaseTestConfiguration (see javadoc there). This
* class must choose the appropriate truth from MDMangBaseTest (new truths might
@@ -26,9 +24,9 @@ import ghidra.app.util.demangler.DemangledObject;
*/
public class MDGhidraTestConfiguration extends MDBaseTestConfiguration {
protected DemangledObject demangledObject;
protected String demangledGhidraObject;
protected DemangledObject demangledObjectCheck;
// protected DemangledObject demangledObject;
// protected String demangledGhidraObject;
// protected DemangledObject demangledObjectCheck;
public MDGhidraTestConfiguration(boolean quiet) {
super(quiet);
@@ -48,10 +46,12 @@ public class MDGhidraTestConfiguration extends MDBaseTestConfiguration {
@Override
protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception {
MDParsableItem returnItem;
mdmIn.setMangledSymbol(mangledIn);
mdmIn.setErrorOnRemainingChars(true);
try {
// For first boolean: set true in operational mode.
returnItem = ((MDMangGhidra) mdmIn).demangle(mangledIn, false, false);
demangledObject = ((MDMangGhidra) mdmIn).getObject();
returnItem = mdmIn.demangle();
// demangledObject = ((MDMangGhidra) mdmIn).getObject();
}
catch (MDException e) {
returnItem = null;
@@ -62,14 +62,14 @@ public class MDGhidraTestConfiguration extends MDBaseTestConfiguration {
@Override
protected void doBasicTestsAndOutput() throws Exception {
super.doBasicTestsAndOutput();
if (demangledObject != null) {
demangledGhidraObject = demangledObject.toString();
outputInfo.append("demangl: " + demangledGhidraObject + "\n");
}
else {
demangledGhidraObject = "";
outputInfo.append("demangled: NO RESULT\n");
}
// if (demangledObject != null) {
// demangledGhidraObject = demangledObject.toString();
// outputInfo.append("demangl: " + demangledGhidraObject + "\n");
// }
// else {
// demangledGhidraObject = "";
// outputInfo.append("demangled: NO RESULT\n");
// }
// For checking the original results, for comparison purposes, this code should probably
// be calling the MicrosoftWineDemangler.
// try {
@@ -86,38 +86,38 @@ public class MDGhidraTestConfiguration extends MDBaseTestConfiguration {
// }
}
@Override
protected void doExtraProcCheck() throws Exception {
if ((demangledObjectCheck != null) && (demangledObject != null)) {
if (demangledObjectCheck.getClass() != demangledObject.getClass()) {
outputInfo.append("ObjComp: notequal NEW: " + demangledObject.getClass().getName() +
", OLD: " + demangledObjectCheck.getClass().getName() + "\n");
}
else {
outputInfo.append("ObjComp: equal NEW: " + demangledObject.getClass().getName() +
", OLD: " + demangledObjectCheck.getClass().getName() + "\n");
}
}
else {
if ((demangledObjectCheck == null) && (demangledObject == null)) {
outputInfo.append("ObjComp: Not possible -- both null\n");
}
else if (demangledObjectCheck == null) {
outputInfo.append("ObjComp: Not possible -- OLD null; NEW: " +
demangledObject.getClass().getName() + "\n");
}
else {
outputInfo.append("ObjComp: Not possible -- NEW null; OLD: " +
demangledObjectCheck.getClass().getName() + "\n");
}
}
if (ghidraTestStringCompare(outputInfo, demangled, demangledGhidraObject)) {
outputInfo.append("RESULTS MATCH------******\n");
}
else {
outputInfo.append("RESULTS MISMATCH------*********************************\n");
}
}
// @Override
// protected void doExtraProcCheck() throws Exception {
// if ((demangledObjectCheck != null) && (demangledObject != null)) {
// if (demangledObjectCheck.getClass() != demangledObject.getClass()) {
// outputInfo.append("ObjComp: notequal NEW: " + demangledObject.getClass().getName() +
// ", OLD: " + demangledObjectCheck.getClass().getName() + "\n");
// }
// else {
// outputInfo.append("ObjComp: equal NEW: " + demangledObject.getClass().getName() +
// ", OLD: " + demangledObjectCheck.getClass().getName() + "\n");
// }
// }
// else {
// if ((demangledObjectCheck == null) && (demangledObject == null)) {
// outputInfo.append("ObjComp: Not possible -- both null\n");
// }
// else if (demangledObjectCheck == null) {
// outputInfo.append("ObjComp: Not possible -- OLD null; NEW: " +
// demangledObject.getClass().getName() + "\n");
// }
// else {
// outputInfo.append("ObjComp: Not possible -- NEW null; OLD: " +
// demangledObjectCheck.getClass().getName() + "\n");
// }
// }
// if (ghidraTestStringCompare(outputInfo, demangled, demangledGhidraObject)) {
// outputInfo.append("RESULTS MATCH------******\n");
// }
// else {
// outputInfo.append("RESULTS MISMATCH------*********************************\n");
// }
// }
private boolean ghidraTestStringCompare(StringBuilder outputInfoArg, String truthString,
String ghidraString) {
@@ -4,9 +4,9 @@
* 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.
@@ -194,6 +194,12 @@ public class MDMangBaseTest extends AbstractGenericTest {
ms2013Truth);
}
private void demangleAndTestFunction() throws Exception {
testConfiguration.setIsFunction(true);
testConfiguration.demangleAndTest(testName, mangled, mdTruth, msTruth, ghTruth,
ms2013Truth);
}
@Test
public void testTripleQ0() throws Exception {
mangled = "???__E??_7name0@name1@@6B@@@YMXXZ@?A0x647dec29@@$$FYMXXZ";
@@ -15312,6 +15318,81 @@ public class MDMangBaseTest extends AbstractGenericTest {
demangleAndTest();
}
//=====================
/*
* Follow are C-style mangling scheme under 32-bit model; __vectorcall also valid for 64-bit
* __cdecl: '_' prefix; no suffix; example "_name"
* __stdcall: '_' prefix; "@<decimal_digits>" suffix; example "_name@12"
* __fastcall: '@' prefix; "@<decimal_digits>" suffix; example "@name@12"
* __vectorcall: no prefix; "@@<decimal_digits>" suffix; example "name@@12"
*
* We've come up with the string output formats for the C-style mangling scheme.
*/
@Test
public void testCStyleCdeclFunction() throws Exception {
mangled = "_name";
mdTruth = "name";
msTruth = "";
demangleAndTestFunction();
}
@Test
public void testCStyleCdeclNoFunction() throws Exception {
mangled = "_name";
mdTruth = "_name";
msTruth = "";
demangleAndTest();
}
@Test
public void testCStyleStdcallFunction() throws Exception {
mangled = "_name@12";
mdTruth = "__stdcall name,12";
msTruth = "";
demangleAndTestFunction();
}
@Test
public void testCStyleStdcallNoFunction() throws Exception {
mangled = "_name@12";
mdTruth = "";
msTruth = "";
demangleAndTest();
}
@Test
public void testCStyleFastcallFunction() throws Exception {
mangled = "@name@12";
mdTruth = "__fastcall name,12";
msTruth = "";
demangleAndTestFunction();
}
@Test
public void testCStyleFastcallNoFunction() throws Exception {
mangled = "@name@12";
mdTruth = "";
msTruth = "";
demangleAndTest();
}
@Test
public void testCStyleVectorcallFunction() throws Exception {
mangled = "name@@12";
mdTruth = "__vectorcall name,12";
msTruth = "";
demangleAndTestFunction();
}
@Test
public void testCStyleVectorcallNoFunction() throws Exception {
mangled = "name@@12";
mdTruth = "";
msTruth = "";
demangleAndTest();
}
//=====================
//TODO: ignore for now.
@@ -4,9 +4,9 @@
* 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.
@@ -22,7 +22,6 @@ import java.util.List;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.app.util.demangler.DemangledObject;
import mdemangler.naming.MDQualification;
import mdemangler.object.MDObjectCPP;
import mdemangler.typeinfo.MDVxTable;
@@ -33,32 +32,6 @@ import mdemangler.typeinfo.MDVxTable;
*/
public class MDMangExtraTest extends AbstractGenericTest {
@Test
//This test checks that we can provide a mangled string for a function namespace.
// The return String from getOriginalMangled() is not null only for this special
// circumstance. So, in normal processing, we should check it for non-null to
// determine that we have a result of this form.
// The symbol here is from our cn3.cpp source target.
public void testFunctionNamespace() throws Exception {
String mangled = "?fn3@?2??Bar3@Foo2b@@SAHXZ@4HA";
String wholeTruth = "int `public: static int __cdecl Foo2b::Bar3(void)'::`3'::fn3";
String functionNamespaceMangledTruth = "?Bar3@Foo2b@@SAHXZ";
String functionNamespaceTruth = "public: static int __cdecl Foo2b::Bar3(void)";
MDMangGhidra demangler = new MDMangGhidra();
MDParsableItem item = demangler.demangle(mangled, true, true);
String demangled = item.toString();
assertEquals(wholeTruth, demangled);
DemangledObject obj = demangler.getObject();
String mangledFunctionNamespace = obj.getNamespace().getNamespace().getMangledString();
assertEquals(functionNamespaceMangledTruth, mangledFunctionNamespace);
item = demangler.demangle(mangledFunctionNamespace, true, true);
demangled = item.toString();
assertEquals(functionNamespaceTruth, demangled);
}
@Test
public void testVxTableNestedQualifications() throws Exception {
// Test string taken from MDMangBaseTest
@@ -66,7 +39,10 @@ public class MDMangExtraTest extends AbstractGenericTest {
String truth = "const b::a::`vftable'{for `e::d::c's `h::g::f's `k::j::i'}";
MDMangGhidra demangler = new MDMangGhidra();
MDParsableItem item = demangler.demangle(mangled, true, true);
demangler.setMangledSymbol(mangled);
demangler.setErrorOnRemainingChars(true);
demangler.setDemangleOnlyKnownPatterns(true);
MDParsableItem item = demangler.demangle();
String demangled = item.toString();
assertEquals(truth, demangled);
@@ -88,7 +64,9 @@ public class MDMangExtraTest extends AbstractGenericTest {
String truth = "enum `void __cdecl name2::name1(bool)'::name0";
MDMangGhidra demangler = new MDMangGhidra();
MDParsableItem item = demangler.demangleType(mangled, true); // note demangleType()
demangler.setMangledSymbol(mangled);
demangler.setErrorOnRemainingChars(true);
MDParsableItem item = demangler.demangleType(); // note demangleType()
String demangled = item.toString();
assertEquals(truth, demangled);
@@ -43,7 +43,9 @@ public class MDMangUtilsTest extends AbstractGenericTest {
"class `struct name1::name2 __cdecl name1::name0(struct name1::name3,struct name1::name4)'::`1'::<lambda_0>";
MDMangGhidra demangler = new MDMangGhidra();
MDDataType item = demangler.demangleType(mangled, true);
demangler.setMangledSymbol(mangled);
demangler.setErrorOnRemainingChars(true);
MDDataType item = demangler.demangleType();
String demangled = item.toString();
SymbolPath symbolPath = MDMangUtils.getSymbolPath(item);
@@ -69,7 +71,9 @@ public class MDMangUtilsTest extends AbstractGenericTest {
"struct name8::name7::name0<class `public: virtual void __cdecl name4::`anonymous namespace'::name2::name1(class Aname3::name5,int,class Aname3::name6 const & __ptr64) __ptr64'::`1'::<lambda_0> && __ptr64>";
MDMangGhidra demangler = new MDMangGhidra();
MDDataType item = demangler.demangleType(mangled, true);
demangler.setMangledSymbol(mangled);
demangler.setErrorOnRemainingChars(true);
MDDataType item = demangler.demangleType();
String demangled = item.toString();
SymbolPath symbolPath = MDMangUtils.getSymbolPath(item);
@@ -94,7 +98,9 @@ public class MDMangUtilsTest extends AbstractGenericTest {
"struct name4::name3::name0<class `public: virtual __cdecl name2::Aname1::~Aname1(void) __ptr64'::`1'::<lambda_0> && __ptr64>";
MDMangGhidra demangler = new MDMangGhidra();
MDDataType item = demangler.demangleType(mangled, true);
demangler.setMangledSymbol(mangled);
demangler.setErrorOnRemainingChars(true);
MDDataType item = demangler.demangleType();
String demangled = item.toString();
SymbolPath symbolPath = MDMangUtils.getSymbolPath(item);
@@ -4,9 +4,9 @@
* 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.
@@ -41,8 +41,10 @@ public class MDVS2013TestConfiguration extends MDBaseTestConfiguration {
@Override
protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception {
mdmIn.setMangledSymbol(mangledIn);
// We are not setting errorOnRemainingChars to true (diff from base test)
try {
return mdmIn.demangle(mangledIn, false); // "false" is different
return mdmIn.demangle();
}
catch (MDException e) {
return null;
@@ -4,9 +4,9 @@
* 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.
@@ -36,8 +36,10 @@ public class MDVS2015TestConfiguration extends MDBaseTestConfiguration {
@Override
protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception {
mdmIn.setMangledSymbol(mangledIn);
// We are not setting errorOnRemainingChars to true (diff from base test)
try {
return mdmIn.demangle(mangledIn, false); // "false" is different
return mdmIn.demangle();
}
catch (MDException e) {
return null;
@@ -4,9 +4,9 @@
* 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.
@@ -75,8 +75,10 @@ public class DumpAllSymbolsDemangledScript extends GhidraScript {
*/
private static String getDemangledString(String mangledString) {
MDMangGhidra demangler = new MDMangGhidra();
demangler.setMangledSymbol(mangledString);
demangler.setErrorOnRemainingChars(true);
try {
MDParsableItem parsableItem = demangler.demangle(mangledString, true);
MDParsableItem parsableItem = demangler.demangle();
if (parsableItem instanceof MDObjectCPP) {
MDObjectCPP mdObject = (MDObjectCPP) parsableItem;
return mdObject.getQualifiedName().toString();
@@ -118,8 +118,10 @@ public abstract class AbstractComplexTypeApplier extends MsDataTypeApplier {
private static SymbolPath getSymbolPathFromMangledTypeName(String mangledString,
String fullPathName) {
MDMang demangler = new MDMangGhidra();
demangler.setErrorOnRemainingChars(true);
demangler.setMangledSymbol(mangledString);
try {
MDDataType mdDataType = demangler.demangleType(mangledString, true);
MDDataType mdDataType = demangler.demangleType();
// 20240626: Ultimately, it might be better to retrieve the Demangled-type to pass
// to the DemangledObject.createNamespace() method to convert to a true Ghidra
// Namespace that are flagged as functions (not capable at this time) or types or
@@ -4,9 +4,9 @@
* 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.
@@ -798,8 +798,10 @@ public class PdbResearch {
return null;
}
MDMangGhidra demangler = new MDMangGhidra();
demangler.setMangledSymbol(mangledString);
demangler.setErrorOnRemainingChars(true);
try {
MDParsableItem parsableItem = demangler.demangle(mangledString, true);
MDParsableItem parsableItem = demangler.demangle();
if (parsableItem instanceof MDObjectCPP) {
MDObjectCPP mdObject = (MDObjectCPP) parsableItem;
return mdObject.getQualifiedName().toString();
@@ -4,9 +4,9 @@
* 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.
@@ -19,6 +19,7 @@
//@category Demangler
import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledObject;
import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.swift.*;
import ghidra.app.util.demangler.swift.SwiftNativeDemangler.SwiftNativeDemangledOutput;
import ghidra.program.model.symbol.*;
@@ -53,12 +54,14 @@ public class SwiftDemanglerScript extends GhidraScript {
println("No mangled Swift symbols found at " + currentAddress);
return;
}
SwiftNativeDemangler nativeDemangler = new SwiftNativeDemangler(options.getSwiftDir());
SwiftNativeDemangledOutput demangledOutput = nativeDemangler.demangle(mangled);
println(demangledOutput.toString());
DemangledObject demangledObject = demangler.demangle(mangled);
MangledContext mangledContext =
demangler.createMangledContext(mangled, options, currentProgram, currentAddress);
DemangledObject demangledObject = demangler.demangle(mangledContext);
if (demangledObject != null) {
println(demangledObject.getClass().getSimpleName() + " " + mangled + " --> " +
demangledObject);
@@ -4,9 +4,9 @@
* 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.
@@ -57,13 +57,13 @@ public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
private File swiftDir;
private boolean useIncompletePrefix = true;
private boolean useUnsupportedPrefix = true;
private SwiftDemangler demangler = new SwiftDemangler();
/**
* Creates a new {@link SwiftDemanglerAnalyzer}
*/
public SwiftDemanglerAnalyzer() {
super(NAME, DESCRIPTION);
demangler = new SwiftDemangler();
setDefaultEnablement(true);
}
@@ -76,7 +76,7 @@ public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
try {
demangler.initialize(program);
((SwiftDemangler) demangler).initialize(program);
}
catch (IOException e) {
log.appendMsg(e.getMessage());
@@ -86,9 +86,9 @@ public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
}
@Override
protected DemangledObject doDemangle(String mangled, DemanglerOptions options, MessageLog log)
protected DemangledObject doDemangle(MangledContext mangledContext, MessageLog log)
throws DemangledException {
return demangler.demangle(mangled, options);
return demangler.demangle(mangledContext);
}
@Override

Some files were not shown because too many files have changed in this diff Show More