/* ### * IP: GHIDRA * * 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. * See the License for the specific language governing permissions and * limitations under the License. */ #include "slghsymbol.hh" #include "sleighbase.hh" #include namespace ghidra { using std::log; SleighSymbol *SymbolScope::addSymbol(SleighSymbol *a) { pair res; res = tree.insert( a ); if (!res.second) return *res.first; // Symbol already exists in this table return a; } SleighSymbol *SymbolScope::findSymbol(const string &nm) const { SleighSymbol dummy(nm); SymbolTree::const_iterator iter; iter = tree.find( &dummy ); if (iter != tree.end()) return *iter; return (SleighSymbol *)0; } SymbolTable::~SymbolTable(void) { vector::iterator iter; for(iter=table.begin();iter!=table.end();++iter) delete *iter; vector::iterator siter; for(siter=symbollist.begin();siter!=symbollist.end();++siter) delete *siter; } void SymbolTable::addScope(void) { curscope = new SymbolScope(curscope,table.size()); table.push_back(curscope); } void SymbolTable::popScope(void) { if (curscope != (SymbolScope *)0) curscope = curscope->getParent(); } SymbolScope *SymbolTable::skipScope(int4 i) const { SymbolScope *res = curscope; while(i>0) { if (res->parent == (SymbolScope *)0) return res; res = res->parent; --i; } return res; } void SymbolTable::addGlobalSymbol(SleighSymbol *a) { a->id = symbollist.size(); symbollist.push_back(a); SymbolScope *scope = getGlobalScope(); a->scopeid = scope->getId(); SleighSymbol *res = scope->addSymbol(a); if (res != a) throw SleighError("Duplicate symbol name '" + a->getName() + "'"); } void SymbolTable::addSymbol(SleighSymbol *a) { a->id = symbollist.size(); symbollist.push_back(a); a->scopeid = curscope->getId(); SleighSymbol *res = curscope->addSymbol(a); if (res != a) throw SleighError("Duplicate symbol name: "+a->getName()); } SleighSymbol *SymbolTable::findSymbolInternal(SymbolScope *scope,const string &nm) const { SleighSymbol *res; while(scope != (SymbolScope *)0) { res = scope->findSymbol(nm); if (res != (SleighSymbol *)0) return res; scope = scope->getParent(); // Try higher scope } return (SleighSymbol *)0; } void SymbolTable::replaceSymbol(SleighSymbol *a,SleighSymbol *b) { // Replace symbol a with symbol b // assuming a and b have the same name SleighSymbol *sym; int4 i = table.size()-1; while(i>=0) { // Find the particular symbol sym = table[i]->findSymbol( a->getName() ); if (sym == a) { table[i]->removeSymbol(a); b->id = a->id; b->scopeid = a->scopeid; symbollist[b->id] = b; table[i]->addSymbol(b); delete a; return; } --i; } } void SymbolTable::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_SYMBOL_TABLE); encoder.writeSignedInteger(sla::ATTRIB_SCOPESIZE, table.size()); encoder.writeSignedInteger(sla::ATTRIB_SYMBOLSIZE, symbollist.size()); for(int4 i=0;igetId()); if (table[i]->getParent() == (SymbolScope *)0) encoder.writeUnsignedInteger(sla::ATTRIB_PARENT, 0); else encoder.writeUnsignedInteger(sla::ATTRIB_PARENT, table[i]->getParent()->getId()); encoder.closeElement(sla::ELEM_SCOPE); } // First save the headers for(int4 i=0;iencodeHeader(encoder); // Now save the content of each symbol for(int4 i=0;iencode(encoder); encoder.closeElement(sla::ELEM_SYMBOL_TABLE); } void SymbolTable::decode(Decoder &decoder,SleighBase *trans) { int4 el = decoder.openElement(sla::ELEM_SYMBOL_TABLE); table.resize(decoder.readSignedInteger(sla::ATTRIB_SCOPESIZE), (SymbolScope *)0); symbollist.resize(decoder.readSignedInteger(sla::ATTRIB_SYMBOLSIZE), (SleighSymbol *)0); for(int4 i=0;idecode(decoder,trans); // Tag closed by decode method // decoder.closeElement(subel); } decoder.closeElement(el); } void SymbolTable::decodeSymbolHeader(Decoder &decoder) { // Put the shell of a symbol in the symbol table // in order to allow recursion SleighSymbol *sym; uint4 el = decoder.peekElement(); if (el == sla::ELEM_USEROP_HEAD) sym = new UserOpSymbol(); else if (el == sla::ELEM_EPSILON_SYM_HEAD) sym = new EpsilonSymbol(); else if (el == sla::ELEM_VALUE_SYM_HEAD) sym = new ValueSymbol(); else if (el == sla::ELEM_VALUEMAP_SYM_HEAD) sym = new ValueMapSymbol(); else if (el == sla::ELEM_NAME_SYM_HEAD) sym = new NameSymbol(); else if (el == sla::ELEM_VARNODE_SYM_HEAD) sym = new VarnodeSymbol(); else if (el == sla::ELEM_CONTEXT_SYM_HEAD) sym = new ContextSymbol(); else if (el == sla::ELEM_VARLIST_SYM_HEAD) sym = new VarnodeListSymbol(); else if (el == sla::ELEM_OPERAND_SYM_HEAD) sym = new OperandSymbol(); else if (el == sla::ELEM_START_SYM_HEAD) sym = new StartSymbol(); else if (el == sla::ELEM_END_SYM_HEAD) sym = new EndSymbol(); else if (el == sla::ELEM_NEXT2_SYM_HEAD) sym = new Next2Symbol(); else if (el == sla::ELEM_SUBTABLE_SYM_HEAD) sym = new SubtableSymbol(); else throw SleighError("Bad symbol xml"); sym->decodeHeader(decoder); // Restore basic elements of symbol symbollist[sym->id] = sym; // Put the basic symbol in the table table[sym->scopeid]->addSymbol(sym); // to allow recursion } void SymbolTable::purge(void) { // Get rid of unsavable symbols and scopes SleighSymbol *sym; for(int4 i=0;iscopeid != 0) { // Not in global scope if (sym->getType() == SleighSymbol::operand_symbol) continue; } else { switch(sym->getType()) { case SleighSymbol::space_symbol: case SleighSymbol::token_symbol: case SleighSymbol::epsilon_symbol: case SleighSymbol::section_symbol: case SleighSymbol::bitrange_symbol: break; case SleighSymbol::macro_symbol: { // Delete macro's local symbols MacroSymbol *macro = (MacroSymbol *)sym; for(int4 i=0;igetNumOperands();++i) { SleighSymbol *opersym = macro->getOperand(i); table[opersym->scopeid]->removeSymbol(opersym); symbollist[opersym->id] = (SleighSymbol *)0; delete opersym; } break; } case SleighSymbol::subtable_symbol: { // Delete unused subtables SubtableSymbol *subsym = (SubtableSymbol *)sym; if (subsym->getPattern() != (TokenPattern *)0) continue; for(int4 i=0;igetNumConstructors();++i) { // Go thru each constructor Constructor *con = subsym->getConstructor(i); for(int4 j=0;jgetNumOperands();++j) { // Go thru each operand OperandSymbol *oper = con->getOperand(j); table[oper->scopeid]->removeSymbol(oper); symbollist[oper->id] = (SleighSymbol *)0; delete oper; } } break; // Remove the subtable symbol itself } default: continue; } } table[sym->scopeid]->removeSymbol(sym); // Remove the symbol symbollist[i] = (SleighSymbol *)0; delete sym; } for(int4 i=1;itree.empty()) { delete table[i]; table[i] = (SymbolScope *)0; } } renumber(); } void SymbolTable::renumber(void) { // Renumber all the scopes and symbols // so that there are no gaps vector newtable; vector newsymbol; // First renumber the scopes SymbolScope *scope; for(int4 i=0;iid = newtable.size(); newtable.push_back(scope); } } // Now renumber the symbols SleighSymbol *sym; for(int4 i=0;iscopeid = table[sym->scopeid]->id; sym->id = newsymbol.size(); newsymbol.push_back(sym); } } table = newtable; symbollist = newsymbol; } void SleighSymbol::encodeHeader(Encoder &encoder) const { // Save the basic attributes of a symbol encoder.writeString(sla::ATTRIB_NAME, name); encoder.writeUnsignedInteger(sla::ATTRIB_ID, id); encoder.writeUnsignedInteger(sla::ATTRIB_SCOPE, scopeid); } void SleighSymbol::decodeHeader(Decoder &decoder) { uint4 el = decoder.openElement(); name = decoder.readString(sla::ATTRIB_NAME); id = decoder.readUnsignedInteger(sla::ATTRIB_ID); scopeid = decoder.readUnsignedInteger(sla::ATTRIB_SCOPE); decoder.closeElement(el); } void SleighSymbol::encode(Encoder &encoder) const { throw LowlevelError("Symbol "+name+" cannot be encoded to stream directly"); } void SleighSymbol::decode(Decoder &decoder,SleighBase *trans) { throw LowlevelError("Symbol "+name+" cannot be decoded from stream directly"); } void UserOpSymbol::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_USEROP); encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); encoder.writeSignedInteger(sla::ATTRIB_INDEX, index); encoder.closeElement(sla::ELEM_USEROP); } void UserOpSymbol::encodeHeader(Encoder &encoder) const { encoder.openElement(sla::ELEM_USEROP_HEAD); SleighSymbol::encodeHeader(encoder); encoder.closeElement(sla::ELEM_USEROP_HEAD); } void UserOpSymbol::decode(Decoder &decoder,SleighBase *trans) { index = decoder.readSignedInteger(sla::ATTRIB_INDEX); decoder.closeElement(sla::ELEM_USEROP.getId()); } PatternlessSymbol::PatternlessSymbol(void) { // The void constructor must explicitly build the ConstantValue. It is not decode (or encoded) patexp = new ConstantValue((intb)0); patexp->layClaim(); } PatternlessSymbol::PatternlessSymbol(const string &nm) : SpecificSymbol(nm) { patexp = new ConstantValue((intb)0); patexp->layClaim(); } PatternlessSymbol::~PatternlessSymbol(void) { PatternExpression::release(patexp); } void EpsilonSymbol::getFixedHandle(FixedHandle &hand,ParserWalker &walker) const { hand.space = const_space; hand.offset_space = (AddrSpace *)0; // Not a dynamic value hand.offset_offset = 0; hand.size = 0; // Cannot provide size } void EpsilonSymbol::print(ostream &s,ParserWalker &walker) const { s << '0'; } VarnodeTpl *EpsilonSymbol::getVarnode(void) const { VarnodeTpl *res = new VarnodeTpl(ConstTpl(const_space), ConstTpl(ConstTpl::real,0), ConstTpl(ConstTpl::real,0)); return res; } void EpsilonSymbol::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_EPSILON_SYM); encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); encoder.closeElement(sla::ELEM_EPSILON_SYM); } void EpsilonSymbol::encodeHeader(Encoder &encoder) const { encoder.openElement(sla::ELEM_EPSILON_SYM_HEAD); SleighSymbol::encodeHeader(encoder); encoder.closeElement(sla::ELEM_EPSILON_SYM_HEAD); } void EpsilonSymbol::decode(Decoder &decoder,SleighBase *trans) { const_space = trans->getConstantSpace(); decoder.closeElement(sla::ELEM_EPSILON_SYM.getId()); } ValueSymbol::ValueSymbol(const string &nm,PatternValue *pv) : FamilySymbol(nm) { (patval=pv)->layClaim(); } ValueSymbol::~ValueSymbol(void) { if (patval != (PatternValue *)0) PatternExpression::release(patval); } void ValueSymbol::getFixedHandle(FixedHandle &hand,ParserWalker &walker) const { hand.space = walker.getConstSpace(); hand.offset_space = (AddrSpace *)0; hand.offset_offset = (uintb) patval->getValue(walker); hand.size = 0; // Cannot provide size } void ValueSymbol::print(ostream &s,ParserWalker &walker) const { intb val = patval->getValue(walker); if (val >= 0) s << "0x" << hex << val; else s << "-0x" << hex << -val; } void ValueSymbol::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_VALUE_SYM); encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); patval->encode(encoder); encoder.closeElement(sla::ELEM_VALUE_SYM); } void ValueSymbol::encodeHeader(Encoder &encoder) const { encoder.openElement(sla::ELEM_VALUE_SYM_HEAD); SleighSymbol::encodeHeader(encoder); encoder.closeElement(sla::ELEM_VALUE_SYM_HEAD); } void ValueSymbol::decode(Decoder &decoder,SleighBase *trans) { patval = (PatternValue *) PatternExpression::decodeExpression(decoder,trans); patval->layClaim(); decoder.closeElement(sla::ELEM_VALUE_SYM.getId()); } void ValueMapSymbol::checkTableFill(void) { // Check if all possible entries in the table have been filled intb min = patval->minValue(); intb max = patval->maxValue(); tableisfilled = (min>=0)&&(maxgetValue(walker); if ((ind >= valuetable.size())||(ind<0)||(valuetable[ind] == 0xBADBEEF)) { ostringstream s; s << walker.getAddr().getShortcut(); walker.getAddr().printRaw(s); s << ": No corresponding entry in valuetable"; throw BadDataError(s.str()); } } return (Constructor *)0; } void ValueMapSymbol::getFixedHandle(FixedHandle &hand,ParserWalker &walker) const { uint4 ind = (uint4) patval->getValue(walker); // The resolve routine has checked that -ind- must be a valid index hand.space = walker.getConstSpace(); hand.offset_space = (AddrSpace *)0; // Not a dynamic value hand.offset_offset = (uintb)valuetable[ind]; hand.size = 0; // Cannot provide size } void ValueMapSymbol::print(ostream &s,ParserWalker &walker) const { uint4 ind = (uint4)patval->getValue(walker); // ind is already checked to be in range by the resolve routine intb val = valuetable[ind]; if (val >= 0) s << "0x" << hex << val; else s << "-0x" << hex << -val; } void ValueMapSymbol::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_VALUEMAP_SYM); encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); patval->encode(encoder); for(uint4 i=0;ilayClaim(); while(decoder.peekElement() != 0) { uint4 subel = decoder.openElement(); intb val = decoder.readSignedInteger(sla::ATTRIB_VAL); valuetable.push_back(val); decoder.closeElement(subel); } decoder.closeElement(sla::ELEM_VALUEMAP_SYM.getId()); checkTableFill(); } void NameSymbol::checkTableFill(void) { // Check if all possible entries in the table have been filled intb min = patval->minValue(); intb max = patval->maxValue(); tableisfilled = (min>=0)&&(maxgetValue(walker); if ((ind >= nametable.size())||(ind<0)||((nametable[ind].size()==1)&&(nametable[ind][0]=='\t'))) { ostringstream s; s << walker.getAddr().getShortcut(); walker.getAddr().printRaw(s); s << ": No corresponding entry in nametable"; throw BadDataError(s.str()); } } return (Constructor *)0; } void NameSymbol::print(ostream &s,ParserWalker &walker) const { uint4 ind = (uint4)patval->getValue(walker); // ind is already checked to be in range by the resolve routine s << nametable[ind]; } void NameSymbol::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_NAME_SYM); encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); patval->encode(encoder); for(int4 i=0;ilayClaim(); while(decoder.peekElement() != 0) { uint4 subel = decoder.openElement(); if (decoder.getNextAttributeId() == sla::ATTRIB_NAME) nametable.push_back(decoder.readString()); else nametable.push_back("\t"); // TAB indicates an illegal index decoder.closeElement(subel); } decoder.closeElement(sla::ELEM_NAME_SYM.getId()); checkTableFill(); } VarnodeSymbol::VarnodeSymbol(const string &nm,AddrSpace *base,uintb offset,int4 size) : PatternlessSymbol(nm) { fix.space = base; fix.offset = offset; fix.size = size; context_bits = false; } VarnodeTpl *VarnodeSymbol::getVarnode(void) const { return new VarnodeTpl(ConstTpl(fix.space),ConstTpl(ConstTpl::real,fix.offset),ConstTpl(ConstTpl::real,fix.size)); } void VarnodeSymbol::getFixedHandle(FixedHandle &hand,ParserWalker &walker) const { hand.space = fix.space; hand.offset_space = (AddrSpace *)0; // Not a dynamic symbol hand.offset_offset = fix.offset; hand.size = fix.size; } void VarnodeSymbol::collectLocalValues(vector &results) const { if (fix.space->getType() == IPTR_INTERNAL) results.push_back(fix.offset); } void VarnodeSymbol::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_VARNODE_SYM); encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); encoder.writeSpace(sla::ATTRIB_SPACE,fix.space); encoder.writeUnsignedInteger(sla::ATTRIB_OFF, fix.offset); encoder.writeSignedInteger(sla::ATTRIB_SIZE, fix.size); encoder.closeElement(sla::ELEM_VARNODE_SYM); } void VarnodeSymbol::encodeHeader(Encoder &encoder) const { encoder.openElement(sla::ELEM_VARNODE_SYM_HEAD); SleighSymbol::encodeHeader(encoder); encoder.closeElement(sla::ELEM_VARNODE_SYM_HEAD); } void VarnodeSymbol::decode(Decoder &decoder,SleighBase *trans) { fix.space = decoder.readSpace(sla::ATTRIB_SPACE); fix.offset = decoder.readUnsignedInteger(sla::ATTRIB_OFF); fix.size = decoder.readSignedInteger(sla::ATTRIB_SIZE); // PatternlessSymbol does not need restoring decoder.closeElement(sla::ELEM_VARNODE_SYM.getId()); } ContextSymbol::ContextSymbol(const string &nm,ContextField *pate,VarnodeSymbol *v, uint4 l,uint4 h,bool fl) : ValueSymbol(nm,pate) { vn = v; low = l; high = h; flow = fl; } void ContextSymbol::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_CONTEXT_SYM); encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); encoder.writeUnsignedInteger(sla::ATTRIB_VARNODE, vn->getId()); encoder.writeSignedInteger(sla::ATTRIB_LOW, low); encoder.writeSignedInteger(sla::ATTRIB_HIGH, high); encoder.writeBool(sla::ATTRIB_FLOW, flow); patval->encode(encoder); encoder.closeElement(sla::ELEM_CONTEXT_SYM); } void ContextSymbol::encodeHeader(Encoder &encoder) const { encoder.openElement(sla::ELEM_CONTEXT_SYM_HEAD); SleighSymbol::encodeHeader(encoder); encoder.closeElement(sla::ELEM_CONTEXT_SYM_HEAD); } void ContextSymbol::decode(Decoder &decoder,SleighBase *trans) { // SleighSymbol::decodeHeader(decoder); // Already filled in by the header tag flow = false; bool highMissing = true; bool lowMissing = true; uint4 attrib = decoder.getNextAttributeId(); while(attrib != 0) { if (attrib == sla::ATTRIB_VARNODE) { uintm id = decoder.readUnsignedInteger(); vn = (VarnodeSymbol *)trans->findSymbol(id); } else if (attrib == sla::ATTRIB_LOW) { low = decoder.readSignedInteger(); lowMissing = false; } else if (attrib == sla::ATTRIB_HIGH) { high = decoder.readSignedInteger(); highMissing = false; } else if (attrib == sla::ATTRIB_FLOW) { flow = decoder.readBool(); } attrib = decoder.getNextAttributeId(); } if (lowMissing || highMissing) { throw DecoderError("Missing high/low attributes"); } patval = (PatternValue *) PatternExpression::decodeExpression(decoder,trans); patval->layClaim(); decoder.closeElement(sla::ELEM_CONTEXT_SYM.getId()); } VarnodeListSymbol::VarnodeListSymbol(const string &nm,PatternValue *pv,const vector &vt) : ValueSymbol(nm,pv) { for(int4 i=0;iminValue(); intb max = patval->maxValue(); tableisfilled = (min>=0)&&(maxgetValue(walker); if ((ind<0)||(ind>=varnode_table.size())||(varnode_table[ind]==(VarnodeSymbol *)0)) { ostringstream s; s << walker.getAddr().getShortcut(); walker.getAddr().printRaw(s); s << ": No corresponding entry in varnode list"; throw BadDataError(s.str()); } } return (Constructor *)0; } void VarnodeListSymbol::getFixedHandle(FixedHandle &hand,ParserWalker &walker) const { uint4 ind = (uint4) patval->getValue(walker); // The resolve routine has checked that -ind- must be a valid index const VarnodeData &fix( varnode_table[ind]->getFixedVarnode() ); hand.space = fix.space; hand.offset_space = (AddrSpace *)0; // Not a dynamic value hand.offset_offset = fix.offset; hand.size = fix.size; } int4 VarnodeListSymbol::getSize(void) const { for(int4 i=0;igetSize(); } throw SleighError("No register attached to: "+getName()); } void VarnodeListSymbol::print(ostream &s,ParserWalker &walker) const { uint4 ind = (uint4)patval->getValue(walker); if (ind >= varnode_table.size()) throw SleighError("Value out of range for varnode table"); s << varnode_table[ind]->getName(); } void VarnodeListSymbol::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_VARLIST_SYM); encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); patval->encode(encoder); for(int4 i=0;igetId()); encoder.closeElement(sla::ELEM_VAR); } } encoder.closeElement(sla::ELEM_VARLIST_SYM); } void VarnodeListSymbol::encodeHeader(Encoder &encoder) const { encoder.openElement(sla::ELEM_VARLIST_SYM_HEAD); SleighSymbol::encodeHeader(encoder); encoder.closeElement(sla::ELEM_VARLIST_SYM_HEAD); } void VarnodeListSymbol::decode(Decoder &decoder,SleighBase *trans) { patval = (PatternValue *) PatternExpression::decodeExpression(decoder,trans); patval->layClaim(); while(decoder.peekElement() != 0) { uint4 subel = decoder.openElement(); if (subel == sla::ELEM_VAR) { uintm id = decoder.readUnsignedInteger(sla::ATTRIB_ID); varnode_table.push_back( (VarnodeSymbol *)trans->findSymbol(id) ); } else varnode_table.push_back( (VarnodeSymbol *)0 ); decoder.closeElement(subel); } decoder.closeElement(sla::ELEM_VARLIST_SYM.getId()); checkTableFill(); } OperandSymbol::OperandSymbol(const string &nm,int4 index,Constructor *ct) : SpecificSymbol(nm) { flags = 0; hand = index; localexp = new OperandValue(index,ct); localexp->layClaim(); defexp = (PatternExpression *)0; triple = (TripleSymbol *)0; } void OperandSymbol::defineOperand(PatternExpression *pe) { if ((defexp != (PatternExpression *)0)||(triple!=(TripleSymbol *)0)) throw SleighError("Redefining operand"); defexp = pe; defexp->layClaim(); } void OperandSymbol::defineOperand(TripleSymbol *tri) { if ((defexp != (PatternExpression *)0)||(triple!=(TripleSymbol *)0)) throw SleighError("Redefining operand"); triple = tri; } OperandSymbol::~OperandSymbol(void) { PatternExpression::release(localexp); if (defexp != (PatternExpression *)0) PatternExpression::release(defexp); } VarnodeTpl *OperandSymbol::getVarnode(void) const { VarnodeTpl *res; if (defexp != (PatternExpression *)0) res = new VarnodeTpl(hand,true); // Definite constant handle else { SpecificSymbol *specsym = dynamic_cast(triple); if (specsym != (SpecificSymbol *)0) res = specsym->getVarnode(); else if ((triple != (TripleSymbol *)0)&& ((triple->getType() == valuemap_symbol)||(triple->getType() == name_symbol))) res = new VarnodeTpl(hand,true); // Zero-size symbols else res = new VarnodeTpl(hand,false); // Possible dynamic handle } return res; } void OperandSymbol::getFixedHandle(FixedHandle &hnd,ParserWalker &walker) const { hnd = walker.getFixedHandle(hand); } int4 OperandSymbol::getSize(void) const { if (triple != (TripleSymbol *)0) return triple->getSize(); return 0; } void OperandSymbol::print(ostream &s,ParserWalker &walker) const { walker.pushOperand(getIndex()); if (triple != (TripleSymbol *)0) { if (triple->getType() == SleighSymbol::subtable_symbol) walker.getConstructor()->print(s,walker); else triple->print(s,walker); } else { intb val = defexp->getValue(walker); if (val >= 0) s << "0x" << hex << val; else s << "-0x" << hex << -val; } walker.popOperand(); } void OperandSymbol::collectLocalValues(vector &results) const { if (triple != (TripleSymbol *)0) triple->collectLocalValues(results); } void OperandSymbol::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_OPERAND_SYM); encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); if (triple != (TripleSymbol *)0) encoder.writeUnsignedInteger(sla::ATTRIB_SUBSYM, triple->getId()); encoder.writeSignedInteger(sla::ATTRIB_OFF, reloffset); encoder.writeSignedInteger(sla::ATTRIB_BASE, offsetbase); encoder.writeSignedInteger(sla::ATTRIB_MINLEN, minimumlength); if (isCodeAddress()) encoder.writeBool(sla::ATTRIB_CODE, true); encoder.writeSignedInteger(sla::ATTRIB_INDEX, hand); localexp->encode(encoder); if (defexp != (PatternExpression *)0) defexp->encode(encoder); encoder.closeElement(sla::ELEM_OPERAND_SYM); } void OperandSymbol::encodeHeader(Encoder &encoder) const { encoder.openElement(sla::ELEM_OPERAND_SYM_HEAD); SleighSymbol::encodeHeader(encoder); encoder.closeElement(sla::ELEM_OPERAND_SYM_HEAD); } void OperandSymbol::decode(Decoder &decoder,SleighBase *trans) { defexp = (PatternExpression *)0; triple = (TripleSymbol *)0; flags = 0; uint4 attrib = decoder.getNextAttributeId(); while(attrib != 0) { attrib = decoder.getNextAttributeId(); if (attrib == sla::ATTRIB_INDEX) hand = decoder.readSignedInteger(); else if (attrib == sla::ATTRIB_OFF) reloffset = decoder.readSignedInteger(); else if (attrib == sla::ATTRIB_BASE) offsetbase = decoder.readSignedInteger(); else if (attrib == sla::ATTRIB_MINLEN) minimumlength = decoder.readSignedInteger(); else if (attrib == sla::ATTRIB_SUBSYM) { uintm id = decoder.readUnsignedInteger(); triple = (TripleSymbol *)trans->findSymbol(id); } else if (attrib == sla::ATTRIB_CODE) { if (decoder.readBool()) flags |= code_address; } } localexp = (OperandValue *)PatternExpression::decodeExpression(decoder,trans); localexp->layClaim(); if (decoder.peekElement() != 0) { defexp = PatternExpression::decodeExpression(decoder,trans); defexp->layClaim(); } decoder.closeElement(sla::ELEM_OPERAND_SYM.getId()); } StartSymbol::StartSymbol(const string &nm,AddrSpace *cspc) : SpecificSymbol(nm) { const_space = cspc; patexp = new StartInstructionValue(); patexp->layClaim(); } StartSymbol::~StartSymbol(void) { if (patexp != (PatternExpression *)0) PatternExpression::release(patexp); } VarnodeTpl *StartSymbol::getVarnode(void) const { // Returns current instruction offset as a constant ConstTpl spc(const_space); ConstTpl off(ConstTpl::j_start); ConstTpl sz_zero; return new VarnodeTpl(spc,off,sz_zero); } void StartSymbol::getFixedHandle(FixedHandle &hand,ParserWalker &walker) const { hand.space = walker.getCurSpace(); hand.offset_space = (AddrSpace *)0; hand.offset_offset = walker.getAddr().getOffset(); // Get starting address of instruction hand.size = hand.space->getAddrSize(); } void StartSymbol::print(ostream &s,ParserWalker &walker) const { intb val = (intb) walker.getAddr().getOffset(); s << "0x" << hex << val; } void StartSymbol::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_START_SYM); encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); encoder.closeElement(sla::ELEM_START_SYM); } void StartSymbol::encodeHeader(Encoder &encoder) const { encoder.openElement(sla::ELEM_START_SYM_HEAD); SleighSymbol::encodeHeader(encoder); encoder.closeElement(sla::ELEM_START_SYM_HEAD); } void StartSymbol::decode(Decoder &decoder,SleighBase *trans) { const_space = trans->getConstantSpace(); patexp = new StartInstructionValue(); patexp->layClaim(); decoder.closeElement(sla::ELEM_START_SYM.getId()); } EndSymbol::EndSymbol(const string &nm,AddrSpace *cspc) : SpecificSymbol(nm) { const_space = cspc; patexp = new EndInstructionValue(); patexp->layClaim(); } EndSymbol::~EndSymbol(void) { if (patexp != (PatternExpression *)0) PatternExpression::release(patexp); } VarnodeTpl *EndSymbol::getVarnode(void) const { // Return next instruction offset as a constant ConstTpl spc(const_space); ConstTpl off(ConstTpl::j_next); ConstTpl sz_zero; return new VarnodeTpl(spc,off,sz_zero); } void EndSymbol::getFixedHandle(FixedHandle &hand,ParserWalker &walker) const { hand.space = walker.getCurSpace(); hand.offset_space = (AddrSpace *)0; hand.offset_offset = walker.getNaddr().getOffset(); // Get starting address of next instruction hand.size = hand.space->getAddrSize(); } void EndSymbol::print(ostream &s,ParserWalker &walker) const { intb val = (intb) walker.getNaddr().getOffset(); s << "0x" << hex << val; } void EndSymbol::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_END_SYM); encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); encoder.closeElement(sla::ELEM_END_SYM); } void EndSymbol::encodeHeader(Encoder &encoder) const { encoder.openElement(sla::ELEM_END_SYM_HEAD); SleighSymbol::encodeHeader(encoder); encoder.closeElement(sla::ELEM_END_SYM_HEAD); } void EndSymbol::decode(Decoder &decoder,SleighBase *trans) { const_space = trans->getConstantSpace(); patexp = new EndInstructionValue(); patexp->layClaim(); decoder.closeElement(sla::ELEM_END_SYM.getId()); } Next2Symbol::Next2Symbol(const string &nm,AddrSpace *cspc) : SpecificSymbol(nm) { const_space = cspc; patexp = new Next2InstructionValue(); patexp->layClaim(); } Next2Symbol::~Next2Symbol(void) { if (patexp != (PatternExpression *)0) PatternExpression::release(patexp); } VarnodeTpl *Next2Symbol::getVarnode(void) const { // Return instruction offset after next instruction offset as a constant ConstTpl spc(const_space); ConstTpl off(ConstTpl::j_next2); ConstTpl sz_zero; return new VarnodeTpl(spc,off,sz_zero); } void Next2Symbol::getFixedHandle(FixedHandle &hand,ParserWalker &walker) const { hand.space = walker.getCurSpace(); hand.offset_space = (AddrSpace *)0; hand.offset_offset = walker.getN2addr().getOffset(); // Get instruction address after next instruction hand.size = hand.space->getAddrSize(); } void Next2Symbol::print(ostream &s,ParserWalker &walker) const { intb val = (intb) walker.getN2addr().getOffset(); s << "0x" << hex << val; } void Next2Symbol::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_NEXT2_SYM); encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); encoder.closeElement(sla::ELEM_NEXT2_SYM); } void Next2Symbol::encodeHeader(Encoder &encoder) const { encoder.openElement(sla::ELEM_NEXT2_SYM_HEAD); SleighSymbol::encodeHeader(encoder); encoder.closeElement(sla::ELEM_NEXT2_SYM_HEAD); } void Next2Symbol::decode(Decoder &decoder,SleighBase *trans) { const_space = trans->getConstantSpace(); patexp = new Next2InstructionValue(); patexp->layClaim(); decoder.closeElement(sla::ELEM_NEXT2_SYM.getId()); } FlowDestSymbol::FlowDestSymbol(const string &nm,AddrSpace *cspc) : SpecificSymbol(nm) { const_space = cspc; } VarnodeTpl *FlowDestSymbol::getVarnode(void) const { ConstTpl spc(const_space); ConstTpl off(ConstTpl::j_flowdest); ConstTpl sz_zero; return new VarnodeTpl(spc,off,sz_zero); } void FlowDestSymbol::getFixedHandle(FixedHandle &hand,ParserWalker &walker) const { Address refAddr = walker.getDestAddr(); hand.space = const_space; hand.offset_space = (AddrSpace *)0; hand.offset_offset = refAddr.getOffset(); hand.size = refAddr.getAddrSize(); } void FlowDestSymbol::print(ostream &s,ParserWalker &walker) const { intb val = (intb) walker.getDestAddr().getOffset(); s << "0x" << hex << val; } FlowRefSymbol::FlowRefSymbol(const string &nm,AddrSpace *cspc) : SpecificSymbol(nm) { const_space = cspc; } VarnodeTpl *FlowRefSymbol::getVarnode(void) const { ConstTpl spc(const_space); ConstTpl off(ConstTpl::j_flowref); ConstTpl sz_zero; return new VarnodeTpl(spc,off,sz_zero); } void FlowRefSymbol::getFixedHandle(FixedHandle &hand,ParserWalker &walker) const { Address refAddr = walker.getRefAddr(); hand.space = const_space; hand.offset_space = (AddrSpace *)0; hand.offset_offset = refAddr.getOffset(); hand.size = refAddr.getAddrSize(); } void FlowRefSymbol::print(ostream &s,ParserWalker &walker) const { intb val = (intb) walker.getRefAddr().getOffset(); s << "0x" << hex << val; } Constructor::Constructor(void) { pattern = (TokenPattern *)0; parent = (SubtableSymbol *)0; pateq = (PatternEquation *)0; templ = (ConstructTpl *)0; firstwhitespace = -1; flowthruindex = -1; inerror = false; } Constructor::Constructor(SubtableSymbol *p) { pattern = (TokenPattern *)0; parent = p; pateq = (PatternEquation *)0; templ = (ConstructTpl *)0; firstwhitespace = -1; inerror = false; } Constructor::~Constructor(void) { if (pattern != (TokenPattern *)0) delete pattern; if (pateq != (PatternEquation *)0) PatternEquation::release(pateq); if (templ != (ConstructTpl *)0) delete templ; for(int4 i=0;i::iterator iter; for(iter=context.begin();iter!=context.end();++iter) delete *iter; } void Constructor::addInvisibleOperand(OperandSymbol *sym) { operands.push_back(sym); } void Constructor::addOperand(OperandSymbol *sym) { string operstring = "\n "; // Indicater character for operand operstring[1] = ('A'+operands.size()); // Encode index of operand operands.push_back(sym); printpiece.push_back(operstring); // Placeholder for operand's string } void Constructor::addSyntax(const string &syn) { string syntrim; if (syn.size() == 0) return; bool hasNonSpace = false; for(int4 i=0;ilayClaim(); } void Constructor::setNamedSection(ConstructTpl *tpl,int4 id) { // Add a named section to the constructor while(namedtempl.size() <= id) namedtempl.push_back((ConstructTpl *)0); namedtempl[id] = tpl; } ConstructTpl *Constructor::getNamedTempl(int4 secnum) const { if (secnum < namedtempl.size()) return namedtempl[secnum]; return (ConstructTpl *)0; } void Constructor::print(ostream &s,ParserWalker &walker) const { vector::const_iterator piter; for(piter=printpiece.begin();piter!=printpiece.end();++piter) { if ((*piter)[0] == '\n') { int4 index = (*piter)[1]-'A'; operands[index]->print(s,walker); } else s << *piter; } } void Constructor::printMnemonic(ostream &s,ParserWalker &walker) const { if (flowthruindex != -1) { SubtableSymbol *sym = dynamic_cast(operands[flowthruindex]->getDefiningSymbol()); if (sym != (SubtableSymbol *)0) { walker.pushOperand(flowthruindex); walker.getConstructor()->printMnemonic(s,walker); walker.popOperand(); return; } } int4 endind = (firstwhitespace==-1) ? printpiece.size() : firstwhitespace; for(int4 i=0;iprint(s,walker); } else s << printpiece[i]; } } void Constructor::printBody(ostream &s,ParserWalker &walker) const { if (flowthruindex != -1) { SubtableSymbol *sym = dynamic_cast(operands[flowthruindex]->getDefiningSymbol()); if (sym != (SubtableSymbol *)0) { walker.pushOperand(flowthruindex); walker.getConstructor()->printBody(s,walker); walker.popOperand(); return; } } if (firstwhitespace == -1) return; // Nothing to print after firstwhitespace for(int4 i=firstwhitespace+1;iprint(s,walker); } else s << printpiece[i]; } } void Constructor::removeTrailingSpace(void) { // Allow for user to force extra space at end of printing if ((!printpiece.empty())&&(printpiece.back()==" ")) printpiece.pop_back(); // while((!printpiece.empty())&&(printpiece.back()==" ")) // printpiece.pop_back(); } void Constructor::markSubtableOperands(vector &check) const { // Adjust -check- so it has one entry for every operand, a 0 if it is a subtable, a 2 if it is not check.resize(operands.size()); for(int4 i=0;igetDefiningSymbol(); if ((sym != (TripleSymbol *)0)&&(sym->getType() == SleighSymbol::subtable_symbol)) check[i] = 0; else check[i] = 2; } } void Constructor::collectLocalExports(vector &results) const { if (templ == (ConstructTpl *)0) return; HandleTpl *handle = templ->getResult(); if (handle == (HandleTpl *)0) return; if (handle->getSpace().isConstSpace()) return; // Even if the value is dynamic, the pointed to value won't get used if (handle->getPtrSpace().getType() != ConstTpl::real) { if (handle->getTempSpace().isUniqueSpace()) results.push_back(handle->getTempOffset().getReal()); return; } if (handle->getSpace().isUniqueSpace()) { results.push_back(handle->getPtrOffset().getReal()); return; } if (handle->getSpace().getType() == ConstTpl::handle) { int4 handleIndex = handle->getSpace().getHandleIndex(); OperandSymbol *opSym = getOperand(handleIndex); opSym->collectLocalValues(results); } } bool Constructor::isRecursive(void) const { // Does this constructor cause recursion with its table for(int4 i=0;igetDefiningSymbol(); if (sym == parent) return true; } return false; } void Constructor::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_CONSTRUCTOR); encoder.writeUnsignedInteger(sla::ATTRIB_PARENT, parent->getId()); encoder.writeSignedInteger(sla::ATTRIB_FIRST, firstwhitespace); encoder.writeSignedInteger(sla::ATTRIB_LENGTH, minimumlength); encoder.writeSignedInteger(sla::ATTRIB_SOURCE, src_index); encoder.writeSignedInteger(sla::ATTRIB_LINE, lineno); for(int4 i=0;igetId()); encoder.closeElement(sla::ELEM_OPER); } for(int4 i=0;iencode(encoder); if (templ != (ConstructTpl *)0) templ->encode(encoder,-1); for(int4 i=0;iencode(encoder,i); } encoder.closeElement(sla::ELEM_CONSTRUCTOR); } void Constructor::decode(Decoder &decoder,SleighBase *trans) { uint4 el = decoder.openElement(sla::ELEM_CONSTRUCTOR); uintm id = decoder.readUnsignedInteger(sla::ATTRIB_PARENT); parent = (SubtableSymbol *)trans->findSymbol(id); firstwhitespace = decoder.readSignedInteger(sla::ATTRIB_FIRST); minimumlength = decoder.readSignedInteger(sla::ATTRIB_LENGTH); src_index = decoder.readSignedInteger(sla::ATTRIB_SOURCE); lineno = decoder.readSignedInteger(sla::ATTRIB_LINE); uint4 subel = decoder.peekElement(); while(subel != 0) { if (subel == sla::ELEM_OPER) { decoder.openElement(); uintm id = decoder.readUnsignedInteger(sla::ATTRIB_ID); OperandSymbol *sym = (OperandSymbol *)trans->findSymbol(id); operands.push_back(sym); decoder.closeElement(subel); } else if (subel == sla::ELEM_PRINT) { decoder.openElement(); printpiece.push_back( decoder.readString(sla::ATTRIB_PIECE)); decoder.closeElement(subel); } else if (subel == sla::ELEM_OPPRINT) { decoder.openElement(); int4 index = decoder.readSignedInteger(sla::ATTRIB_ID); string operstring = "\n "; operstring[1] = ('A' + index); printpiece.push_back(operstring); decoder.closeElement(subel); } else if (subel == sla::ELEM_CONTEXT_OP) { ContextOp *c_op = new ContextOp(); c_op->decode(decoder,trans); context.push_back(c_op); } else if (subel == sla::ELEM_COMMIT) { ContextCommit *c_op = new ContextCommit(); c_op->decode(decoder,trans); context.push_back(c_op); } else { ConstructTpl *cur = new ConstructTpl(); int4 sectionid = cur->decode(decoder); if (sectionid < 0) { if (templ != (ConstructTpl *)0) throw LowlevelError("Duplicate main section"); templ = cur; } else { while(namedtempl.size() <= sectionid) namedtempl.push_back((ConstructTpl *)0); if (namedtempl[sectionid] != (ConstructTpl *)0) throw LowlevelError("Duplicate named section"); namedtempl[sectionid] = cur; } } subel = decoder.peekElement(); } pattern = (TokenPattern *)0; if ((printpiece.size()==1)&&(printpiece[0][0]=='\n')) flowthruindex = printpiece[0][1] - 'A'; else flowthruindex = -1; decoder.closeElement(el); } void Constructor::orderOperands(void) { OperandSymbol *sym; vector patternorder; vector newops; // New order of the operands int4 lastsize; pateq->operandOrder(this,patternorder); for(int4 i=0;iisMarked()) { patternorder.push_back(sym); sym->setMark(); // Make sure all operands are marked } } do { lastsize = newops.size(); for(int4 i=0;iisMarked()) continue; // "unmarked" means it is already in newops if (sym->isOffsetIrrelevant()) continue; // expression Operands come last if ((sym->offsetbase == -1)||(!operands[sym->offsetbase]->isMarked())) { newops.push_back(sym); sym->clearMark(); } } } while(newops.size() != lastsize); for(int4 i=0;iisOffsetIrrelevant()) { newops.push_back(sym); sym->clearMark(); } } if (newops.size() != operands.size()) throw SleighError("Circular offset dependency between operands"); for(int4 i=0;ihand = i; newops[i]->localexp->changeIndex(i); } vector handmap; // Create index translation map for(int4 i=0;ihand); // Fix up offsetbase for(int4 i=0;ioffsetbase == -1) continue; sym->offsetbase = handmap[sym->offsetbase]; } if (templ != (ConstructTpl *)0) // Fix up templates templ->changeHandleIndex(handmap); for(int4 i=0;ichangeHandleIndex(handmap); } // Fix up printpiece operand refs for(int4 i=0;i oppattern; bool recursion = false; // Generate pattern for each operand, store in oppattern for(int4 i=0;igetDefiningSymbol(); PatternExpression *defexp = sym->getDefiningExpression(); if (triple != (TripleSymbol *)0) { SubtableSymbol *subsym = dynamic_cast(triple); if (subsym != (SubtableSymbol *)0) { if (subsym->isBeingBuilt()) { // Detected recursion if (recursion) { throw SleighError("Illegal recursion"); } // We should also check that recursion is rightmost extreme recursion = true; oppattern.emplace_back(); } else oppattern.push_back(*subsym->buildPattern(s)); } else oppattern.push_back(triple->getPatternExpression()->genMinPattern(oppattern)); } else if (defexp != (PatternExpression *)0) oppattern.push_back(defexp->genMinPattern(oppattern)); else { throw SleighError(sym->getName()+": operand is undefined"); } TokenPattern &sympat( oppattern.back() ); sym->minimumlength = sympat.getMinimumLength(); if (sympat.getLeftEllipsis() || sympat.getRightEllipsis()) sym->setVariableLength(); } if (pateq == (PatternEquation *)0) throw SleighError("Missing equation"); // Build the entire pattern pateq->genPattern(oppattern); *pattern = pateq->getTokenPattern(); if (pattern->alwaysFalse()) throw SleighError("Impossible pattern"); if (recursion) pattern->setRightEllipsis(true); minimumlength = pattern->getMinimumLength(); // Get length of the pattern in bytes // Resolve offsets of the operands OperandResolve resolve(operands); if (!pateq->resolveOperandLeft(resolve)) throw SleighError("Unable to resolve operand offsets"); for(int4 i=0;iisOffsetIrrelevant()) { sym->offsetbase = -1; sym->reloffset = 0; continue; } base = sym->offsetbase; offset = sym->reloffset; while(base >= 0) { sym = operands[base]; if (sym->isVariableLength()) break; // Cannot resolve to absolute base = sym->offsetbase; offset += sym->getMinimumLength(); offset += sym->reloffset; if (base < 0) { operands[i]->offsetbase = base; operands[i]->reloffset = offset; } } } // Make sure context expressions are valid for(int4 i=0;ivalidate(); orderOperands(); // Order the operands based on offset dependency return pattern; } void Constructor::printInfo(ostream &s) const { // Print identifying information about constructor // for use in error messages s << "table \"" << parent->getName(); s << "\" constructor starting at line " << dec << lineno; } SubtableSymbol::SubtableSymbol(const string &nm) : TripleSymbol(nm) { beingbuilt = false; pattern = (TokenPattern *)0; decisiontree = (DecisionNode *)0; errors = 0; } SubtableSymbol::~SubtableSymbol(void) { if (pattern != (TokenPattern *)0) delete pattern; if (decisiontree != (DecisionNode *)0) delete decisiontree; vector::iterator iter; for(iter=construct.begin();iter!=construct.end();++iter) delete *iter; } void SubtableSymbol::collectLocalValues(vector &results) const { for(int4 i=0;icollectLocalExports(results); } void SubtableSymbol::encode(Encoder &encoder) const { if (decisiontree == (DecisionNode *)0) return; // Not fully formed encoder.openElement(sla::ELEM_SUBTABLE_SYM); encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); encoder.writeSignedInteger(sla::ATTRIB_NUMCT, construct.size()); for(int4 i=0;iencode(encoder); decisiontree->encode(encoder); encoder.closeElement(sla::ELEM_SUBTABLE_SYM); } void SubtableSymbol::encodeHeader(Encoder &encoder) const { encoder.openElement(sla::ELEM_SUBTABLE_SYM_HEAD); SleighSymbol::encodeHeader(encoder); encoder.closeElement(sla::ELEM_SUBTABLE_SYM_HEAD); } void SubtableSymbol::decode(Decoder &decoder,SleighBase *trans) { int4 numct = decoder.readSignedInteger(sla::ATTRIB_NUMCT); construct.reserve(numct); uint4 subel = decoder.peekElement(); while(subel != 0) { if (subel == sla::ELEM_CONSTRUCTOR) { Constructor *ct = new Constructor(); addConstructor(ct); ct->decode(decoder,trans); } else if (subel == sla::ELEM_DECISION) { decisiontree = new DecisionNode(); decisiontree->decode(decoder,(DecisionNode *)0,this); } subel = decoder.peekElement(); } pattern = (TokenPattern *)0; beingbuilt = false; errors = 0; decoder.closeElement(sla::ELEM_SUBTABLE_SYM.getId()); } void SubtableSymbol::buildDecisionTree(DecisionProperties &props) { // Associate pattern disjoints to constructors if (pattern == (TokenPattern *)0) return; // Pattern not fully formed Pattern *pat; decisiontree = new DecisionNode((DecisionNode *)0); for(int4 i=0;igetPattern()->getPattern(); if (pat->numDisjoint() == 0) decisiontree->addConstructorPair((const DisjointPattern *)pat,construct[i]); else for(int4 j=0;jnumDisjoint();++j) decisiontree->addConstructorPair(pat->getDisjoint(j),construct[i]); } decisiontree->split(props); // Create the decision strategy } TokenPattern *SubtableSymbol::buildPattern(ostream &s) { if (pattern != (TokenPattern *)0) return pattern; // Already built errors = false; beingbuilt = true; pattern = new TokenPattern(); if (construct.empty()) { s << "Error: There are no constructors in table: "+getName() << endl; errors = true; return pattern; } try { construct.front()->buildPattern(s); } catch(SleighError &err) { s << "Error: " << err.explain << ": for "; construct.front()->printInfo(s); s << endl; errors = true; } *pattern = *construct.front()->getPattern(); for(int4 i=1;ibuildPattern(s); } catch(SleighError &err) { s << "Error: " << err.explain << ": for "; construct[i]->printInfo(s); s << endl; errors = true; } *pattern = construct[i]->getPattern()->commonSubPattern(*pattern); } beingbuilt = false; return pattern; } void DecisionProperties::identicalPattern(Constructor *a,Constructor *b) { // Note that -a- and -b- have identical patterns if ((!a->isError())&&(!b->isError())) { a->setError(true); b->setError(true); identerrors.push_back(make_pair(a, b)); } } void DecisionProperties::conflictingPattern(Constructor *a,Constructor *b) { // Note that -a- and -b- have (potentially) conflicting patterns if ((!a->isError())&&(!b->isError())) { a->setError(true); b->setError(true); conflicterrors.push_back(make_pair(a, b)); } } DecisionNode::DecisionNode(DecisionNode *p) { parent = p; num = 0; startbit = 0; bitsize = 0; contextdecision = false; } DecisionNode::~DecisionNode(void) { // We own sub nodes vector::iterator iter; for(iter=children.begin();iter!=children.end();++iter) delete *iter; vector >::iterator piter; for(piter=list.begin();piter!=list.end();++piter) delete (*piter).first; // Delete the patterns } void DecisionNode::addConstructorPair(const DisjointPattern *pat,Constructor *ct) { DisjointPattern *clone = (DisjointPattern *)pat->simplifyClone(); // We need to own pattern list.push_back(pair(clone,ct)); num += 1; } int4 DecisionNode::getMaximumLength(bool context) { // Get maximum length of instruction pattern in bytes int4 max = 0; int4 val,i; for(i=0;igetLength(context); if (val > max) max = val; } return max; } int4 DecisionNode::getNumFixed(int4 low,int4 size,bool context) { // Get number of patterns that specify this field int4 count = 0; uintm mask; // Bits which must be specified in the mask uintm m = (size==8*sizeof(uintm)) ? 0 : (((uintm)1)<getMask(low,size,context); if ((mask&m)==m) count += 1; } return count; } double DecisionNode::getScore(int4 low,int4 size,bool context) { int4 numBins = 1 << size; // size is between 1 and 8 int4 i; uintm val,mask; uintm m = ((uintm)1)< count(numBins,0); for(i=0;igetMask(low,size,context); if ((mask&m)!=m) continue; // Skip if field not fully specified val = list[i].first->getValue(low,size,context); total += 1; count[val] += 1; } if (total <= 0) return -1.0; double sc = 0.0; for(i=0;i= list.size()) return -1.0; double p = ((double)count[i])/total; sc -= p * log(p); } return ( sc / log(2.0) ); } void DecisionNode::chooseOptimalField(void) { double score = 0.0; int4 sbit,size; // The current field bool context; double sc; int4 maxlength,numfixed,maxfixed; maxfixed = 1; context = true; do { maxlength = 8*getMaximumLength(context); for(sbit=0;sbit maxfixed)&&(sc > 0.0)) { score = sc; maxfixed = numfixed; startbit = sbit; bitsize = 1; contextdecision = context; continue; } // We have maximum patterns if (sc > score) { score = sc; startbit = sbit; bitsize = 1; contextdecision = context; } } context = !context; } while(!context); context = true; do { maxlength = 8*getMaximumLength(context); for(size=2;size <= 8;++size) { for(sbit=0;sbit score) { score = sc; startbit = sbit; bitsize = size; contextdecision = context; } } } context = !context; } while(!context); if (score <= 0.0) // If we failed to get a positive score bitsize = 0; // treat the node as terminal } void DecisionNode::consistentValues(vector &bins,DisjointPattern *pat) { // Produce all possible values of -pat- by // iterating through all possible values of the // "don't care" bits within the value of -pat- // that intersects with this node (startbit,bitsize,context) uintm m = (bitsize==8*sizeof(uintm)) ? 0 : (((uintm)1)<getMask(startbit,bitsize,contextdecision); uintm commonValue = commonMask & pat->getValue(startbit,bitsize,contextdecision); uintm dontCareMask = m^commonMask; for(uintm i=0;i<=dontCareMask;++i) { // Iterate over values that contain all don't care bits if ((i&dontCareMask)!=i) continue; // If all 1 bits in the value are don't cares bins.push_back( commonValue | i ); // add 1 bits into full value and store } } void DecisionNode::split(DecisionProperties &props) { if (list.size() <= 1) { bitsize = 0; // Only one pattern, terminal node by default return; } chooseOptimalField(); if (bitsize == 0) { orderPatterns(props); return; } if ((parent != (DecisionNode *)0) && (list.size() >= parent->num)) throw LowlevelError("Child has as many Patterns as parent"); int4 numChildren = 1 << bitsize; for(int4 i=0;i vals; // Bins this pattern belongs in // If the pattern does not care about some // bits in the field we are splitting on, that // pattern will get put into multiple bins consistentValues(vals,list[i].first); for(int4 j=0;jaddConstructorPair(list[i].first,list[i].second); delete list[i].first; // We no longer need original pattern } list.clear(); for(int4 i=0;isplit(props); } void DecisionNode::orderPatterns(DecisionProperties &props) { // This is a tricky routine. When this routine is called, the patterns remaining in the // the decision node can no longer be distinguished by examining additional bits. The basic // idea here is that the patterns should be ordered so that the most specialized should come // first in the list. Pattern 1 is a specialization of pattern 2, if the set of instructions // matching 1 is contained in the set matching 2. So in the simplest case, the pattern order // should represent a strict nesting. Unfortunately, there are many potential situations where // patterns don't necessarily nest. // 1) An "or" of two patterns. This can be an explicit '|' operator in the Constructor, in // which case this can be detected because the two patterns point to the same constructor // But the "or" can be implied across two constructors that do the same thing. This should // probably be flagged as an error except in the following case. // 2) Two patterns aren't properly nested, but they are "resolved" by a third pattern which // covers the intersection of the first two patterns. Sometimes its easier to specify // three cases that need to be distinguished in this way. // 3) Recursive constructors that use a "guard" context bit. The guard bit is used to prevent // the recursive constructor from matching repeatedly, but it's too much work to put a // constraint an the bit for every other pattern. // 4) Other situations where the ability to distinguish between constructors is hidden in // the subconstructors. // This routine can determine if an intersection results from case 1) or case 2) int4 i,j,k; vector > newlist; vector > conflictlist; // Check for identical patterns for(i=0;iidentical(jpat)) props.identicalPattern(list[i].second,list[j].second); } } newlist = list; for(i=0;ispecializes(jpat)) break; if (!jpat->specializes(ipat)) { // We have a potential conflict Constructor *iconst = newlist[i].second; Constructor *jconst = list[j].second; if (iconst == jconst) { // This is an OR in the pattern for ONE constructor // So there is no conflict } else { // A true conflict that needs to be resolved conflictlist.push_back(pair(ipat,iconst)); conflictlist.push_back(pair(jpat,jconst)); } } } for(k=i-1;k>=j;--k) list[k+1] = list[k]; list[j] = newlist[i]; } // Check if intersection patterns are present, which resolve conflicts for(i=0;iresolvesIntersect(pat1,pat2)) { resolved = true; break; } } if (!resolved) props.conflictingPattern(const1,const2); } } Constructor *DecisionNode::resolve(ParserWalker &walker) const { if (bitsize == 0) { // The node is terminal vector >::const_iterator iter; for(iter=list.begin();iter!=list.end();++iter) if ((*iter).first->isMatch(walker)) return (*iter).second; ostringstream s; s << walker.getAddr().getShortcut(); walker.getAddr().printRaw(s); s << ": Unable to resolve constructor"; throw BadDataError(s.str()); } uintm val; if (contextdecision) val = walker.getContextBits(startbit,bitsize); else val = walker.getInstructionBits(startbit,bitsize); return children[val]->resolve(walker); } void DecisionNode::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_DECISION); encoder.writeSignedInteger(sla::ATTRIB_NUMBER, num); encoder.writeBool(sla::ATTRIB_CONTEXT, contextdecision); encoder.writeSignedInteger(sla::ATTRIB_STARTBIT, startbit); encoder.writeSignedInteger(sla::ATTRIB_SIZE, bitsize); for(int4 i=0;igetId()); list[i].first->encode(encoder); encoder.closeElement(sla::ELEM_PAIR); } for(int4 i=0;iencode(encoder); encoder.closeElement(sla::ELEM_DECISION); } void DecisionNode::decode(Decoder &decoder,DecisionNode *par,SubtableSymbol *sub) { uint4 el = decoder.openElement(sla::ELEM_DECISION); parent = par; num = decoder.readSignedInteger(sla::ATTRIB_NUMBER); contextdecision = decoder.readBool(sla::ATTRIB_CONTEXT); startbit = decoder.readSignedInteger(sla::ATTRIB_STARTBIT); bitsize = decoder.readSignedInteger(sla::ATTRIB_SIZE); uint4 subel = decoder.peekElement(); while(subel != 0) { if (subel == sla::ELEM_PAIR) { decoder.openElement(); uintm id = decoder.readSignedInteger(sla::ATTRIB_ID); Constructor *ct = sub->getConstructor(id); DisjointPattern *pat = DisjointPattern::decodeDisjoint(decoder); list.push_back(pair(pat,ct)); decoder.closeElement(subel); } else if (subel == sla::ELEM_DECISION) { DecisionNode *subnode = new DecisionNode(); subnode->decode(decoder,this,sub); children.push_back(subnode); } subel = decoder.peekElement(); } decoder.closeElement(el); } static void calc_maskword(int4 sbit,int4 ebit,int4 &num,int4 &shift,uintm &mask) { num = sbit/(8*sizeof(uintm)); if ( num != ebit/(8*sizeof(uintm))) throw SleighError("Context field not contained within one machine int"); sbit -= num*8*sizeof(uintm); ebit -= num*8*sizeof(uintm); shift = 8*sizeof(uintm)-ebit-1; mask = (~((uintm)0))>>(sbit+shift); mask <<= shift; } ContextOp::ContextOp(int4 startbit,int4 endbit,PatternExpression *pe) { calc_maskword(startbit,endbit,num,shift,mask); patexp = pe; patexp->layClaim(); } void ContextOp::apply(ParserWalkerChange &walker) const { uintm val = patexp->getValue(walker); // Get our value based on context val <<= shift; walker.getParserContext()->setContextWord(num,val,mask); } void ContextOp::validate(void) const { // Throw an exception if the PatternExpression is not valid vector values; patexp->listValues(values); // Get all the expression tokens for(int4 i=0;i(values[i]); if (val == (const OperandValue *)0) continue; // Certain operands cannot be used in context expressions // because these are evaluated BEFORE the operand offset // has been recovered. If the offset is not relative to // the base constructor, then we throw an error if (!val->isConstructorRelative()) throw SleighError(val->getName()+": cannot be used in context expression"); } } void ContextOp::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_CONTEXT_OP); encoder.writeSignedInteger(sla::ATTRIB_I, num); encoder.writeSignedInteger(sla::ATTRIB_SHIFT, shift); encoder.writeUnsignedInteger(sla::ATTRIB_MASK, mask); patexp->encode(encoder); encoder.closeElement(sla::ELEM_CONTEXT_OP); } void ContextOp::decode(Decoder &decoder,SleighBase *trans) { uint4 el = decoder.openElement(sla::ELEM_CONTEXT_OP); num = decoder.readSignedInteger(sla::ATTRIB_I); shift = decoder.readSignedInteger(sla::ATTRIB_SHIFT); mask = decoder.readUnsignedInteger(sla::ATTRIB_MASK); patexp = PatternExpression::decodeExpression(decoder,trans); patexp->layClaim(); decoder.closeElement(el); } ContextChange *ContextOp::clone(void) const { ContextOp *res = new ContextOp(); (res->patexp = patexp)->layClaim(); res->mask = mask; res->num = num; res->shift = shift; return res; } ContextCommit::ContextCommit(TripleSymbol *s,int4 sbit,int4 ebit,bool fl) { sym = s; flow = fl; int4 shift; calc_maskword(sbit,ebit,num,shift,mask); } void ContextCommit::apply(ParserWalkerChange &walker) const { walker.getParserContext()->addCommit(sym,num,mask,flow,walker.getPoint()); } void ContextCommit::encode(Encoder &encoder) const { encoder.openElement(sla::ELEM_COMMIT); encoder.writeUnsignedInteger(sla::ATTRIB_ID, sym->getId()); encoder.writeSignedInteger(sla::ATTRIB_NUMBER, num); encoder.writeUnsignedInteger(sla::ATTRIB_MASK, mask); encoder.writeBool(sla::ATTRIB_FLOW, flow); encoder.closeElement(sla::ELEM_COMMIT); } void ContextCommit::decode(Decoder &decoder,SleighBase *trans) { uint4 el = decoder.openElement(sla::ELEM_COMMIT); uintm id = decoder.readUnsignedInteger(sla::ATTRIB_ID); sym = (TripleSymbol *)trans->findSymbol(id); num = decoder.readSignedInteger(sla::ATTRIB_NUMBER); mask = decoder.readUnsignedInteger(sla::ATTRIB_MASK); flow = decoder.readBool(sla::ATTRIB_FLOW); decoder.closeElement(el); } ContextChange *ContextCommit::clone(void) const { ContextCommit *res = new ContextCommit(); res->sym = sym; res->flow = flow; res->mask = mask; res->num = num; return res; } } // End namespace ghidra