GP-5189 Add range attributes to VarargsFilter

This commit is contained in:
caheckman 2024-12-02 20:33:01 +00:00
parent 57df41297f
commit e3aa064061
10 changed files with 128 additions and 28 deletions

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -15,30 +15,54 @@
*/
package ghidra.program.model.lang.protorules;
import static ghidra.program.model.pcode.AttributeId.*;
import static ghidra.program.model.pcode.ElementId.*;
import java.io.IOException;
import ghidra.program.model.lang.PrototypePieces;
import ghidra.program.model.pcode.Encoder;
import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.*;
/**
* A filter that selects function parameters that are considered optional.
* If the underlying function prototype is considered to take variable arguments, the first
* n parameters (as determined by PrototypePieces.firstVarArgSlot) are considered non-optional.
* A filter that selects a range of function parameters that are considered optional.
* If the underlying function prototype takes variable arguments, the first n
* parameters (as determined by PrototypePieces.firstVarArgSlot) are considered non-optional.
* If additional data-types are provided beyond the initial n, these are considered optional.
* This filter returns true for these optional parameters
* By default this filter matches on all parameters in a prototype with variable arguments.
* Optionally, it can filter on a range of parameters that are specified relative to the
* first variable argument.
* {@code <varargs first="0"/>} - matches optional arguments but not non-optional ones.
* {@code <varargs first="0" last="0"/>} - matches the first optional argument.
* {@code <varargs first="-1"/>} - matches the last non-optional argument and all optional ones.
*/
public class VarargsFilter implements QualifierFilter {
private int firstPos; // Range of params to match (relative to first variable arg)
private int lastPos;
public VarargsFilter() {
firstPos = Integer.MIN_VALUE;
lastPos = Integer.MAX_VALUE;
}
public VarargsFilter(int first, int last) {
firstPos = first;
lastPos = last;
}
@Override
public QualifierFilter clone() {
return new VarargsFilter();
return new VarargsFilter(firstPos, lastPos);
}
@Override
public boolean isEquivalent(QualifierFilter op) {
return (this.getClass() == op.getClass());
if (this.getClass() != op.getClass()) {
return false;
}
VarargsFilter otherFilter = (VarargsFilter) op;
return (firstPos == otherFilter.firstPos && lastPos == otherFilter.lastPos);
}
@Override
@ -46,18 +70,33 @@ public class VarargsFilter implements QualifierFilter {
if (proto.firstVarArgSlot < 0) {
return false;
}
return (pos >= proto.firstVarArgSlot);
pos -= proto.firstVarArgSlot;
return (pos >= firstPos && pos <= lastPos);
}
@Override
public void encode(Encoder encoder) throws IOException {
encoder.openElement(ELEM_VARARGS);
if (firstPos != Integer.MIN_VALUE) {
encoder.writeSignedInteger(ATTRIB_FIRST, firstPos);
}
if (lastPos != Integer.MAX_VALUE) {
encoder.writeSignedInteger(ATTRIB_LAST, lastPos);
}
encoder.closeElement(ELEM_VARARGS);
}
@Override
public void restoreXml(XmlPullParser parser) throws XmlParseException {
XmlElement elem = parser.start(ELEM_VARARGS.name());
String firstPosString = elem.getAttribute(ATTRIB_FIRST.name());
if (firstPosString != null) {
firstPos = SpecXmlUtils.decodeInt(firstPosString);
}
String lastPosString = elem.getAttribute(ATTRIB_LAST.name());
if (lastPosString != null) {
lastPos = SpecXmlUtils.decodeInt(lastPosString);
}
parser.end(elem);
}
}

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -311,9 +311,11 @@ public class FunctionPrototype {
* Encode this function prototype to a stream.
* @param encoder is the stream encoder
* @param dtmanage is the DataTypeManager for building type reference tags
* @param firstVarArg is index of first variable argument or -1
* @throws IOException for errors in the underlying stream
*/
public void encodePrototype(Encoder encoder, PcodeDataTypeManager dtmanage) throws IOException {
public void encodePrototype(Encoder encoder, PcodeDataTypeManager dtmanage, int firstVarArg)
throws IOException {
encoder.openElement(ELEM_PROTOTYPE);
if (extrapop == PrototypeModel.UNKNOWN_EXTRAPOP) {
encoder.writeString(ATTRIB_EXTRAPOP, "unknown");
@ -378,6 +380,10 @@ public class FunctionPrototype {
}
if (params != null) {
encoder.openElement(ELEM_INTERNALLIST);
if (firstVarArg >= 0) {
// Encoding detail because we are not sending the storage address
encoder.writeSignedInteger(ATTRIB_FIRST, firstVarArg);
}
for (ParameterDefinition param : params) {
encoder.openElement(ELEM_PARAM);
String name = param.getName();

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -454,7 +454,7 @@ public class HighFunction extends PcodeSyntaxTree {
AddressXML.encode(encoder, entryPoint); // Address is forced on XML
}
localSymbols.encodeLocalDb(encoder, namespace, getDataTypeManager().getNameTransformer());
proto.encodePrototype(encoder, getDataTypeManager());
proto.encodePrototype(encoder, getDataTypeManager(), -1);
if ((jumpTables != null) && (jumpTables.size() > 0)) {
encoder.openElement(ELEM_JUMPTABLELIST);
for (JumpTable jumpTable : jumpTables) {
@ -466,13 +466,15 @@ public class HighFunction extends PcodeSyntaxTree {
if (hasOverrideTag) {
encoder.openElement(ELEM_OVERRIDE);
PcodeDataTypeManager dtmanage = getDataTypeManager();
Program prog = func.getProgram();
for (DataTypeSymbol sym : protoOverrides) {
Address addr = sym.getAddress();
int firstVarArg = HighFunctionDBUtil.getFirstVarArg(prog, addr);
FunctionPrototype fproto = new FunctionPrototype(
(FunctionSignature) sym.getDataType(), compilerSpec, false);
encoder.openElement(ELEM_PROTOOVERRIDE);
AddressXML.encode(encoder, addr);
fproto.encodePrototype(encoder, dtmanage);
fproto.encodePrototype(encoder, dtmanage, firstVarArg);
encoder.closeElement(ELEM_PROTOOVERRIDE);
}
encoder.closeElement(ELEM_OVERRIDE);

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -739,6 +739,27 @@ public class HighFunctionDBUtil {
return datsym;
}
/**
* If there is a call to a function at the given address, and the function takes variable arguments,
* return the index of the first variable argument. Return -1 otherwise.
* @param program is the Program
* @param addr is the given address of the call
* @return the index of the first variable argument or -1
*/
public static int getFirstVarArg(Program program, Address addr) {
for (Reference ref : program.getReferenceManager().getReferencesFrom(addr)) {
if (ref.isPrimary() && ref.getReferenceType().isCall()) {
Address callDestAddr = ref.getToAddress();
Function func = program.getFunctionManager().getFunctionAt(callDestAddr);
if (func != null && func.hasVarArgs()) {
return func.getParameterCount();
}
break;
}
}
return -1;
}
/**
* Get the Address referred to by a spacebase reference. Address-of references are encoded in
* the p-code syntax tree as: {@code vn = PTRSUB(<spacebase>, #const)}. This decodes the reference and

View file

@ -681,7 +681,7 @@ public class PcodeDataTypeManager {
encoder.writeSignedInteger(ATTRIB_SIZE, 1); // Force size of 1
CompilerSpec cspec = program.getCompilerSpec();
FunctionPrototype fproto = new FunctionPrototype(type, cspec, voidInputIsVarargs);
fproto.encodePrototype(encoder, this);
fproto.encodePrototype(encoder, this, -1);
encoder.closeElement(ELEM_TYPE);
}