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