mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
GP-4139 Improve demanglers function signature source type applied.
Renamed rustcall to __rustcall. Minor fix to legacy rust demangling for namespaces.
This commit is contained in:
parent
ed46dde304
commit
d4c854ddbc
18 changed files with 140 additions and 103 deletions
|
@ -145,15 +145,6 @@ public class RustDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
||||||
try {
|
try {
|
||||||
if (demangled instanceof DemangledFunction defunc) {
|
if (demangled instanceof DemangledFunction defunc) {
|
||||||
defunc.applyTo(program, address, options, monitor);
|
defunc.applyTo(program, address, options, monitor);
|
||||||
Function func = program.getFunctionManager().getFunctionAt(address);
|
|
||||||
if (func != null) {
|
|
||||||
// if has no return type and no parameters, don't trust that it is void and unlock
|
|
||||||
// the signature so the decompiler can figure it out
|
|
||||||
if (defunc.getReturnType() == null && defunc.getParameters().size() == 0) {
|
|
||||||
func.setSignatureSource(SourceType.DEFAULT);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package ghidra.app.plugin.core.analysis.rust.demangler;
|
package ghidra.app.plugin.core.analysis.rust.demangler;
|
||||||
|
|
||||||
import ghidra.app.util.demangler.*;
|
import ghidra.app.util.demangler.*;
|
||||||
|
import ghidra.program.model.lang.CompilerSpec;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,8 +69,9 @@ public class RustDemangler implements Demangler {
|
||||||
RustDemanglerParser parser = new RustDemanglerParser();
|
RustDemanglerParser parser = new RustDemanglerParser();
|
||||||
DemangledObject demangledObject = parser.parse(mangled, demangled);
|
DemangledObject demangledObject = parser.parse(mangled, demangled);
|
||||||
|
|
||||||
if (options.applyCallingConvention() && demangledObject instanceof DemangledFunction) {
|
if (options.applyCallingConvention() &&
|
||||||
((DemangledFunction) demangledObject).setCallingConvention("rustcall");
|
demangledObject instanceof DemangledFunction demangledFunction) {
|
||||||
|
demangledFunction.setCallingConvention(CompilerSpec.CALLING_CONVENTION_rustcall);
|
||||||
}
|
}
|
||||||
|
|
||||||
return demangledObject;
|
return demangledObject;
|
||||||
|
|
|
@ -72,6 +72,9 @@ public class RustDemanglerLegacy {
|
||||||
element = element.replace("$LP$", "(");
|
element = element.replace("$LP$", "(");
|
||||||
element = element.replace("$RP$", ")");
|
element = element.replace("$RP$", ")");
|
||||||
element = element.replace("$C$", ",");
|
element = element.replace("$C$", ",");
|
||||||
|
|
||||||
|
// Ghidra uses :: between namespace names
|
||||||
|
element = element.replace("..", "::");
|
||||||
|
|
||||||
int k = 0;
|
int k = 0;
|
||||||
while (k < element.length()) {
|
while (k < element.length()) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.util.stream.Collectors;
|
||||||
import generic.json.Json;
|
import generic.json.Json;
|
||||||
import ghidra.app.util.SymbolPathParser;
|
import ghidra.app.util.SymbolPathParser;
|
||||||
import ghidra.app.util.demangler.*;
|
import ghidra.app.util.demangler.*;
|
||||||
|
import ghidra.program.model.symbol.SourceType;
|
||||||
|
|
||||||
/** Parses a demangled rust string */
|
/** Parses a demangled rust string */
|
||||||
public class RustDemanglerParser {
|
public class RustDemanglerParser {
|
||||||
|
@ -67,10 +68,12 @@ public class RustDemanglerParser {
|
||||||
|
|
||||||
private DemangledObject parseNext(String demangled) {
|
private DemangledObject parseNext(String demangled) {
|
||||||
String nameString = removeBadSpaces(demangled).trim();
|
String nameString = removeBadSpaces(demangled).trim();
|
||||||
DemangledFunction variable =
|
DemangledFunction demangledFunction =
|
||||||
new DemangledFunction(mangledSource, demangledSource, (String) null);
|
new DemangledFunction(mangledSource, demangledSource, (String) null);
|
||||||
setNameAndNamespace(variable, nameString);
|
setNameAndNamespace(demangledFunction, nameString);
|
||||||
return variable;
|
// Restrict to applying name, namespace and calling-convention
|
||||||
|
demangledFunction.setSignatureSourceType(SourceType.DEFAULT);
|
||||||
|
return demangledFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -36,8 +36,7 @@ public class DataTypeNamingUtil {
|
||||||
* @throws IllegalArgumentException if generated name contains unsupported characters
|
* @throws IllegalArgumentException if generated name contains unsupported characters
|
||||||
*/
|
*/
|
||||||
public static String setMangledAnonymousFunctionName(
|
public static String setMangledAnonymousFunctionName(
|
||||||
FunctionDefinitionDataType functionDefinition)
|
FunctionDefinitionDataType functionDefinition) throws IllegalArgumentException {
|
||||||
throws IllegalArgumentException {
|
|
||||||
|
|
||||||
DataType returnType = functionDefinition.getReturnType();
|
DataType returnType = functionDefinition.getReturnType();
|
||||||
ParameterDefinition[] parameters = functionDefinition.getArguments();
|
ParameterDefinition[] parameters = functionDefinition.getArguments();
|
||||||
|
@ -49,7 +48,7 @@ public class DataTypeNamingUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
String convention = functionDefinition.getCallingConventionName();
|
String convention = functionDefinition.getCallingConventionName();
|
||||||
if (convention != null && !Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(convention)) {
|
if (!Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(convention)) {
|
||||||
sb.append("_").append(convention);
|
sb.append("_").append(convention);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -289,12 +289,12 @@ public class ToolTipUtils {
|
||||||
}
|
}
|
||||||
buffy.append(friendlyEncodeHTML(function.getReturnType().getName()));
|
buffy.append(friendlyEncodeHTML(function.getReturnType().getName()));
|
||||||
buffy.append(HTML_SPACE);
|
buffy.append(HTML_SPACE);
|
||||||
|
|
||||||
String callingConvention = function.getCallingConventionName();
|
String callingConvention = function.getCallingConventionName();
|
||||||
if (callingConvention.equals(Function.DEFAULT_CALLING_CONVENTION_STRING)) {
|
if (callingConvention.equals(Function.DEFAULT_CALLING_CONVENTION_STRING)) {
|
||||||
callingConvention = function.getCallingConvention().getName();
|
callingConvention = function.getCallingConvention().getName();
|
||||||
}
|
}
|
||||||
if (!callingConvention.equals(Function.UNKNOWN_CALLING_CONVENTION_STRING)) {
|
if (!Function.UNKNOWN_CALLING_CONVENTION_STRING.equals(callingConvention)) {
|
||||||
String ccHtml = friendlyEncodeHTML(callingConvention);
|
String ccHtml = friendlyEncodeHTML(callingConvention);
|
||||||
if (function.hasUnknownCallingConventionName()) {
|
if (function.hasUnknownCallingConventionName()) {
|
||||||
ccHtml = colorString(Color.RED, ccHtml);
|
ccHtml = colorString(Color.RED, ccHtml);
|
||||||
|
@ -302,7 +302,7 @@ public class ToolTipUtils {
|
||||||
buffy.append(ccHtml);
|
buffy.append(ccHtml);
|
||||||
buffy.append(HTML_SPACE);
|
buffy.append(HTML_SPACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
String functionName = StringUtilities.trimMiddle(function.getName(), LINE_LENGTH);
|
String functionName = StringUtilities.trimMiddle(function.getName(), LINE_LENGTH);
|
||||||
buffy.append(colorString(FunctionColors.NAME, friendlyEncodeHTML(functionName)));
|
buffy.append(colorString(FunctionColors.NAME, friendlyEncodeHTML(functionName)));
|
||||||
buffy.append(HTML_SPACE).append("(");
|
buffy.append(HTML_SPACE).append("(");
|
||||||
|
|
|
@ -24,9 +24,11 @@ import ghidra.app.cmd.function.*;
|
||||||
import ghidra.app.util.NamespaceUtils;
|
import ghidra.app.util.NamespaceUtils;
|
||||||
import ghidra.app.util.PseudoDisassembler;
|
import ghidra.app.util.PseudoDisassembler;
|
||||||
import ghidra.program.database.data.DataTypeUtilities;
|
import ghidra.program.database.data.DataTypeUtilities;
|
||||||
|
import ghidra.program.database.data.ProgramBasedDataTypeManagerDB;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.AddressSetView;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
import ghidra.program.model.lang.CompilerSpec;
|
||||||
import ghidra.program.model.lang.PrototypeModel;
|
import ghidra.program.model.lang.PrototypeModel;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
|
@ -55,6 +57,7 @@ public class DemangledFunction extends DemangledObject {
|
||||||
protected List<DemangledDataType> parameters = new ArrayList<>();
|
protected List<DemangledDataType> parameters = new ArrayList<>();
|
||||||
protected DemangledTemplate template;
|
protected DemangledTemplate template;
|
||||||
protected boolean isOverloadedOperator = false;
|
protected boolean isOverloadedOperator = false;
|
||||||
|
protected SourceType signatureSourceType = SourceType.ANALYSIS;
|
||||||
|
|
||||||
/** Special constructor where it has a templated type before the parameter list */
|
/** Special constructor where it has a templated type before the parameter list */
|
||||||
private String templatedConstructorType;
|
private String templatedConstructorType;
|
||||||
|
@ -67,11 +70,43 @@ public class DemangledFunction extends DemangledObject {
|
||||||
private boolean isTypeCast;
|
private boolean isTypeCast;
|
||||||
private String throwAttribute;
|
private String throwAttribute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a {@link DemangledFunction} instance which is marked with a
|
||||||
|
* signature {@link SourceType} of {@link SourceType#ANALYSIS} which will be used
|
||||||
|
* when function signatures are applied to a program. This source type may be changed
|
||||||
|
* if needed using {@link #setSignatureSourceType(SourceType)}.
|
||||||
|
* The function name and namespace is always applied using a symbol source
|
||||||
|
* of {@link SourceType#ANALYSIS}.
|
||||||
|
* @param mangled original mangled symbol name
|
||||||
|
* @param originalDemangled demangled function signature generally used when generating comments
|
||||||
|
* @param name demangled function name
|
||||||
|
*/
|
||||||
public DemangledFunction(String mangled, String originalDemangled, String name) {
|
public DemangledFunction(String mangled, String originalDemangled, String name) {
|
||||||
super(mangled, originalDemangled);
|
super(mangled, originalDemangled);
|
||||||
setName(name);
|
setName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set signature {@link SourceType} of {@link SourceType#ANALYSIS} which will be used
|
||||||
|
* when function signatures are applied to a program. Specifying {@link SourceType#DEFAULT}
|
||||||
|
* will prevent function return and parameters from being applied but will still apply
|
||||||
|
* calling convention name if specified.
|
||||||
|
* @param signatureSourceType signature source type
|
||||||
|
*/
|
||||||
|
public void setSignatureSourceType(SourceType signatureSourceType) {
|
||||||
|
this.signatureSourceType = signatureSourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the signature source type which is used when applying the function signature
|
||||||
|
* to a program. A value of {@link SourceType#DEFAULT} indicates that
|
||||||
|
* function return and parameters should not be applied.
|
||||||
|
* @return signature source type
|
||||||
|
*/
|
||||||
|
public SourceType getSignatureSourceType() {
|
||||||
|
return signatureSourceType;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the function return type.
|
* Sets the function return type.
|
||||||
* @param returnType the function return type
|
* @param returnType the function return type
|
||||||
|
@ -433,6 +468,22 @@ public class DemangledFunction extends DemangledObject {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean hasCallingConvention = !CompilerSpec.isUnknownCallingConvention(callingConvention);
|
||||||
|
if (hasCallingConvention) {
|
||||||
|
// Ensure that calling convention name exists and can be used
|
||||||
|
ProgramBasedDataTypeManagerDB dtm =
|
||||||
|
(ProgramBasedDataTypeManagerDB) program.getDataTypeManager();
|
||||||
|
dtm.getCallingConventionID(callingConvention, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signatureSourceType == SourceType.DEFAULT) {
|
||||||
|
// Only apply calling convention if specified with DEFAULT source
|
||||||
|
if (hasCallingConvention) {
|
||||||
|
function.setCallingConvention(callingConvention);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Structure classStructure =
|
Structure classStructure =
|
||||||
maybeUpdateCallingConventionAndCreateClass(program, function, options);
|
maybeUpdateCallingConventionAndCreateClass(program, function, options);
|
||||||
|
|
||||||
|
@ -454,7 +505,7 @@ public class DemangledFunction extends DemangledObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplyFunctionSignatureCmd cmd = new ApplyFunctionSignatureCmd(function.getEntryPoint(),
|
ApplyFunctionSignatureCmd cmd = new ApplyFunctionSignatureCmd(function.getEntryPoint(),
|
||||||
signature, SourceType.IMPORTED, true, false, DataTypeConflictHandler.DEFAULT_HANDLER,
|
signature, signatureSourceType, true, false, DataTypeConflictHandler.DEFAULT_HANDLER,
|
||||||
FunctionRenameOption.RENAME_IF_DEFAULT);
|
FunctionRenameOption.RENAME_IF_DEFAULT);
|
||||||
cmd.applyTo(program);
|
cmd.applyTo(program);
|
||||||
|
|
||||||
|
|
|
@ -363,6 +363,18 @@ public abstract class DemangledObject implements Demangled {
|
||||||
this.errorMessage = message;
|
this.errorMessage = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply this demangled object detail to the specified program.
|
||||||
|
* <br>
|
||||||
|
* NOTE: An open Program transaction must be established prior to invoking this method.
|
||||||
|
*
|
||||||
|
* @param program program to which demangled data should be applied.
|
||||||
|
* @param address address which corresponds to this demangled object
|
||||||
|
* @param options options which control how demangled data is applied
|
||||||
|
* @param monitor task monitor
|
||||||
|
* @return true if successfully applied, else false
|
||||||
|
* @throws Exception if an error occurs during the apply operation
|
||||||
|
*/
|
||||||
public boolean applyTo(Program program, Address address, DemanglerOptions options,
|
public boolean applyTo(Program program, Address address, DemanglerOptions options,
|
||||||
TaskMonitor monitor) throws Exception {
|
TaskMonitor monitor) throws Exception {
|
||||||
return applyPlateCommentOnly(program, address);
|
return applyPlateCommentOnly(program, address);
|
||||||
|
|
|
@ -22,8 +22,12 @@ import org.junit.Test;
|
||||||
import ghidra.app.plugin.core.analysis.rust.demangler.RustDemangler;
|
import ghidra.app.plugin.core.analysis.rust.demangler.RustDemangler;
|
||||||
import ghidra.app.util.demangler.DemangledException;
|
import ghidra.app.util.demangler.DemangledException;
|
||||||
import ghidra.app.util.demangler.DemangledObject;
|
import ghidra.app.util.demangler.DemangledObject;
|
||||||
|
import ghidra.program.model.lang.CompilerSpec;
|
||||||
|
|
||||||
public class RustDemanglerLegacyTest {
|
public class RustDemanglerLegacyTest {
|
||||||
|
|
||||||
|
private static final String RUSTCALL = CompilerSpec.CALLING_CONVENTION_rustcall;
|
||||||
|
|
||||||
private static String[] symbols =
|
private static String[] symbols =
|
||||||
{ "_ZN43_$LT$char$u20$as$u20$core..fmt..Display$GT$3fmt17h31c4c24bbd08aa24E",
|
{ "_ZN43_$LT$char$u20$as$u20$core..fmt..Display$GT$3fmt17h31c4c24bbd08aa24E",
|
||||||
"_ZN4core6option13expect_failed17h09b982639336e7eaE",
|
"_ZN4core6option13expect_failed17h09b982639336e7eaE",
|
||||||
|
@ -32,13 +36,13 @@ public class RustDemanglerLegacyTest {
|
||||||
"_ZN5alloc5alloc18handle_alloc_error8rt_error17h4b79f8a717741b7cE",
|
"_ZN5alloc5alloc18handle_alloc_error8rt_error17h4b79f8a717741b7cE",
|
||||||
"_ZN3std6thread7current17h20e47a880e55afd5E", };
|
"_ZN3std6thread7current17h20e47a880e55afd5E", };
|
||||||
|
|
||||||
private static String[] names = { "rustcall _<char_as_core..fmt..Display>::fmt(void)",
|
private static String[] names = { RUSTCALL + " _<char_as_core::fmt::Display>::fmt(void)",
|
||||||
"rustcall core::option::expect_failed(void)",
|
RUSTCALL + " core::option::expect_failed(void)",
|
||||||
"rustcall core::fmt::Formatter::debug_lower_hex(void)",
|
RUSTCALL + " core::fmt::Formatter::debug_lower_hex(void)",
|
||||||
"rustcall std::path::Components::as_path(void)",
|
RUSTCALL + " std::path::Components::as_path(void)",
|
||||||
"rustcall alloc::alloc::handle_alloc_error::rt_error(void)",
|
RUSTCALL + " alloc::alloc::handle_alloc_error::rt_error(void)",
|
||||||
"rustcall std::thread::current(void)",
|
RUSTCALL + " std::thread::current(void)",
|
||||||
"rustcall gimli::read::abbrev::Attributes::new(void)" };
|
RUSTCALL + " gimli::read::abbrev::Attributes::new(void)" };
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void demangle() {
|
public void demangle() {
|
||||||
|
|
|
@ -27,6 +27,7 @@ import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
import ghidra.program.model.lang.CompilerSpec;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.symbol.Namespace;
|
import ghidra.program.model.symbol.Namespace;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.SourceType;
|
||||||
|
@ -206,8 +207,7 @@ public class DecompilerCallConventionAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
// must be an unknown signature
|
// must be an unknown signature
|
||||||
String callingConventionName = function.getCallingConventionName();
|
String callingConventionName = function.getCallingConventionName();
|
||||||
|
if (!CompilerSpec.isUnknownCallingConvention(callingConventionName)) {
|
||||||
if (!callingConventionName.equals(Function.UNKNOWN_CALLING_CONVENTION_STRING)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.util.Iterator;
|
||||||
|
|
||||||
import ghidra.app.util.demangler.*;
|
import ghidra.app.util.demangler.*;
|
||||||
import ghidra.program.model.lang.CompilerSpec;
|
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.MDVarArgsType;
|
||||||
import mdemangler.datatype.complex.*;
|
import mdemangler.datatype.complex.*;
|
||||||
|
@ -216,6 +217,7 @@ public class MDMangGhidra extends MDMang {
|
||||||
else {
|
else {
|
||||||
DemangledFunction function =
|
DemangledFunction function =
|
||||||
new DemangledFunction(mangledSource, demangledSource, objectCPP.getName());
|
new DemangledFunction(mangledSource, demangledSource, objectCPP.getName());
|
||||||
|
function.setSignatureSourceType(SourceType.IMPORTED);
|
||||||
function.setNamespace(processNamespace(objectCPP.getQualification()));
|
function.setNamespace(processNamespace(objectCPP.getQualification()));
|
||||||
resultObject = function;
|
resultObject = function;
|
||||||
objectResult = processFunction((MDFunctionInfo) typeinfo, function);
|
objectResult = processFunction((MDFunctionInfo) typeinfo, function);
|
||||||
|
|
|
@ -15,68 +15,24 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.feature.vt.api.stringable;
|
package ghidra.feature.vt.api.stringable;
|
||||||
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.CALLING_CONVENTION;
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.*;
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.CALL_FIXUP;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_CALLING_CONVENTION;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_CALL_FIXUP;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_FUNCTION_RETURN_TYPE;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_FUNCTION_SIGNATURE;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_HIGHEST_NAME_PRIORITY;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_INLINE;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_NO_RETURN;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_PARAMETER_COMMENTS;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_PARAMETER_DATA_TYPES;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_PARAMETER_NAMES;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_PARAMETER_NAMES_REPLACE_IF_SAME_PRIORITY;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_VAR_ARGS;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.FUNCTION_RETURN_TYPE;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.INLINE;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.NO_RETURN;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.PARAMETER_COMMENTS;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.PARAMETER_NAMES_REPLACE_IF_SAME_PRIORITY;
|
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.VAR_ARGS;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
|
|
||||||
import ghidra.feature.vt.api.util.Stringable;
|
import ghidra.feature.vt.api.util.Stringable;
|
||||||
import ghidra.feature.vt.api.util.VersionTrackingApplyException;
|
import ghidra.feature.vt.api.util.VersionTrackingApplyException;
|
||||||
import ghidra.feature.vt.gui.util.VTMatchApplyChoices;
|
import ghidra.feature.vt.gui.util.VTMatchApplyChoices;
|
||||||
import ghidra.feature.vt.gui.util.VTMatchApplyChoices.CallingConventionChoices;
|
import ghidra.feature.vt.gui.util.VTMatchApplyChoices.*;
|
||||||
import ghidra.feature.vt.gui.util.VTMatchApplyChoices.CommentChoices;
|
|
||||||
import ghidra.feature.vt.gui.util.VTMatchApplyChoices.FunctionSignatureChoices;
|
|
||||||
import ghidra.feature.vt.gui.util.VTMatchApplyChoices.HighestSourcePriorityChoices;
|
|
||||||
import ghidra.feature.vt.gui.util.VTMatchApplyChoices.ParameterDataTypeChoices;
|
|
||||||
import ghidra.feature.vt.gui.util.VTMatchApplyChoices.ReplaceChoices;
|
|
||||||
import ghidra.feature.vt.gui.util.VTOptionDefines;
|
import ghidra.feature.vt.gui.util.VTOptionDefines;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.program.database.data.DataTypeUtilities;
|
import ghidra.program.database.data.DataTypeUtilities;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.DataTypeManager;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.data.Pointer;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.data.PointerDataType;
|
|
||||||
import ghidra.program.model.data.Undefined;
|
|
||||||
import ghidra.program.model.lang.CompilerSpec;
|
|
||||||
import ghidra.program.model.lang.Language;
|
|
||||||
import ghidra.program.model.lang.PrototypeModel;
|
|
||||||
import ghidra.program.model.listing.Function;
|
|
||||||
import ghidra.program.model.listing.Function.FunctionUpdateType;
|
import ghidra.program.model.listing.Function.FunctionUpdateType;
|
||||||
import ghidra.program.model.listing.FunctionSignature;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.model.listing.Parameter;
|
|
||||||
import ghidra.program.model.listing.ParameterImpl;
|
|
||||||
import ghidra.program.model.listing.Program;
|
|
||||||
import ghidra.program.model.listing.ReturnParameterImpl;
|
|
||||||
import ghidra.program.model.listing.VariableStorage;
|
|
||||||
import ghidra.program.model.symbol.SourceType;
|
|
||||||
import ghidra.program.model.symbol.SymbolTable;
|
|
||||||
import ghidra.program.model.symbol.SymbolUtilities;
|
|
||||||
import ghidra.program.util.FunctionUtility;
|
import ghidra.program.util.FunctionUtility;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.*;
|
||||||
import ghidra.util.StringUtilities;
|
|
||||||
import ghidra.util.SystemUtilities;
|
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
|
||||||
|
@ -544,9 +500,8 @@ public class FunctionSignatureStringable extends Stringable {
|
||||||
public boolean applyFunctionSignature(Function toFunction, ToolOptions markupOptions,
|
public boolean applyFunctionSignature(Function toFunction, ToolOptions markupOptions,
|
||||||
boolean forceApply) throws VersionTrackingApplyException {
|
boolean forceApply) throws VersionTrackingApplyException {
|
||||||
|
|
||||||
VTMatchApplyChoices.FunctionSignatureChoices functionSignatureChoice =
|
VTMatchApplyChoices.FunctionSignatureChoices functionSignatureChoice = markupOptions
|
||||||
markupOptions.getEnum(VTOptionDefines.FUNCTION_SIGNATURE,
|
.getEnum(VTOptionDefines.FUNCTION_SIGNATURE, DEFAULT_OPTION_FOR_FUNCTION_SIGNATURE);
|
||||||
DEFAULT_OPTION_FOR_FUNCTION_SIGNATURE);
|
|
||||||
|
|
||||||
int toParamCount = toFunction.getParameterCount();
|
int toParamCount = toFunction.getParameterCount();
|
||||||
|
|
||||||
|
@ -586,10 +541,11 @@ public class FunctionSignatureStringable extends Stringable {
|
||||||
List<Parameter> newParams =
|
List<Parameter> newParams =
|
||||||
getParameters(toFunction, markupOptions, forceApply, useCustomStorage);
|
getParameters(toFunction, markupOptions, forceApply, useCustomStorage);
|
||||||
|
|
||||||
toFunction.updateFunction(conventionName, returnParam, newParams,
|
toFunction
|
||||||
useCustomStorage ? FunctionUpdateType.CUSTOM_STORAGE
|
.updateFunction(conventionName, returnParam, newParams,
|
||||||
: FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS,
|
useCustomStorage ? FunctionUpdateType.CUSTOM_STORAGE
|
||||||
true, signatureSource);
|
: FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS,
|
||||||
|
true, signatureSource);
|
||||||
if (forceApply) {
|
if (forceApply) {
|
||||||
// must force signatureSource if precedence has been lowered
|
// must force signatureSource if precedence has been lowered
|
||||||
// TODO: Should any manual change in function signature force source to be USER_DEFINED instead ??
|
// TODO: Should any manual change in function signature force source to be USER_DEFINED instead ??
|
||||||
|
@ -723,8 +679,8 @@ public class FunctionSignatureStringable extends Stringable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getCallingConvention(Function toFunction, ToolOptions markupOptions) {
|
private String getCallingConvention(Function toFunction, ToolOptions markupOptions) {
|
||||||
boolean isFromUnknownCallingConvention = ((callingConventionName == null) ||
|
boolean isFromUnknownCallingConvention =
|
||||||
callingConventionName.equals(Function.UNKNOWN_CALLING_CONVENTION_STRING));
|
CompilerSpec.isUnknownCallingConvention(callingConventionName);
|
||||||
CallingConventionChoices callingConventionChoice =
|
CallingConventionChoices callingConventionChoice =
|
||||||
markupOptions.getEnum(CALLING_CONVENTION, DEFAULT_OPTION_FOR_CALLING_CONVENTION);
|
markupOptions.getEnum(CALLING_CONVENTION, DEFAULT_OPTION_FOR_CALLING_CONVENTION);
|
||||||
String toCallingConventionName = toFunction.getCallingConventionName();
|
String toCallingConventionName = toFunction.getCallingConventionName();
|
||||||
|
@ -854,8 +810,8 @@ public class FunctionSignatureStringable extends Stringable {
|
||||||
throws VersionTrackingApplyException {
|
throws VersionTrackingApplyException {
|
||||||
|
|
||||||
// See what options the user has specified when applying parameter names.
|
// See what options the user has specified when applying parameter names.
|
||||||
VTMatchApplyChoices.SourcePriorityChoices parameterNamesChoice = markupOptions.getEnum(
|
VTMatchApplyChoices.SourcePriorityChoices parameterNamesChoice = markupOptions
|
||||||
VTOptionDefines.PARAMETER_NAMES, DEFAULT_OPTION_FOR_PARAMETER_NAMES);
|
.getEnum(VTOptionDefines.PARAMETER_NAMES, DEFAULT_OPTION_FOR_PARAMETER_NAMES);
|
||||||
VTMatchApplyChoices.HighestSourcePriorityChoices highestPriorityChoice =
|
VTMatchApplyChoices.HighestSourcePriorityChoices highestPriorityChoice =
|
||||||
markupOptions.getEnum(VTOptionDefines.HIGHEST_NAME_PRIORITY,
|
markupOptions.getEnum(VTOptionDefines.HIGHEST_NAME_PRIORITY,
|
||||||
DEFAULT_OPTION_FOR_HIGHEST_NAME_PRIORITY);
|
DEFAULT_OPTION_FOR_HIGHEST_NAME_PRIORITY);
|
||||||
|
|
|
@ -67,8 +67,8 @@ class CallingConventionDBAdapterV0 extends CallingConventionDBAdapter {
|
||||||
String tableName = tablePrefix + CALLING_CONVENTION_TABLE_NAME;
|
String tableName = tablePrefix + CALLING_CONVENTION_TABLE_NAME;
|
||||||
if (create) {
|
if (create) {
|
||||||
// No additional indexed fields.
|
// No additional indexed fields.
|
||||||
callingConventionTable = handle.createTable(tableName,
|
callingConventionTable =
|
||||||
V0_CALLING_CONVENTION_SCHEMA, new int[] {});
|
handle.createTable(tableName, V0_CALLING_CONVENTION_SCHEMA, new int[] {});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
callingConventionTable = handle.getTable(tableName);
|
callingConventionTable = handle.getTable(tableName);
|
||||||
|
@ -138,7 +138,7 @@ class CallingConventionDBAdapterV0 extends CallingConventionDBAdapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
byte getCallingConventionId(String name, Consumer<String> conventionAdded) throws IOException {
|
byte getCallingConventionId(String name, Consumer<String> conventionAdded) throws IOException {
|
||||||
if (name == null || name.equals(CompilerSpec.CALLING_CONVENTION_unknown)) {
|
if (CompilerSpec.isUnknownCallingConvention(name)) {
|
||||||
return UNKNOWN_CALLING_CONVENTION_ID;
|
return UNKNOWN_CALLING_CONVENTION_ID;
|
||||||
}
|
}
|
||||||
else if (name.equals(CompilerSpec.CALLING_CONVENTION_default)) {
|
else if (name.equals(CompilerSpec.CALLING_CONVENTION_default)) {
|
||||||
|
|
|
@ -4008,7 +4008,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
public byte getCallingConventionID(String name, boolean restrictive)
|
public byte getCallingConventionID(String name, boolean restrictive)
|
||||||
throws InvalidInputException, IOException {
|
throws InvalidInputException, IOException {
|
||||||
|
|
||||||
if (name == null || CompilerSpec.CALLING_CONVENTION_unknown.equals(name)) {
|
if (CompilerSpec.isUnknownCallingConvention(name)) {
|
||||||
return UNKNOWN_CALLING_CONVENTION_ID;
|
return UNKNOWN_CALLING_CONVENTION_ID;
|
||||||
}
|
}
|
||||||
if (CompilerSpec.CALLING_CONVENTION_default.equals(name)) {
|
if (CompilerSpec.CALLING_CONVENTION_default.equals(name)) {
|
||||||
|
|
|
@ -178,8 +178,7 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
|
||||||
@Override
|
@Override
|
||||||
public void setCallingConvention(String conventionName) throws InvalidInputException {
|
public void setCallingConvention(String conventionName) throws InvalidInputException {
|
||||||
|
|
||||||
if (conventionName == null ||
|
if (CompilerSpec.isUnknownCallingConvention(conventionName)) {
|
||||||
CompilerSpec.CALLING_CONVENTION_unknown.equals(conventionName)) {
|
|
||||||
this.callingConventionName = CompilerSpec.CALLING_CONVENTION_unknown;
|
this.callingConventionName = CompilerSpec.CALLING_CONVENTION_unknown;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -365,8 +364,7 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
|
||||||
if ((signature.getName().equals(this.name)) && (compareComment(signature)) &&
|
if ((signature.getName().equals(this.name)) && (compareComment(signature)) &&
|
||||||
(DataTypeUtilities.isSameOrEquivalentDataType(signature.getReturnType(),
|
(DataTypeUtilities.isSameOrEquivalentDataType(signature.getReturnType(),
|
||||||
this.returnType)) &&
|
this.returnType)) &&
|
||||||
(hasVarArgs == signature.hasVarArgs()) &&
|
(hasVarArgs == signature.hasVarArgs()) && (hasNoReturn == signature.hasNoReturn()) &&
|
||||||
(hasNoReturn == signature.hasNoReturn()) &&
|
|
||||||
callingConventionName.equals(signature.getCallingConventionName())) {
|
callingConventionName.equals(signature.getCallingConventionName())) {
|
||||||
ParameterDefinition[] args = signature.getArguments();
|
ParameterDefinition[] args = signature.getArguments();
|
||||||
if (args.length == this.params.length) {
|
if (args.length == this.params.length) {
|
||||||
|
|
|
@ -1089,7 +1089,7 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PrototypeModel matchConvention(String conventionName) {
|
public PrototypeModel matchConvention(String conventionName) {
|
||||||
if (conventionName == null || CALLING_CONVENTION_unknown.equals(conventionName) ||
|
if (CompilerSpec.isUnknownCallingConvention(conventionName) ||
|
||||||
CALLING_CONVENTION_default.equals(conventionName)) {
|
CALLING_CONVENTION_default.equals(conventionName)) {
|
||||||
return defaultModel;
|
return defaultModel;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ package ghidra.program.model.lang;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSpace;
|
import ghidra.program.model.address.AddressSpace;
|
||||||
import ghidra.program.model.data.DataOrganization;
|
import ghidra.program.model.data.DataOrganization;
|
||||||
|
@ -48,6 +50,7 @@ public interface CompilerSpec {
|
||||||
public final static String CALLING_CONVENTION_stdcall = "__stdcall";
|
public final static String CALLING_CONVENTION_stdcall = "__stdcall";
|
||||||
public final static String CALLING_CONVENTION_fastcall = "__fastcall";
|
public final static String CALLING_CONVENTION_fastcall = "__fastcall";
|
||||||
public final static String CALLING_CONVENTION_vectorcall = "__vectorcall";
|
public final static String CALLING_CONVENTION_vectorcall = "__vectorcall";
|
||||||
|
public final static String CALLING_CONVENTION_rustcall = "__rustcall";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Labels for PrototypeModels that are used by default for various analysis/evaluation
|
* Labels for PrototypeModels that are used by default for various analysis/evaluation
|
||||||
|
@ -59,6 +62,19 @@ public interface CompilerSpec {
|
||||||
EVAL_CALLED // A PrototypeModel used to evaluate a "called" function
|
EVAL_CALLED // A PrototypeModel used to evaluate a "called" function
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the specified calling convention name is treated as the unknown calling
|
||||||
|
* convention (blank or {code "unknown"}). Other unrecognized names will return false.
|
||||||
|
* This static method does not assume any specific compiler specification.
|
||||||
|
*
|
||||||
|
* @param callingConventionName calling convention name or null
|
||||||
|
* @return true if specified name is blank or {code "unknown"}
|
||||||
|
*/
|
||||||
|
public static boolean isUnknownCallingConvention(String callingConventionName) {
|
||||||
|
return StringUtils.isBlank(callingConventionName) ||
|
||||||
|
CompilerSpec.CALLING_CONVENTION_unknown.equals(callingConventionName);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Language this compiler spec is based on. Note that
|
* Get the Language this compiler spec is based on. Note that
|
||||||
* compiler specs may be reused across multiple languages in the
|
* compiler specs may be reused across multiple languages in the
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<prototype name="rustcall" extrapop="8" stackshift="8">
|
<prototype name="__rustcall" extrapop="8" stackshift="8">
|
||||||
<input pointermax="8">
|
<input pointermax="8">
|
||||||
<pentry minsize="4" maxsize="8" metatype="float">
|
<pentry minsize="4" maxsize="8" metatype="float">
|
||||||
<register name="XMM0_Qa"/>
|
<register name="XMM0_Qa"/>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue