GP-4898 - All Demanglers: added MangledContext; Microsoft MDMang: added

C-style mangling scheme and moved Demangler type hierarchies out of
MDMang
This commit is contained in:
ghizard 2024-09-18 08:50:28 -04:00
parent 3670d91d80
commit 737ea4d31f
53 changed files with 3016 additions and 1460 deletions

View File

@ -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>

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}
//==================================================================================================

View File

@ -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
*/

View File

@ -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();

View File

@ -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

View File

@ -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);
}
}

View File

@ -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() {

View File

@ -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;
}
}

View File

@ -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() + "$")) {

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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()) {

View File

@ -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);
}
//==================================================================================================

View File

@ -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;
}

View File

@ -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")
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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
}
}

View File

@ -0,0 +1,975 @@
/* ###
* 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 java.util.Iterator;
import ghidra.app.util.demangler.*;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.symbol.SourceType;
import mdemangler.*;
import mdemangler.datatype.MDDataType;
import mdemangler.datatype.MDVarArgsType;
import mdemangler.datatype.complex.*;
import mdemangler.datatype.extended.MDArrayReferencedType;
import mdemangler.datatype.modifier.*;
import mdemangler.functiontype.*;
import mdemangler.naming.*;
import mdemangler.object.*;
import mdemangler.template.MDTemplateNameAndArguments;
import mdemangler.typeinfo.*;
/**
* A utility class to aid the MicrosoftDemangler
* <p>
* The contents of this class that do the processing came from {@link MDMangGhidra}, and will
* likely go through future rounds of clean-up. {@link MDMangGhidra}, an extension of
* {@link MDMang}, might eventually be removed.
*/
public class MicrosoftDemanglerUtil {
private MicrosoftDemanglerUtil() {
// purposefully empty
}
/**
* Method to convert an {@link MDParsableItem} into a {@link DemangledObject}. This method
* is not appropriate for {@link MDDataType} and some other types of {@link MDParsableItem}
* @param item the item to convert
* @param mangled the original mangled string
* @return the {@link DemangledObject} result
* @throws DemangledException up issue converting to a {@link DemangledObject}
*/
static DemangledObject convertToDemangledObject(MDParsableItem item, String mangled)
throws DemangledException {
return processItem(item, mangled, item.toString());
}
/**
* Method to convert an {@link MDDataType} into a {@link DemangledDataType}
* @param type the type to convert
* @param mangled the original mangled string
* @return the result
*/
static DemangledDataType convertToDemangledDataType(MDDataType type, String mangled) {
return processDataType(null, type, mangled, type.toString());
}
//==============================================================================================
private static Demangled processNamespace(MDQualifiedName qualifiedName, String mangled,
String demangledSource) {
return processNamespace(qualifiedName.getQualification(), mangled, demangledSource);
}
private static Demangled processNamespace(MDQualification qualification, String mangled,
String demangledSource) {
Iterator<MDQualifier> it = qualification.iterator();
if (!it.hasNext()) {
return null;
}
MDQualifier qual = it.next();
Demangled type = getDemangled(qual, mangled, demangledSource);
Demangled current = type;
// Note that qualifiers come in reverse order, from most refined to root being the last
while (it.hasNext()) {
qual = it.next();
Demangled parent = getDemangled(qual, mangled, demangledSource);
current.setNamespace(parent);
current = parent;
}
return type;
}
private static Demangled getDemangled(MDQualifier qual, String mangled,
String demangledSource) {
Demangled demangled = null;
if (qual.isNested()) {
String subMangled = qual.getNested().getMangled();
MDObjectCPP obj = qual.getNested().getNestedObject();
if (!obj.isHashObject()) {
MDTypeInfo typeInfo = obj.getTypeInfo();
MDType type = typeInfo.getMDType();
if (type instanceof MDDataType dt) {
demangled = new DemangledType(subMangled, qual.toString(), qual.toString());
}
else if (type instanceof MDFunctionType ft) {
// We currently cannot handle functions as part of a namespace, so we will just
// treat the demangled function namespace string as a plain namespace.
//demangled = new DemangledFunction(subMangled, qual.toString(), qual.toString());
demangled =
new DemangledNamespaceNode(subMangled, qual.toString(), qual.toString());
}
}
if (demangled == null) {
demangled =
new DemangledNamespaceNode(subMangled, qual.toString(), qual.toString());
}
}
else if (qual.isAnon()) {
// Instead of using the standard qual.toString() method, which returns
// "`anonymous namespace'" for anonymous qualifiers, we use qual.getAnonymousName()
// which will have the underlying anonymous name of the form "A0xfedcba98" to create
// a standardized anonymous name that is distinguishable from other anonymous names.
// The standardized name comes from createStandardAnonymousNamespaceNode(). This
// is especially important when there are sibling anonymous names.
String anon = MDMangUtils.createStandardAnonymousNamespaceNode(qual.getAnonymousName());
demangled = new DemangledNamespaceNode(mangled, qual.toString(), anon);
}
else if (qual.isInterface()) {
// TODO: need to do better; setting namespace for now
demangled = new DemangledNamespaceNode(mangled, qual.toString(), qual.toString());
}
else if (qual.isNameQ()) {
// TODO: need to do better; setting namespace for now, as it looks like interface
demangled = new DemangledNamespaceNode(mangled, qual.toString(), qual.toString());
}
else if (qual.isNameC()) {
// TODO: need to do better; setting type for now, but not processed yet and not sure
// what it is
demangled = new DemangledType(mangled, qual.toString(), qual.toString());
}
else if (qual.isLocalNamespace()) {
String local =
MDMangUtils.createStandardLocalNamespaceNode(qual.getLocalNamespaceNumber());
demangled = new DemangledNamespaceNode(mangled, qual.toString(), local);
}
else {
demangled = new DemangledNamespaceNode(mangled, qual.toString(), qual.toString());
}
return demangled;
}
private static DemangledObject processItem(MDParsableItem item, String mangled,
String demangledSource) throws DemangledException {
DemangledObject result = null;
if (item instanceof MDObjectReserved) {
result = processObjectReserved((MDObjectReserved) item, mangled, demangledSource);
}
else if (item instanceof MDObjectCodeView codeView) {
result = processObjectCPP(codeView, mangled, demangledSource);
result.setSpecialPrefix(codeView.getPrefix());
}
else if (item instanceof MDObjectCPP objCpp) { // Base class of MDObjectBracket/MDObjectCodeView.
result = processObjectCPP(objCpp, mangled, demangledSource);
}
else if (item instanceof MDObjectC objC) {
result = processObjectC(objC, mangled, demangledSource);
}
else if (item instanceof MDDataType dataType) {
// TODO: how do we fix this? DemangledDataType extends DemangledType, but not
// DemangleObject...
throw new DemangledException("DemangledDataType instead of DemangledObject");
//result = processDataType(null, dataType, mangled, demangledSource);
// object = getDemangledDataType();
}
else if (item instanceof MDTemplateNameAndArguments templateNameAndArgs) {
result = processTemplate(templateNameAndArgs, mangled, demangledSource);
}
return result;
}
private static DemangledObject processObjectReserved(
MDObjectReserved objectReserved,
String mangled, String demangledSource) {
DemangledObject object = null;
if (objectReserved.getClass().equals(MDObjectReserved.class)) {
//Testing if the class is not a derived class of MDObjectReserved;
// In other words, is it exactly a MDObjectReserved?
// If so, then return null, which will allow it to get processed
// outside of the demangler.
return null;
}
if (objectReserved instanceof MDObjectBracket objectBracket) {
MDObjectCPP objectCPP = objectBracket.getObjectCPP();
object = processObjectCPP(objectCPP, mangled, demangledSource);
object.setSpecialPrefix(objectBracket.getPrefix());
}
//TODO: put other objectReserved derivative types here and return something that Ghidra
// can use.
else {
object =
new DemangledUnknown(mangled, demangledSource, objectReserved.toString());
}
return object;
}
private static DemangledObject processObjectC(MDObjectC objectC, String mangled,
String demangledSource) {
// 20240905: modification to MDObjectC to processing C-style mangling has been added.
// If null is returned here, then we have a standard variable.
DemangledFunction demangledFunction =
processObjectCFunction(objectC, mangled, demangledSource);
if (demangledFunction != null) {
return demangledFunction;
}
// We are returning null here because we do not want Ghidra to put up a plate
// comment for a standard C symbol.
// FUTURE WORK: After discussion, easiest way to deal with this for now (without
// exploding work into other demanglers) is to keep the "return null" for now.
// The problem is with the DemangledObject making a revision of the
// success/failure of demangling by doing a comparison of the input string to
// the output string in the applyTo() method. In a previous encoding, I moved
// this logic into other demanglers and set a flag in DemangledObject, that way
// my MDMangGhidra could set a flag to succeed when we have a C-language variable
// (vs. C++) where the input == output is valid. We didn't like this pattern.
// The better way forward, which will require digging into the other demanglers
// further (keeping this for future work), is to throw an exception on failure
// instead of returning null as well as pushing this success/failure logic
// upstream (where I was attempting to put it) and removing the input == output
// test from DemangledObject; an object is only returned upon success and no
// rescinding of the success determination is made later.
return null;
// Following is the code that we had originally intended to use.
// DemangledVariable variable = new DemangledVariable(objectC.toString());
// return variable;
}
private static DemangledFunction processObjectCFunction(MDObjectC objectC, String mangled,
String demangledSource) {
String callingConvention = objectC.getCallingConvention();
if (callingConvention == null) {
// null means it is a standard variable; not a function
return null;
}
DemangledFunction function =
new DemangledFunction(mangled, demangledSource, objectC.getName());
// Setting the signature SourceType to DEFAULT allows us to set the calling convention
// without changing or locking in parameters or return type.
function.setSignatureSourceType(SourceType.DEFAULT);
function.setCallingConvention(callingConvention);
return function;
}
private static DemangledObject processObjectCPP(MDObjectCPP objectCPP, String mangled,
String demangledSource) {
MDTypeInfo typeinfo = objectCPP.getTypeInfo();
DemangledObject result = null;
if (typeinfo != null) {
if (typeinfo instanceof MDVariableInfo) {
DemangledVariable variable;
MDVariableInfo variableInfo = (MDVariableInfo) typeinfo;
MDType mdtype = variableInfo.getMDType();
DemangledDataType dt =
processDataType(null, (MDDataType) mdtype, mangled, demangledSource);
if ("std::nullptr_t".equals(dt.getName())) {
variable = new DemangledVariable(mangled, demangledSource, "");
}
else {
variable =
new DemangledVariable(mangled, demangledSource, objectCPP.getName());
variable.setNamespace(
processNamespace(objectCPP.getQualification(), mangled, demangledSource));
}
variable.setDatatype(dt);
result = variable;
variable.setConst(variableInfo.isConst());
variable.setVolatile(variableInfo.isVolatile());
variable.setPointer64(variableInfo.isPointer64());
if (variableInfo.isRestrict()) {
variable.setRestrict();
}
if (variableInfo.isUnaligned()) {
variable.setUnaligned();
}
variable.setBasedName(variableInfo.getBasedName());
if (variableInfo.isMember()) {
variable.setMemberScope(variableInfo.getMemberScope());
}
}
else if (typeinfo instanceof MDFunctionInfo) {
if (typeinfo.getSpecialHandlingCode() == 'F') {
result = new DemangledUnknown(mangled, demangledSource, null);
}
else {
DemangledFunction function =
new DemangledFunction(mangled, demangledSource, objectCPP.getName());
function.setSignatureSourceType(SourceType.IMPORTED);
function.setNamespace(
processNamespace(objectCPP.getQualification(), mangled, demangledSource));
result = function;
processFunction((MDFunctionInfo) typeinfo, function, mangled,
demangledSource);
// Any other special values to be set?
if (typeinfo instanceof MDMemberFunctionInfo) {
if (typeinfo instanceof MDVCall) {
// Empty for now--placeholder for possible future logic.
}
else if (typeinfo instanceof MDVFAdjustor) {
// Empty for now--placeholder for possible future logic.
}
else if (typeinfo instanceof MDVtordisp) {
// Empty for now--placeholder for possible future logic.
}
else if (typeinfo instanceof MDVtordispex) {
// Empty for now--placeholder for possible future logic.
}
else {
// plain member function
}
}
else {
// global function
}
}
}
else if (typeinfo instanceof MDVxTable) { //Includes VFTable, VBTable, and RTTI4
MDVxTable vxtable = (MDVxTable) typeinfo;
DemangledVariable variable =
new DemangledVariable(mangled, demangledSource, objectCPP.getName());
variable.setNamespace(
processNamespace(objectCPP.getQualification(), mangled, demangledSource));
variable.setConst(vxtable.isConst());
variable.setVolatile(vxtable.isVolatile());
variable.setPointer64(vxtable.isPointer64());
result = variable;
// The following code would be an alternative, depending on whether we get
// customer complaints or other fall-out from having created a variable here.
//resultObject = new DemangledUnknown();
}
else if (typeinfo instanceof AbstractMDMetaClass) { //Includes all RTTI, except RTTI4
DemangledVariable variable =
new DemangledVariable(mangled, demangledSource, objectCPP.getName());
variable.setNamespace(
processNamespace(objectCPP.getQualification(), mangled, demangledSource));
result = variable;
// The following code would be an alternative, depending on whether we get
// customer complaints or other fall-out from having created a variable here.
//resultObject = new DemangledUnknown();
}
else if (typeinfo instanceof MDGuard) {
DemangledVariable variable =
new DemangledVariable(mangled, demangledSource, objectCPP.getName());
variable.setNamespace(
processNamespace(objectCPP.getQualification(), mangled, demangledSource));
result = variable;
// The following code would be an alternative, depending on whether we get
// customer complaints or other fall-out from having created a variable here.
//resultObject = new DemangledUnknown();
}
else {
// Any others (e.g., case '9')
DemangledVariable variable =
new DemangledVariable(mangled, demangledSource, objectCPP.getName());
variable.setNamespace(
processNamespace(objectCPP.getQualification(), mangled, demangledSource));
result = variable;
// The following code would be an alternative, depending on whether we get
// customer complaints or other fall-out from having created a variable here.
//resultObject = new DemangledUnknown();
}
if (typeinfo.isPrivate()) {
result.setVisibilty("private");
}
else if (typeinfo.isProtected()) {
result.setVisibilty("protected");
}
else if (typeinfo.isPublic()) {
result.setVisibilty("public");
}
result.setStatic(typeinfo.isStatic());
result.setVirtual(typeinfo.isVirtual());
result.setThunk(typeinfo.isThunk());
if (typeinfo.isExternC()) {
result.setSpecialPrefix("extern \"C\"");
}
}
else {
String baseName = objectCPP.getName();
if (objectCPP.isString()) {
MDString mstring = objectCPP.getMDString();
DemangledString demangledString =
new DemangledString(mangled, demangledSource, mstring.getName(),
mstring.toString(), mstring.getLength(), mstring.isUnicode());
result = demangledString;
}
else if (baseName.length() != 0) {
DemangledVariable variable;
variable = new DemangledVariable(mangled, demangledSource, baseName);
variable.setNamespace(
processNamespace(objectCPP.getQualification(), mangled, demangledSource));
result = variable;
}
}
return result;
// //Various RTTI types (MDType '8' or '9')
// DemangledVariable variable =
// new
// DemangledVariable(objectCPP.getQualifiedName().getBasicName().toString());
// variable.setNamespace(processNamespace(objectCPP.getQualifiedName()));
// return variable;
// TODO: fill in lots of object.____ items
// object.setVisibilty(typeinfo.g);
// object.setConst(isConst);
}
// I think that this is a kludge. The mapping of MDTemplateNameAndArguments
// doesn't match
// well to the current DemangledObject hierarchy.
private static DemangledVariable processTemplate(MDTemplateNameAndArguments template,
String mangled, String demangledSource) {
DemangledVariable variable =
new DemangledVariable(mangled, demangledSource, template.toString());
// NO NAMESPACE for high level template: variable.setNamespace(XXX);
// DemangledTemplate objectTemplate = new DemangledTemplate();
// DemangledDataType dataType = new DemangledDataType((String) null);
// MDTemplateArgumentsList args = template.getArgumentsList();
// if (args != null) {
// for (int index = 0; index < args.getNumArgs(); index++) {
// objectTemplate.addParameter(processDataType(null, (MDDataType)
// args.getArg(index)));
// }
// }
// dataType.setTemplate(objectTemplate);
// variable.setDatatype(dataType);
return variable;
}
private static DemangledFunction processFunction(MDFunctionInfo functionInfo,
DemangledFunction function, String mangled, String demangledSource) {
MDFunctionType functionType = (MDFunctionType) functionInfo.getMDType();
String convention = functionType.getCallingConvention().toString();
if ("__cdecl".equals(convention) && functionInfo.isMember() && !functionInfo.isStatic()) {
// TODO: ultimately the presence of a 'this' parareter will not be keyed
// to the calling convention, but for now we need to force it
convention = CompilerSpec.CALLING_CONVENTION_thiscall;
}
function.setCallingConvention(convention);
if (functionType.hasReturn() && functionType.getReturnType() != null) {
MDDataType retType = functionType.getReturnType();
if (!retType.toString().isEmpty()) {
function.setReturnType(processDataType(null, retType, mangled, demangledSource));
}
}
MDArgumentsList args = functionType.getArgumentsList();
if (functionType.hasArgs() && args != null) {
for (int index = 0; index < args.getNumArgs(); index++) {
function.addParameter(
new DemangledParameter(
processDataType(null, args.getArg(index), mangled, demangledSource)));
}
}
if (functionType.isTypeCast()) {
function.setTypeCast();
}
// function.setVirtual(functionType.isVirtual());
// function.setStatic(functionType.isStatic());
// if (functionType.isPrivate()) {
// function.setVisibilty("private");
// }
// else if (functionType.isProtected()) {
// function.setVisibilty("protected");
// }
// else if (functionType.isPublic()) {
// function.setVisibilty("public");
// }
// TODO: fix this kludge. Need to add appropriate suffixes to DemangledFunction (look
// at DemangledFunctionPointer?). Missing other possible suffixes from
// functionType.getCVMod().
// String suffix = "";
MDCVMod thisPointerCVMod = functionType.getThisPointerCVMod();
if (thisPointerCVMod != null) {
if (thisPointerCVMod.isConst()) {
function.setTrailingConst();
}
if (thisPointerCVMod.isVolatile()) {
function.setTrailingVolatile();
}
if (thisPointerCVMod.isPointer64()) {
function.setTrailingPointer64();
}
if (thisPointerCVMod.isRestricted()) {
function.setTrailingRestrict();
}
if (thisPointerCVMod.isUnaligned()) {
function.setTrailingUnaligned();
}
}
MDThrowAttribute ta = functionType.getThrowAttribute();
if (ta != null) {
function.setThrowAttribute(ta.toString());
}
// TODO: fill in lots of function.____ items
return function;
}
private static DemangledFunctionPointer processDemangledFunctionPointer(
MDPointerType pointerType, String mangled, String demangledSource) {
DemangledFunctionPointer functionPointer =
new DemangledFunctionPointer(mangled, demangledSource);
MDFunctionType functionType = (MDFunctionType) pointerType.getReferencedType();
functionPointer.setCallingConvention(functionType.getCallingConvention().toString());
functionPointer.setModifier(pointerType.getCVMod().toString());
if (functionType.hasReturn() && functionType.getReturnType() != null) {
functionPointer.setReturnType(
processDataType(null, functionType.getReturnType(), mangled, demangledSource));
}
MDArgumentsList args = functionType.getArgumentsList();
if (functionType.hasArgs() && args != null) {
for (int index = 0; index < args.getNumArgs(); index++) {
functionPointer.addParameter(
processDataType(null, args.getArg(index), mangled, demangledSource));
}
}
MDCVMod thisPointerCVMod = functionType.getThisPointerCVMod();
if (thisPointerCVMod != null) {
if (thisPointerCVMod.isConst()) {
functionPointer.setConst();
}
if (thisPointerCVMod.isVolatile()) {
functionPointer.setVolatile();
}
if (thisPointerCVMod.isPointer64()) {
functionPointer.setTrailingPointer64();
}
if (thisPointerCVMod.isRestricted()) {
functionPointer.setTrailingRestrict();
}
if (thisPointerCVMod.isUnaligned()) {
functionPointer.setTrailingUnaligned();
}
}
// TODO: fill in lots of functionPointer.____ items
return functionPointer;
}
private static DemangledFunctionReference processDemangledFunctionReference(
MDModifierType refType, String mangled, String demangledSource) {
if (!((refType instanceof MDReferenceType) ||
(refType instanceof MDDataRightReferenceType))) {
return null; // Not planning on anything else yet.
}
DemangledFunctionReference functionReference =
new DemangledFunctionReference(mangled, demangledSource);
MDFunctionType functionType = (MDFunctionType) refType.getReferencedType();
functionReference.setCallingConvention(functionType.getCallingConvention().toString());
functionReference.setModifier(refType.getCVMod().toString());
if (functionType.hasReturn() && functionType.getReturnType() != null) {
functionReference.setReturnType(
processDataType(null, functionType.getReturnType(), mangled, demangledSource));
}
MDArgumentsList args = functionType.getArgumentsList();
if (functionType.hasArgs() && args != null) {
for (int index = 0; index < args.getNumArgs(); index++) {
functionReference.addParameter(
processDataType(null, args.getArg(index), mangled, demangledSource));
}
}
// TODO: fill in lots of functionReference.____ items
return functionReference;
}
private static DemangledFunctionIndirect processDemangledFunctionIndirect(
MDFunctionIndirectType functionIndirectType, String mangled, String demangledSource) {
DemangledFunctionIndirect functionDefinition =
new DemangledFunctionIndirect(mangled, demangledSource);
MDFunctionType functionType = (MDFunctionType) functionIndirectType.getReferencedType();
functionDefinition.setCallingConvention(functionType.getCallingConvention().toString());
functionDefinition.setModifier(functionIndirectType.getCVMod().toString());
functionDefinition.incrementPointerLevels();
if (functionType.hasReturn() && functionType.getReturnType() != null) {
functionDefinition.setReturnType(
processDataType(null, functionType.getReturnType(), mangled, demangledSource));
}
MDArgumentsList args = functionType.getArgumentsList();
if (functionType.hasArgs() && args != null) {
for (int index = 0; index < args.getNumArgs(); index++) {
functionDefinition.addParameter(
processDataType(null, args.getArg(index), mangled, demangledSource));
}
}
// TODO: fill in lots of functionIndirect.____ items
return functionDefinition;
}
// The following is/might be a kludge: using DemangledFunctionIndirect to see if it will
// hold the things that we need; regardless, the follow-on use of the DemangledFunction
// indirect might be clouded between the real, two underlying types.
private static DemangledFunctionIndirect processDemangledFunctionQuestion(
MDModifierType modifierType, String mangled, String demangledSource) {
DemangledFunctionIndirect functionDefinition =
new DemangledFunctionIndirect(mangled, demangledSource);
MDFunctionType functionType = (MDFunctionType) modifierType.getReferencedType();
functionDefinition.setCallingConvention(functionType.getCallingConvention().toString());
functionDefinition.setModifier(modifierType.getCVMod().toString());
functionDefinition.incrementPointerLevels();
if (functionType.hasReturn() && functionType.getReturnType() != null) {
functionDefinition.setReturnType(
processDataType(null, functionType.getReturnType(), mangled, demangledSource));
}
MDArgumentsList args = functionType.getArgumentsList();
if (functionType.hasArgs() && args != null) {
for (int index = 0; index < args.getNumArgs(); index++) {
functionDefinition.addParameter(
processDataType(null, args.getArg(index), mangled, demangledSource));
}
}
// TODO: fill in lots of functionIndirect.____ items
return functionDefinition;
}
// Passing "DemangledDataType resultDataType" in is a kludge, as this is done so
// incrementPointerLevels() can be used, but doing this recursion like this loses all
// storageClass information from the various nested pointers and such. TODO: need to add
// a "pointer type" with a contained "referenced data type" to DemangledObject (perhaps
// PointerObject?)
private static DemangledDataType processDataType(DemangledDataType resultDataType,
MDDataType datatype, String mangled, String demangledSource) {
if (resultDataType == null) {
resultDataType =
new DemangledDataType(mangled, demangledSource, getDataTypeName(datatype));
}
if (datatype.isSpecifiedSigned()) {
// Returns true if default signed or specified signed. TODO: There is no place to
// capture default signed versus specified signed (i.e., there are three types of
// char: default signed, specified signed, and unsigned)
resultDataType.setSigned();
}
if (datatype.isUnsigned()) {
resultDataType.setUnsigned();
}
// Bunch of else-ifs for exclusive types
if (datatype instanceof MDModifierType) {
MDModifierType modifierType = (MDModifierType) datatype;
// if (modifierType.isBased()) {
// resultDataType.set___();
// modifierType.getCVMod().getBasedName();
// }
if (modifierType.isConst()) {
resultDataType.setConst();
}
if (modifierType.isVolatile()) {
resultDataType.setVolatile();
}
if (modifierType.isPointer64()) {
resultDataType.setPointer64();
}
if (modifierType.isRestrict()) {
resultDataType.setRestrict();
}
if (modifierType.isUnaligned()) {
resultDataType.setUnaligned();
}
resultDataType.setBasedName(modifierType.getBasedName());
// if (modifierType.isMember()) {
resultDataType.setMemberScope(modifierType.getMemberScope());
// }
// TODO: fix. Following is a kludge because DemangledObject has no DemangledReference
// with corresponding referencedType.
if (modifierType instanceof MDArrayBasicType) {
resultDataType.setArray(1);
if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
// MDType ref = modifierType.getReferencedType();
// TODO: A demangled function reference is needed here.
// DemangledFunction function = new
// DemangledFunction(objectCPP.getQualifiedName().getBasicName().toString());
// function.setNamespace(processNamespace(objectCPP.getQualifiedName()));
// //resultObject = function;
// return processFunction(ref, resultDataType);
}
else if (modifierType.getReferencedType() instanceof MDDataType) {
return processDataType(resultDataType,
(MDDataType) modifierType.getReferencedType(), mangled, demangledSource);
}
else {
// Empty for now--placeholder for possible future logic.
}
}
else if (modifierType instanceof MDPointerType) {
if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
// TODO---------what are we returning... need to work on called routine.
DemangledFunctionPointer fp =
processDemangledFunctionPointer((MDPointerType) modifierType, mangled,
demangledSource);
// TODO: fix. Following is a kludge because DemangledObject has no
// DemangledPointer with corresponding referencedType.
for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
fp.incrementPointerLevels();
}
if (resultDataType.isConst()) {
fp.setConst();
}
if (resultDataType.isVolatile()) {
fp.setVolatile();
}
if (resultDataType.isPointer64()) {
fp.setPointer64();
}
return fp;
}
// modifierType.getArrayString();
// resultDataType.setArray();
//Processing the referenced type (for Ghidra, and then setting attributes on it)
DemangledDataType newResult =
processDataType(resultDataType, (MDDataType) modifierType.getReferencedType(),
mangled, demangledSource);
newResult.incrementPointerLevels();
if (modifierType.getCVMod().isConst()) {
newResult.setConst();
}
if (modifierType.getCVMod().isVolatile()) {
newResult.setVolatile();
}
if (modifierType.getCVMod().isPointer64()) {
newResult.setPointer64();
}
return newResult;
}
// TODO: fix. Following is a kludge because DemangledObject has no
// DemangledReference
// with corresponding referencedType.
else if (modifierType instanceof MDReferenceType) {
// TODO---------what are we returning... need to work on called
// routine.
if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
DemangledFunctionReference fr =
processDemangledFunctionReference(modifierType, mangled, demangledSource);
// TODO: fix. Following is a kludge because DemangledObject has no
// DemangledPointer with corresponding referencedType.
for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
fr.incrementPointerLevels();
}
if (resultDataType.isConst()) {
fr.setConst();
}
if (resultDataType.isVolatile()) {
fr.setVolatile();
}
if (resultDataType.isPointer64()) {
fr.setPointer64();
}
return fr;
}
//Processing the referenced type (for Ghidra, and then setting attributes on it)
DemangledDataType newResult =
processDataType(resultDataType, (MDDataType) modifierType.getReferencedType(),
mangled, demangledSource);
newResult.setLValueReference();
if (modifierType.getCVMod().isConst()) {
newResult.setConst();
}
if (modifierType.getCVMod().isVolatile()) {
newResult.setVolatile();
}
if (modifierType.getCVMod().isPointer64()) {
newResult.setPointer64();
}
return newResult;
}
// TODO: fix. Following is a kludge because DemangledObject has no DemangledReference
// with corresponding referencedType.
else if (modifierType instanceof MDFunctionIndirectType) {
// TODO---------what are we returning... need to work on called routine.
DemangledFunctionIndirect fd =
processDemangledFunctionIndirect((MDFunctionIndirectType) modifierType, mangled,
demangledSource);
for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
fd.incrementPointerLevels();
}
if (resultDataType.isConst()) {
fd.setConst();
}
if (resultDataType.isVolatile()) {
fd.setVolatile();
}
if (resultDataType.isPointer64()) {
fd.setPointer64();
}
return fd;
}
else if (modifierType instanceof MDPointerRefDataType) {
resultDataType.setName(getDataTypeName(datatype));
// Not sure if this is the correct thing to do for MDPointerRefDataType, but we
// are just going to assign the referred-to type:
//Processing the referenced type (for Ghidra, and then setting attributes on it)
return processDataType(resultDataType,
(MDDataType) modifierType.getReferencedType(), mangled, demangledSource);
}
else if (modifierType instanceof MDDataReferenceType) {
// Not sure if this is the correct thing to do for MDDataReferenceType, but we
// are just going to assign the referred-to type:
//Processing the referenced type (for Ghidra, and then setting attributes on it)
processDataType(resultDataType, (MDDataType) modifierType.getReferencedType(),
mangled, demangledSource);
if (modifierType.getCVMod().isConst()) {
resultDataType.setConst();
}
if (modifierType.getCVMod().isVolatile()) {
resultDataType.setVolatile();
}
return resultDataType;
}
else if (modifierType instanceof MDDataRightReferenceType) {
if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
resultDataType.setName(getDataTypeName(datatype));
// TODO---------what are we returning... need to work on called routine.
DemangledFunctionReference fr =
processDemangledFunctionReference(modifierType, mangled, demangledSource);
// TODO: fix. Following is a kludge because DemangledObject has no
// DemangledPointer with corresponding referencedType.
for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
fr.incrementPointerLevels();
}
if (resultDataType.isConst()) {
fr.setConst();
}
if (resultDataType.isVolatile()) {
fr.setVolatile();
}
if (resultDataType.isPointer64()) {
fr.setPointer64();
}
return fr;
}
//Processing the referenced type (for Ghidra, and then setting attributes on it)
processDataType(resultDataType, (MDDataType) modifierType.getReferencedType(),
mangled, demangledSource);
resultDataType.setRValueReference();
if (modifierType.getCVMod().isConst()) {
resultDataType.setConst();
}
if (modifierType.getCVMod().isVolatile()) {
resultDataType.setVolatile();
}
if (modifierType.getCVMod().isPointer64()) {
resultDataType.setPointer64();
}
return resultDataType;
}
else {
// not pointer, reference, or array type
if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
// TODO---------what are we returning... need to work on called routine.
DemangledFunctionIndirect fx =
processDemangledFunctionQuestion(modifierType, mangled, demangledSource);
// TODO: fix. Following is a kludge because DemangledObject has no
// DemangledPointer with corresponding referencedType.
if (resultDataType.isConst()) {
fx.setConst();
}
if (resultDataType.isVolatile()) {
fx.setVolatile();
}
if (resultDataType.isPointer64()) {
fx.setPointer64();
}
return fx;
}
// resultDataType.incrementPointerLevels();//Not sure if we should do/use this.
DemangledDataType dataType =
processDataType(resultDataType, (MDDataType) modifierType.getReferencedType(),
mangled, demangledSource);
if (modifierType.getCVMod().isConst()) {
resultDataType.setConst();
}
if (modifierType.getCVMod().isVolatile()) {
resultDataType.setVolatile();
}
if (modifierType.getCVMod().isPointer64()) {
resultDataType.setPointer64();
}
return dataType;
}
}
else if (datatype instanceof MDComplexType) {
MDComplexType complexType = (MDComplexType) datatype;
// Hope this is correct... will return "class" or other
resultDataType.setName(complexType.getNamespace().getName());
// TODO: setNamespace() wants a "DemangledType" for a namespace.
// Two problems:
// 1) we don't have an appropriate method to use
// 2) not sure DemangledType is appropriate; in MDComplexType we have an
// MDQualification--not an MDQualifiedName
resultDataType.setNamespace(
processNamespace(complexType.getNamespace(), mangled, demangledSource));
// Bunch of else-ifs for exclusive types
if (datatype instanceof MDEnumType) {
resultDataType.setEnum();
// Put in underlying type (for sizing too).
MDEnumType enumType = (MDEnumType) datatype;
resultDataType.setEnumType(enumType.getUnderlyingFullTypeName());
}
else if (datatype instanceof MDClassType) {
resultDataType.setClass();
}
else if (datatype instanceof MDStructType) {
resultDataType.setStruct();
}
else if (datatype instanceof MDUnionType) {
resultDataType.setUnion();
}
else if (datatype instanceof MDCoclassType) {
resultDataType.setCoclass();
}
else if (datatype instanceof MDCointerfaceType) {
resultDataType.setCointerface();
}
}
else if (datatype instanceof MDReferenceType) {
resultDataType.setLValueReference();
}
else if (datatype instanceof MDArrayBasicType) {
resultDataType.setArray(1);
}
else if (datatype instanceof MDVarArgsType) {
resultDataType.setVarArgs();
}
else if (datatype instanceof MDArrayReferencedType arrRefType) {
return processDataType(resultDataType, arrRefType.getReferencedType(), mangled,
demangledSource);
}
else if (datatype instanceof MDStdNullPtrType) {
resultDataType.setName(datatype.toString());
}
else {
// MDDataType
// TODO MDW64Type needs repeated reference type parsing, just as modifier types need
// them.
resultDataType.setName(getDataTypeName(datatype));
}
// TODO: No place to indicate a general pointer--we can indicate Pointer64
// TODO: Not sure if anything fits this: resultDataType.setComplex();
// TODO: resultDataType.setTemplate(); //TODO: Not sure templates are data types
// according to how MSFT demangles them.
// TODO: resultDataType.setTemplate(null); //TODO: Not sure templates are data types
// according to how MSFT demangles them.
return resultDataType;
}
/**
* Returns either a formal type name or a representative type name to fill into a
* MangledDataType if the formal name is blank
* @return the name
*/
private static String getDataTypeName(MDDataType dataType) {
String name = dataType.getName();
if (!name.isBlank()) {
return name;
}
name = dataType.getTypeName();
if (!name.isBlank()) {
return name;
}
return dataType.toString();
}
}

View File

@ -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);
}
}

View File

@ -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
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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");

View File

@ -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());

View File

@ -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) {

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -15,918 +15,64 @@
*/
package mdemangler;
import java.util.Iterator;
import ghidra.app.util.demangler.*;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.symbol.SourceType;
import mdemangler.datatype.MDDataType;
import mdemangler.datatype.MDVarArgsType;
import mdemangler.datatype.complex.*;
import mdemangler.datatype.extended.MDArrayReferencedType;
import mdemangler.datatype.modifier.*;
import mdemangler.functiontype.*;
import mdemangler.naming.*;
import mdemangler.object.*;
import mdemangler.template.MDTemplateNameAndArguments;
import mdemangler.typeinfo.*;
/**
* A new built-from-scratch class for demangling debug symbols created using
* Microsoft Visual Studio.
* <p>
* Note: the processing of {@link MDParsableItem} that was in this class was moved to a
* package-projected utility class of the MicrosoftDemangler. Ghidra users should defer to
* using the MicrosoftDemangler.
* <p>
* This {@link MDMangGhidra} class might be removed in the future, with deferred use to MDMang.
*/
public class MDMangGhidra extends MDMang {
private DemangledObject objectResult;
private DemangledDataType dataTypeResult;
private boolean demangleOnlyKnownPatterns = false;
private String mangledSource;
private String demangledSource;
//==============================================================================================
// Control
public DemangledObject getObject() {
return objectResult;
/**
* Controls whether a symbol is skipped (returns null) if it doesn't match a known mangling
* pattern, which is generally the start pattern of a symbol. Default is {@code false}
* @param demangleOnlyKnownPatternsArg {@code true} to skip a symbol that doesn't match a
* known pattern
*/
public void setDemangleOnlyKnownPatterns(boolean demangleOnlyKnownPatternsArg) {
demangleOnlyKnownPatterns = demangleOnlyKnownPatternsArg;
}
public DemangledDataType getDataType() {
return dataTypeResult;
/**
* Returns {@code true} if the process will skip a symbol that doesn't match a known pattern
* @return {@code true} if a symbol that doesn't a known pattern will be skipped
*/
public boolean demangleOnlyKnownPatterns() {
return demangleOnlyKnownPatterns;
}
public MDParsableItem demangle(String mangledArg, boolean errorOnRemainingChars,
boolean demangleOnlyKnownPatterns) throws MDException {
// TODO: Could possibly just ignore "demangleOnlyKnownpatterns"
//==============================================================================================
@Override
public MDParsableItem demangle() throws MDException {
if (demangleOnlyKnownPatterns) {
if (!(mangledArg.startsWith("?") || mangledArg.startsWith(".") ||
mangledArg.startsWith("__") || (mangledArg.charAt(0) < 'a') ||
(mangledArg.charAt(0) > 'z') || (mangledArg.charAt(0) < 'A') ||
(mangledArg.charAt(0) > 'Z'))) {
if (!(mangled.startsWith("?") || mangled.startsWith(".") || mangled.startsWith("_") ||
(mangled.charAt(0) < 'a') ||
(mangled.charAt(0) >= 'a') && (mangled.charAt(0) <= 'z') ||
(mangled.charAt(0) >= 'A') && (mangled.charAt(0) <= 'Z'))) {
return null;
}
}
return demangle(mangledArg, errorOnRemainingChars);
}
@Override
public MDParsableItem demangle(String mangledArg, boolean errorOnRemainingChars)
throws MDException {
this.mangledSource = mangledArg;
MDParsableItem returnedItem = super.demangle(mangledArg, true);
this.demangledSource = item.toString();
objectResult = processItem();
MDParsableItem returnedItem = super.demangle();
// TODO: Investigate... seems that mangledSource should be eliminated throughout and
// that mangled should be used instead.
return returnedItem;
}
@Override
public MDDataType demangleType(String mangledArg, boolean errorOnRemainingChars)
throws MDException {
this.mangledSource = mangledArg;
MDDataType returnedType = super.demangleType(mangledArg, errorOnRemainingChars);
this.demangledSource = returnedType.toString();
dataTypeResult = processDataType(null, returnedType);
public MDDataType demangleType() throws MDException {
MDDataType returnedType = super.demangleType();
return returnedType;
}
public Demangled processNamespace(MDQualifiedName qualifiedName) {
return processNamespace(qualifiedName.getQualification());
}
private Demangled processNamespace(MDQualification qualification) {
Iterator<MDQualifier> it = qualification.iterator();
if (!it.hasNext()) {
return null;
}
MDQualifier qual = it.next();
Demangled type = getDemangled(qual);
Demangled current = type;
// Note that qualifiers come in reverse order, from most refined to root being the last
while (it.hasNext()) {
qual = it.next();
Demangled parent = getDemangled(qual);
current.setNamespace(parent);
current = parent;
}
return type;
}
private Demangled getDemangled(MDQualifier qual) {
Demangled demangled;
if (qual.isNested()) {
String subMangled = qual.getNested().getMangled();
MDObjectCPP obj = qual.getNested().getNestedObject();
MDTypeInfo typeInfo = obj.getTypeInfo();
MDType type = typeInfo.getMDType();
if (type instanceof MDDataType dt) {
demangled = new DemangledType(subMangled, qual.toString(), qual.toString());
}
else if (type instanceof MDFunctionType ft) {
// We currently cannot handle functions as part of a namespace, so we will just
// treat the demangled function namespace string as a plain namespace.
//demangled = new DemangledFunction(subMangled, qual.toString(), qual.toString());
demangled =
new DemangledNamespaceNode(subMangled, qual.toString(), qual.toString());
}
else {
demangled =
new DemangledNamespaceNode(subMangled, qual.toString(), qual.toString());
}
}
else if (qual.isAnon()) {
// Instead of using the standard qual.toString() method, which returns
// "`anonymous namespace'" for anonymous qualifiers, we use qual.getAnonymousName()
// which will have the underlying anonymous name of the form "A0xfedcba98" to create
// a standardized anonymous name that is distinguishable from other anonymous names.
// The standardized name comes from createStandardAnonymousNamespaceNode(). This
// is especially important when there are sibling anonymous names.
String anon = MDMangUtils.createStandardAnonymousNamespaceNode(qual.getAnonymousName());
demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), anon);
}
else if (qual.isInterface()) {
// TODO: need to do better; setting namespace for now
demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), qual.toString());
}
else if (qual.isNameQ()) {
// TODO: need to do better; setting namespace for now, as it looks like interface
demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), qual.toString());
}
else if (qual.isNameC()) {
// TODO: need to do better; setting type for now, but not processed yet and not sure
// what it is
demangled = new DemangledType(mangledSource, qual.toString(), qual.toString());
}
else if (qual.isLocalNamespace()) {
String local =
MDMangUtils.createStandardLocalNamespaceNode(qual.getLocalNamespaceNumber());
demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), local);
}
else {
demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), qual.toString());
}
return demangled;
}
private DemangledObject processItem() {
objectResult = null;
if (item instanceof MDObjectReserved) {
objectResult = processObjectReserved((MDObjectReserved) item);
}
else if (item instanceof MDObjectCodeView codeView) {
objectResult = processObjectCPP(codeView);
objectResult.setSpecialPrefix(codeView.getPrefix());
}
else if (item instanceof MDObjectCPP objCpp) { // Base class of MDObjectBracket/MDObjectCodeView.
objectResult = processObjectCPP(objCpp);
}
else if (item instanceof MDObjectC objC) {
objectResult = processObjectC(objC);
}
else if (item instanceof MDDataType dataType) {
// TODO: how do we fix this? DemangledDataType extends DemangledType, but not
// DemangleObject...
dataTypeResult = processDataType(null, dataType);
// object = getDemangledDataType();
}
else if (item instanceof MDTemplateNameAndArguments templateNameAndArgs) {
objectResult = processTemplate(templateNameAndArgs);
}
return objectResult;
}
private DemangledObject processObjectReserved(MDObjectReserved objectReserved) {
DemangledObject object = null;
if (objectReserved.getClass().equals(MDObjectReserved.class)) {
//Testing if the class is not a derived class of MDObjectReserved;
// In other words, is it exactly a MDObjectReserved?
// If so, then return null, which will allow it to get processed
// outside of the demangler.
return null;
}
if (objectReserved instanceof MDObjectBracket) {
MDObjectBracket objectBracket = (MDObjectBracket) objectReserved;
MDObjectCPP objectCPP = objectBracket.getObjectCPP();
object = processObjectCPP(objectCPP);
object.setSpecialPrefix(((MDObjectBracket) item).getPrefix());
}
//TODO: put other objectReserved derivative types here and return something that Ghidra
// can use.
else {
object =
new DemangledUnknown(mangledSource, demangledSource, objectReserved.toString());
}
return object;
}
private DemangledObject processObjectC(MDObjectC objectC) {
// We are returning null here because we do not want Ghidra to put up a plate
// comment for a standard C symbol.
// FUTURE WORK: After discussion, easiest way to deal with this for now (without
// exploding work into other demanglers) is to keep the "return null" for now.
// The problem is with the DemangledObject making a revision of the
// success/failure of demangling by doing a comparison of the input string to
// the output string in the applyTo() method. In a previous encoding, I moved
// this logic into other demanglers and set a flag in DemangledObject, that way
// my MDMangGhidra could set a flag to succeed when we have a C-language variable
// (vs. C++) where the input == output is valid. We didn't like this pattern.
// The better way forward, which will require digging into the other demanglers
// further (keeping this for future work), is to throw an exception on failure
// instead of returning null as well as pushing this success/failure logic
// upstream (where I was attempting to put it) and removing the input == output
// test from DemangledObject; an object is only returned upon success and no
// rescinding of the success determination is made later.
return null;
// Following is the code that we had originally intended to use.
// DemangledVariable variable = new DemangledVariable(objectC.toString());
// return variable;
}
private DemangledObject processObjectCPP(MDObjectCPP objectCPP) {
MDTypeInfo typeinfo = objectCPP.getTypeInfo();
DemangledObject resultObject = null;
if (typeinfo != null) {
if (typeinfo instanceof MDVariableInfo) {
DemangledVariable variable;
MDVariableInfo variableInfo = (MDVariableInfo) typeinfo;
MDType mdtype = variableInfo.getMDType();
DemangledDataType dt = processDataType(null, (MDDataType) mdtype);
if ("std::nullptr_t".equals(dt.getName())) {
variable = new DemangledVariable(mangledSource, demangledSource, "");
}
else {
variable =
new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
variable.setNamespace(processNamespace(objectCPP.getQualification()));
}
variable.setDatatype(dt);
resultObject = variable;
variable.setConst(variableInfo.isConst());
variable.setVolatile(variableInfo.isVolatile());
variable.setPointer64(variableInfo.isPointer64());
if (variableInfo.isRestrict()) {
variable.setRestrict();
}
if (variableInfo.isUnaligned()) {
variable.setUnaligned();
}
variable.setBasedName(variableInfo.getBasedName());
if (variableInfo.isMember()) {
variable.setMemberScope(variableInfo.getMemberScope());
}
}
else if (typeinfo instanceof MDFunctionInfo) {
if (typeinfo.getSpecialHandlingCode() == 'F') {
resultObject = new DemangledUnknown(mangledSource, demangledSource, null);
}
else {
DemangledFunction function =
new DemangledFunction(mangledSource, demangledSource, objectCPP.getName());
function.setSignatureSourceType(SourceType.IMPORTED);
function.setNamespace(processNamespace(objectCPP.getQualification()));
resultObject = function;
objectResult = processFunction((MDFunctionInfo) typeinfo, function);
// Any other special values to be set?
if (typeinfo instanceof MDMemberFunctionInfo) {
if (typeinfo instanceof MDVCall) {
// Empty for now--placeholder for possible future logic.
}
else if (typeinfo instanceof MDVFAdjustor) {
// Empty for now--placeholder for possible future logic.
}
else if (typeinfo instanceof MDVtordisp) {
// Empty for now--placeholder for possible future logic.
}
else if (typeinfo instanceof MDVtordispex) {
// Empty for now--placeholder for possible future logic.
}
else {
// plain member function
}
}
else {
// global function
}
}
}
else if (typeinfo instanceof MDVxTable) { //Includes VFTable, VBTable, and RTTI4
MDVxTable vxtable = (MDVxTable) typeinfo;
DemangledVariable variable =
new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
variable.setNamespace(processNamespace(objectCPP.getQualification()));
variable.setConst(vxtable.isConst());
variable.setVolatile(vxtable.isVolatile());
variable.setPointer64(vxtable.isPointer64());
resultObject = variable;
// The following code would be an alternative, depending on whether we get
// customer complaints or other fall-out from having created a variable here.
//resultObject = new DemangledUnknown();
}
else if (typeinfo instanceof AbstractMDMetaClass) { //Includes all RTTI, except RTTI4
DemangledVariable variable =
new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
variable.setNamespace(processNamespace(objectCPP.getQualification()));
resultObject = variable;
// The following code would be an alternative, depending on whether we get
// customer complaints or other fall-out from having created a variable here.
//resultObject = new DemangledUnknown();
}
else if (typeinfo instanceof MDGuard) {
DemangledVariable variable =
new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
variable.setNamespace(processNamespace(objectCPP.getQualification()));
resultObject = variable;
// The following code would be an alternative, depending on whether we get
// customer complaints or other fall-out from having created a variable here.
//resultObject = new DemangledUnknown();
}
else {
// Any others (e.g., case '9')
DemangledVariable variable =
new DemangledVariable(mangledSource, demangledSource, objectCPP.getName());
variable.setNamespace(processNamespace(objectCPP.getQualification()));
resultObject = variable;
// The following code would be an alternative, depending on whether we get
// customer complaints or other fall-out from having created a variable here.
//resultObject = new DemangledUnknown();
}
if (typeinfo.isPrivate()) {
resultObject.setVisibilty("private");
}
else if (typeinfo.isProtected()) {
resultObject.setVisibilty("protected");
}
else if (typeinfo.isPublic()) {
resultObject.setVisibilty("public");
}
resultObject.setStatic(typeinfo.isStatic());
resultObject.setVirtual(typeinfo.isVirtual());
resultObject.setThunk(typeinfo.isThunk());
if (typeinfo.isExternC()) {
resultObject.setSpecialPrefix("extern \"C\"");
}
}
else {
String baseName = objectCPP.getName();
if (objectCPP.isString()) {
MDString mstring = objectCPP.getMDString();
DemangledString demangledString =
new DemangledString(mangledSource, demangledSource, mstring.getName(),
mstring.toString(), mstring.getLength(), mstring.isUnicode());
resultObject = demangledString;
}
else if (baseName.length() != 0) {
DemangledVariable variable;
variable = new DemangledVariable(mangledSource, demangledSource, baseName);
variable.setNamespace(processNamespace(objectCPP.getQualification()));
resultObject = variable;
}
}
return resultObject;
// //Various RTTI types (MDType '8' or '9')
// DemangledVariable variable =
// new
// DemangledVariable(objectCPP.getQualifiedName().getBasicName().toString());
// variable.setNamespace(processNamespace(objectCPP.getQualifiedName()));
// return variable;
// TODO: fill in lots of object.____ items
// object.setVisibilty(typeinfo.g);
// object.setConst(isConst);
}
// I think that this is a kludge. The mapping of MDTemplateNameAndArguments
// doesn't match
// well to the current DemangledObject hierarchy.
private DemangledVariable processTemplate(MDTemplateNameAndArguments template) {
DemangledVariable variable =
new DemangledVariable(mangledSource, demangledSource, template.toString());
// NO NAMESPACE for high level template: variable.setNamespace(XXX);
// DemangledTemplate objectTemplate = new DemangledTemplate();
// DemangledDataType dataType = new DemangledDataType((String) null);
// MDTemplateArgumentsList args = template.getArgumentsList();
// if (args != null) {
// for (int index = 0; index < args.getNumArgs(); index++) {
// objectTemplate.addParameter(processDataType(null, (MDDataType)
// args.getArg(index)));
// }
// }
// dataType.setTemplate(objectTemplate);
// variable.setDatatype(dataType);
return variable;
}
private DemangledFunction processFunction(MDFunctionInfo functionInfo,
DemangledFunction function) {
MDFunctionType functionType = (MDFunctionType) functionInfo.getMDType();
String convention = functionType.getCallingConvention().toString();
if ("__cdecl".equals(convention) && functionInfo.isMember() && !functionInfo.isStatic()) {
// TODO: ultimately the presence of a 'this' parareter will not be keyed
// to the calling convention, but for now we need to force it
convention = CompilerSpec.CALLING_CONVENTION_thiscall;
}
function.setCallingConvention(convention);
if (functionType.hasReturn() && functionType.getReturnType() != null) {
MDDataType retType = functionType.getReturnType();
if (!retType.toString().isEmpty()) {
function.setReturnType(processDataType(null, retType));
}
}
MDArgumentsList args = functionType.getArgumentsList();
if (functionType.hasArgs() && args != null) {
for (int index = 0; index < args.getNumArgs(); index++) {
function.addParameter(
new DemangledParameter(processDataType(null, args.getArg(index))));
}
}
if (functionType.isTypeCast()) {
function.setTypeCast();
}
// function.setVirtual(functionType.isVirtual());
// function.setStatic(functionType.isStatic());
// if (functionType.isPrivate()) {
// function.setVisibilty("private");
// }
// else if (functionType.isProtected()) {
// function.setVisibilty("protected");
// }
// else if (functionType.isPublic()) {
// function.setVisibilty("public");
// }
// TODO: fix this kludge. Need to add appropriate suffixes to DemangledFunction (look
// at DemangledFunctionPointer?). Missing other possible suffixes from
// functionType.getCVMod().
// String suffix = "";
MDCVMod thisPointerCVMod = functionType.getThisPointerCVMod();
if (thisPointerCVMod != null) {
if (thisPointerCVMod.isConst()) {
function.setTrailingConst();
}
if (thisPointerCVMod.isVolatile()) {
function.setTrailingVolatile();
}
if (thisPointerCVMod.isPointer64()) {
function.setTrailingPointer64();
}
if (thisPointerCVMod.isRestricted()) {
function.setTrailingRestrict();
}
if (thisPointerCVMod.isUnaligned()) {
function.setTrailingUnaligned();
}
}
MDThrowAttribute ta = functionType.getThrowAttribute();
if (ta != null) {
function.setThrowAttribute(ta.toString());
}
// TODO: fill in lots of function.____ items
return function;
}
private DemangledFunctionPointer processDemangledFunctionPointer(MDPointerType pointerType) {
DemangledFunctionPointer functionPointer =
new DemangledFunctionPointer(mangledSource, demangledSource);
MDFunctionType functionType = (MDFunctionType) pointerType.getReferencedType();
functionPointer.setCallingConvention(functionType.getCallingConvention().toString());
functionPointer.setModifier(pointerType.getCVMod().toString());
if (functionType.hasReturn() && functionType.getReturnType() != null) {
functionPointer.setReturnType(processDataType(null, functionType.getReturnType()));
}
MDArgumentsList args = functionType.getArgumentsList();
if (functionType.hasArgs() && args != null) {
for (int index = 0; index < args.getNumArgs(); index++) {
functionPointer.addParameter(processDataType(null, args.getArg(index)));
}
}
MDCVMod thisPointerCVMod = functionType.getThisPointerCVMod();
if (thisPointerCVMod != null) {
if (thisPointerCVMod.isConst()) {
functionPointer.setConst();
}
if (thisPointerCVMod.isVolatile()) {
functionPointer.setVolatile();
}
if (thisPointerCVMod.isPointer64()) {
functionPointer.setTrailingPointer64();
}
if (thisPointerCVMod.isRestricted()) {
functionPointer.setTrailingRestrict();
}
if (thisPointerCVMod.isUnaligned()) {
functionPointer.setTrailingUnaligned();
}
}
// TODO: fill in lots of functionPointer.____ items
return functionPointer;
}
private DemangledFunctionReference processDemangledFunctionReference(MDModifierType refType) {
if (!((refType instanceof MDReferenceType) ||
(refType instanceof MDDataRightReferenceType))) {
return null; // Not planning on anything else yet.
}
DemangledFunctionReference functionReference =
new DemangledFunctionReference(mangledSource, demangledSource);
MDFunctionType functionType = (MDFunctionType) refType.getReferencedType();
functionReference.setCallingConvention(functionType.getCallingConvention().toString());
functionReference.setModifier(refType.getCVMod().toString());
if (functionType.hasReturn() && functionType.getReturnType() != null) {
functionReference.setReturnType(processDataType(null, functionType.getReturnType()));
}
MDArgumentsList args = functionType.getArgumentsList();
if (functionType.hasArgs() && args != null) {
for (int index = 0; index < args.getNumArgs(); index++) {
functionReference.addParameter(processDataType(null, args.getArg(index)));
}
}
// TODO: fill in lots of functionReference.____ items
return functionReference;
}
private DemangledFunctionIndirect processDemangledFunctionIndirect(
MDFunctionIndirectType functionIndirectType) {
DemangledFunctionIndirect functionDefinition =
new DemangledFunctionIndirect(mangledSource, demangledSource);
MDFunctionType functionType = (MDFunctionType) functionIndirectType.getReferencedType();
functionDefinition.setCallingConvention(functionType.getCallingConvention().toString());
functionDefinition.setModifier(functionIndirectType.getCVMod().toString());
functionDefinition.incrementPointerLevels();
if (functionType.hasReturn() && functionType.getReturnType() != null) {
functionDefinition.setReturnType(processDataType(null, functionType.getReturnType()));
}
MDArgumentsList args = functionType.getArgumentsList();
if (functionType.hasArgs() && args != null) {
for (int index = 0; index < args.getNumArgs(); index++) {
functionDefinition.addParameter(processDataType(null, args.getArg(index)));
}
}
// TODO: fill in lots of functionIndirect.____ items
return functionDefinition;
}
// The following is/might be a kludge: using DemangledFunctionIndirect to see if it will
// hold the things that we need; regardless, the follow-on use of the DemangledFunction
// indirect might be clouded between the real, two underlying types.
private DemangledFunctionIndirect processDemangledFunctionQuestion(
MDModifierType modifierType) {
DemangledFunctionIndirect functionDefinition =
new DemangledFunctionIndirect(mangledSource, demangledSource);
MDFunctionType functionType = (MDFunctionType) modifierType.getReferencedType();
functionDefinition.setCallingConvention(functionType.getCallingConvention().toString());
functionDefinition.setModifier(modifierType.getCVMod().toString());
functionDefinition.incrementPointerLevels();
if (functionType.hasReturn() && functionType.getReturnType() != null) {
functionDefinition.setReturnType(processDataType(null, functionType.getReturnType()));
}
MDArgumentsList args = functionType.getArgumentsList();
if (functionType.hasArgs() && args != null) {
for (int index = 0; index < args.getNumArgs(); index++) {
functionDefinition.addParameter(processDataType(null, args.getArg(index)));
}
}
// TODO: fill in lots of functionIndirect.____ items
return functionDefinition;
}
// Passing "DemangledDataType resultDataType" in is a kludge, as this is done so
// incrementPointerLevels() can be used, but doing this recursion like this loses all
// storageClass information from the various nested pointers and such. TODO: need to add
// a "pointer type" with a contained "referenced data type" to DemangledObject (perhaps
// PointerObject?)
private DemangledDataType processDataType(DemangledDataType resultDataType,
MDDataType datatype) {
if (resultDataType == null) {
resultDataType =
new DemangledDataType(mangledSource, demangledSource, getDataTypeName(datatype));
}
if (datatype.isSpecifiedSigned()) {
// Returns true if default signed or specified signed. TODO: There is no place to
// capture default signed versus specified signed (i.e., there are three types of
// char: default signed, specified signed, and unsigned)
resultDataType.setSigned();
}
if (datatype.isUnsigned()) {
resultDataType.setUnsigned();
}
// Bunch of else-ifs for exclusive types
if (datatype instanceof MDModifierType) {
MDModifierType modifierType = (MDModifierType) datatype;
// if (modifierType.isBased()) {
// resultDataType.set___();
// modifierType.getCVMod().getBasedName();
// }
if (modifierType.isConst()) {
resultDataType.setConst();
}
if (modifierType.isVolatile()) {
resultDataType.setVolatile();
}
if (modifierType.isPointer64()) {
resultDataType.setPointer64();
}
if (modifierType.isRestrict()) {
resultDataType.setRestrict();
}
if (modifierType.isUnaligned()) {
resultDataType.setUnaligned();
}
resultDataType.setBasedName(modifierType.getBasedName());
// if (modifierType.isMember()) {
resultDataType.setMemberScope(modifierType.getMemberScope());
// }
// TODO: fix. Following is a kludge because DemangledObject has no DemangledReference
// with corresponding referencedType.
if (modifierType instanceof MDArrayBasicType) {
resultDataType.setArray(1);
if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
// MDType ref = modifierType.getReferencedType();
// TODO: A demangled function reference is needed here.
// DemangledFunction function = new
// DemangledFunction(objectCPP.getQualifiedName().getBasicName().toString());
// function.setNamespace(processNamespace(objectCPP.getQualifiedName()));
// //resultObject = function;
// return processFunction(ref, resultDataType);
}
else if (modifierType.getReferencedType() instanceof MDDataType) {
return processDataType(resultDataType,
(MDDataType) modifierType.getReferencedType());
}
else {
// Empty for now--placeholder for possible future logic.
}
}
else if (modifierType instanceof MDPointerType) {
if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
// TODO---------what are we returning... need to work on called routine.
DemangledFunctionPointer fp =
processDemangledFunctionPointer((MDPointerType) modifierType);
// TODO: fix. Following is a kludge because DemangledObject has no
// DemangledPointer with corresponding referencedType.
for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
fp.incrementPointerLevels();
}
if (resultDataType.isConst()) {
fp.setConst();
}
if (resultDataType.isVolatile()) {
fp.setVolatile();
}
if (resultDataType.isPointer64()) {
fp.setPointer64();
}
return fp;
}
// modifierType.getArrayString();
// resultDataType.setArray();
//Processing the referenced type (for Ghidra, and then setting attributes on it)
DemangledDataType newResult =
processDataType(resultDataType, (MDDataType) modifierType.getReferencedType());
newResult.incrementPointerLevels();
if (modifierType.getCVMod().isConst()) {
newResult.setConst();
}
if (modifierType.getCVMod().isVolatile()) {
newResult.setVolatile();
}
if (modifierType.getCVMod().isPointer64()) {
newResult.setPointer64();
}
return newResult;
}
// TODO: fix. Following is a kludge because DemangledObject has no
// DemangledReference
// with corresponding referencedType.
else if (modifierType instanceof MDReferenceType) {
// TODO---------what are we returning... need to work on called
// routine.
if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
DemangledFunctionReference fr = processDemangledFunctionReference(modifierType);
// TODO: fix. Following is a kludge because DemangledObject has no
// DemangledPointer with corresponding referencedType.
for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
fr.incrementPointerLevels();
}
if (resultDataType.isConst()) {
fr.setConst();
}
if (resultDataType.isVolatile()) {
fr.setVolatile();
}
if (resultDataType.isPointer64()) {
fr.setPointer64();
}
return fr;
}
//Processing the referenced type (for Ghidra, and then setting attributes on it)
DemangledDataType newResult =
processDataType(resultDataType, (MDDataType) modifierType.getReferencedType());
newResult.setLValueReference();
if (modifierType.getCVMod().isConst()) {
newResult.setConst();
}
if (modifierType.getCVMod().isVolatile()) {
newResult.setVolatile();
}
if (modifierType.getCVMod().isPointer64()) {
newResult.setPointer64();
}
return newResult;
}
// TODO: fix. Following is a kludge because DemangledObject has no DemangledReference
// with corresponding referencedType.
else if (modifierType instanceof MDFunctionIndirectType) {
// TODO---------what are we returning... need to work on called routine.
DemangledFunctionIndirect fd =
processDemangledFunctionIndirect((MDFunctionIndirectType) modifierType);
for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
fd.incrementPointerLevels();
}
if (resultDataType.isConst()) {
fd.setConst();
}
if (resultDataType.isVolatile()) {
fd.setVolatile();
}
if (resultDataType.isPointer64()) {
fd.setPointer64();
}
return fd;
}
else if (modifierType instanceof MDPointerRefDataType) {
resultDataType.setName(getDataTypeName(datatype));
// Not sure if this is the correct thing to do for MDPointerRefDataType, but we
// are just going to assign the referred-to type:
//Processing the referenced type (for Ghidra, and then setting attributes on it)
return processDataType(resultDataType,
(MDDataType) modifierType.getReferencedType());
}
else if (modifierType instanceof MDDataReferenceType) {
// Not sure if this is the correct thing to do for MDDataReferenceType, but we
// are just going to assign the referred-to type:
//Processing the referenced type (for Ghidra, and then setting attributes on it)
processDataType(resultDataType, (MDDataType) modifierType.getReferencedType());
if (modifierType.getCVMod().isConst()) {
resultDataType.setConst();
}
if (modifierType.getCVMod().isVolatile()) {
resultDataType.setVolatile();
}
return resultDataType;
}
else if (modifierType instanceof MDDataRightReferenceType) {
if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
resultDataType.setName(getDataTypeName(datatype));
// TODO---------what are we returning... need to work on called routine.
DemangledFunctionReference fr = processDemangledFunctionReference(modifierType);
// TODO: fix. Following is a kludge because DemangledObject has no
// DemangledPointer with corresponding referencedType.
for (int i = 0; i < resultDataType.getPointerLevels(); i++) {
fr.incrementPointerLevels();
}
if (resultDataType.isConst()) {
fr.setConst();
}
if (resultDataType.isVolatile()) {
fr.setVolatile();
}
if (resultDataType.isPointer64()) {
fr.setPointer64();
}
return fr;
}
//Processing the referenced type (for Ghidra, and then setting attributes on it)
processDataType(resultDataType, (MDDataType) modifierType.getReferencedType());
resultDataType.setRValueReference();
if (modifierType.getCVMod().isConst()) {
resultDataType.setConst();
}
if (modifierType.getCVMod().isVolatile()) {
resultDataType.setVolatile();
}
if (modifierType.getCVMod().isPointer64()) {
resultDataType.setPointer64();
}
return resultDataType;
}
else {
// not pointer, reference, or array type
if ((modifierType.getReferencedType() instanceof MDFunctionType)) {
// TODO---------what are we returning... need to work on called routine.
DemangledFunctionIndirect fx = processDemangledFunctionQuestion(modifierType);
// TODO: fix. Following is a kludge because DemangledObject has no
// DemangledPointer with corresponding referencedType.
if (resultDataType.isConst()) {
fx.setConst();
}
if (resultDataType.isVolatile()) {
fx.setVolatile();
}
if (resultDataType.isPointer64()) {
fx.setPointer64();
}
return fx;
}
// resultDataType.incrementPointerLevels();//Not sure if we should do/use this.
DemangledDataType dataType =
processDataType(resultDataType, (MDDataType) modifierType.getReferencedType());
if (modifierType.getCVMod().isConst()) {
resultDataType.setConst();
}
if (modifierType.getCVMod().isVolatile()) {
resultDataType.setVolatile();
}
if (modifierType.getCVMod().isPointer64()) {
resultDataType.setPointer64();
}
return dataType;
}
}
else if (datatype instanceof MDComplexType) {
MDComplexType complexType = (MDComplexType) datatype;
// Hope this is correct... will return "class" or other
resultDataType.setName(complexType.getNamespace().getName());
// TODO: setNamespace() wants a "DemangledType" for a namespace.
// Two problems:
// 1) we don't have an appropriate method to use
// 2) not sure DemangledType is appropriate; in MDComplexType we have an
// MDQualification--not an MDQualifiedName
resultDataType.setNamespace(processNamespace(complexType.getNamespace()));
// Bunch of else-ifs for exclusive types
if (datatype instanceof MDEnumType) {
resultDataType.setEnum();
// Put in underlying type (for sizing too).
MDEnumType enumType = (MDEnumType) datatype;
resultDataType.setEnumType(enumType.getUnderlyingFullTypeName());
}
else if (datatype instanceof MDClassType) {
resultDataType.setClass();
}
else if (datatype instanceof MDStructType) {
resultDataType.setStruct();
}
else if (datatype instanceof MDUnionType) {
resultDataType.setUnion();
}
else if (datatype instanceof MDCoclassType) {
resultDataType.setCoclass();
}
else if (datatype instanceof MDCointerfaceType) {
resultDataType.setCointerface();
}
}
else if (datatype instanceof MDReferenceType) {
resultDataType.setLValueReference();
}
else if (datatype instanceof MDArrayBasicType) {
resultDataType.setArray(1);
}
else if (datatype instanceof MDVarArgsType) {
resultDataType.setVarArgs();
}
else if (datatype instanceof MDArrayReferencedType arrRefType) {
return processDataType(resultDataType, arrRefType.getReferencedType());
}
else if (datatype instanceof MDStdNullPtrType) {
resultDataType.setName(datatype.toString());
}
else {
// MDDataType
// TODO MDW64Type needs repeated reference type parsing, just as modifier types need
// them.
resultDataType.setName(getDataTypeName(datatype));
}
// TODO: No place to indicate a general pointer--we can indicate Pointer64
// TODO: Not sure if anything fits this: resultDataType.setComplex();
// TODO: resultDataType.setTemplate(); //TODO: Not sure templates are data types
// according to how MSFT demangles them.
// TODO: resultDataType.setTemplate(null); //TODO: Not sure templates are data types
// according to how MSFT demangles them.
return resultDataType;
}
/**
* Returns either a formal type name or a representative type name to fill into a
* MangledDataType if the formal name is blank
* @return the name
*/
private String getDataTypeName(MDDataType dataType) {
String name = dataType.getName();
if (!name.isBlank()) {
return name;
}
name = dataType.getTypeName();
if (!name.isBlank()) {
return name;
}
return dataType.toString();
}
}

View File

@ -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) {

View File

@ -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");
}
}
}
/******************************************************************************/

View File

@ -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.

View File

@ -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;

View File

@ -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) {

View File

@ -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.

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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();

View File

@ -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);

View File

@ -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

View File

@ -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.
@ -54,7 +54,7 @@ public class SwiftDemangler implements Demangler {
/**
* Creates a new {@link SwiftDemangler} that is associated with the given {@link Program}
*
*
* @param program The {@link Program} to demangle
* @throws IOException if there was a problem parsing the Swift type metadata
*/
@ -73,12 +73,6 @@ public class SwiftDemangler implements Demangler {
return new SwiftDemanglerOptions();
}
@Override
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
throws DemangledException {
return demangle(mangled);
}
public void initialize(Program program) throws IOException {
cache = new HashMap<>();
nativeDemangler = null;
@ -95,6 +89,7 @@ public class SwiftDemangler implements Demangler {
}
@Override
@Deprecated(since = "11.3", forRemoval = true)
public DemangledObject demangle(String mangled, DemanglerOptions op) throws DemangledException {
SwiftDemanglerOptions options = getSwiftDemanglerOptions(op);
Demangled demangled = getDemangled(mangled, options);
@ -111,9 +106,18 @@ public class SwiftDemangler implements Demangler {
return null;
}
@Override
public DemangledObject demangle(MangledContext context) throws DemangledException {
DemanglerOptions op = context.getOptions();
String mangled = context.getMangled();
DemangledObject demangledObject = demangle(mangled, op);
demangledObject.setMangledContext(context);
return demangledObject;
}
/**
* Get a new {@link Demangled} by demangling the given mangled string
*
*
* @param mangled The mangled string
* @param op The options (could be null)
* @return A new {@link Demangled}
@ -145,7 +149,7 @@ public class SwiftDemangler implements Demangler {
/**
* Gets the {@link SwiftTypeMetadata}
*
*
* @return The {@link SwiftTypeMetadata}, or null if it is not available
*/
public SwiftTypeMetadata getTypeMetadata() {
@ -154,7 +158,7 @@ public class SwiftDemangler implements Demangler {
/**
* Checks to see whether the given symbol name is a mangled Swift symbol
*
*
* @param symbolName The symbol name to check
* @return True if the given symbol name is a mangled Swift symbol; otherwise, false
*/
@ -165,7 +169,7 @@ public class SwiftDemangler implements Demangler {
/**
* Gets the {@link SwiftDemanglerOptions} from the given {@link DemanglerOptions}
*
*
* @param opt The options
* @return The @link SwiftDemanglerOptions}
* @throws DemangledException If the given options are not {@link SwiftDemanglerOptions}
@ -180,7 +184,7 @@ public class SwiftDemangler implements Demangler {
/**
* Ensures that this demangler has access to a {@link SwiftNativeDemangler}
*
*
* @param options The options
* @throws DemangledException if there was a problem getting the {@link SwiftNativeDemangler}
*/

View File

@ -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 static org.junit.Assert.*;
import org.junit.*;
import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
@ -74,9 +75,10 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
}
/**
* Test that the DemangledAddressTable will properly create a sequence of data
* Test that the DemangledAddressTable will properly create a sequence of data
* pointers. This test deals with the simple case where no existing data
* is present. End of block considered end of address table.
* @throws Exception upon error
*/
@Test
public void testApply_NoNextSymbol_NoData() throws Exception {
@ -88,10 +90,13 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
SymbolTable symbolTable = program.getSymbolTable();
symbolTable.createLabel(addr, mangled, SourceType.IMPORTED);
DemangledObject demangled = DemanglerUtil.demangle(mangled);
GnuDemangler demangler = new GnuDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, addr);
DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledAddressTable);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
assertTrue(demangled.getMangledContext() != null);
assertTrue(demangled.applyUsingContext(TaskMonitor.DUMMY));
// expected: UniqueSpace::vtable
Symbol[] symbols = symbolTable.getSymbols(addr);
@ -107,9 +112,10 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
}
/**
* Test that the DemangledAddressTable will not create a sequence of data
* pointers due to a data collision. This test deals with the case where primitive types have been
* Test that the DemangledAddressTable will not create a sequence of data
* pointers due to a data collision. This test deals with the case where primitive types have been
* previously created. End of block considered end of address table.
* @throws Exception upon error
*/
@Test
public void testApply_NoNextSymbol_DataCollision() throws Exception {
@ -126,10 +132,13 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
listing.createData(addr("0x118"), Undefined4DataType.dataType);
listing.createData(addr("0x120"), DWordDataType.dataType);
DemangledObject demangled = DemanglerUtil.demangle(mangled);
GnuDemangler demangler = new GnuDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, addr);
DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledAddressTable);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
assertTrue(demangled.getMangledContext() != null);
assertTrue(demangled.applyUsingContext(TaskMonitor.DUMMY));
// expected: UniqueSpace::vtable
Symbol[] symbols = symbolTable.getSymbols(addr);
@ -146,9 +155,10 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
}
/**
* Test that the DemangledAddressTable will properly create a sequence of data
* pointers. This test deals with the case where primitive types have been
* Test that the DemangledAddressTable will properly create a sequence of data
* pointers. This test deals with the case where primitive types have been
* previously created. Next label considered end of address table.
* @throws Exception upon error
*/
@Test
public void testApply_WithNextSymbol_UndefinedData() throws Exception {
@ -167,10 +177,13 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
symbolTable.createLabel(addr("0x120"), "NextLabel", SourceType.IMPORTED);
DemangledObject demangled = DemanglerUtil.demangle(mangled);
GnuDemangler demangler = new GnuDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, addr);
DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledAddressTable);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
assertTrue(demangled.getMangledContext() != null);
assertTrue(demangled.applyUsingContext(TaskMonitor.DUMMY));
// expected: UniqueSpace::vtable
Symbol[] symbols = symbolTable.getSymbols(addr);
@ -185,10 +198,11 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
}
/**
* Test that the DemangledAddressTable will properly create a sequence of data
* pointers. This test deals with the case where primitive types have been
* previously created where the first is an undefined array which dictates the
* Test that the DemangledAddressTable will properly create a sequence of data
* pointers. This test deals with the case where primitive types have been
* previously created where the first is an undefined array which dictates the
* extent of the address table. Next label beyond end of address table.
* @throws Exception upon error
*/
@Test
public void testApply_WithUndefinedArray() throws Exception {
@ -207,10 +221,13 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
symbolTable.createLabel(addr("0x120"), "NextLabel", SourceType.IMPORTED);
DemangledObject demangled = DemanglerUtil.demangle(mangled);
GnuDemangler demangler = new GnuDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, addr);
DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledAddressTable);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
assertTrue(demangled.getMangledContext() != null);
assertTrue(demangled.applyUsingContext(TaskMonitor.DUMMY));
// expected: UniqueSpace::vtable
Symbol[] symbols = symbolTable.getSymbols(addr);

View File

@ -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,8 @@ import java.util.Arrays;
import org.junit.*;
import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.app.util.demangler.microsoft.*;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address;
@ -62,11 +64,16 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
// this is: public long __thiscall ATL::CRegKey::Close(void)
String mangled = "?CloseM@CRegKeyM@ATL@@QAEJXZ";
DemangledObject demangled = DemanglerUtil.demangle(mangled);
Address addr = addr("0x0101");
MicrosoftDemangler demangler = new MicrosoftDemangler();
MicrosoftDemanglerOptions options = demangler.createDefaultOptions();
MicrosoftMangledContext mangledContext =
demangler.createMangledContext(mangled, options, program, addr);
options.setInterpretation(MsCInterpretation.FUNCTION);
DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
Address addr = addr("0x0101");
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
assertFunction("CloseM", addr);
@ -95,7 +102,14 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
// this is: public long __thiscall ATL::CRegKey::Close(void)
String mangled = "?Close@CRegKey@ATL@@QAEJXZ";
DemangledObject demangled = DemanglerUtil.demangle(mangled);
Address addr = addr("0x0100");
MicrosoftDemangler demangler = new MicrosoftDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, addr);
DemanglerOptions options = mangledContext.getOptions();
// TODO: need direct way to change "for function" vs. just address and program; which might mean MicrosoftDemanglerContext
//mangledContext.setIsFunction(true);
DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
FunctionManager functionMgr = program.getFunctionManager();
@ -105,8 +119,7 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
new AddressSet(addr("0x0100")), SourceType.IMPORTED);
f2.setThunkedFunction(f1);
Address addr = addr("0x0100");
demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY);
demangled.applyTo(program, addr, options, TaskMonitor.DUMMY);
assertFunction("Close", addr);
assertNoBookmarkAt(addr);
@ -148,10 +161,16 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
SymbolTable symbolTable = program.getSymbolTable();
symbolTable.createLabel(addr, mangled, SourceType.IMPORTED);
DemangledObject demangled = DemanglerUtil.demangle(mangled);
MicrosoftDemangler demangler = new MicrosoftDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, addr);
DemanglerOptions options = mangledContext.getOptions();
// TODO: need direct way to change "for function" vs. just address and program; which might mean MicrosoftDemanglerContext
//mangledContext.setIsFunction(true);
DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
assertFunction("Close", addr);
assertNoBookmarkAt(addr);
@ -185,10 +204,16 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
String mangledWithAddr = SymbolUtilities.getAddressAppendedName(mangled, addr);
symbolTable.createLabel(addr, mangledWithAddr, SourceType.IMPORTED);
DemangledObject demangled = DemanglerUtil.demangle(mangled);
MicrosoftDemangler demangler = new MicrosoftDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, addr);
DemanglerOptions options = mangledContext.getOptions();
// TODO: need direct way to change "for function" vs. just address and program; which might mean MicrosoftDemanglerContext
//mangledContext.setIsFunction(true);
DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
assertFunction("Close", addr);
assertNoBookmarkAt(addr);
@ -223,10 +248,16 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
symbolTable.createLabel(addr, "Close", SourceType.IMPORTED);
symbolTable.createLabel(addr, mangled, SourceType.IMPORTED);
DemangledObject demangled = DemanglerUtil.demangle(mangled);
MicrosoftDemangler demangler = new MicrosoftDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, addr);
DemanglerOptions options = mangledContext.getOptions();
// TODO: need direct way to change "for function" vs. just address and program; which might mean MicrosoftDemanglerContext
//mangledContext.setIsFunction(true);
DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
assertFunction("Close", addr);
assertNoBookmarkAt(addr);
@ -258,9 +289,15 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
SymbolTable symbolTable = program.getSymbolTable();
symbolTable.createLabel(addr, mangled, SourceType.IMPORTED);
DemangledObject demangled = DemanglerUtil.demangle(mangled);
MicrosoftDemangler demangler = new MicrosoftDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, addr);
DemanglerOptions options = mangledContext.getOptions();
// TODO: need direct way to change "for function" vs. just address and program; which might mean MicrosoftDemanglerContext
//mangledContext.setIsFunction(true);
DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
String className =
"F<class_E::D::G<struct_E::D::H<bool_(__cdecl*const)(enum_C::B_const&),0>,bool,enum_C::B_const&>_>";
@ -306,10 +343,16 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
Address addr = extLoc.getExternalSpaceAddress();
DemangledObject demangled = DemanglerUtil.demangle(mangled);
MicrosoftDemangler demangler = new MicrosoftDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, addr);
DemanglerOptions options = mangledContext.getOptions();
// TODO: need direct way to change "for function" vs. just address and program; which might mean MicrosoftDemanglerContext
//mangledContext.setIsFunction(true);
DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
assertFunction("Close", addr);
assertNoBookmarkAt(addr);
@ -348,16 +391,20 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
String functionName = "__gthread_active_p";
programBuilder.createEmptyFunction(functionName, "0x0101", 10, new VoidDataType());
Address addr = addr("0x0103");
programBuilder.createLabel("0x0103", mangled);
DemangledObject demangled = DemanglerUtil.demangle(program, mangled);
GnuDemangler demangler = new GnuDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, addr);
DemanglerOptions options = mangledContext.getOptions();
DemangledObject demangled = demangler.demangle(mangledContext);
assertNotNull(demangled);
assertTrue(demangled instanceof DemangledVariable);
assertEquals("__gthread_active_p()::__gthread_active_ptr", demangled.getSignature(false));
Address addr = addr("0x0103");
demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY);
demangled.applyTo(program, addr, options, TaskMonitor.DUMMY);
assertSimpleNamespaceExists("__gthread_active_p()");
assertNoBookmarkAt(addr);
@ -376,14 +423,19 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
public void testApply_Function_DoNotApplyCallingConvention() throws Exception {
String mangled = "?CloseM@CRegKeyM@ATL@@QAEJXZ";
DemangledObject demangled = DemanglerUtil.demangle(mangled);
Address addr = addr("0x0101");
MicrosoftDemangler demangler = new MicrosoftDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, addr);
DemanglerOptions options = mangledContext.getOptions();
// TODO: need direct way to change "for function" vs. just address and program; which might mean MicrosoftDemanglerContext
//mangledContext.setIsFunction(true);
DemangledObject demangled = demangler.demangle(mangledContext);
assertTrue(demangled instanceof DemangledFunction);
DemangledFunction demangledFunction = (DemangledFunction) demangled;
demangledFunction.setCallingConvention(CompilerSpec.CALLING_CONVENTION_stdcall);
Address addr = addr("0x0101");
DemanglerOptions options = new DemanglerOptions();
options.setApplyCallingConvention(false);
assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));