mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-5189 Add range attributes to VarargsFilter
This commit is contained in:
parent
57df41297f
commit
e3aa064061
10 changed files with 128 additions and 28 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue