mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 01:39:21 +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
|
@ -3433,6 +3433,10 @@ void ProtoStoreInternal::decode(Decoder &decoder,ProtoModel *model)
|
|||
addressesdetermined = false;
|
||||
|
||||
uint4 elemId = decoder.openElement(ELEM_INTERNALLIST);
|
||||
uint4 firstId = decoder.getNextAttributeId();
|
||||
if (firstId == ATTRIB_FIRST) {
|
||||
proto.firstVarArgSlot = decoder.readSignedInteger();
|
||||
}
|
||||
for(;;) { // This is only the input params
|
||||
uint4 subId = decoder.openElement(); // <retparam> or <param>
|
||||
if (subId == 0) break;
|
||||
|
|
|
@ -412,13 +412,22 @@ bool VarargsFilter::filter(const PrototypePieces &proto,int4 pos) const
|
|||
|
||||
{
|
||||
if (proto.firstVarArgSlot < 0) return false;
|
||||
return (pos >= proto.firstVarArgSlot);
|
||||
pos -= proto.firstVarArgSlot;
|
||||
return (pos >= firstPos && pos <= lastPos);
|
||||
}
|
||||
|
||||
void VarargsFilter::decode(Decoder &decoder)
|
||||
|
||||
{
|
||||
uint4 elemId = decoder.openElement(ELEM_VARARGS);
|
||||
for(;;) {
|
||||
uint4 attribId = decoder.getNextAttributeId();
|
||||
if (attribId == 0) break;
|
||||
if (attribId == ATTRIB_FIRST)
|
||||
firstPos = decoder.readSignedInteger();
|
||||
else if (attribId == ATTRIB_LAST)
|
||||
lastPos = decoder.readSignedInteger();
|
||||
}
|
||||
decoder.closeElement(elemId);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -190,15 +190,24 @@ public:
|
|||
virtual void decode(Decoder &decoder) {}
|
||||
};
|
||||
|
||||
/// \brief A filter that selects function parameters that are considered optional
|
||||
/// \brief A filter that selects a range of function parameters that are considered optional.
|
||||
///
|
||||
/// If the underlying function prototype is considered to take variable arguments, the first
|
||||
/// \e n parameters (as determined by PrototypePieces.firstVarArgSlot) are considered non-optional.
|
||||
/// If additional data-types are provided beyond the initial \e n, these are considered optional.
|
||||
/// This filter returns \b true for these optional parameters
|
||||
/// n parameters (as determined by PrototypePieces.firstVarArgSlot) are considered non-optional.
|
||||
///\e If additional data-types are provided beyond the initial \e n, these are considered optional.
|
||||
/// By default this filter matches on any parameter in a prototype with variable arguments.
|
||||
/// Optionally, it can filter on a range of parameters that are specified relative to the
|
||||
/// first variable argument.
|
||||
/// - \<varargs first="0"/> - matches optional arguments but not non-optional ones.
|
||||
/// - \<varargs first="0" last="0"/> - matches the first optional argument.
|
||||
/// - \<varargs first="-1"/> - matches the last non-optional argument and all optional ones.
|
||||
class VarargsFilter : public QualifierFilter {
|
||||
int4 firstPos; ///< Start of range to match (offset relative to first variable arg)
|
||||
int4 lastPos; ///< End of range to match
|
||||
public:
|
||||
virtual QualifierFilter *clone(void) const { return new VarargsFilter(); }
|
||||
VarargsFilter(void) { firstPos = 0x80000000; lastPos = 0x7fffffff; }
|
||||
VarargsFilter(int4 first,int4 last) { firstPos = first; lastPos = last; }
|
||||
virtual QualifierFilter *clone(void) const { return new VarargsFilter(firstPos,lastPos); }
|
||||
virtual bool filter(const PrototypePieces &proto,int4 pos) const;
|
||||
virtual void decode(Decoder &decoder);
|
||||
};
|
||||
|
|
|
@ -355,7 +355,12 @@
|
|||
<interleave>
|
||||
<optional>
|
||||
<element name="varargs">
|
||||
<empty/>
|
||||
<optional>
|
||||
<attribute name="first"/>
|
||||
</optional>
|
||||
<optional>
|
||||
<attribute name="last"/>
|
||||
</optional>
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,11 @@
|
|||
<pentry maxsize="500" minsize="1" align="1">
|
||||
<addr space="stack" offset="2"/>
|
||||
</pentry>
|
||||
<rule>
|
||||
<datatype name="any"/>
|
||||
<varargs first="-1"/>
|
||||
<goto_stack/>
|
||||
</rule>
|
||||
<rule>
|
||||
<datatype name="struct" minsize="1"/>
|
||||
<convert_to_ptr/>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue