mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-18 00:20:10 +00:00
Use InjectPayload for segment ops
This commit is contained in:
parent
06de0d46a0
commit
4c3289f09f
@ -124,31 +124,6 @@ SegmentOp::SegmentOp(Architecture *g,const string &nm,int4 ind)
|
||||
constresolve.space = (AddrSpace *)0;
|
||||
}
|
||||
|
||||
/// \brief Execute a stream of operations (OpFollow) given a starting input value
|
||||
///
|
||||
/// Each operation is performed in turn, with output from the previous becoming
|
||||
/// input of the next. The final output is returned.
|
||||
/// \param follow is the ordered set of operations to perform
|
||||
/// \param input is the constant input for the first operation
|
||||
/// \return the final constant output
|
||||
uintb SegmentOp::executeSide(const vector<OpFollow> &follow,uintb input)
|
||||
|
||||
{
|
||||
for(int4 i=0;i<follow.size();++i) {
|
||||
switch(follow[i].opc) {
|
||||
case CPUI_INT_AND:
|
||||
input &= follow[i].val;
|
||||
break;
|
||||
case CPUI_INT_LEFT:
|
||||
input <<= follow[i].val;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
bool SegmentOp::unify(Funcdata &data,PcodeOp *op,
|
||||
vector<Varnode *> &bindlist) const
|
||||
{
|
||||
@ -163,7 +138,7 @@ bool SegmentOp::unify(Funcdata &data,PcodeOp *op,
|
||||
if (op->getIn(0)->getOffset() != useropindex) return false;
|
||||
if (op->numInput() != 3) return false;
|
||||
innervn = op->getIn(1);
|
||||
if (basepresent) {
|
||||
if (baseinsize != 0) {
|
||||
basevn = op->getIn(1);
|
||||
innervn = op->getIn(2);
|
||||
if (basevn->isConstant())
|
||||
@ -181,40 +156,23 @@ bool SegmentOp::unify(Funcdata &data,PcodeOp *op,
|
||||
uintb SegmentOp::execute(const vector<uintb> &input) const
|
||||
|
||||
{
|
||||
uintb base,inner;
|
||||
|
||||
if (basepresent)
|
||||
base = executeSide(basefollow,input[1]);
|
||||
else
|
||||
base = 0;
|
||||
|
||||
inner = executeSide(innerfollow,input[0]);
|
||||
return (base+inner);
|
||||
ExecutablePcode *pcodeScript = (ExecutablePcode *)glb->pcodeinjectlib->getPayload(injectId);
|
||||
return pcodeScript->evaluate(input);
|
||||
}
|
||||
|
||||
void SegmentOp::restoreXml(const Element *el)
|
||||
|
||||
{
|
||||
spc = glb->getSpaceByName(el->getAttributeValue("space"));
|
||||
injectId = -1;
|
||||
baseinsize = 0;
|
||||
innerinsize = 0;
|
||||
bool userdefined = false;
|
||||
forcesegment = true;
|
||||
supportsfarpointer = false;
|
||||
name = "segment"; // Default name, might be overridden by userop attribute
|
||||
for(int4 i=0;i<el->getNumAttributes();++i) {
|
||||
const string &nm(el->getAttributeName(i));
|
||||
if (nm == "space") continue;
|
||||
else if (nm == "baseinsize") {
|
||||
istringstream s(el->getAttributeValue(i));
|
||||
s.unsetf(ios::dec | ios::hex | ios::oct);
|
||||
s >> baseinsize;
|
||||
}
|
||||
else if (nm == "innerinsize") {
|
||||
istringstream s1(el->getAttributeValue(i));
|
||||
s1.unsetf(ios::dec | ios::hex | ios::oct);
|
||||
s1 >> innerinsize;
|
||||
}
|
||||
else if (nm == "farpointer")
|
||||
supportsfarpointer = true;
|
||||
else if (nm == "userop") { // Based on existing sleigh op
|
||||
@ -227,28 +185,17 @@ void SegmentOp::restoreXml(const Element *el)
|
||||
throw LowlevelError("Redefining userop "+name);
|
||||
}
|
||||
}
|
||||
else if (nm == "force")
|
||||
forcesegment = xml_readbool(el->getAttributeValue(i));
|
||||
else
|
||||
throw LowlevelError("Bad segmentop tag attribute: "+nm);
|
||||
}
|
||||
if (!userdefined)
|
||||
throw LowlevelError("Missing userop attribute in segmentop tag");
|
||||
basepresent = (baseinsize != 0);
|
||||
|
||||
const List &list(el->getChildren());
|
||||
List::const_iterator iter;
|
||||
for(iter=list.begin();iter!=list.end();++iter) {
|
||||
const Element *subel = *iter;
|
||||
if (subel->getName()=="baseop") {
|
||||
basefollow.push_back(OpFollow());
|
||||
basefollow.back().restoreXml(subel);
|
||||
}
|
||||
else if (subel->getName()=="innerop") {
|
||||
innerfollow.push_back(OpFollow());
|
||||
innerfollow.back().restoreXml(subel);
|
||||
}
|
||||
else if (subel->getName()=="constresolve") {
|
||||
if (subel->getName()=="constresolve") {
|
||||
int4 sz;
|
||||
const List &sublist(subel->getChildren());
|
||||
if (!sublist.empty()) {
|
||||
@ -260,9 +207,28 @@ void SegmentOp::restoreXml(const Element *el)
|
||||
constresolve.size = sz;
|
||||
}
|
||||
}
|
||||
else if (subel->getName() == "pcode") {
|
||||
string nm = name + "_pcode";
|
||||
string source = "cspec";
|
||||
injectId = glb->pcodeinjectlib->restoreXmlInject(source, nm, InjectPayload::EXECUTABLEPCODE_TYPE, subel);
|
||||
}
|
||||
else
|
||||
throw LowlevelError("Bad segment pattern tag: "+subel->getName());
|
||||
}
|
||||
if (injectId < 0)
|
||||
throw LowlevelError("Missing <execute> child in <segmentop> tag");
|
||||
InjectPayload *payload = glb->pcodeinjectlib->getPayload(injectId);
|
||||
if (payload->sizeOutput() != 1)
|
||||
throw LowlevelError("<execute> child of <segmentop> tag must declare one <output>");
|
||||
if (payload->sizeInput() == 1) {
|
||||
innerinsize = payload->getInput(0).getSize();
|
||||
}
|
||||
else if (payload->sizeInput() == 2) {
|
||||
baseinsize = payload->getInput(0).getSize();
|
||||
innerinsize = payload->getInput(1).getSize();
|
||||
}
|
||||
else
|
||||
throw LowlevelError("<execute> child of <segmentop> tag must declare one or two <input> tags");
|
||||
}
|
||||
|
||||
/// \param g is the Architecture owning this set of jump assist scripts
|
||||
|
@ -198,24 +198,19 @@ struct OpFollow {
|
||||
/// The core routine that looks for the term-tree is unify().
|
||||
class SegmentOp : public TermPatternOp {
|
||||
AddrSpace *spc; ///< The physical address space into which a segmented pointer points
|
||||
int4 injectId; ///< Id of InjectPayload that emulates \b this operation
|
||||
int4 baseinsize; ///< The size in bytes of the \e base or \e segment value
|
||||
int4 innerinsize; ///< The size in bytes of the \e near pointer value
|
||||
bool basepresent; ///< Is \b true is a base value must be present in the raw p-code
|
||||
bool forcesegment; ///< Is \b true if an exception is thrown when a segment op can't be unified
|
||||
bool supportsfarpointer; ///< Is \b true if the joined pair base:near acts as a \b far pointer
|
||||
vector<OpFollow> basefollow; ///< Sequence of operations performed on the \b base value
|
||||
vector<OpFollow> innerfollow; ///< Sequence of operations performed on the \b near value
|
||||
VarnodeData constresolve; ///< How to resolve constant near pointers
|
||||
static uintb executeSide(const vector<OpFollow> &follow,uintb input);
|
||||
public:
|
||||
SegmentOp(Architecture *g,const string &nm,int4 ind); ///< Constructor
|
||||
AddrSpace *getSpace(void) const { return spc; } ///< Get the address space being pointed to
|
||||
bool hasFarPointerSupport(void) const { return supportsfarpointer; } ///< Return \b true, if \b this op supports far pointers
|
||||
bool isForced(void) const { return forcesegment; } ///< Return \b true if exceptions are thrown for bad unification
|
||||
int4 getBaseSize(void) const { return baseinsize; } ///< Get size in bytes of the base/segment value
|
||||
int4 getInnerSize(void) const { return innerinsize; } ///< Get size in bytes of the near value
|
||||
const VarnodeData &getResolve(void) const { return constresolve; } ///< Get the default register for resolving indirect segments
|
||||
virtual int4 getNumVariableTerms(void) const { if (basepresent) return 2; return 1; }
|
||||
virtual int4 getNumVariableTerms(void) const { if (baseinsize!=0) return 2; return 1; }
|
||||
virtual bool unify(Funcdata &data,PcodeOp *op,vector<Varnode *> &bindlist) const;
|
||||
virtual uintb execute(const vector<uintb> &input) const;
|
||||
virtual void restoreXml(const Element *el);
|
||||
|
@ -227,51 +227,19 @@
|
||||
</optional>
|
||||
</define>
|
||||
|
||||
<define name="segment_op_type">
|
||||
<attribute name="code">
|
||||
<choice>
|
||||
<value type="string">INT_ZEXT</value>
|
||||
<value type="string">INT_LEFT</value>
|
||||
<value type="string">INT_AND</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
<optional>
|
||||
<attribute name="value"/>
|
||||
</optional>
|
||||
<optional>
|
||||
<attribute name="slot"/>
|
||||
</optional>
|
||||
</define>
|
||||
|
||||
<define name="segmentop_type">
|
||||
<element name="segmentop">
|
||||
<attribute name="space"/>
|
||||
<optional> <attribute name="userop"/> </optional>
|
||||
<optional> <attribute name="baseinsize"/> </optional>
|
||||
<optional> <attribute name="innerinsize"/> </optional>
|
||||
<optional> <attribute name="farpointer"/> </optional>
|
||||
<element name="pcode">
|
||||
<ref name="pcode_type"/>
|
||||
</element>
|
||||
<optional>
|
||||
<attribute name="force">
|
||||
<ref name="boolean_type"/>
|
||||
</attribute>
|
||||
<element name="constresolve">
|
||||
<ref name="varnode_tags_type"/>
|
||||
</element>
|
||||
</optional>
|
||||
<interleave>
|
||||
<zeroOrMore>
|
||||
<element name="baseop">
|
||||
<ref name="segment_op_type"/>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
<zeroOrMore>
|
||||
<element name="innerop">
|
||||
<ref name="segment_op_type"/>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
<optional>
|
||||
<element name="constresolve">
|
||||
<ref name="varnode_tags_type"/>
|
||||
</element>
|
||||
</optional>
|
||||
</interleave>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
|
@ -599,6 +599,29 @@ public class SleighLanguage implements Language {
|
||||
}
|
||||
}
|
||||
|
||||
private void parseSegmentOp(XmlElement el, XmlPullParser parser) {
|
||||
String name = el.getAttribute("userop");
|
||||
if (name == null) {
|
||||
name = "segment";
|
||||
}
|
||||
name = name + "_pcode";
|
||||
String source = "pspec: " + getLanguageID().getIdAsString();
|
||||
if (parser.peek().isStart()) {
|
||||
if (parser.peek().getName().equals("pcode")) {
|
||||
InjectPayloadSleigh payload =
|
||||
new InjectPayloadSleigh(name, InjectPayload.EXECUTABLEPCODE_TYPE, source);
|
||||
if (additionalInject == null) {
|
||||
additionalInject = new ArrayList<>();
|
||||
}
|
||||
payload.restoreXml(parser);
|
||||
additionalInject.add(payload);
|
||||
}
|
||||
}
|
||||
while (parser.peek().isStart()) {
|
||||
parser.discardSubTree();
|
||||
}
|
||||
}
|
||||
|
||||
private void read(XmlPullParser parser) {
|
||||
Set<String> registerDataSet = new HashSet<>();
|
||||
|
||||
@ -775,9 +798,7 @@ public class SleighLanguage implements Language {
|
||||
}
|
||||
}
|
||||
else if (element.getName().equals("segmentop")) {
|
||||
while (parser.peek().isStart()) {
|
||||
parser.discardSubTree();
|
||||
}
|
||||
parseSegmentOp(element, parser);
|
||||
}
|
||||
// get rid of the end tag of whatever we started with at the top of the while
|
||||
parser.end(element);
|
||||
|
@ -163,29 +163,30 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
language.getProperty(GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
|
||||
if (classname == null) {
|
||||
pcodeInject = new PcodeInjectLibrary(language); // This is the default implementation
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Class<?> c = Class.forName(classname);
|
||||
if (!PcodeInjectLibrary.class.isAssignableFrom(c)) {
|
||||
else {
|
||||
try {
|
||||
Class<?> c = Class.forName(classname);
|
||||
if (!PcodeInjectLibrary.class.isAssignableFrom(c)) {
|
||||
Msg.error(this,
|
||||
"Language " + language.getLanguageID() + " does not specify a valid " +
|
||||
GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
|
||||
throw new RuntimeException(classname + " does not implement interface " +
|
||||
PcodeInjectLibrary.class.getName());
|
||||
}
|
||||
Class<? extends PcodeInjectLibrary> injectLibraryClass =
|
||||
(Class<? extends PcodeInjectLibrary>) c;
|
||||
Constructor<? extends PcodeInjectLibrary> constructor =
|
||||
injectLibraryClass.getConstructor(SleighLanguage.class);
|
||||
pcodeInject = constructor.newInstance(language);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.error(this,
|
||||
"Language " + language.getLanguageID() + " does not specify a valid " +
|
||||
GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
|
||||
throw new RuntimeException(classname + " does not implement interface " +
|
||||
PcodeInjectLibrary.class.getName());
|
||||
throw new RuntimeException("Failed to instantiate " + classname + " for language " +
|
||||
language.getLanguageID(), e);
|
||||
}
|
||||
Class<? extends PcodeInjectLibrary> injectLibraryClass =
|
||||
(Class<? extends PcodeInjectLibrary>) c;
|
||||
Constructor<? extends PcodeInjectLibrary> constructor =
|
||||
injectLibraryClass.getConstructor(SleighLanguage.class);
|
||||
pcodeInject = constructor.newInstance(language);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.error(this, "Language " + language.getLanguageID() + " does not specify a valid " +
|
||||
GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
|
||||
throw new RuntimeException(
|
||||
"Failed to instantiate " + classname + " for language " + language.getLanguageID(),
|
||||
e);
|
||||
}
|
||||
List<InjectPayloadSleigh> additionalInject = language.getAdditionalInject();
|
||||
if (additionalInject != null) {
|
||||
|
@ -7,10 +7,15 @@
|
||||
</properties>
|
||||
<programcounter register="EIP"/>
|
||||
<segmented_address space="ram" type="real" />
|
||||
<segmentop space="ram" userop="segment" baseinsize="2" innerinsize="2" farpointer="yes">
|
||||
<baseop code="INT_ZEXT"/>
|
||||
<baseop code="INT_LEFT" value="4"/>
|
||||
<innerop code="INT_ZEXT"/>
|
||||
<segmentop space="ram" userop="segment" farpointer="yes">
|
||||
<pcode>
|
||||
<input name="inner" size="2"/>
|
||||
<input name="base" size="2"/>
|
||||
<output name="res" size="4"/>
|
||||
<body><![CDATA[
|
||||
res = (zext(base) << 4) + zext(inner);
|
||||
]]></body>
|
||||
</pcode>
|
||||
<constresolve>
|
||||
<register name="DS"/>
|
||||
</constresolve>
|
||||
|
@ -8,10 +8,15 @@
|
||||
</properties>
|
||||
<programcounter register="EIP"/>
|
||||
<segmented_address space="ram" type="protected"/>
|
||||
<segmentop space="ram" userop="segment" baseinsize="2" innerinsize="2" farpointer="yes">
|
||||
<baseop code="INT_ZEXT"/>
|
||||
<baseop code="INT_LEFT" value="16"/>
|
||||
<innerop code="INT_ZEXT"/>
|
||||
<segmentop space="ram" userop="segment" farpointer="yes">
|
||||
<pcode>
|
||||
<input name="inner" size="2"/>
|
||||
<input name="base" size="2"/>
|
||||
<output name="res" size="4"/>
|
||||
<body><![CDATA[
|
||||
res = (zext(base) << 16) + zext(inner);
|
||||
]]></body>
|
||||
</pcode>
|
||||
<constresolve>
|
||||
<register name="DS"/>
|
||||
</constresolve>
|
||||
|
Loading…
Reference in New Issue
Block a user