/* ### * 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 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::saveXml(ostream &s) const { s << "\n"; for(int4 i=0;igetId() << "\""; s << " parent=\"0x"; if (table[i]->getParent() == (SymbolScope *)0) s << "0"; else s << hex << table[i]->getParent()->getId(); s << "\"/>\n"; } // First save the headers for(int4 i=0;isaveXmlHeader(s); // Now save the content of each symbol for(int4 i=0;isaveXml(s); s << "\n"; } void SymbolTable::restoreXml(const Element *el,SleighBase *trans) { { uint4 size; istringstream s(el->getAttributeValue("scopesize")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> size; table.resize(size,(SymbolScope *)0); } { uint4 size; istringstream s(el->getAttributeValue("symbolsize")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> size; symbollist.resize(size,(SleighSymbol *)0); } const List &list(el->getChildren()); List::const_iterator iter; iter = list.begin(); for(int4 i=0;igetName() != "scope") throw SleighError("Misnumbered symbol scopes"); uintm id; uintm parent; { istringstream s(subel->getAttributeValue("id")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> id; } { istringstream s(subel->getAttributeValue("parent")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> parent; } SymbolScope *parscope = (parent==id) ? (SymbolScope *)0 : table[parent]; table[id] = new SymbolScope( parscope, id ); ++iter; } curscope = table[0]; // Current scope is global // Now restore the symbol shells for(int4 i=0;igetAttributeValue("id")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> id; } sym = findSymbol(id); sym->restoreXml(subel,trans); ++iter; } } void SymbolTable::restoreSymbolHeader(const Element *el) { // Put the shell of a symbol in the symbol table // in order to allow recursion SleighSymbol *sym; if (el->getName() == "userop_head") sym = new UserOpSymbol(); else if (el->getName() == "epsilon_sym_head") sym = new EpsilonSymbol(); else if (el->getName() == "value_sym_head") sym = new ValueSymbol(); else if (el->getName() == "valuemap_sym_head") sym = new ValueMapSymbol(); else if (el->getName() == "name_sym_head") sym = new NameSymbol(); else if (el->getName() == "varnode_sym_head") sym = new VarnodeSymbol(); else if (el->getName() == "context_sym_head") sym = new ContextSymbol(); else if (el->getName() == "varlist_sym_head") sym = new VarnodeListSymbol(); else if (el->getName() == "operand_sym_head") sym = new OperandSymbol(); else if (el->getName() == "start_sym_head") sym = new StartSymbol(); else if (el->getName() == "end_sym_head") sym = new EndSymbol(); else if (el->getName() == "subtable_sym_head") sym = new SubtableSymbol(); else if (el->getName() == "flowdest_sym_head") sym = new FlowDestSymbol(); else if (el->getName() == "flowref_sym_head") sym = new FlowRefSymbol(); else throw SleighError("Bad symbol xml"); sym->restoreXmlHeader(el); // 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: 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::saveXmlHeader(ostream &s) const { // Save the basic attributes of a symbol s << " name=\"" << name << "\""; s << " id=\"0x" << hex << id << "\""; s << " scope=\"0x" << scopeid << "\""; } void SleighSymbol::restoreXmlHeader(const Element *el) { name = el->getAttributeValue("name"); { istringstream s(el->getAttributeValue("id")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> id; } { istringstream s(el->getAttributeValue("scope")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> scopeid; } } void UserOpSymbol::saveXml(ostream &s) const { s << "\n"; } void UserOpSymbol::saveXmlHeader(ostream &s) const { s << "\n"; } void UserOpSymbol::restoreXml(const Element *el,SleighBase *trans) { istringstream s(el->getAttributeValue("index")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> index; } PatternlessSymbol::PatternlessSymbol(void) { // The void constructor must explicitly build // the ConstantValue because it is not stored // or restored via xml 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::saveXml(ostream &s) const { s << "\n"; } void EpsilonSymbol::saveXmlHeader(ostream &s) const { s << "\n"; } void EpsilonSymbol::restoreXml(const Element *el,SleighBase *trans) { const_space = trans->getConstantSpace(); } 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::saveXml(ostream &s) const { s << "\n"; patval->saveXml(s); s << "\n"; } void ValueSymbol::saveXmlHeader(ostream &s) const { s << "\n"; } void ValueSymbol::restoreXml(const Element *el,SleighBase *trans) { const List &list(el->getChildren()); List::const_iterator iter; iter = list.begin(); patval = (PatternValue *) PatternExpression::restoreExpression(*iter,trans); patval->layClaim(); } 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::saveXml(ostream &s) const { s << "\n"; patval->saveXml(s); for(uint4 i=0;i\n"; s << "\n"; } void ValueMapSymbol::saveXmlHeader(ostream &s) const { s << "\n"; } void ValueMapSymbol::restoreXml(const Element *el,SleighBase *trans) { const List &list(el->getChildren()); List::const_iterator iter; iter = list.begin(); patval = (PatternValue *) PatternExpression::restoreExpression(*iter,trans); patval->layClaim(); ++iter; while(iter != list.end()) { istringstream s((*iter)->getAttributeValue("val")); s.unsetf(ios::dec | ios::hex | ios::oct); intb val; s >> val; valuetable.push_back(val); ++iter; } 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::saveXml(ostream &s) const { s << "\n"; patval->saveXml(s); for(int4 i=0;i\n"; // Emit tag with no name attribute else s << "\n"; } s << "\n"; } void NameSymbol::saveXmlHeader(ostream &s) const { s << "\n"; } void NameSymbol::restoreXml(const Element *el,SleighBase *trans) { const List &list(el->getChildren()); List::const_iterator iter; iter = list.begin(); patval = (PatternValue *) PatternExpression::restoreExpression(*iter,trans); patval->layClaim(); ++iter; while(iter != list.end()) { const Element *subel = *iter; if (subel->getNumAttributes() >= 1) nametable.push_back(subel->getAttributeValue("name")); else nametable.push_back("\t"); // TAB indicates an illegal index ++iter; } 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::saveXml(ostream &s) const { s << "getName() << "\""; s << " offset=\"0x" << hex << fix.offset << "\""; s << " size=\"" << dec << fix.size << "\""; s << ">\n"; PatternlessSymbol::saveXml(s); s << "\n"; } void VarnodeSymbol::saveXmlHeader(ostream &s) const { s << "\n"; } void VarnodeSymbol::restoreXml(const Element *el,SleighBase *trans) { fix.space = trans->getSpaceByName(el->getAttributeValue("space")); { istringstream s(el->getAttributeValue("offset")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> fix.offset; } { istringstream s(el->getAttributeValue("size")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> fix.size; } // PatternlessSymbol does not need restoring } 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::saveXml(ostream &s) const { s << "getId() << "\""; s << " low=\"" << dec << low << "\""; s << " high=\"" << high << "\""; a_v_b(s,"flow",flow); s << ">\n"; patval->saveXml(s); s << "\n"; } void ContextSymbol::saveXmlHeader(ostream &s) const { s << "\n"; } void ContextSymbol::restoreXml(const Element *el,SleighBase *trans) { ValueSymbol::restoreXml(el,trans); { uintm id; istringstream s(el->getAttributeValue("varnode")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> id; vn = (VarnodeSymbol *)trans->findSymbol(id); } { istringstream s(el->getAttributeValue("low")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> low; } { istringstream s(el->getAttributeValue("high")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> high; } flow = true; for(int4 i=el->getNumAttributes()-1;i>=0;--i) { if (el->getAttributeName(i)=="flow") { flow = xml_readbool(el->getAttributeValue(i)); break; } } } 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::saveXml(ostream &s) const { s << "\n"; patval->saveXml(s); for(int4 i=0;i\n"; else s << "getId() << "\"/>\n"; } s << "\n"; } void VarnodeListSymbol::saveXmlHeader(ostream &s) const { s << "\n"; } void VarnodeListSymbol::restoreXml(const Element *el,SleighBase *trans) { const List &list(el->getChildren()); List::const_iterator iter; iter = list.begin(); patval = (PatternValue *) PatternExpression::restoreExpression(*iter,trans); patval->layClaim(); ++iter; while(iter!=list.end()) { const Element *subel = *iter; if (subel->getName() == "var") { uintm id; istringstream s(subel->getAttributeValue("id")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> id; varnode_table.push_back( (VarnodeSymbol *)trans->findSymbol(id) ); } else varnode_table.push_back( (VarnodeSymbol *)0 ); ++iter; } 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::saveXml(ostream &s) const { s << "getId() << "\""; s << " off=\"" << dec << reloffset << "\""; s << " base=\"" << offsetbase << "\""; s << " minlen=\"" << minimumlength << "\""; if (isCodeAddress()) s << " code=\"true\""; s << " index=\"" << dec << hand << "\">\n"; localexp->saveXml(s); if (defexp != (PatternExpression *)0) defexp->saveXml(s); s << "\n"; } void OperandSymbol::saveXmlHeader(ostream &s) const { s << "\n"; } void OperandSymbol::restoreXml(const Element *el,SleighBase *trans) { defexp = (PatternExpression *)0; triple = (TripleSymbol *)0; flags = 0; { istringstream s(el->getAttributeValue("index")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> hand; } { istringstream s(el->getAttributeValue("off")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> reloffset; } { istringstream s(el->getAttributeValue("base")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> offsetbase; } { istringstream s(el->getAttributeValue("minlen")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> minimumlength; } for(int4 i=0;igetNumAttributes();++i) { if (el->getAttributeName(i) == "subsym") { uintm id; istringstream s(el->getAttributeValue(i)); s.unsetf(ios::dec | ios::hex | ios::oct); s >> id; triple = (TripleSymbol *)trans->findSymbol(id); } else if (el->getAttributeName(i) == "code") { if (xml_readbool(el->getAttributeValue(i))) flags |= code_address; } } const List &list(el->getChildren()); List::const_iterator iter; iter = list.begin(); localexp = (OperandValue *)PatternExpression::restoreExpression(*iter,trans); localexp->layClaim(); ++iter; if (iter != list.end()) { defexp = PatternExpression::restoreExpression(*iter,trans); defexp->layClaim(); } } 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::saveXml(ostream &s) const { s << "\n"; } void StartSymbol::saveXmlHeader(ostream &s) const { s << "\n"; } void StartSymbol::restoreXml(const Element *el,SleighBase *trans) { const_space = trans->getConstantSpace(); patexp = new StartInstructionValue(); patexp->layClaim(); } 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::saveXml(ostream &s) const { s << "\n"; } void EndSymbol::saveXmlHeader(ostream &s) const { s << "\n"; } void EndSymbol::restoreXml(const Element *el,SleighBase *trans) { const_space = trans->getConstantSpace(); patexp = new EndInstructionValue(); patexp->layClaim(); } 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; } void FlowDestSymbol::saveXml(ostream &s) const { s << "\n"; } void FlowDestSymbol::saveXmlHeader(ostream &s) const { s << "\n"; } void FlowDestSymbol::restoreXml(const Element *el,SleighBase *trans) { const_space = trans->getConstantSpace(); } 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; } void FlowRefSymbol::saveXml(ostream &s) const { s << "\n"; } void FlowRefSymbol::saveXmlHeader(ostream &s) const { s << "\n"; } void FlowRefSymbol::restoreXml(const Element *el,SleighBase *trans) { const_space = trans->getConstantSpace(); } 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::saveXml(ostream &s) const { s << "getId() << "\""; s << " first=\"" << dec << firstwhitespace << "\""; s << " length=\"" << minimumlength << "\""; s << " line=\"" << src_index << ":" << lineno << "\">\n"; for(int4 i=0;igetId() << "\"/>\n"; for(int4 i=0;i\n"; } else { s << "\n"; } } for(int4 i=0;isaveXml(s); if (templ != (ConstructTpl *)0) templ->saveXml(s,-1); for(int4 i=0;isaveXml(s,i); } s << "\n"; } void Constructor::restoreXml(const Element *el,SleighBase *trans) { uintm id; { istringstream s(el->getAttributeValue("parent")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> id; parent = (SubtableSymbol *)trans->findSymbol(id); } { istringstream s(el->getAttributeValue("first")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> firstwhitespace; } { istringstream s(el->getAttributeValue("length")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> minimumlength; } { string src_and_line = el->getAttributeValue("line"); size_t pos = src_and_line.find(":"); src_index = stoi(src_and_line.substr(0, pos),NULL,10); lineno = stoi(src_and_line.substr(pos+1,src_and_line.length()),NULL,10); } const List &list(el->getChildren()); List::const_iterator iter; iter = list.begin(); while(iter != list.end()) { if ((*iter)->getName() == "oper") { uintm id; { istringstream s((*iter)->getAttributeValue("id")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> id; } OperandSymbol *sym = (OperandSymbol *)trans->findSymbol(id); operands.push_back(sym); } else if ((*iter)->getName() == "print") printpiece.push_back( (*iter)->getAttributeValue("piece")); else if ((*iter)->getName() == "opprint") { int4 index; istringstream s((*iter)->getAttributeValue("id")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> index; string operstring = "\n "; operstring[1] = ('A' + index); printpiece.push_back(operstring); } else if ((*iter)->getName() == "context_op") { ContextOp *c_op = new ContextOp(); c_op->restoreXml(*iter,trans); context.push_back(c_op); } else if ((*iter)->getName() == "commit") { ContextCommit *c_op = new ContextCommit(); c_op->restoreXml(*iter,trans); context.push_back(c_op); } else { ConstructTpl *cur = new ConstructTpl(); int4 sectionid = cur->restoreXml(*iter,trans); 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; } } ++iter; } pattern = (TokenPattern *)0; if ((printpiece.size()==1)&&(printpiece[0][0]=='\n')) flowthruindex = printpiece[0][1] - 'A'; else flowthruindex = -1; } 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::saveXml(ostream &s) const { if (decisiontree == (DecisionNode *)0) return; // Not fully formed s << "\n"; for(int4 i=0;isaveXml(s); decisiontree->saveXml(s); s << "\n"; } void SubtableSymbol::saveXmlHeader(ostream &s) const { s << "\n"; } void SubtableSymbol::restoreXml(const Element *el,SleighBase *trans) { { int4 numct; istringstream s(el->getAttributeValue("numct")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> numct; construct.reserve(numct); } const List &list(el->getChildren()); List::const_iterator iter; iter = list.begin(); while(iter != list.end()) { if ((*iter)->getName() == "constructor") { Constructor *ct = new Constructor(); addConstructor(ct); ct->restoreXml(*iter,trans); } else if ((*iter)->getName() == "decision") { decisiontree = new DecisionNode(); decisiontree->restoreXml(*iter,(DecisionNode *)0,this); } ++iter; } pattern = (TokenPattern *)0; beingbuilt = false; errors = 0; } 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::saveXml(ostream &s) const { s << "\n"; for(int4 i=0;igetId() << "\">\n"; list[i].first->saveXml(s); s << "\n"; } for(int4 i=0;isaveXml(s); s << "\n"; } void DecisionNode::restoreXml(const Element *el,DecisionNode *par,SubtableSymbol *sub) { parent = par; { istringstream s(el->getAttributeValue("number")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> num; } contextdecision = xml_readbool(el->getAttributeValue("context")); { istringstream s(el->getAttributeValue("start")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> startbit; } { istringstream s(el->getAttributeValue("size")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> bitsize; } const List &childlist(el->getChildren()); List::const_iterator iter; iter = childlist.begin(); while(iter != childlist.end()) { if ((*iter)->getName() == "pair") { Constructor *ct; DisjointPattern *pat; uintm id; istringstream s((*iter)->getAttributeValue("id")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> id; ct = sub->getConstructor(id); pat = DisjointPattern::restoreDisjoint((*iter)->getChildren().front()); //This increments num addConstructorPair(pat,ct); list.push_back(pair(pat,ct)); //delete pat; // addConstructorPair makes its own copy } else if ((*iter)->getName() == "decision") { DecisionNode *subnode = new DecisionNode(); subnode->restoreXml(*iter,this,sub); children.push_back(subnode); } ++iter; } } 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::saveXml(ostream &s) const { s << "\n"; patexp->saveXml(s); s << "\n"; } void ContextOp::restoreXml(const Element *el,SleighBase *trans) { { istringstream s(el->getAttributeValue("i")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> num; } { istringstream s(el->getAttributeValue("shift")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> shift; } { istringstream s(el->getAttributeValue("mask")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> mask; } const List &list(el->getChildren()); List::const_iterator iter; iter = list.begin(); patexp = (PatternValue *)PatternExpression::restoreExpression(*iter,trans); patexp->layClaim(); } 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::saveXml(ostream &s) const { s << "getId()); a_v_i(s,"num",num); a_v_u(s,"mask",mask); a_v_b(s,"flow",flow); s << "/>\n"; } void ContextCommit::restoreXml(const Element *el,SleighBase *trans) { uintm id; { istringstream s(el->getAttributeValue("id")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> id; sym = (TripleSymbol *)trans->findSymbol(id); } { istringstream s(el->getAttributeValue("num")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> num; } { istringstream s(el->getAttributeValue("mask")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> mask; } if (el->getNumAttributes()==4) flow = xml_readbool(el->getAttributeValue("flow")); else flow = true; // Default is to flow. flow=true } ContextChange *ContextCommit::clone(void) const { ContextCommit *res = new ContextCommit(); res->sym = sym; res->flow = flow; res->mask = mask; res->num = num; return res; }