Merge remote-tracking branch

'origin/GP-4898_ghizard_MDMang_process_C_style_mangled_function_symbols--SQUASHED'
(Closes #1514)
This commit is contained in:
Ryan Kurtz 2024-09-19 09:45:47 -04:00
commit 4cbd20b3df
53 changed files with 3016 additions and 1460 deletions

View file

@ -498,6 +498,38 @@
</BLOCKQUOTE> </BLOCKQUOTE>
<P STYLE="margin-top: 30px;"><U>Started By:</U> New defined functions</P> <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> </BLOCKQUOTE>
<H3><A name="Auto_Analysis_Option_Byte"></A>Entry Point Analyzer</H3> <H3><A name="Auto_Analysis_Option_Byte"></A>Entry Point Analyzer</H3>

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -70,8 +70,10 @@ public class DemanglerCmd extends BackgroundCommand<Program> {
private boolean doDemangle(Demangler demangler, Program program, TaskMonitor monitor) { private boolean doDemangle(Demangler demangler, Program program, TaskMonitor monitor) {
MangledContext mangledContext =
demangler.createMangledContext(mangled, options, program, addr);
try { try {
demangledObject = demangler.demangle(mangled, options); demangledObject = demangler.demangle(mangledContext);
} }
catch (DemangledException e) { catch (DemangledException e) {
if (e.isInvalidMangledName()) { if (e.isInvalidMangledName()) {
@ -85,13 +87,13 @@ public class DemanglerCmd extends BackgroundCommand<Program> {
return false; // error return false; // error
// This produces too many messages for non-demangled symbols. If we could // 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 // 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 // failing, then we should print those. The problem is not knowing how to
// tell a mangled from a non-mangled symbol. // tell a mangled from a non-mangled symbol.
// Msg.debug(this, "Unable to demangle name: " + mangled); // Msg.debug(this, "Unable to demangle name: " + mangled);
} }
catch (Exception e) { 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: " + setStatusMsg("Unable to demangle symbol: " + mangled + " at " + addr + ". Message: " +
e.getMessage()); e.getMessage());
return false; return false;

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -37,7 +37,7 @@ import ghidra.util.task.TaskMonitor;
* the analyzer UI. * the analyzer UI.
* *
* <P>This analyzer will call each implementation's * <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. * 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( private static final AddressSetView EXTERNAL_SET = new AddressSet(
AddressSpace.EXTERNAL_SPACE.getMinAddress(), AddressSpace.EXTERNAL_SPACE.getMaxAddress()); AddressSpace.EXTERNAL_SPACE.getMinAddress(), AddressSpace.EXTERNAL_SPACE.getMaxAddress());
protected Demangler demangler;
public AbstractDemanglerAnalyzer(String name, String description) { public AbstractDemanglerAnalyzer(String name, String description) {
super(name, description, AnalyzerType.BYTE_ANALYZER); super(name, description, AnalyzerType.BYTE_ANALYZER);
setPriority(AnalysisPriority.DATA_TYPE_PROPOGATION.before().before().before()); setPriority(AnalysisPriority.DATA_TYPE_PROPOGATION.before().before().before());
@ -102,6 +104,23 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
return true; 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, private int demangleSymbols(Program program, AddressSetView set, int initialCount,
DemanglerOptions options, MessageLog log, TaskMonitor monitor) DemanglerOptions options, MessageLog log, TaskMonitor monitor)
throws CancelledException { throws CancelledException {
@ -124,10 +143,10 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
} }
Address address = symbol.getAddress(); Address address = symbol.getAddress();
String mangled = cleanSymbol(address, symbol.getName()); MangledContext mangledContext = createMangledContext(program, options, symbol);
DemangledObject demangled = demangle(mangled, address, options, log); DemangledObject demangled = demangle(mangledContext, log);
if (demangled != null) { if (demangled != null) {
apply(program, address, demangled, options, log, monitor); apply(mangledContext, demangled, log, monitor);
continue; continue;
} }
@ -141,10 +160,10 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
if (altSym.isPrimary() || skipSymbol(altSym)) { if (altSym.isPrimary() || skipSymbol(altSym)) {
continue; continue;
} }
mangled = cleanSymbol(address, altSym.getName()); mangledContext = createMangledContext(program, options, altSym);
demangled = demangle(mangled, address, options, log); demangled = demangle(mangledContext, log);
if (demangled != null) { if (demangled != null) {
apply(program, address, demangled, options, log, monitor); apply(mangledContext, demangled, log, monitor);
break; break;
} }
} }
@ -156,14 +175,13 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
/** /**
* The implementation-specific demangling callback * The implementation-specific demangling callback
* *
* @param mangled the mangled string * @param mangledContext the demangler context
* @param options the demangler options
* @param log the error log * @param log the error log
* @return the demangled object; null if demangling was unsuccessful * @return the demangled object; null if demangling was unsuccessful
* @throws DemangledException if there is a problem demangling or building the result * @throws DemangledException if there is a problem demangling or building the result
*/ */
protected abstract DemangledObject doDemangle(String mangled, DemanglerOptions options, protected abstract DemangledObject doDemangle(MangledContext mangledContext, MessageLog log)
MessageLog log) throws DemangledException; throws DemangledException;
/** /**
* Called before each analysis request to ensure that the current options (which may have * 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. * handled.
* *
* @param mangled the mangled string * @param mangledContext the mangled context
* @param address the symbol address
* @param options the demangler options
* @param log the error log * @param log the error log
* @return the demangled object; null if unsuccessful * @return the demangled object; null if unsuccessful
*/ */
protected DemangledObject demangle(String mangled, Address address, DemanglerOptions options, protected DemangledObject demangle(MangledContext mangledContext, MessageLog log) {
MessageLog log) {
DemangledObject demangled = null; DemangledObject demangled = null;
try { try {
demangled = doDemangle(mangled, options, log); demangled = doDemangle(mangledContext, log);
} }
catch (Throwable e) { catch (Throwable e) {
@ -258,8 +273,8 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
} }
} }
log.appendMsg(getName(), "Unable to demangle symbol: " + mangled + " at " + address + log.appendMsg(getName(), "Unable to demangle symbol: " + mangledContext.getMangled() +
". Message: " + e.getMessage()); " at " + mangledContext.getAddress() + ". Message: " + e.getMessage());
return null; return null;
} }
@ -269,24 +284,24 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
/** /**
* Applies the given demangled object to the program * Applies the given demangled object to the program
* *
* @param program the program * @param mangledContext the mangled context
* @param address the apply address
* @param demangled the demangled object * @param demangled the demangled object
* @param options the options used during the apply
* @param log the error log * @param log the error log
* @param monitor the task monitor * @param monitor the task monitor
*/ */
protected void apply(Program program, Address address, DemangledObject demangled, protected void apply(MangledContext mangledContext, DemangledObject demangled, MessageLog log,
DemanglerOptions options, MessageLog log, TaskMonitor monitor) { TaskMonitor monitor) {
try { try {
if (demangled.applyTo(program, address, options, monitor)) { if (demangled.applyTo(mangledContext.getProgram(), mangledContext.getAddress(),
mangledContext.getOptions(), monitor)) {
return; return;
} }
String errorString = demangled.getErrorMessage(); String errorString = demangled.getErrorMessage();
logApplyErrorMessage(log, demangled, address, null, errorString); logApplyErrorMessage(log, demangled, mangledContext.getAddress(), null,
errorString);
} }
catch (Exception e) { catch (Exception e) {
logApplyErrorMessage(log, demangled, address, e, null); logApplyErrorMessage(log, demangled, mangledContext.getAddress(), e, null);
} }
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -25,7 +25,6 @@ import ghidra.app.services.AnalysisPriority;
import ghidra.app.util.demangler.*; import ghidra.app.util.demangler.*;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.*; import ghidra.framework.options.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
import ghidra.util.SystemUtilities; import ghidra.util.SystemUtilities;
@ -64,10 +63,9 @@ public class RustDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
private RustDemanglerFormat demanglerFormat = RustDemanglerFormat.AUTO; private RustDemanglerFormat demanglerFormat = RustDemanglerFormat.AUTO;
private boolean useDeprecatedDemangler = false; private boolean useDeprecatedDemangler = false;
private RustDemangler demangler = new RustDemangler();
public RustDemanglerAnalyzer() { public RustDemanglerAnalyzer() {
super(NAME, DESCRIPTION); super(NAME, DESCRIPTION);
demangler = new RustDemangler();
// Set priority to one before the default AbstractDemanglerAnalyzer priority // Set priority to one before the default AbstractDemanglerAnalyzer priority
setPriority(AnalysisPriority.DATA_TYPE_PROPOGATION.before().before().before().before()); setPriority(AnalysisPriority.DATA_TYPE_PROPOGATION.before().before().before().before());
setDefaultEnablement(true); setDefaultEnablement(true);
@ -121,17 +119,18 @@ public class RustDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
} }
@Override @Override
protected DemangledObject doDemangle(String mangled, DemanglerOptions demanglerOptions, protected DemangledObject doDemangle(MangledContext mangledContext, MessageLog log)
MessageLog log) throws DemangledException { throws DemangledException {
return demangler.demangle(mangled, demanglerOptions); return demangler.demangle(mangledContext);
} }
@Override @Override
protected void apply(Program program, Address address, DemangledObject demangled, protected void apply(MangledContext mangledContext, DemangledObject demangled, MessageLog log,
DemanglerOptions options, MessageLog log, TaskMonitor monitor) { TaskMonitor monitor) {
try { try {
if (demangled instanceof DemangledFunction defunc) { if (demangled instanceof DemangledFunction defunc) {
defunc.applyTo(program, address, options, monitor); defunc.applyTo(mangledContext.getProgram(), mangledContext.getAddress(),
mangledContext.getOptions(), monitor);
} }
} }
catch (Exception e) { catch (Exception e) {
@ -148,7 +147,7 @@ public class RustDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
DemangledVariable demangledVariable = new DemangledVariable(mangled, original, name); DemangledVariable demangledVariable = new DemangledVariable(mangled, original, name);
demangledVariable.setNamespace(namespace); demangledVariable.setNamespace(namespace);
super.apply(program, address, demangledVariable, options, log, monitor); super.apply(mangledContext, demangledVariable, log, monitor);
} }
//================================================================================================== //==================================================================================================

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -40,16 +40,18 @@ public class RustDemangler implements Demangler {
} }
@Override @Override
@Deprecated(since = "9.2", forRemoval = true) @Deprecated(since = "11.3", forRemoval = true)
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns) public DemangledObject demangle(String mangled, DemanglerOptions options) {
throws DemangledException { MangledContext mangledContext = createMangledContext(mangled, options, null, null);
return null; return demangle(mangledContext);
} }
@Override @Override
public DemangledObject demangle(String mangled, DemanglerOptions options) { public DemangledObject demangle(MangledContext context) {
DemanglerOptions options = context.getOptions();
RustDemanglerOptions rustOptions = getRustOptions(options); RustDemanglerOptions rustOptions = getRustOptions(options);
String mangled = context.getMangled();
if (skip(mangled, rustOptions)) { if (skip(mangled, rustOptions)) {
return null; return null;
} }
@ -74,6 +76,7 @@ public class RustDemangler implements Demangler {
demangledFunction.setCallingConvention(CompilerSpec.CALLING_CONVENTION_rustcall); demangledFunction.setCallingConvention(CompilerSpec.CALLING_CONVENTION_rustcall);
} }
demangledObject.setMangledContext(context);
return demangledObject; return demangledObject;
} }
@ -88,7 +91,7 @@ public class RustDemangler implements Demangler {
/** /**
* Determines if the given mangled string should not be demangled, on the basis * Determines if the given mangled string should not be demangled, on the basis
* of if it has a known start pattern * of if it has a known start pattern
* *
* @param mangled the mangled string * @param mangled the mangled string
* @param options the options * @param options the options
* @return true if the string should not be demangled * @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 * Return true if the string is a mangled rust string in a rust program
* *
* @param mangled potential mangled string * @param mangled potential mangled string
* @return true if the string could be a mangled string in a rust program * @return true if the string could be a mangled string in a rust program
*/ */

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -17,8 +17,8 @@ package ghidra.app.util.demangler;
/** /**
* A unifying top-level interface for all {@link DemangledObject}s and {@link DemangledType}s * 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: * future date. Below is a listing of known uses:
* <TABLE> * <TABLE>
* <TR> * <TR>
@ -26,6 +26,22 @@ package ghidra.app.util.demangler;
* </TR> * </TR>
* <TR> * <TR>
* <TD> * <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()} * {@link #getName()}
* </TD> * </TD>
* <TD> * <TD>
@ -38,7 +54,7 @@ package ghidra.app.util.demangler;
* {@link #getDemangledName()} * {@link #getDemangledName()}
* </TD> * </TD>
* <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> * </TD>
* </TR> * </TR>
* <TR> * <TR>
@ -46,7 +62,7 @@ package ghidra.app.util.demangler;
* {@link #getNamespaceName()} * {@link #getNamespaceName()}
* </TD> * </TD>
* <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 * parameter and template information. Further, some characters within templates and
* function signatures are replaced, such as spaces and namespace separators. * function signatures are replaced, such as spaces and namespace separators.
* <P> * <P>
@ -59,9 +75,9 @@ package ghidra.app.util.demangler;
* {@link #getNamespaceString()} * {@link #getNamespaceString()}
* </TD> * </TD>
* <TD> * <TD>
* This returns the unmodified name of this item, along with any unmodified parent * This returns the unmodified name of this item, along with any unmodified parent
* namespace names, all separated by a namespace delimiter. Unlike * namespace names, all separated by a namespace delimiter. Unlike
* {@link #getNamespaceName()}, the spaces and internal namespace tokens will not be * {@link #getNamespaceName()}, the spaces and internal namespace tokens will not be
* replaced. * replaced.
* <P> * <P>
* Given this full demangled string: {@code Foo::Bar::Baz<int>}, this method will return * 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()} * {@link #getSignature()}
* </TD> * </TD>
* <TD> * <TD>
* Returns the complete string form of this object, with most known attributes. For * Returns the complete string form of this object, with most known attributes. For
* functions, this will be a complete signature. * functions, this will be a complete signature.
* </TD> * </TD>
* </TR> * </TR>
* <TR> * <TR>
@ -90,6 +106,35 @@ package ghidra.app.util.demangler;
*/ */
public interface Demangled { 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 * Returns the original mangled string
* @return the string * @return the string
@ -102,7 +147,7 @@ public interface Demangled {
*/ */
public String getOriginalDemangled(); public String getOriginalDemangled();
/** /**
* Returns the demangled name of this object. * Returns the demangled name of this object.
* NOTE: unsupported symbol characters, like whitespace, will be converted to an underscore. * NOTE: unsupported symbol characters, like whitespace, will be converted to an underscore.
* @return name of this DemangledObject with unsupported characters converted to underscore * @return name of this DemangledObject with unsupported characters converted to underscore
@ -116,9 +161,9 @@ public interface Demangled {
*/ */
public void setName(String name); public void setName(String name);
/** /**
* Returns the unmodified demangled name of this object. This name may contain whitespace * 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()} * and other characters not supported for symbol or data type creation. See {@link #getName()}
* for the same name modified for use within Ghidra. * for the same name modified for use within Ghidra.
* @return name of this DemangledObject * @return name of this DemangledObject
*/ */
@ -137,7 +182,7 @@ public interface Demangled {
public void setNamespace(Demangled ns); 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 * value returned here may have had some special characters replaced, such as ' ' replaced
* with '_' and '::' replaced with '--'. * with '_' and '::' replaced with '--'.
* @return the full namespace * @return the full namespace
@ -145,17 +190,17 @@ public interface Demangled {
public String getNamespaceString(); 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 * value returned here may have had some special characters replaced, such as ' ' replaced
* with '_' and '::' replaced with '--'. * with '_' and '::' replaced with '--'.
* *
* @return the name * @return the name
*/ */
public String getNamespaceName(); public String getNamespaceName();
/** /**
* Generates a complete representation of this object to include all know attributes of this * Generates a complete representation of this object to include all know attributes of this
* object * object
* @return the signature * @return the signature
*/ */
public String getSignature(); public String getSignature();

View file

@ -44,37 +44,38 @@ public abstract class DemangledObject implements Demangled {
/* /*
The following names probably need to be refactored. Until then, this is how the following The following names probably need to be refactored. Until then, this is how the following
fields are used. fields are used.
mangled - mangled -
Source: The original mangled string as seen in the program Source: The original mangled string as seen in the program
Usage: Can be used to see if a program symbol has already been demangled Usage: Can be used to see if a program symbol has already been demangled
originalDemangled - originalDemangled -
Source: The raw demangled string returned from the demangler Source: The raw demangled string returned from the demangler
Usage: for display Usage: for display
demangledName - demangledName -
Source: The name as created by the parser which may transform or even replace the Source: The name as created by the parser which may transform or even replace the
string returned from the demangler string returned from the demangler
Usage: for display Usage: for display
name - name -
Source: This is derived from the 'demangledName' This is updated to be suitable 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 for use as a symbol name. This may be null while building, but is
expected to be non-null when applyTo() is called expected to be non-null when applyTo() is called
Usage: The name that will be applied 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, Future: These variables should be refactored and renamed to be clearer and more cohesive,
something like: something like:
mangled mangled
rawDemangled rawDemangled
escapedDemangled escapedDemangled
symbolName symbolName
*/ */
protected MangledContext mangledContext; // the mangled context, which includes mangled string
protected final String mangled; // original mangled string protected final String mangled; // original mangled string
protected String originalDemangled; // raw demangled string protected String originalDemangled; // raw demangled string
private String demangledName; // updated demangled string private String demangledName; // updated demangled string
@ -110,11 +111,29 @@ public abstract class DemangledObject implements Demangled {
private boolean demangledNameSucceeded = false; private boolean demangledNameSucceeded = false;
private String errorMessage = null; 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) { DemangledObject(String mangled, String originalDemangled) {
this.mangled = mangled; this.mangled = mangled;
this.originalDemangled = originalDemangled; 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 @Override
public String getDemangledName() { public String getDemangledName() {
return demangledName; return demangledName;
@ -230,6 +249,16 @@ public abstract class DemangledObject implements Demangled {
return demangledNameSucceeded; return demangledNameSucceeded;
} }
@Override
public void setMangledContext(MangledContext mangledContextArg) {
mangledContext = mangledContextArg;
}
@Override
public MangledContext getMangledContext() {
return mangledContext;
}
@Override @Override
public String getMangledString() { public String getMangledString() {
return mangled; return mangled;
@ -378,7 +407,7 @@ public abstract class DemangledObject implements Demangled {
* Apply this demangled object detail to the specified program. * Apply this demangled object detail to the specified program.
* <br> * <br>
* NOTE: An open Program transaction must be established prior to invoking this method. * NOTE: An open Program transaction must be established prior to invoking this method.
* *
* @param program program to which demangled data should be applied. * @param program program to which demangled data should be applied.
* @param address address which corresponds to this demangled object * @param address address which corresponds to this demangled object
* @param options options which control how demangled data is applied * @param options options which control how demangled data is applied
@ -391,6 +420,25 @@ public abstract class DemangledObject implements Demangled {
return applyPlateCommentOnly(program, address); 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 program The program for which to apply the comment
* @param address The address for the comment * @param address The address for the comment

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -15,6 +15,7 @@
*/ */
package ghidra.app.util.demangler; package ghidra.app.util.demangler;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.classfinder.ExtensionPoint; import ghidra.util.classfinder.ExtensionPoint;
@ -24,46 +25,53 @@ import ghidra.util.classfinder.ExtensionPoint;
*/ */
public interface Demangler extends 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); public boolean canDemangle(Program program);
/** /**
* Deprecated. Use {@link #demangle(String)} or * Attempts to demangle the given string using a context
* {@link #demangle(String, DemanglerOptions)}. * ({@link #createMangledContext(String, DemanglerOptions, Program, Address)} with
* default options ({@link #createDefaultOptions()}.
* *
* @param mangled the mangled string * @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 * @return the result
* @throws DemangledException if the string cannot be demangled * @throws DemangledException if the string cannot be demangled
*/ */
public default DemangledObject demangle(String mangled) throws DemangledException { 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 * Attempts to demangle the given string using the given options
* *
* @param mangled the mangled string * @param mangled the mangled string
* @param options the options * @param options the options
* @return the result * @return the result
* @throws DemangledException if the string cannot be demangled * @throws DemangledException if the string cannot be demangled
* @deprecated see above
*/ */
@Deprecated(since = "11.3", forRemoval = true)
public DemangledObject demangle(String mangled, DemanglerOptions options) public DemangledObject demangle(String mangled, DemanglerOptions options)
throws DemangledException; 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 * Creates default options for this particular demangler
* @return the options * @return the options
@ -71,4 +79,21 @@ public interface Demangler extends ExtensionPoint {
public default DemanglerOptions createDefaultOptions() { public default DemanglerOptions createDefaultOptions() {
return new DemanglerOptions(); return new DemanglerOptions();
} }
/**
* Creates a mangled context
* @param mangled the mangled name
* @param options the demangler options; if null, the default options are created
* @param program the program; can be null
* @param address the address for the name in the program; can be null
* @return the mangled context
*/
public default MangledContext createMangledContext(String mangled, DemanglerOptions options,
Program program, Address address) {
if (options == null) {
options = createDefaultOptions();
}
return new MangledContext(program, options, mangled, address);
}
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -15,39 +15,59 @@
*/ */
package ghidra.app.util.demangler; package ghidra.app.util.demangler;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.classfinder.ClassSearcher; 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 { 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 = private static final Pattern LEADING_PARAMETER_SPACE_PATTERN =
Pattern.compile(" ([\\*\\&\\)])"); Pattern.compile(" ([\\*\\&\\)])");
private static final Pattern TRAILING_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 * Locates all available demanglers, then it attempts to demangle. This method will
* query all demanglers regardless of architecture. * query all demanglers regardless of architecture.
* *
* <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 * 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()}. * {@link Demangler#createDefaultOptions()}.
* *
* @param mangled the mangled name * @param mangled the mangled name
* @return the demangled object or null * @return the demangled object or null
* @deprecated see above
*/ */
@Deprecated(since = "11.3", forRemoval = true)
public static DemangledObject demangle(String mangled) { public static DemangledObject demangle(String mangled) {
List<Demangler> demanglers = getDemanglers(); List<Demangler> demanglers = getDemanglers();
for (Demangler demangler : demanglers) { for (Demangler demangler : demanglers) {
try { try {
DemangledObject demangledObject = demangler.demangle(mangled); MangledContext mangledContext =
demangler.createMangledContext(mangled, null, null, null);
DemangledObject demangledObject = demangler.demangle(mangledContext);
if (demangledObject != null) { if (demangledObject != null) {
return demangledObject; 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. * 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 * 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()}. * {@link Demangler#createDefaultOptions()}.
* *
* @param program the program containing the mangled name * @param program the program containing the mangled name
* @param mangled the mangled name * @param mangled the mangled name
* @return the demangled object or null * @return the demangled object or null
* @deprecated see above
*/ */
@Deprecated(since = "11.3", forRemoval = true)
public static DemangledObject demangle(Program program, String mangled) { public static DemangledObject demangle(Program program, String mangled) {
List<Demangler> demanglers = getDemanglers(); List<Demangler> demanglers = getDemanglers();
for (Demangler demangler : demanglers) { for (Demangler demangler : demanglers) {
@ -80,7 +106,9 @@ public class DemanglerUtil {
continue; continue;
} }
DemangledObject demangledObject = demangler.demangle(mangled); MangledContext mangledContext =
demangler.createMangledContext(mangled, null, null, null);
DemangledObject demangledObject = demangler.demangle(mangledContext);
if (demangledObject != null) { if (demangledObject != null) {
return demangledObject; return demangledObject;
} }
@ -92,9 +120,48 @@ public class DemanglerUtil {
return null; 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. * Dynamically locates all available demangler implementations.
* *
* @return a list of all demanglers * @return a list of all demanglers
*/ */
private static List<Demangler> getDemanglers() { private static List<Demangler> getDemanglers() {

View file

@ -0,0 +1,80 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler;
import java.util.Objects;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
/**
* A simple class to contain the context of a mangled symbol for demangling
*/
public class MangledContext {
protected Program program;
protected DemanglerOptions options;
protected String mangled;
protected Address address;
/**
* Constructor for mangled context
* @param program the program; can be null
* @param options the demangler options
* @param mangled the mangled string
* @param address the address; can be null
*/
public MangledContext(Program program, DemanglerOptions options, String mangled,
Address address) {
this.program = program;
this.options = Objects.requireNonNull(options, "Options cannot be null");
this.mangled = Objects.requireNonNull(mangled, "Mangled cannot be null");
this.address = address;
}
/**
* Returns the program
* @return the program; can be null
*/
public Program getProgram() {
return program;
}
/**
* Returns the demangler options
* @return the options
*/
public DemanglerOptions getOptions() {
return options;
}
/**
* Returns the mangled string
* @return the mangled string
*/
public String getMangled() {
return mangled;
}
/**
* Returns the address
* @return the address; can be null
*/
public Address getAddress() {
return address;
}
}

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -259,15 +259,21 @@ abstract class AbstractPeDebugLoader extends AbstractOrdinalSupportLoader {
} }
private void demangle(Address address, String name, Program program) { private void demangle(Address address, String name, Program program) {
DemangledObject demangledObj = null; StringBuilder builder = new StringBuilder();
try { 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) { catch (Exception e) {
//log.appendMsg("Unable to demangle: "+name); //log.appendMsg("Unable to demangle: "+name);
} }
if (demangledObj != null) { if (builder.length() > 0) {
setComment(CodeUnit.PLATE_COMMENT, address, demangledObj.getSignature(true)); setComment(CodeUnit.PLATE_COMMENT, address, builder.toString());
} }
} }
@ -426,7 +432,7 @@ abstract class AbstractPeDebugLoader extends AbstractOrdinalSupportLoader {
Symbol newSymbol = Symbol newSymbol =
program.getSymbolTable().createLabel(address, sym, SourceType.IMPORTED); 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 // .text$func_name) to be primary because we don't want to use them for function names
// or demangling. // or demangling.
if (!sym.equals(section.getName()) && !sym.startsWith(section.getName() + "$")) { if (!sym.equals(section.getName()) && !sym.startsWith(section.getName() + "$")) {

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -21,6 +21,7 @@
//@category Examples.Demangler //@category Examples.Demangler
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledObject; import ghidra.app.util.demangler.DemangledObject;
import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.gnu.*; import ghidra.app.util.demangler.gnu.*;
import ghidra.program.model.symbol.Symbol; import ghidra.program.model.symbol.Symbol;
@ -56,7 +57,9 @@ public class DemangleElfWithOptionScript extends GhidraScript {
options = options.withDemanglerFormat(GnuDemanglerFormat.ARM, true); 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) { if (demangledObject == null) {
println("Could not demangle: " + mangled); println("Could not demangle: " + mangled);
return; return;

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -53,6 +53,7 @@ import java.util.List;
import ghidra.app.cmd.label.DemanglerCmd; import ghidra.app.cmd.label.DemanglerCmd;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledException; import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.gnu.GnuDemangler; import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.Memory;
@ -143,7 +144,9 @@ public class VxWorksSymTab_5_4 extends GhidraScript {
String symDemangledName = null; String symDemangledName = null;
try { try {
// if successful, symDemangledName will be non-NULL // 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) { catch (DemangledException e) {
// if symName wasn't a mangled name, silently continue // if symName wasn't a mangled name, silently continue

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -51,6 +51,7 @@ import java.util.List;
import ghidra.app.cmd.label.DemanglerCmd; import ghidra.app.cmd.label.DemanglerCmd;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledException; import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.gnu.GnuDemangler; import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.Memory;
@ -139,7 +140,9 @@ public class VxWorksSymTab_6_1 extends GhidraScript {
String symDemangledName = null; String symDemangledName = null;
try { try {
// if successful, symDemangledName will be non-NULL // 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) { catch (DemangledException e) {
// if symName wasn't a mangled name, silently continue // if symName wasn't a mangled name, silently continue

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -49,6 +49,7 @@ import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.services.DataTypeManagerService; import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.demangler.DemangledException; import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.gnu.GnuDemangler; import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet; 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 * 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 symTbl
* @param vxSymbol * @param vxSymbol
* @param tableLen * @param tableLen
@ -784,7 +785,9 @@ public class VxWorksSymTab_Finder extends GhidraScript {
// Demangle symName // Demangle symName
String symDemangledName = null; String symDemangledName = null;
try { 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 catch (DemangledException e) { // report demangling error
if (!e.isInvalidMangledName()) { if (!e.isInvalidMangledName()) {

View file

@ -73,10 +73,9 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
private GnuDemanglerFormat demanglerFormat = GnuDemanglerFormat.AUTO; private GnuDemanglerFormat demanglerFormat = GnuDemanglerFormat.AUTO;
private boolean useDeprecatedDemangler = false; private boolean useDeprecatedDemangler = false;
private GnuDemangler demangler = new GnuDemangler();
public GnuDemanglerAnalyzer() { public GnuDemanglerAnalyzer() {
super(NAME, DESCRIPTION); super(NAME, DESCRIPTION);
demangler = new GnuDemangler();
setDefaultEnablement(true); setDefaultEnablement(true);
} }
@ -142,9 +141,9 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
} }
@Override @Override
protected DemangledObject doDemangle(String mangled, DemanglerOptions demanglerOtions, protected DemangledObject doDemangle(MangledContext mangledContext, MessageLog log)
MessageLog log) throws DemangledException { throws DemangledException {
return demangler.demangle(mangled, demanglerOtions); return demangler.demangle(mangledContext);
} }
//================================================================================================== //==================================================================================================

View file

@ -66,19 +66,27 @@ public class GnuDemangler implements Demangler {
} }
@Override @Override
@Deprecated(since = "9.2", forRemoval = true) @Deprecated(since = "11.3", forRemoval = true)
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns) public DemangledObject demangle(String mangled, DemanglerOptions demanglerOptions)
throws DemangledException { throws DemangledException {
GnuDemanglerOptions options = new GnuDemanglerOptions(); MangledContext mangledContext = createMangledContext(mangled, demanglerOptions, null, null);
options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns); return demangle(mangledContext);
return demangle(mangled, options);
} }
@Override @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 { throws DemangledException {
GnuDemanglerOptions options = getGnuOptions(demanglerOtions); DemanglerOptions demanglerOptions = mangledContext.getOptions();
String mangled = mangledContext.getMangled();
GnuDemanglerOptions options = getGnuOptions(demanglerOptions);
if (skip(mangled, options)) { if (skip(mangled, options)) {
return null; return null;
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -22,6 +22,6 @@ apply plugin: 'eclipse'
eclipse.project.name = 'Features MicrosoftCodeAnalyzer' eclipse.project.name = 'Features MicrosoftCodeAnalyzer'
dependencies { dependencies {
api project(":MicrosoftDmang") api project(":MicrosoftDemangler")
api project(":Base") api project(":Base")
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,6 +19,7 @@ import ghidra.app.cmd.data.rtti.RttiUtil;
import ghidra.app.util.datatype.microsoft.DataValidationOptions; import ghidra.app.util.datatype.microsoft.DataValidationOptions;
import ghidra.app.util.datatype.microsoft.MSDataTypeUtils; import ghidra.app.util.datatype.microsoft.MSDataTypeUtils;
import ghidra.app.util.demangler.*; import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.microsoft.MicrosoftDemangler;
import ghidra.docking.settings.SettingsImpl; import ghidra.docking.settings.SettingsImpl;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
@ -33,8 +34,6 @@ import ghidra.util.Msg;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
import mdemangler.MDException;
import mdemangler.MDMangGhidra;
/** /**
* Model for the TypeDescriptor data type. * Model for the TypeDescriptor data type.
@ -446,7 +445,8 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
Object value = terminatedStringDt.getValue(nameMemBuffer, SettingsImpl.NO_SETTINGS, 1); Object value = terminatedStringDt.getValue(nameMemBuffer, SettingsImpl.NO_SETTINGS, 1);
if (value instanceof String) { if (value instanceof String) {
originalTypeName = (String) value; originalTypeName = (String) value;
demangledDataType = getDemangledDataType(originalTypeName); // Can be null // The returned demangledDataType an be null
demangledDataType = getDemangledDataType(originalTypeName, program, nameAddress);
} }
hasProcessedName = true; hasProcessedName = true;
return originalTypeName; return originalTypeName;
@ -597,20 +597,22 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
/** /**
* Gets a DemangledDataType for the indicated mangled string * Gets a DemangledDataType for the indicated mangled string
* @param mangledString the mangled string to be demangled * @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 * @return the DemangledDataType or null if couldn't demangle or is not a class type
*/ */
private static DemangledDataType getDemangledDataType(String mangledString) { private static DemangledDataType getDemangledDataType(String mangledString, Program program,
MDMangGhidra demangler = new MDMangGhidra(); Address address) {
MicrosoftDemangler demangler = new MicrosoftDemangler();
try { try {
// Note that we could play with the return value, but it is not needed; instead, we MangledContext mangledContext =
// get the DemangledDataType by calling the appropriate method demangler.createMangledContext(mangledString, null, program, address);
demangler.demangleType(mangledString, true); DemangledDataType demangledType = demangler.demangleType(mangledContext);
DemangledDataType demangledType = demangler.getDataType();
if (isPermittedType(demangledType)) { if (isPermittedType(demangledType)) {
return demangledType; return demangledType;
} }
} }
catch (MDException e) { catch (DemangledException e) {
// Couldn't demangle. // Couldn't demangle.
} }
return null; return null;

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -17,6 +17,7 @@
//@category Symbol //@category Symbol
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledObject; import ghidra.app.util.demangler.DemangledObject;
import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.microsoft.MicrosoftDemangler; import ghidra.app.util.demangler.microsoft.MicrosoftDemangler;
public class MicrosoftDemanglerScript extends GhidraScript { 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("??$?0G@?$allocator@U_Container_proxy@std@@@std@@QAE@ABV?$allocator@G@1@@Z");
/* /*
demangle("??0__non_rtti_object@@QAE@PBD@Z"); demangle("??0__non_rtti_object@@QAE@PBD@Z");
demangle("??0bad_cast@@AAE@PBQBD@Z"); demangle("??0bad_cast@@AAE@PBQBD@Z");
demangle("??0bad_cast@@QAE@ABQBD@Z"); demangle("??0bad_cast@@QAE@ABQBD@Z");
@ -94,7 +95,11 @@ public class MicrosoftDemanglerScript extends GhidraScript {
} }
private void demangle(String mangled) throws Exception { private void demangle(String mangled) throws Exception {
DemangledObject demangled = demangler.demangle(mangled); // Using a null address instead of currentAddress because we are not demangling a symbol
printf("magled %s\ndemangled %s", mangled, demangled); // at the address... just a symbol to dump to the output
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, currentProgram, null);
DemangledObject demangled = demangler.demangle(mangledContext);
printf("mangled %s\ndemangled %s", mangled, demangled);
} }
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -16,10 +16,11 @@
package ghidra.app.plugin.core.analysis; package ghidra.app.plugin.core.analysis;
import ghidra.app.util.demangler.*; 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.app.util.importer.MessageLog;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
/** /**
* A version of the demangler analyzer to handle microsoft symbols * 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 = private static final String OPTION_DESCRIPTION_APPLY_CALLING_CONVENTION =
"Apply any recovered function signature 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 applyFunctionSignature = true;
private boolean applyCallingConvention = true; private boolean applyCallingConvention = true;
private MicrosoftDemangler demangler = new MicrosoftDemangler(); private boolean demangleOnlyKnownPatterns = false;
private MsCInterpretation interpretation = MsCInterpretation.FUNCTION_IF_EXISTS;
public MicrosoftDemanglerAnalyzer() { public MicrosoftDemanglerAnalyzer() {
super(NAME, DESCRIPTION); super(NAME, DESCRIPTION);
demangler = new MicrosoftDemangler();
setDefaultEnablement(true); setDefaultEnablement(true);
} }
@ -56,11 +71,20 @@ public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
@Override @Override
public void registerOptions(Options options, Program program) { 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); 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); 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 @Override
@ -70,20 +94,28 @@ public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
applyCallingConvention = applyCallingConvention =
options.getBoolean(OPTION_NAME_APPLY_CALLING_CONVENTION, applyCallingConvention); options.getBoolean(OPTION_NAME_APPLY_CALLING_CONVENTION, applyCallingConvention);
demangleOnlyKnownPatterns =
options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns);
interpretation = options.getEnum(OPTION_NAME_MS_C_INTERPRETATION, interpretation);
} }
@Override @Override
protected DemanglerOptions getOptions() { protected DemanglerOptions getOptions() {
DemanglerOptions options = new DemanglerOptions(); MicrosoftDemanglerOptions options = new MicrosoftDemanglerOptions();
options.setApplySignature(applyFunctionSignature); options.setApplySignature(applyFunctionSignature);
options.setApplyCallingConvention(applyCallingConvention); options.setApplyCallingConvention(applyCallingConvention);
options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
options.setInterpretation(interpretation);
options.setErrorOnRemainingChars(true);
return options; return options;
} }
@Override @Override
protected DemangledObject doDemangle(String mangled, DemanglerOptions options, MessageLog log) protected DemangledObject doDemangle(MangledContext context, MessageLog log)
throws DemangledException { throws DemangledException {
DemangledObject demangled = demangler.demangle(mangled, options); DemangledObject demangled = demangler.demangle(context);
return demangled; return demangled;
} }
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -18,18 +18,29 @@ package ghidra.app.util.demangler.microsoft;
import ghidra.app.util.demangler.*; import ghidra.app.util.demangler.*;
import ghidra.app.util.opinion.MSCoffLoader; import ghidra.app.util.opinion.MSCoffLoader;
import ghidra.app.util.opinion.PeLoader; import ghidra.app.util.opinion.PeLoader;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import mdemangler.MDException; import mdemangler.*;
import mdemangler.MDMangGhidra; import mdemangler.datatype.MDDataType;
/** /**
* A class for demangling debug symbols created using Microsoft Visual Studio. * A class for demangling debug symbols created using Microsoft Visual Studio.
*/ */
public class MicrosoftDemangler implements Demangler { public class MicrosoftDemangler implements Demangler {
private MDMangGhidra demangler;
private MDParsableItem item;
private DemangledObject object;
private MDDataType mdType;
private DemangledDataType dataType;
public MicrosoftDemangler() { 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 @Override
public boolean canDemangle(Program program) { public boolean canDemangle(Program program) {
String executableFormat = program.getExecutableFormat(); String executableFormat = program.getExecutableFormat();
@ -38,47 +49,128 @@ public class MicrosoftDemangler implements Demangler {
} }
@Override @Override
@Deprecated(since = "9.2", forRemoval = true) @Deprecated(since = "11.3", forRemoval = true)
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns) public DemangledObject demangle(String mangled, DemanglerOptions options)
throws DemangledException { throws DemangledException {
try { MangledContext mangledContext = new MangledContext(null, options, mangled, null);
DemangledObject demangled = demangleMS(mangled, demangleOnlyKnownPatterns); return demangle(mangledContext);
return demangled;
}
catch (DemangledException e) {
throw new DemangledException(true);
}
} }
@Override @Override
public DemangledObject demangle(String mangled, DemanglerOptions options) public DemangledObject demangle(MangledContext context) throws DemangledException {
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 { try {
DemangledObject demangled = demangleMS(mangled, options.demangleOnlyKnownPatterns()); item = demangler.demangle();
return demangled; object = MicrosoftDemanglerUtil.convertToDemangledObject(item, mangled);
} if (object != null) {
catch (DemangledException e) { object.setMangledContext(context);
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();
return object; return object;
} }
catch (MDException e) { catch (MDException e) {
DemangledException de = new DemangledException("Unable to demangle symbol: " + mangled); DemangledException de = new DemangledException(true);
de.initCause(e); de.initCause(e);
throw de; throw de;
} }
} }
/**
* Attempts to demangle the type string of the mangled context into a type
*
* @param context the mangled context
* @return the result
* @throws DemangledException if the string cannot be demangled
*/
public DemangledDataType demangleType(MangledContext context) throws DemangledException {
if (!(context instanceof MicrosoftMangledContext mContext)) {
throw new DemangledException("Wrong context type");
}
if (!(context.getOptions() instanceof MicrosoftDemanglerOptions options)) {
throw new DemangledException("MicrosoftDemanglerOptions expected");
}
String mangled = context.getMangled();
demangler = new MDMangGhidra();
demangler.setMangledSymbol(mangled);
demangler.setErrorOnRemainingChars(options.errorOnRemainingChars());
demangler.setDemangleOnlyKnownPatterns(options.demangleOnlyKnownPatterns());
demangler.setArchitectureSize(mContext.getArchitectureSize());
demangler.setIsFunction(mContext.shouldInterpretAsFunction());
try {
mdType = demangler.demangleType();
dataType = MicrosoftDemanglerUtil.convertToDemangledDataType(mdType, mangled);
if (dataType != null) {
dataType.setMangledContext(context);
}
return dataType;
}
catch (MDException e) {
DemangledException de = new DemangledException(true);
de.initCause(e);
throw de;
}
}
/**
* Returns the {@link MDParsableItem} used in demangling to a {@link DemangledObject}
* @return the item; can be null if item wasn't demangled
*/
public MDParsableItem getMdItem() {
return item;
}
/**
* Returns the {@link MDDataType} used in demangling to a @link DemangledDataType}
* @return the type; can be null if type wasn't demangled
*/
public MDDataType getMdType() {
return mdType;
}
/**
* Creates default options for microsoft demangler
* @return the options
*/
@Override
public MicrosoftDemanglerOptions createDefaultOptions() {
return new MicrosoftDemanglerOptions();
}
/**
* Creates a microsoft mangled context
* @param mangled the mangled name
* @param options the demangler options; if null, the default options are created
* @param program the program; can be null
* @param address the address for the name in the program; can be null
* @return the mangled context
*/
@Override
public MicrosoftMangledContext createMangledContext(String mangled, DemanglerOptions options,
Program program, Address address) {
return new MicrosoftMangledContext(program, getMicrosoftOptions(options), mangled, address);
}
private MicrosoftDemanglerOptions getMicrosoftOptions(DemanglerOptions options) {
if (options instanceof MicrosoftDemanglerOptions mOptions) {
return mOptions;
}
if (options == null) {
return createDefaultOptions();
}
return new MicrosoftDemanglerOptions(options);
}
} }

View file

@ -0,0 +1,109 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler.microsoft;
import ghidra.app.util.demangler.DemanglerOptions;
/**
* Microsoft demangler options
*/
public class MicrosoftDemanglerOptions extends DemanglerOptions {
private boolean errorOnRemainingChars;
private MsCInterpretation interpretation;
/**
* Default constructor for MicrosoftDemanglerOptions
*/
public MicrosoftDemanglerOptions() {
this(true);
interpretation = MsCInterpretation.FUNCTION_IF_EXISTS;
}
/**
* Constructor for MicrosoftDemanglerOptions
* @param errorOnRemainingChars {@code true} to error on remaining characters
*/
public MicrosoftDemanglerOptions(boolean errorOnRemainingChars) {
super();
this.errorOnRemainingChars = errorOnRemainingChars;
}
/**
* Copy constructor to create a version of this class from a more generic set of options
* @param copy the options to copy
*/
public MicrosoftDemanglerOptions(DemanglerOptions copy) {
super(copy);
if (copy instanceof MicrosoftDemanglerOptions mCopy) {
errorOnRemainingChars = mCopy.errorOnRemainingChars;
interpretation = mCopy.interpretation;
}
else {
errorOnRemainingChars = true;
interpretation = MsCInterpretation.FUNCTION_IF_EXISTS;
}
}
/**
* Sets the control for erroring on remaining characters at demangler completion
* @param errorOnRemainingCharsArg {@code true} to error when remaining characters exist
*/
public void setErrorOnRemainingChars(boolean errorOnRemainingCharsArg) {
errorOnRemainingChars = errorOnRemainingCharsArg;
}
/**
* Returns {@code true} if the process will error when remaining characters exist at the end
* of processing
* @return {@code true} if will error
*/
public boolean errorOnRemainingChars() {
return errorOnRemainingChars;
}
/**
* Sets the interpretation for processing a C-style mangled symbol if there could be multiple
* interpretations
* @param interpretationArg the interpretation to use
*/
public void setInterpretation(MsCInterpretation interpretationArg) {
interpretation = interpretationArg;
}
/**
* Returns the interpretation for processing a C-style mangled symbol if there could be multiple
* interpretations
* @return the interpretation used
*/
public MsCInterpretation getInterpretation() {
return interpretation;
}
@Override
public String toString() {
//@formatter:off
return "{\n" +
"\tdoDisassembly: " + doDisassembly() + ",\n" +
"\tapplySignature: " + applySignature() + ",\n" +
"\terrorOnRemainingChars: " + errorOnRemainingChars + ",\n" +
"\tinterpretation: " + interpretation + ",\n" +
"\tdemangleOnlyKnownPatterns: " + demangleOnlyKnownPatterns() + ",\n" +
"}";
//@formatter:on
}
}

View file

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

View file

@ -0,0 +1,77 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler.microsoft;
import ghidra.app.util.demangler.MangledContext;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
/**
* A simple class to contain the context of a mangled symbol for demangling
*/
public class MicrosoftMangledContext extends MangledContext {
/**
* Constructor for mangled context
* @param program the program; can be null
* @param options the demangler options
* @param mangled the mangled string
* @param address the address; can be null
*/
public MicrosoftMangledContext(Program program, MicrosoftDemanglerOptions options,
String mangled, Address address) {
super(program, options, mangled, address);
}
/**
* Returns the program architecture size
* @return the architecture size or zero if not known (program is null)
*/
public int getArchitectureSize() {
if (program == null) {
return 0;
}
return program.getAddressFactory().getDefaultAddressSpace().getSize();
}
/**
* Returns whether the symbol should be interpreted as a function
* @return {@code true} if should be interpreted as a function
*/
boolean shouldInterpretAsFunction() {
MsCInterpretation control =
((MicrosoftDemanglerOptions) options).getInterpretation();
return switch (control) {
case FUNCTION -> true;
case NON_FUNCTION -> false;
case FUNCTION_IF_EXISTS -> getExistingFunction() != null;
default -> throw new AssertionError("Invalid case");
};
}
/**
* Returns the function at the context address
* @return the function or null if program or address is null
*/
private Function getExistingFunction() {
if (program == null || address == null) {
return null;
}
return program.getFunctionManager().getFunctionAt(address);
}
}

View file

@ -0,0 +1,37 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler.microsoft;
/**
* Class to control whether a symbol should be demangled as a function symbols or a some other
* (e.g., variable) symbol
*/
public enum MsCInterpretation {
/**
* Forces processing as a function symbol if there are multiple symbol interpretations
*/
FUNCTION,
/**
* Forces processing as a non-function (e.g., variable) if there are multiple symbol
* interpretations
*/
NON_FUNCTION,
/**
* If there are multiple symbol interpretations, forces processing as a function only if
* there is already a function at the address
*/
FUNCTION_IF_EXISTS
}

View file

@ -0,0 +1,428 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler.microsoft;
import static org.junit.Assert.*;
import org.junit.*;
import generic.test.AbstractGenericTest;
import ghidra.app.util.demangler.*;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.VoidDataType;
import mdemangler.MDMangBaseTest;
import mdemangler.object.MDObjectC;
/**
* This class performs extra demangler testing for special cases that do not fit
* the testing pattern found in {@link MDMangBaseTest} and {@link MicrosoftDemanglerTest}
*/
public class MicrosoftDemanglerExtraTest extends AbstractGenericTest {
ProgramBuilder builder32;
ProgramBuilder builder64;
private ProgramDB program32;
private ProgramDB program64;
private Address address32;
private Address functionAddress32;
private Address address64;
private Address functionAddress64;
@Before
public void setUp() throws Exception {
String blockAddress = "0x01001000";
String nonFunctionAddress = "0x01001000";
String functionAddress = "0x01001010";
builder32 = new ProgramBuilder("test32", "x86:LE:32:default");
builder32.createMemory(".text", blockAddress, 0x100);
builder32.createEmptyFunction("function", functionAddress, 1, VoidDataType.dataType);
program32 = builder32.getProgram();
address32 = program32.getAddressFactory().getAddress(nonFunctionAddress);
functionAddress32 = program32.getAddressFactory().getAddress(functionAddress);
builder64 = new ProgramBuilder("test64", "x86:LE:64:default");
builder64.createMemory(".text", blockAddress, 0x100);
builder64.createEmptyFunction("function", functionAddress, 1, VoidDataType.dataType);
program64 = builder64.getProgram();
address64 = program64.getAddressFactory().getAddress(nonFunctionAddress);
functionAddress64 = program64.getAddressFactory().getAddress(functionAddress);
}
@After
public void tearDown() throws Exception {
builder32.dispose();
builder64.dispose();
}
//==============================================================================================
// Helpers
private void processWith32Function(String mangled, String expectDemangled,
String expectedFunction, String expectedConvention, int expectedNumBytes)
throws DemangledException {
MicrosoftDemangler demangler = new MicrosoftDemangler();
MicrosoftMangledContext context =
demangler.createMangledContext(mangled, null, program32, functionAddress32);
// We do not need to do this here: options.setErrorOnRemainingChars(false);
// Testing Demangled hierarchy
DemangledFunction demangledFunction = (DemangledFunction) demangler.demangle(context);
assertEquals(expectedFunction,
demangledFunction == null ? null : demangledFunction.toString());
// Testing MDMang hierarchy
MDObjectC objc = (MDObjectC) demangler.getMdItem();
String convention = objc.getCallingConvention();
int numParameterBytes = objc.getNumParameterBytes();
assertEquals(expectedConvention, convention);
assertEquals(expectedNumBytes, numParameterBytes);
assertEquals(expectDemangled, objc.toString());
}
private void processWith32NonFunction(String mangled, String expectDemangled)
throws DemangledException {
MicrosoftDemangler demangler = new MicrosoftDemangler();
MicrosoftMangledContext context =
demangler.createMangledContext(mangled, null, program32, address32);
MicrosoftDemanglerOptions options = (MicrosoftDemanglerOptions) context.getOptions();
// Important to set to false to standardize our test results to simple expected
// results. When the C-style symbols do not create function results either because
// there is not a function at the address or because of the architecture, we might end
// up with remaining charactes because the demangler sets its index back tot he start.
options.setErrorOnRemainingChars(false);
// Testing Demangled hierarchy
DemangledFunction demangledFunction = (DemangledFunction) demangler.demangle(context);
assertEquals(null, demangledFunction);
// Testing MDMang hierarchy
MDObjectC objc = (MDObjectC) demangler.getMdItem();
String convention = objc.getCallingConvention();
int numParameterBytes = objc.getNumParameterBytes();
assertEquals(null, convention);
assertEquals(0, numParameterBytes);
assertEquals(expectDemangled, objc.toString());
}
private void processWith64Function(String mangled, String expectDemangled,
String expectedFunction, String expectedConvention, int expectedNumBytes)
throws DemangledException {
MicrosoftDemangler demangler = new MicrosoftDemangler();
MicrosoftMangledContext context =
demangler.createMangledContext(mangled, null, program64, functionAddress64);
MicrosoftDemanglerOptions options = (MicrosoftDemanglerOptions) context.getOptions();
// Important to set to false to standardize our test results to simple expected
// results. When the C-style symbols do not create function results either because
// there is not a function at the address or because of the architecture, we might end
// up with remaining charactes because the demangler sets its index back tot he start.
options.setErrorOnRemainingChars(false);
// Testing Demangled hierarchy
DemangledFunction demangledFunction = (DemangledFunction) demangler.demangle(context);
assertEquals(expectedFunction,
demangledFunction == null ? null : demangledFunction.toString());
// Testing MDMang hierarchy
MDObjectC objc = (MDObjectC) demangler.getMdItem();
String convention = objc.getCallingConvention();
int numParameterBytes = objc.getNumParameterBytes();
assertEquals(expectedConvention, convention);
assertEquals(expectedNumBytes, numParameterBytes);
assertEquals(expectDemangled, objc.toString());
}
private void processWith64NonFunction(String mangled, String expectDemangled)
throws DemangledException {
MicrosoftDemangler demangler = new MicrosoftDemangler();
MicrosoftMangledContext context =
demangler.createMangledContext(mangled, null, program64, address64);
MicrosoftDemanglerOptions options = (MicrosoftDemanglerOptions) context.getOptions();
// Important to set to false to standardize our test results to simple expected
// results. When the C-style symbols do not create function results either because
// there is not a function at the address or because of the architecture, we might end
// up with remaining charactes because the demangler sets its index back tot he start.
options.setErrorOnRemainingChars(false);
// Testing Demangled hierarchy
DemangledFunction demangledFunction = (DemangledFunction) demangler.demangle(context);
assertEquals(null, demangledFunction);
// Testing MDMang hierarchy
MDObjectC objc = (MDObjectC) demangler.getMdItem();
String convention = objc.getCallingConvention();
int numParameterBytes = objc.getNumParameterBytes();
assertEquals(null, convention);
assertEquals(0, numParameterBytes);
assertEquals(expectDemangled, objc.toString());
}
//==============================================================================================
@Test
//This test checks that we can provide a mangled string for a function namespace.
// The return String from getOriginalMangled() is not null only for this special
// circumstance. So, in normal processing, we should check it for non-null to
// determine that we have a result of this form.
// The symbol here is from our cn3.cpp source target.
public void testFunctionNamespace() throws Exception {
String mangled = "?fn3@?2??Bar3@Foo2b@@SAHXZ@4HA";
String wholeTruth = "int `public: static int __cdecl Foo2b::Bar3(void)'::`3'::fn3";
String functionNamespaceMangledTruth = "?Bar3@Foo2b@@SAHXZ";
String functionNamespaceTruth = "public: static int __cdecl Foo2b::Bar3(void)";
MicrosoftDemangler demangler = new MicrosoftDemangler();
MicrosoftMangledContext context =
demangler.createMangledContext(mangled, null, program32, address32);
DemangledObject obj = demangler.demangle(context);
String demangled = demangler.getMdItem().toString();
assertEquals(wholeTruth, demangled);
String mangledFunctionNS = obj.getNamespace().getNamespace().getMangledString();
assertEquals(functionNamespaceMangledTruth, mangledFunctionNS);
context = demangler.createMangledContext(mangledFunctionNS, null, program32, address32);
demangler.demangle(context);
demangled = demangler.getMdItem().toString();
assertEquals(functionNamespaceTruth, demangled);
}
//==============================================================================================
/*
* Follow are C-style mangling scheme under 32-bit model; __vectorcall also valid for 64-bit
* __cdecl: '_' prefix; no suffix; example "_name"
* __stdcall: '_' prefix; "@<decimal_digits>" suffix; example "_name@12"
* __fastcall: '@' prefix; "@<decimal_digits>" suffix; example "@name@12"
* __vectorcall: no prefix; "@@<decimal_digits>" suffix; example "name@@12"
*/
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: cdecl; Architecture size: 32; Function present: yes
// Result: cdecl function (stripped '_'); 0 bytes
public void testCStyleCdeclWith32Function() throws Exception {
String mangled = "_func_cdecl";
String expectedDemangled = "func_cdecl";
String expectedFunction = "__cdecl func_cdecl(void)";
String expectedConvention = "__cdecl";
int expectedNumBytes = 0;
processWith32Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: cdecl; Architecture size: 32; Function present: no
// Result: no function; 0 bytes
public void testCStyleCdeclWith32NoFunction() throws Exception {
String mangled = "_func_cdecl";
String expectedDemangled = "_func_cdecl";
processWith32NonFunction(mangled, expectedDemangled);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: cdecl; Architecture size: 64; Function present: yes
// Result: no function; 0 bytes
public void testCStyleCdeclWith64Function() throws Exception {
String mangled = "_func_cdecl";
String expectedDemangled = "_func_cdecl";
String expectedFunction = null;
String expectedConvention = null;
int expectedNumBytes = 0;
processWith64Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: cdecl; Architecture size: 64; Function present: no
// Result: no function; 0 bytes
public void testCStyleCdeclWith64NoFunction() throws Exception {
String mangled = "_func_cdecl";
String expectedDemangled = "_func_cdecl";
processWith64NonFunction(mangled, expectedDemangled);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: stdcall; Architecture size: 32; Function present: yes
// Result: stdcall function; 12 bytes
public void testCStyleStdcallWith32Function() throws Exception {
String mangled = "_func_stdcall@12";
String expectedDemangled = "func_stdcall";
String expectedFunction = "__stdcall func_stdcall(undefined4,undefined4,undefined4)";
String expectedConvention = "__stdcall";
int expectedNumBytes = 12;
processWith32Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: stdcall; Architecture size: 32; Function present: no
// Result: no function; 0 bytes
public void testCStyleStdcallWith32NoFunction() throws Exception {
String mangled = "_func_stdcall@12";
String expectedDemangled = "_func_stdcall";
processWith32NonFunction(mangled, expectedDemangled);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: stdcall; Architecture size: 64; Function present: yes
// Result: no function; 0 bytes
public void testCStyleStdcallWith64Function() throws Exception {
String mangled = "_func_stdcall@12";
String expectedDemangled = "_func_stdcall";
String expectedFunction = null;
String expectedConvention = null;
int expectedNumBytes = 0;
processWith64Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: stdcall; Architecture size: 64; Function present: no
// Result: no function; 0 bytes
public void testCStyleStdcallWith64NoFunction() throws Exception {
String mangled = "_func_stdcall@12";
String expectedDemangled = "_func_stdcall";
processWith64NonFunction(mangled, expectedDemangled);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: fastcall; Architecture size: 32; Function present: yes
// Result: fastcall function (stripped '@'); 12 bytes
public void testCStyleFastcallWith32Function() throws Exception {
String mangled = "@func_fastcall@12";
String expectedDemangled = "func_fastcall";
String expectedFunction = "__fastcall func_fastcall(undefined4,undefined4,undefined4)";
String expectedConvention = "__fastcall";
int expectedNumBytes = 12;
processWith32Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: fastcall; Architecture size: 32; Function present: no
// Result: no function; 12 bytes
public void testCStyleFastcallWith32NoFunction() throws Exception {
String mangled = "@func_fastcall@12";
String expectedDemangled = ""; // empty because the prefix '@' causes an empty name
processWith32NonFunction(mangled, expectedDemangled);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: fastcall; Architecture size: 64; Function present: yes
// Result: no function; 12 bytes
public void testCStyleFastcallWith64Function() throws Exception {
String mangled = "@func_fastcall@12";
String expectedDemangled = ""; // empty because the prefix '@' causes an empty name
String expectedFunction = null;
String expectedConvention = null;
int expectedNumBytes = 0;
processWith64Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: fastcall; Architecture size: 64; Function present: no
// Result: fastcall function; 12 bytes
public void testCStyleFastcallWith64NoFunction() throws Exception {
String mangled = "@func_fastcall@12";
String expectedDemangled = ""; // empty because the prefix '@' causes an empty name
processWith64NonFunction(mangled, expectedDemangled);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: vectorcall; Architecture size: 32; Function present: yes
// Result: vectorcall function; 12 bytes
public void testCStyleVectorcallWith32Function() throws Exception {
String mangled = "func_vectorcall@@12";
String expectedDemangled = "func_vectorcall";
String expectedFunction = "__vectorcall func_vectorcall(undefined4,undefined4,undefined4)";
String expectedConvention = "__vectorcall";
int expectedNumBytes = 12;
processWith32Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: vectorcall; Architecture size: 32; Function present: no
// Result: no function; 0 bytes
public void testCStyleVectorcallWith32NoFunction() throws Exception {
String mangled = "func_vectorcall@@12";
String expectedDemangled = "func_vectorcall";
processWith32NonFunction(mangled, expectedDemangled);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: vectorcall; Architecture size: 32; Function present: yes
// Result: vectorcall function; 12 bytes
public void testCStyleVectorcallWith64Function() throws Exception {
String mangled = "func_vectorcall@@12";
String expectedDemangled = "func_vectorcall";
String expectedFunction = "__vectorcall func_vectorcall(undefined4,undefined4,undefined4)";
String expectedConvention = "__vectorcall";
int expectedNumBytes = 12;
processWith64Function(mangled, expectedDemangled, expectedFunction, expectedConvention,
expectedNumBytes);
}
@Test
//Uses additional context information for demangling: architecture size and whether
// demangling symbol for a known function
// Scheme: vectorcall; Architecture size: 64; Function present: no
// Result: no function; 0 bytes
public void testCStyleVectorcallWith64NoFunction() throws Exception {
String mangled = "func_vectorcall@@12";
String expectedDemangled = "func_vectorcall";
processWith64NonFunction(mangled, expectedDemangled);
}
}

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -45,21 +45,24 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
public void testUnsignedShortParameter() throws Exception { public void testUnsignedShortParameter() throws Exception {
String mangled = "?InvokeHelperV@COleDispatchDriver@@QAEXJGGPAXPBEPAD@Z"; String mangled = "?InvokeHelperV@COleDispatchDriver@@QAEXJGGPAXPBEPAD@Z";
Address address = addr("01001000");
MicrosoftDemangler demangler = new MicrosoftDemangler(); 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"); int txID = program.startTransaction("Test");
SymbolTable st = program.getSymbolTable(); 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); program.endTransaction(txID, true);
FunctionManager fm = program.getFunctionManager(); FunctionManager fm = program.getFunctionManager();
Function function = fm.getFunctionAt(addr("01001000")); Function function = fm.getFunctionAt(address);
Parameter[] parameters = function.getParameters(); Parameter[] parameters = function.getParameters();
// this was broken at one point, returning 'unsigned_short' // this was broken at one point, returning 'unsigned_short'
@ -69,17 +72,19 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
@Test @Test
public void testArrayVariable() throws Exception { // NullPointerException public void testArrayVariable() throws Exception { // NullPointerException
String mangled = "?Te@NS1@BobsStuff@@0QAY0BAA@$$CBIA"; String mangled = "?Te@NS1@BobsStuff@@0QAY0BAA@$$CBIA";
Address address = addr("01001000");
MicrosoftDemangler demangler = new MicrosoftDemangler(); 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"); int txID = program.startTransaction("Test");
SymbolTable st = program.getSymbolTable(); SymbolTable st = program.getSymbolTable();
st.createLabel(addr("01001000"), mangled, SourceType.ANALYSIS); st.createLabel(address, mangled, SourceType.ANALYSIS);
DemanglerOptions options = new DemanglerOptions(); demangledObject.applyTo(program, address, options, TaskMonitor.DUMMY);
demangledObject.applyTo(program, addr("01001000"), options, TaskMonitor.DUMMY);
program.endTransaction(txID, false); program.endTransaction(txID, false);
} }
@ -203,8 +208,11 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
String mangled = "?BobsStuffIO@344GPAUHINSTANCE__@@U_COMMPROP@@+W"; String mangled = "?BobsStuffIO@344GPAUHINSTANCE__@@U_COMMPROP@@+W";
MicrosoftDemangler demangler = new MicrosoftDemangler(); MicrosoftDemangler demangler = new MicrosoftDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, null);
try { try {
demangler.demangle(mangled); demangler.demangle(mangledContext);
} }
catch (DemangledException e) { catch (DemangledException e) {
// Expected // Expected
@ -218,8 +226,10 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
String mangled = "?BobsStuffIO@344GPAUHINSTANCE__@@U_COMMPROP@@/W"; String mangled = "?BobsStuffIO@344GPAUHINSTANCE__@@U_COMMPROP@@/W";
MicrosoftDemangler demangler = new MicrosoftDemangler(); MicrosoftDemangler demangler = new MicrosoftDemangler();
MangledContext mangledContext =
demangler.createMangledContext(mangled, null, program, null);
try { try {
demangler.demangle(mangled); demangler.demangle(mangledContext);
} }
catch (DemangledException e) { catch (DemangledException e) {
// Expected // Expected

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -93,8 +93,9 @@ public class DeveloperDumpMDMangParseInfoScript extends GhidraScript {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("\nName: " + name + "\n"); builder.append("\nName: " + name + "\n");
MDMangParseInfo demangler = new MDMangParseInfo(); MDMangParseInfo demangler = new MDMangParseInfo();
demangler.setMangledSymbol(name);
try { try {
demangler.demangle(name, false); demangler.demangle();
String parseInfo = demangler.getParseInfoIncremental(); String parseInfo = demangler.getParseInfoIncremental();
builder.append(parseInfo); builder.append(parseInfo);
builder.append("Num remaining chars:" + demangler.getNumCharsRemaining() + "\n"); builder.append("Num remaining chars:" + demangler.getNumCharsRemaining() + "\n");

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -125,8 +125,9 @@ public class MDMangDeveloperGenericizeMangledNamesScript extends GhidraScript {
return getError(name, "contains white space"); return getError(name, "contains white space");
} }
MDMangGenericize demangler = new MDMangGenericize(); MDMangGenericize demangler = new MDMangGenericize();
demangler.setMangledSymbol(name);
try { try {
demangler.demangle(name, false); demangler.demangle();
} }
catch (MDException e) { catch (MDException e) {
return getError(name, e.getMessage()); return getError(name, e.getMessage());

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -17,13 +17,13 @@ package mdemangler;
/** /**
* A class for bidirectional iteration over a string. * A class for bidirectional iteration over a string.
* *
* Iterators maintain a current character index, whose valid range is from * Iterators maintain a current character index, whose valid range is from
* 0 to string.length()-1. * 0 to string.length()-1.
* *
* The current index can be retrieved by calling getIndex() and set directly * The current index can be retrieved by calling getIndex() and set directly
* by calling setIndex(). * by calling setIndex().
* *
* The methods previous() and next() are used for iteration. They return DONE if * 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. * 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. * Sets the position to the specified position in the text. Can set index to just beyond
* @param index the position within the text. * the text to represent the iterator being at the end of the text
* @return the character at the specified position * @param index the position within the text.
* @throws IllegalArgumentException if index is not in range from 0 to string.length()-1 * @throws IllegalArgumentException if index is not in range from 0 to string.length()
*/ */
public void setIndex(int index) { public void setIndex(int index) {
if (index < 0 || index > string.length() - 1) { if (index < 0 || index > string.length()) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
this.index = index; 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 * @return the next character without incrementing the current index
*/ */
public char peek() { 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 * If the resulting index is greater or equal
* to the end index, the current index is reset to the end index and * to the end index, the current index is reset to the end index and
* a value of DONE is returned. * 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. * Does no testing for whether the index surpasses the length of the string.
*/ */
public void increment() { 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. * Does no testing for whether the index surpasses the length of the string.
*/ */
public void increment(int count) { public void increment(int count) {

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -59,7 +59,10 @@ public class MDDotSeparatedItem extends MDParsableItem {
try { try {
Constructor<? extends MDMang> ctor = dmang.getClass().getDeclaredConstructor(); Constructor<? extends MDMang> ctor = dmang.getClass().getDeclaredConstructor();
MDMang subDmang = ctor.newInstance(); 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 // might want to handle these separately for now... later can possibly group all
// together // together

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,6 +19,8 @@ import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils;
import mdemangler.MDContext.MDContextType; import mdemangler.MDContext.MDContextType;
import mdemangler.datatype.MDDataType; import mdemangler.datatype.MDDataType;
import mdemangler.datatype.MDDataTypeParser; import mdemangler.datatype.MDDataTypeParser;
@ -38,6 +40,9 @@ import mdemangler.template.MDTemplateArgumentsList;
public class MDMang { public class MDMang {
public static final char DONE = MDCharacterIterator.DONE; public static final char DONE = MDCharacterIterator.DONE;
protected int architectureSize = 32;
protected boolean isFunction = false;
protected String mangled; protected String mangled;
protected MDCharacterIterator iter; protected MDCharacterIterator iter;
protected String errorMessage; protected String errorMessage;
@ -45,12 +50,147 @@ public class MDMang {
protected List<MDContext> contextStack; protected List<MDContext> contextStack;
protected boolean errorOnRemainingChars = false;
public enum ProcessingMode { public enum ProcessingMode {
DEFAULT_STANDARD, LLVM DEFAULT_STANDARD, LLVM
} }
private ProcessingMode processingMode; 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) { public void setProcessingMode(ProcessingMode processingMode) {
this.processingMode = processingMode; this.processingMode = processingMode;
} }
@ -67,33 +207,13 @@ public class MDMang {
return processingMode == ProcessingMode.LLVM; 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. * Variables that get set at the very beginning.
* @throws MDException if mangled name is not set * @throws MDException if mangled name is not set
*/ */
protected void initState() throws MDException { protected void initState() throws MDException {
if (mangled == null) { if (StringUtils.isBlank(mangled)) {
throw new MDException("MDMang: Mangled string is null."); throw new MDException("MDMang: Mangled string is null or blank.");
} }
errorMessage = ""; errorMessage = "";
processingMode = ProcessingMode.DEFAULT_STANDARD; processingMode = ProcessingMode.DEFAULT_STANDARD;
@ -109,108 +229,7 @@ public class MDMang {
setIndex(0); 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. * Sets the current index. Can set index to just beyond the text to represent the iterator
* @param index the position to set. * being at the end of the text
* @throws IllegalArgumentException if index is not in range from 0 to string.length()-1 * @param index the position to set
* @throws IllegalArgumentException if index is not in range from 0 to string.length()
*/ */
public void setIndex(int index) { public void setIndex(int index) {
iter.setIndex(index); iter.setIndex(index);

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -67,7 +67,7 @@ public class MDMangGenericize extends MDMang {
// return item; // return item;
// } // }
@Override @Override
public MDParsableItem demangle(boolean errorOnRemainingChars) throws MDException { public MDParsableItem demangle() throws MDException {
// ignoring the 'errorOnRemainingChars' parameter (for now) // ignoring the 'errorOnRemainingChars' parameter (for now)
initState(); initState();
item = MDMangObjectParser.determineItemAndParse(this); item = MDMangObjectParser.determineItemAndParse(this);

View file

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

View file

@ -28,9 +28,8 @@ import mdemangler.template.MDTemplateArgumentsList;
public class MDMangVS2015 extends MDMang { public class MDMangVS2015 extends MDMang {
@Override @Override
public MDParsableItem demangle(String mangledIn, boolean errorOnRemainingChars) public MDParsableItem demangle() throws MDException {
throws MDException { MDParsableItem returnedItem = super.demangle();
MDParsableItem returnedItem = super.demangle(mangledIn, errorOnRemainingChars);
//VS2015 does not understand all of the object types that we made up. These all fall //VS2015 does not understand all of the object types that we made up. These all fall
// under MDObjectReserved; but it does understand MDObjectBracket objects. // under MDObjectReserved; but it does understand MDObjectBracket objects.
if (returnedItem instanceof MDObjectBracket) { if (returnedItem instanceof MDObjectBracket) {

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -25,21 +25,131 @@ import mdemangler.naming.MDFragmentName;
*/ */
public class MDObjectC extends MDObject { public class MDObjectC extends MDObject {
protected MDFragmentName name; protected MDFragmentName name;
int conventionIndex;
int numParameterBytes;
private final String callingConvention[] =
{ "__cdecl", "__stdcall", "__fastcall", "__vectorcall" };
public MDObjectC(MDMang dmang) { public MDObjectC(MDMang dmang) {
super(dmang); super(dmang);
conventionIndex = -1;
numParameterBytes = 0;
name = new MDFragmentName(dmang); 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 @Override
public void insert(StringBuilder builder) { 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); 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 @Override
protected void parseInternal() throws MDException { protected void parseInternal() throws MDException {
name.parse(); if (!dmang.isFunction()) {
name.parse();
return;
}
int index = dmang.getIndex();
char c = dmang.peek();
if (c == '@') {
conventionIndex = 2;
dmang.next();
}
else if (c == '_') {
conventionIndex = 0; // will be 0 or 1
dmang.next();
}
else {
conventionIndex = 3;
}
name.parse(); // This strips a trailing '@' if it exists
c = dmang.peek();
if (c == '@') {
if (conventionIndex != 3) {
throw new MDException("Error parsing C Object calling convention");
}
dmang.next(); // skip the '@'
}
else if (conventionIndex == 0 &&
dmang.getMangledSymbol().charAt(dmang.getIndex() - 1) == '@') {
conventionIndex = 1;
}
if (dmang.getArchitectureSize() != 32 && conventionIndex != 3) {
conventionIndex = -1;
dmang.setIndex(index); // reset iterator back to original location
name.parse();
return;
}
if (conventionIndex != 0) {
numParameterBytes = parseNumParameterBytes();
}
} }
private int parseNumParameterBytes() throws MDException {
int loc = dmang.getIndex();
String str = dmang.getMangledSymbol().substring(loc);
dmang.setIndex(loc + dmang.getNumCharsRemaining());
try {
return Integer.parseInt(str);
}
catch (NumberFormatException e) {
throw new MDException("Error parsing C Object calling convention");
}
}
} }
/******************************************************************************/ /******************************************************************************/

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -56,6 +56,14 @@ public class MDObjectCPP extends MDObject {
return this; 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. * Returns the name of the symbol, minus any namespace component.
* @return the name. * @return the name.

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -44,6 +44,7 @@ public class MDBaseTestConfiguration {
// Internal variables // Internal variables
protected String mangled; protected String mangled;
protected MDParsableItem demangItem; protected MDParsableItem demangItem;
protected boolean isFunction = false;
protected String demangled; protected String demangled;
protected String truth; 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, * Runs through the process of creating a demangler, demangling a symbol string,
* testing the output, and performing other ancillary outputs and tests. * testing the output, and performing other ancillary outputs and tests.
@ -85,6 +90,7 @@ public class MDBaseTestConfiguration {
outputInfo.append(getTestHeader()); outputInfo.append(getTestHeader());
} }
mdm.setIsFunction(isFunction);
// Meant to be overridden, as needed by extended classes // Meant to be overridden, as needed by extended classes
demangItem = doDemangleSymbol(mdm, mangled); demangItem = doDemangleSymbol(mdm, mangled);
demangled = (demangItem == null) ? "" : demangItem.toString(); demangled = (demangItem == null) ? "" : demangItem.toString();
@ -123,6 +129,7 @@ public class MDBaseTestConfiguration {
} }
} }
// Need to do a better job here
private boolean isMangled(String s) { private boolean isMangled(String s) {
if (s.charAt(0) == '?') { if (s.charAt(0) == '?') {
return true; return true;
@ -130,9 +137,9 @@ public class MDBaseTestConfiguration {
else if (s.startsWith("__")) { else if (s.startsWith("__")) {
return true; return true;
} }
else if ((s.charAt(0) == '_') || Character.isUpperCase(s.charAt(1))) { // else if ((s.charAt(0) == '_') || Character.isUpperCase(s.charAt(1))) {
return true; // return true;
} // }
return false; return false;
} }
@ -193,8 +200,10 @@ public class MDBaseTestConfiguration {
// Meant to be overridden, as needed by extended classes // Meant to be overridden, as needed by extended classes
protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception { protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception {
mdmIn.setMangledSymbol(mangledIn);
mdmIn.setErrorOnRemainingChars(true);
try { try {
return mdmIn.demangle(mangledIn, true); return mdmIn.demangle();
} }
catch (MDException e) { catch (MDException e) {
return null; return null;

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -15,8 +15,6 @@
*/ */
package mdemangler; package mdemangler;
import ghidra.app.util.demangler.DemangledObject;
/** /**
* This class is a derivation of MDBaseTestConfiguration (see javadoc there). This * This class is a derivation of MDBaseTestConfiguration (see javadoc there). This
* class must choose the appropriate truth from MDMangBaseTest (new truths might * 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 { public class MDGhidraTestConfiguration extends MDBaseTestConfiguration {
protected DemangledObject demangledObject; // protected DemangledObject demangledObject;
protected String demangledGhidraObject; // protected String demangledGhidraObject;
protected DemangledObject demangledObjectCheck; // protected DemangledObject demangledObjectCheck;
public MDGhidraTestConfiguration(boolean quiet) { public MDGhidraTestConfiguration(boolean quiet) {
super(quiet); super(quiet);
@ -48,10 +46,12 @@ public class MDGhidraTestConfiguration extends MDBaseTestConfiguration {
@Override @Override
protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception { protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception {
MDParsableItem returnItem; MDParsableItem returnItem;
mdmIn.setMangledSymbol(mangledIn);
mdmIn.setErrorOnRemainingChars(true);
try { try {
// For first boolean: set true in operational mode. // For first boolean: set true in operational mode.
returnItem = ((MDMangGhidra) mdmIn).demangle(mangledIn, false, false); returnItem = mdmIn.demangle();
demangledObject = ((MDMangGhidra) mdmIn).getObject(); // demangledObject = ((MDMangGhidra) mdmIn).getObject();
} }
catch (MDException e) { catch (MDException e) {
returnItem = null; returnItem = null;
@ -62,14 +62,14 @@ public class MDGhidraTestConfiguration extends MDBaseTestConfiguration {
@Override @Override
protected void doBasicTestsAndOutput() throws Exception { protected void doBasicTestsAndOutput() throws Exception {
super.doBasicTestsAndOutput(); super.doBasicTestsAndOutput();
if (demangledObject != null) { // if (demangledObject != null) {
demangledGhidraObject = demangledObject.toString(); // demangledGhidraObject = demangledObject.toString();
outputInfo.append("demangl: " + demangledGhidraObject + "\n"); // outputInfo.append("demangl: " + demangledGhidraObject + "\n");
} // }
else { // else {
demangledGhidraObject = ""; // demangledGhidraObject = "";
outputInfo.append("demangled: NO RESULT\n"); // outputInfo.append("demangled: NO RESULT\n");
} // }
// For checking the original results, for comparison purposes, this code should probably // For checking the original results, for comparison purposes, this code should probably
// be calling the MicrosoftWineDemangler. // be calling the MicrosoftWineDemangler.
// try { // try {
@ -86,38 +86,38 @@ public class MDGhidraTestConfiguration extends MDBaseTestConfiguration {
// } // }
} }
@Override // @Override
protected void doExtraProcCheck() throws Exception { // protected void doExtraProcCheck() throws Exception {
if ((demangledObjectCheck != null) && (demangledObject != null)) { // if ((demangledObjectCheck != null) && (demangledObject != null)) {
if (demangledObjectCheck.getClass() != demangledObject.getClass()) { // if (demangledObjectCheck.getClass() != demangledObject.getClass()) {
outputInfo.append("ObjComp: notequal NEW: " + demangledObject.getClass().getName() + // outputInfo.append("ObjComp: notequal NEW: " + demangledObject.getClass().getName() +
", OLD: " + demangledObjectCheck.getClass().getName() + "\n"); // ", OLD: " + demangledObjectCheck.getClass().getName() + "\n");
} // }
else { // else {
outputInfo.append("ObjComp: equal NEW: " + demangledObject.getClass().getName() + // outputInfo.append("ObjComp: equal NEW: " + demangledObject.getClass().getName() +
", OLD: " + demangledObjectCheck.getClass().getName() + "\n"); // ", OLD: " + demangledObjectCheck.getClass().getName() + "\n");
} // }
} // }
else { // else {
if ((demangledObjectCheck == null) && (demangledObject == null)) { // if ((demangledObjectCheck == null) && (demangledObject == null)) {
outputInfo.append("ObjComp: Not possible -- both null\n"); // outputInfo.append("ObjComp: Not possible -- both null\n");
} // }
else if (demangledObjectCheck == null) { // else if (demangledObjectCheck == null) {
outputInfo.append("ObjComp: Not possible -- OLD null; NEW: " + // outputInfo.append("ObjComp: Not possible -- OLD null; NEW: " +
demangledObject.getClass().getName() + "\n"); // demangledObject.getClass().getName() + "\n");
} // }
else { // else {
outputInfo.append("ObjComp: Not possible -- NEW null; OLD: " + // outputInfo.append("ObjComp: Not possible -- NEW null; OLD: " +
demangledObjectCheck.getClass().getName() + "\n"); // demangledObjectCheck.getClass().getName() + "\n");
} // }
} // }
if (ghidraTestStringCompare(outputInfo, demangled, demangledGhidraObject)) { // if (ghidraTestStringCompare(outputInfo, demangled, demangledGhidraObject)) {
outputInfo.append("RESULTS MATCH------******\n"); // outputInfo.append("RESULTS MATCH------******\n");
} // }
else { // else {
outputInfo.append("RESULTS MISMATCH------*********************************\n"); // outputInfo.append("RESULTS MISMATCH------*********************************\n");
} // }
} // }
private boolean ghidraTestStringCompare(StringBuilder outputInfoArg, String truthString, private boolean ghidraTestStringCompare(StringBuilder outputInfoArg, String truthString,
String ghidraString) { String ghidraString) {

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -194,6 +194,12 @@ public class MDMangBaseTest extends AbstractGenericTest {
ms2013Truth); ms2013Truth);
} }
private void demangleAndTestFunction() throws Exception {
testConfiguration.setIsFunction(true);
testConfiguration.demangleAndTest(testName, mangled, mdTruth, msTruth, ghTruth,
ms2013Truth);
}
@Test @Test
public void testTripleQ0() throws Exception { public void testTripleQ0() throws Exception {
mangled = "???__E??_7name0@name1@@6B@@@YMXXZ@?A0x647dec29@@$$FYMXXZ"; mangled = "???__E??_7name0@name1@@6B@@@YMXXZ@?A0x647dec29@@$$FYMXXZ";
@ -15312,6 +15318,81 @@ public class MDMangBaseTest extends AbstractGenericTest {
demangleAndTest(); 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. //TODO: ignore for now.

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -22,7 +22,6 @@ import java.util.List;
import org.junit.Test; import org.junit.Test;
import generic.test.AbstractGenericTest; import generic.test.AbstractGenericTest;
import ghidra.app.util.demangler.DemangledObject;
import mdemangler.naming.MDQualification; import mdemangler.naming.MDQualification;
import mdemangler.object.MDObjectCPP; import mdemangler.object.MDObjectCPP;
import mdemangler.typeinfo.MDVxTable; import mdemangler.typeinfo.MDVxTable;
@ -33,32 +32,6 @@ import mdemangler.typeinfo.MDVxTable;
*/ */
public class MDMangExtraTest extends AbstractGenericTest { 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 @Test
public void testVxTableNestedQualifications() throws Exception { public void testVxTableNestedQualifications() throws Exception {
// Test string taken from MDMangBaseTest // 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'}"; String truth = "const b::a::`vftable'{for `e::d::c's `h::g::f's `k::j::i'}";
MDMangGhidra demangler = new MDMangGhidra(); 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(); String demangled = item.toString();
assertEquals(truth, demangled); assertEquals(truth, demangled);
@ -88,7 +64,9 @@ public class MDMangExtraTest extends AbstractGenericTest {
String truth = "enum `void __cdecl name2::name1(bool)'::name0"; String truth = "enum `void __cdecl name2::name1(bool)'::name0";
MDMangGhidra demangler = new MDMangGhidra(); 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(); String demangled = item.toString();
assertEquals(truth, demangled); assertEquals(truth, demangled);

View file

@ -43,7 +43,9 @@ public class MDMangUtilsTest extends AbstractGenericTest {
"class `struct name1::name2 __cdecl name1::name0(struct name1::name3,struct name1::name4)'::`1'::<lambda_0>"; "class `struct name1::name2 __cdecl name1::name0(struct name1::name3,struct name1::name4)'::`1'::<lambda_0>";
MDMangGhidra demangler = new MDMangGhidra(); MDMangGhidra demangler = new MDMangGhidra();
MDDataType item = demangler.demangleType(mangled, true); demangler.setMangledSymbol(mangled);
demangler.setErrorOnRemainingChars(true);
MDDataType item = demangler.demangleType();
String demangled = item.toString(); String demangled = item.toString();
SymbolPath symbolPath = MDMangUtils.getSymbolPath(item); 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>"; "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(); MDMangGhidra demangler = new MDMangGhidra();
MDDataType item = demangler.demangleType(mangled, true); demangler.setMangledSymbol(mangled);
demangler.setErrorOnRemainingChars(true);
MDDataType item = demangler.demangleType();
String demangled = item.toString(); String demangled = item.toString();
SymbolPath symbolPath = MDMangUtils.getSymbolPath(item); 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>"; "struct name4::name3::name0<class `public: virtual __cdecl name2::Aname1::~Aname1(void) __ptr64'::`1'::<lambda_0> && __ptr64>";
MDMangGhidra demangler = new MDMangGhidra(); MDMangGhidra demangler = new MDMangGhidra();
MDDataType item = demangler.demangleType(mangled, true); demangler.setMangledSymbol(mangled);
demangler.setErrorOnRemainingChars(true);
MDDataType item = demangler.demangleType();
String demangled = item.toString(); String demangled = item.toString();
SymbolPath symbolPath = MDMangUtils.getSymbolPath(item); SymbolPath symbolPath = MDMangUtils.getSymbolPath(item);

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -41,8 +41,10 @@ public class MDVS2013TestConfiguration extends MDBaseTestConfiguration {
@Override @Override
protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception { protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception {
mdmIn.setMangledSymbol(mangledIn);
// We are not setting errorOnRemainingChars to true (diff from base test)
try { try {
return mdmIn.demangle(mangledIn, false); // "false" is different return mdmIn.demangle();
} }
catch (MDException e) { catch (MDException e) {
return null; return null;

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -36,8 +36,10 @@ public class MDVS2015TestConfiguration extends MDBaseTestConfiguration {
@Override @Override
protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception { protected MDParsableItem doDemangleSymbol(MDMang mdmIn, String mangledIn) throws Exception {
mdmIn.setMangledSymbol(mangledIn);
// We are not setting errorOnRemainingChars to true (diff from base test)
try { try {
return mdmIn.demangle(mangledIn, false); // "false" is different return mdmIn.demangle();
} }
catch (MDException e) { catch (MDException e) {
return null; return null;

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -75,8 +75,10 @@ public class DumpAllSymbolsDemangledScript extends GhidraScript {
*/ */
private static String getDemangledString(String mangledString) { private static String getDemangledString(String mangledString) {
MDMangGhidra demangler = new MDMangGhidra(); MDMangGhidra demangler = new MDMangGhidra();
demangler.setMangledSymbol(mangledString);
demangler.setErrorOnRemainingChars(true);
try { try {
MDParsableItem parsableItem = demangler.demangle(mangledString, true); MDParsableItem parsableItem = demangler.demangle();
if (parsableItem instanceof MDObjectCPP) { if (parsableItem instanceof MDObjectCPP) {
MDObjectCPP mdObject = (MDObjectCPP) parsableItem; MDObjectCPP mdObject = (MDObjectCPP) parsableItem;
return mdObject.getQualifiedName().toString(); return mdObject.getQualifiedName().toString();

View file

@ -118,8 +118,10 @@ public abstract class AbstractComplexTypeApplier extends MsDataTypeApplier {
private static SymbolPath getSymbolPathFromMangledTypeName(String mangledString, private static SymbolPath getSymbolPathFromMangledTypeName(String mangledString,
String fullPathName) { String fullPathName) {
MDMang demangler = new MDMangGhidra(); MDMang demangler = new MDMangGhidra();
demangler.setErrorOnRemainingChars(true);
demangler.setMangledSymbol(mangledString);
try { try {
MDDataType mdDataType = demangler.demangleType(mangledString, true); MDDataType mdDataType = demangler.demangleType();
// 20240626: Ultimately, it might be better to retrieve the Demangled-type to pass // 20240626: Ultimately, it might be better to retrieve the Demangled-type to pass
// to the DemangledObject.createNamespace() method to convert to a true Ghidra // 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 // Namespace that are flagged as functions (not capable at this time) or types or

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -798,8 +798,10 @@ public class PdbResearch {
return null; return null;
} }
MDMangGhidra demangler = new MDMangGhidra(); MDMangGhidra demangler = new MDMangGhidra();
demangler.setMangledSymbol(mangledString);
demangler.setErrorOnRemainingChars(true);
try { try {
MDParsableItem parsableItem = demangler.demangle(mangledString, true); MDParsableItem parsableItem = demangler.demangle();
if (parsableItem instanceof MDObjectCPP) { if (parsableItem instanceof MDObjectCPP) {
MDObjectCPP mdObject = (MDObjectCPP) parsableItem; MDObjectCPP mdObject = (MDObjectCPP) parsableItem;
return mdObject.getQualifiedName().toString(); return mdObject.getQualifiedName().toString();

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,6 +19,7 @@
//@category Demangler //@category Demangler
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledObject; import ghidra.app.util.demangler.DemangledObject;
import ghidra.app.util.demangler.MangledContext;
import ghidra.app.util.demangler.swift.*; import ghidra.app.util.demangler.swift.*;
import ghidra.app.util.demangler.swift.SwiftNativeDemangler.SwiftNativeDemangledOutput; import ghidra.app.util.demangler.swift.SwiftNativeDemangler.SwiftNativeDemangledOutput;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
@ -53,12 +54,14 @@ public class SwiftDemanglerScript extends GhidraScript {
println("No mangled Swift symbols found at " + currentAddress); println("No mangled Swift symbols found at " + currentAddress);
return; return;
} }
SwiftNativeDemangler nativeDemangler = new SwiftNativeDemangler(options.getSwiftDir()); SwiftNativeDemangler nativeDemangler = new SwiftNativeDemangler(options.getSwiftDir());
SwiftNativeDemangledOutput demangledOutput = nativeDemangler.demangle(mangled); SwiftNativeDemangledOutput demangledOutput = nativeDemangler.demangle(mangled);
println(demangledOutput.toString()); println(demangledOutput.toString());
DemangledObject demangledObject = demangler.demangle(mangled); MangledContext mangledContext =
demangler.createMangledContext(mangled, options, currentProgram, currentAddress);
DemangledObject demangledObject = demangler.demangle(mangledContext);
if (demangledObject != null) { if (demangledObject != null) {
println(demangledObject.getClass().getSimpleName() + " " + mangled + " --> " + println(demangledObject.getClass().getSimpleName() + " " + mangled + " --> " +
demangledObject); demangledObject);

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -57,13 +57,13 @@ public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
private File swiftDir; private File swiftDir;
private boolean useIncompletePrefix = true; private boolean useIncompletePrefix = true;
private boolean useUnsupportedPrefix = true; private boolean useUnsupportedPrefix = true;
private SwiftDemangler demangler = new SwiftDemangler();
/** /**
* Creates a new {@link SwiftDemanglerAnalyzer} * Creates a new {@link SwiftDemanglerAnalyzer}
*/ */
public SwiftDemanglerAnalyzer() { public SwiftDemanglerAnalyzer() {
super(NAME, DESCRIPTION); super(NAME, DESCRIPTION);
demangler = new SwiftDemangler();
setDefaultEnablement(true); setDefaultEnablement(true);
} }
@ -76,7 +76,7 @@ public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException { throws CancelledException {
try { try {
demangler.initialize(program); ((SwiftDemangler) demangler).initialize(program);
} }
catch (IOException e) { catch (IOException e) {
log.appendMsg(e.getMessage()); log.appendMsg(e.getMessage());
@ -86,9 +86,9 @@ public class SwiftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
} }
@Override @Override
protected DemangledObject doDemangle(String mangled, DemanglerOptions options, MessageLog log) protected DemangledObject doDemangle(MangledContext mangledContext, MessageLog log)
throws DemangledException { throws DemangledException {
return demangler.demangle(mangled, options); return demangler.demangle(mangledContext);
} }
@Override @Override

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -54,7 +54,7 @@ public class SwiftDemangler implements Demangler {
/** /**
* Creates a new {@link SwiftDemangler} that is associated with the given {@link Program} * Creates a new {@link SwiftDemangler} that is associated with the given {@link Program}
* *
* @param program The {@link Program} to demangle * @param program The {@link Program} to demangle
* @throws IOException if there was a problem parsing the Swift type metadata * @throws IOException if there was a problem parsing the Swift type metadata
*/ */
@ -73,12 +73,6 @@ public class SwiftDemangler implements Demangler {
return new SwiftDemanglerOptions(); return new SwiftDemanglerOptions();
} }
@Override
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
throws DemangledException {
return demangle(mangled);
}
public void initialize(Program program) throws IOException { public void initialize(Program program) throws IOException {
cache = new HashMap<>(); cache = new HashMap<>();
nativeDemangler = null; nativeDemangler = null;
@ -95,6 +89,7 @@ public class SwiftDemangler implements Demangler {
} }
@Override @Override
@Deprecated(since = "11.3", forRemoval = true)
public DemangledObject demangle(String mangled, DemanglerOptions op) throws DemangledException { public DemangledObject demangle(String mangled, DemanglerOptions op) throws DemangledException {
SwiftDemanglerOptions options = getSwiftDemanglerOptions(op); SwiftDemanglerOptions options = getSwiftDemanglerOptions(op);
Demangled demangled = getDemangled(mangled, options); Demangled demangled = getDemangled(mangled, options);
@ -111,9 +106,18 @@ public class SwiftDemangler implements Demangler {
return null; 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 * Get a new {@link Demangled} by demangling the given mangled string
* *
* @param mangled The mangled string * @param mangled The mangled string
* @param op The options (could be null) * @param op The options (could be null)
* @return A new {@link Demangled} * @return A new {@link Demangled}
@ -145,7 +149,7 @@ public class SwiftDemangler implements Demangler {
/** /**
* Gets the {@link SwiftTypeMetadata} * Gets the {@link SwiftTypeMetadata}
* *
* @return The {@link SwiftTypeMetadata}, or null if it is not available * @return The {@link SwiftTypeMetadata}, or null if it is not available
*/ */
public SwiftTypeMetadata getTypeMetadata() { 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 * Checks to see whether the given symbol name is a mangled Swift symbol
* *
* @param symbolName The symbol name to check * @param symbolName The symbol name to check
* @return True if the given symbol name is a mangled Swift symbol; otherwise, false * @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} * Gets the {@link SwiftDemanglerOptions} from the given {@link DemanglerOptions}
* *
* @param opt The options * @param opt The options
* @return The @link SwiftDemanglerOptions} * @return The @link SwiftDemanglerOptions}
* @throws DemangledException If the given options are not {@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} * Ensures that this demangler has access to a {@link SwiftNativeDemangler}
* *
* @param options The options * @param options The options
* @throws DemangledException if there was a problem getting the {@link SwiftNativeDemangler} * @throws DemangledException if there was a problem getting the {@link SwiftNativeDemangler}
*/ */

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,6 +19,7 @@ import static org.junit.Assert.*;
import org.junit.*; import org.junit.*;
import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.*; 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 * pointers. This test deals with the simple case where no existing data
* is present. End of block considered end of address table. * is present. End of block considered end of address table.
* @throws Exception upon error
*/ */
@Test @Test
public void testApply_NoNextSymbol_NoData() throws Exception { public void testApply_NoNextSymbol_NoData() throws Exception {
@ -88,10 +90,13 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
SymbolTable symbolTable = program.getSymbolTable(); SymbolTable symbolTable = program.getSymbolTable();
symbolTable.createLabel(addr, mangled, SourceType.IMPORTED); 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 instanceof DemangledAddressTable);
assertTrue(demangled.getMangledContext() != null);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY)); assertTrue(demangled.applyUsingContext(TaskMonitor.DUMMY));
// expected: UniqueSpace::vtable // expected: UniqueSpace::vtable
Symbol[] symbols = symbolTable.getSymbols(addr); 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 * 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 * 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. * previously created. End of block considered end of address table.
* @throws Exception upon error
*/ */
@Test @Test
public void testApply_NoNextSymbol_DataCollision() throws Exception { 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("0x118"), Undefined4DataType.dataType);
listing.createData(addr("0x120"), DWordDataType.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 instanceof DemangledAddressTable);
assertTrue(demangled.getMangledContext() != null);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY)); assertTrue(demangled.applyUsingContext(TaskMonitor.DUMMY));
// expected: UniqueSpace::vtable // expected: UniqueSpace::vtable
Symbol[] symbols = symbolTable.getSymbols(addr); 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 * Test that the DemangledAddressTable will properly create a sequence of data
* pointers. This test deals with the case where primitive types have been * pointers. This test deals with the case where primitive types have been
* previously created. Next label considered end of address table. * previously created. Next label considered end of address table.
* @throws Exception upon error
*/ */
@Test @Test
public void testApply_WithNextSymbol_UndefinedData() throws Exception { public void testApply_WithNextSymbol_UndefinedData() throws Exception {
@ -167,10 +177,13 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
symbolTable.createLabel(addr("0x120"), "NextLabel", SourceType.IMPORTED); 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 instanceof DemangledAddressTable);
assertTrue(demangled.getMangledContext() != null);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY)); assertTrue(demangled.applyUsingContext(TaskMonitor.DUMMY));
// expected: UniqueSpace::vtable // expected: UniqueSpace::vtable
Symbol[] symbols = symbolTable.getSymbols(addr); 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 * Test that the DemangledAddressTable will properly create a sequence of data
* pointers. This test deals with the case where primitive types have been * pointers. This test deals with the case where primitive types have been
* previously created where the first is an undefined array which dictates the * previously created where the first is an undefined array which dictates the
* extent of the address table. Next label beyond end of address table. * extent of the address table. Next label beyond end of address table.
* @throws Exception upon error
*/ */
@Test @Test
public void testApply_WithUndefinedArray() throws Exception { public void testApply_WithUndefinedArray() throws Exception {
@ -207,10 +221,13 @@ public class DemangledAddressTableTest extends AbstractGhidraHeadlessIntegration
symbolTable.createLabel(addr("0x120"), "NextLabel", SourceType.IMPORTED); 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 instanceof DemangledAddressTable);
assertTrue(demangled.getMangledContext() != null);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY)); assertTrue(demangled.applyUsingContext(TaskMonitor.DUMMY));
// expected: UniqueSpace::vtable // expected: UniqueSpace::vtable
Symbol[] symbols = symbolTable.getSymbols(addr); Symbol[] symbols = symbolTable.getSymbols(addr);

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -21,6 +21,8 @@ import java.util.Arrays;
import org.junit.*; 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.ProgramBuilder;
import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
@ -62,11 +64,16 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
// this is: public long __thiscall ATL::CRegKey::Close(void) // this is: public long __thiscall ATL::CRegKey::Close(void)
String mangled = "?CloseM@CRegKeyM@ATL@@QAEJXZ"; 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); assertTrue(demangled instanceof DemangledFunction);
Address addr = addr("0x0101"); assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY));
assertFunction("CloseM", addr); assertFunction("CloseM", addr);
@ -95,7 +102,14 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
// this is: public long __thiscall ATL::CRegKey::Close(void) // this is: public long __thiscall ATL::CRegKey::Close(void)
String mangled = "?Close@CRegKey@ATL@@QAEJXZ"; 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); assertTrue(demangled instanceof DemangledFunction);
FunctionManager functionMgr = program.getFunctionManager(); FunctionManager functionMgr = program.getFunctionManager();
@ -105,8 +119,7 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
new AddressSet(addr("0x0100")), SourceType.IMPORTED); new AddressSet(addr("0x0100")), SourceType.IMPORTED);
f2.setThunkedFunction(f1); f2.setThunkedFunction(f1);
Address addr = addr("0x0100"); demangled.applyTo(program, addr, options, TaskMonitor.DUMMY);
demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY);
assertFunction("Close", addr); assertFunction("Close", addr);
assertNoBookmarkAt(addr); assertNoBookmarkAt(addr);
@ -148,10 +161,16 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
SymbolTable symbolTable = program.getSymbolTable(); SymbolTable symbolTable = program.getSymbolTable();
symbolTable.createLabel(addr, mangled, 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 instanceof DemangledFunction);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY)); assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
assertFunction("Close", addr); assertFunction("Close", addr);
assertNoBookmarkAt(addr); assertNoBookmarkAt(addr);
@ -185,10 +204,16 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
String mangledWithAddr = SymbolUtilities.getAddressAppendedName(mangled, addr); String mangledWithAddr = SymbolUtilities.getAddressAppendedName(mangled, addr);
symbolTable.createLabel(addr, mangledWithAddr, SourceType.IMPORTED); 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 instanceof DemangledFunction);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY)); assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
assertFunction("Close", addr); assertFunction("Close", addr);
assertNoBookmarkAt(addr); assertNoBookmarkAt(addr);
@ -223,10 +248,16 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
symbolTable.createLabel(addr, "Close", SourceType.IMPORTED); symbolTable.createLabel(addr, "Close", SourceType.IMPORTED);
symbolTable.createLabel(addr, mangled, 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 instanceof DemangledFunction);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY)); assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
assertFunction("Close", addr); assertFunction("Close", addr);
assertNoBookmarkAt(addr); assertNoBookmarkAt(addr);
@ -258,9 +289,15 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
SymbolTable symbolTable = program.getSymbolTable(); SymbolTable symbolTable = program.getSymbolTable();
symbolTable.createLabel(addr, mangled, 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 instanceof DemangledFunction);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY)); assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
String className = String className =
"F<class_E::D::G<struct_E::D::H<bool_(__cdecl*const)(enum_C::B_const&),0>,bool,enum_C::B_const&>_>"; "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(); 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 instanceof DemangledFunction);
assertTrue(demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY)); assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));
assertFunction("Close", addr); assertFunction("Close", addr);
assertNoBookmarkAt(addr); assertNoBookmarkAt(addr);
@ -348,16 +391,20 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
String functionName = "__gthread_active_p"; String functionName = "__gthread_active_p";
programBuilder.createEmptyFunction(functionName, "0x0101", 10, new VoidDataType()); programBuilder.createEmptyFunction(functionName, "0x0101", 10, new VoidDataType());
Address addr = addr("0x0103");
programBuilder.createLabel("0x0103", mangled); 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); assertNotNull(demangled);
assertTrue(demangled instanceof DemangledVariable); assertTrue(demangled instanceof DemangledVariable);
assertEquals("__gthread_active_p()::__gthread_active_ptr", demangled.getSignature(false)); assertEquals("__gthread_active_p()::__gthread_active_ptr", demangled.getSignature(false));
Address addr = addr("0x0103"); demangled.applyTo(program, addr, options, TaskMonitor.DUMMY);
demangled.applyTo(program, addr, new DemanglerOptions(), TaskMonitor.DUMMY);
assertSimpleNamespaceExists("__gthread_active_p()"); assertSimpleNamespaceExists("__gthread_active_p()");
assertNoBookmarkAt(addr); assertNoBookmarkAt(addr);
@ -376,14 +423,19 @@ public class DemangledFunctionTest extends AbstractGhidraHeadlessIntegrationTest
public void testApply_Function_DoNotApplyCallingConvention() throws Exception { public void testApply_Function_DoNotApplyCallingConvention() throws Exception {
String mangled = "?CloseM@CRegKeyM@ATL@@QAEJXZ"; 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); assertTrue(demangled instanceof DemangledFunction);
DemangledFunction demangledFunction = (DemangledFunction) demangled; DemangledFunction demangledFunction = (DemangledFunction) demangled;
demangledFunction.setCallingConvention(CompilerSpec.CALLING_CONVENTION_stdcall); demangledFunction.setCallingConvention(CompilerSpec.CALLING_CONVENTION_stdcall);
Address addr = addr("0x0101");
DemanglerOptions options = new DemanglerOptions();
options.setApplyCallingConvention(false); options.setApplyCallingConvention(false);
assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY)); assertTrue(demangled.applyTo(program, addr, options, TaskMonitor.DUMMY));