mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
2646 lines
68 KiB
C++
2646 lines
68 KiB
C++
/* ###
|
|
* 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 <cmath>
|
|
using std::log;
|
|
|
|
SleighSymbol *SymbolScope::addSymbol(SleighSymbol *a)
|
|
|
|
{
|
|
pair<SymbolTree::iterator,bool> 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<SymbolScope *>::iterator iter;
|
|
for(iter=table.begin();iter!=table.end();++iter)
|
|
delete *iter;
|
|
vector<SleighSymbol *>::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 << "<symbol_table";
|
|
s << " scopesize=\"" << dec << table.size() << "\"";
|
|
s << " symbolsize=\"" << symbollist.size() << "\">\n";
|
|
for(int4 i=0;i<table.size();++i) {
|
|
s << "<scope id=\"0x" << hex << table[i]->getId() << "\"";
|
|
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;i<symbollist.size();++i)
|
|
symbollist[i]->saveXmlHeader(s);
|
|
|
|
// Now save the content of each symbol
|
|
for(int4 i=0;i<symbollist.size();++i) // Must save IN ORDER
|
|
symbollist[i]->saveXml(s);
|
|
s << "</symbol_table>\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;i<table.size();++i) { // Restore the scopes
|
|
Element *subel = *iter;
|
|
if (subel->getName() != "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;i<symbollist.size();++i) {
|
|
restoreSymbolHeader(*iter);
|
|
++iter;
|
|
}
|
|
// Now restore the symbol content
|
|
while(iter != list.end()) {
|
|
Element *subel = *iter;
|
|
uintm id;
|
|
SleighSymbol *sym;
|
|
{
|
|
istringstream s(subel->getAttributeValue("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() == "next2_sym_head")
|
|
sym = new Next2Symbol();
|
|
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;i<symbollist.size();++i) {
|
|
sym = symbollist[i];
|
|
if (sym == (SleighSymbol *)0) continue;
|
|
if (sym->scopeid != 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;i<macro->getNumOperands();++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;i<subsym->getNumConstructors();++i) { // Go thru each constructor
|
|
Constructor *con = subsym->getConstructor(i);
|
|
for(int4 j=0;j<con->getNumOperands();++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;i<table.size();++i) { // Remove any empty scopes
|
|
if (table[i]->tree.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<SymbolScope *> newtable;
|
|
vector<SleighSymbol *> newsymbol;
|
|
// First renumber the scopes
|
|
SymbolScope *scope;
|
|
for(int4 i=0;i<table.size();++i) {
|
|
scope = table[i];
|
|
if (scope != (SymbolScope *)0) {
|
|
scope->id = newtable.size();
|
|
newtable.push_back(scope);
|
|
}
|
|
}
|
|
// Now renumber the symbols
|
|
SleighSymbol *sym;
|
|
for(int4 i=0;i<symbollist.size();++i) {
|
|
sym = symbollist[i];
|
|
if (sym != (SleighSymbol *)0) {
|
|
sym->scopeid = 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 << "<userop";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << " index=\"" << dec << index << "\"";
|
|
s << "/>\n";
|
|
}
|
|
|
|
void UserOpSymbol::saveXmlHeader(ostream &s) const
|
|
|
|
{
|
|
s << "<userop_head";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
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 << "<epsilon_sym";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << "/>\n";
|
|
}
|
|
|
|
void EpsilonSymbol::saveXmlHeader(ostream &s) const
|
|
|
|
{
|
|
s << "<epsilon_sym_head";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
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 << "<value_sym";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << ">\n";
|
|
patval->saveXml(s);
|
|
s << "</value_sym>\n";
|
|
}
|
|
|
|
void ValueSymbol::saveXmlHeader(ostream &s) const
|
|
|
|
{
|
|
s << "<value_sym_head";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
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)&&(max<valuetable.size());
|
|
for(uint4 i=0;i<valuetable.size();++i) {
|
|
if (valuetable[i] == 0xBADBEEF)
|
|
tableisfilled = false;
|
|
}
|
|
}
|
|
|
|
Constructor *ValueMapSymbol::resolve(ParserWalker &walker)
|
|
|
|
{
|
|
if (!tableisfilled) {
|
|
intb ind = patval->getValue(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 << "<valuemap_sym";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << ">\n";
|
|
patval->saveXml(s);
|
|
for(uint4 i=0;i<valuetable.size();++i)
|
|
s << "<valuetab val=\"" << dec << valuetable[i] << "\"/>\n";
|
|
s << "</valuemap_sym>\n";
|
|
}
|
|
|
|
void ValueMapSymbol::saveXmlHeader(ostream &s) const
|
|
|
|
{
|
|
s << "<valuemap_sym_head";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
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)&&(max<nametable.size());
|
|
for(uint4 i=0;i<nametable.size();++i) {
|
|
if ((nametable[i] == "_")||(nametable[i] == "\t")) {
|
|
nametable[i] = "\t"; // TAB indicates illegal index
|
|
tableisfilled = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
Constructor *NameSymbol::resolve(ParserWalker &walker)
|
|
|
|
{
|
|
if (!tableisfilled) {
|
|
intb ind = patval->getValue(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 << "<name_sym";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << ">\n";
|
|
patval->saveXml(s);
|
|
for(int4 i=0;i<nametable.size();++i) {
|
|
if (nametable[i] == "\t") // TAB indicates an illegal index
|
|
s << "<nametab/>\n"; // Emit tag with no name attribute
|
|
else
|
|
s << "<nametab name=\"" << nametable[i] << "\"/>\n";
|
|
}
|
|
s << "</name_sym>\n";
|
|
}
|
|
|
|
void NameSymbol::saveXmlHeader(ostream &s) const
|
|
|
|
{
|
|
s << "<name_sym_head";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
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<uintb> &results) const
|
|
|
|
{
|
|
if (fix.space->getType() == IPTR_INTERNAL)
|
|
results.push_back(fix.offset);
|
|
}
|
|
|
|
void VarnodeSymbol::saveXml(ostream &s) const
|
|
|
|
{
|
|
s << "<varnode_sym";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << " space=\"" << fix.space->getName() << "\"";
|
|
s << " offset=\"0x" << hex << fix.offset << "\"";
|
|
s << " size=\"" << dec << fix.size << "\"";
|
|
s << ">\n";
|
|
PatternlessSymbol::saveXml(s);
|
|
s << "</varnode_sym>\n";
|
|
}
|
|
|
|
void VarnodeSymbol::saveXmlHeader(ostream &s) const
|
|
|
|
{
|
|
s << "<varnode_sym_head";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
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 << "<context_sym";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << " varnode=\"0x" << hex << vn->getId() << "\"";
|
|
s << " low=\"" << dec << low << "\"";
|
|
s << " high=\"" << high << "\"";
|
|
a_v_b(s,"flow",flow);
|
|
s << ">\n";
|
|
patval->saveXml(s);
|
|
s << "</context_sym>\n";
|
|
}
|
|
|
|
void ContextSymbol::saveXmlHeader(ostream &s) const
|
|
|
|
{
|
|
s << "<context_sym_head";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
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<SleighSymbol *> &vt)
|
|
: ValueSymbol(nm,pv)
|
|
{
|
|
for(int4 i=0;i<vt.size();++i)
|
|
varnode_table.push_back((VarnodeSymbol *)vt[i]);
|
|
checkTableFill();
|
|
}
|
|
|
|
void VarnodeListSymbol::checkTableFill(void)
|
|
|
|
{
|
|
intb min = patval->minValue();
|
|
intb max = patval->maxValue();
|
|
tableisfilled = (min>=0)&&(max<varnode_table.size());
|
|
for(uint4 i=0;i<varnode_table.size();++i) {
|
|
if (varnode_table[i] == (VarnodeSymbol *)0)
|
|
tableisfilled = false;
|
|
}
|
|
}
|
|
|
|
Constructor *VarnodeListSymbol::resolve(ParserWalker &walker)
|
|
|
|
{
|
|
if (!tableisfilled) {
|
|
intb ind = patval->getValue(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;i<varnode_table.size();++i) {
|
|
VarnodeSymbol *vnsym = varnode_table[i]; // Assume all are same size
|
|
if (vnsym != (VarnodeSymbol *)0)
|
|
return vnsym->getSize();
|
|
}
|
|
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 << "<varlist_sym";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << ">\n";
|
|
patval->saveXml(s);
|
|
for(int4 i=0;i<varnode_table.size();++i) {
|
|
if (varnode_table[i] == (VarnodeSymbol *)0)
|
|
s << "<null/>\n";
|
|
else
|
|
s << "<var id=\"0x" << hex << varnode_table[i]->getId() << "\"/>\n";
|
|
}
|
|
s << "</varlist_sym>\n";
|
|
}
|
|
|
|
void VarnodeListSymbol::saveXmlHeader(ostream &s) const
|
|
|
|
{
|
|
s << "<varlist_sym_head";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
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<SpecificSymbol *>(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<uintb> &results) const
|
|
|
|
{
|
|
if (triple != (TripleSymbol *)0)
|
|
triple->collectLocalValues(results);
|
|
}
|
|
|
|
void OperandSymbol::saveXml(ostream &s) const
|
|
|
|
{
|
|
s << "<operand_sym";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
if (triple != (TripleSymbol *)0)
|
|
s << " subsym=\"0x" << hex << triple->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 << "</operand_sym>\n";
|
|
}
|
|
|
|
void OperandSymbol::saveXmlHeader(ostream &s) const
|
|
|
|
{
|
|
s << "<operand_sym_head";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
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;i<el->getNumAttributes();++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 << "<start_sym";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << "/>\n";
|
|
}
|
|
|
|
void StartSymbol::saveXmlHeader(ostream &s) const
|
|
|
|
{
|
|
s << "<start_sym_head";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
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 << "<end_sym";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << "/>\n";
|
|
}
|
|
|
|
void EndSymbol::saveXmlHeader(ostream &s) const
|
|
|
|
{
|
|
s << "<end_sym_head";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << "/>\n";
|
|
}
|
|
|
|
void EndSymbol::restoreXml(const Element *el,SleighBase *trans)
|
|
|
|
{
|
|
const_space = trans->getConstantSpace();
|
|
patexp = new EndInstructionValue();
|
|
patexp->layClaim();
|
|
}
|
|
|
|
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::saveXml(ostream &s) const
|
|
|
|
{
|
|
s << "<next2_sym";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << "/>\n";
|
|
}
|
|
|
|
void Next2Symbol::saveXmlHeader(ostream &s) const
|
|
|
|
{
|
|
s << "<next2_sym_head";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << "/>\n";
|
|
}
|
|
|
|
void Next2Symbol::restoreXml(const Element *el,SleighBase *trans)
|
|
|
|
{
|
|
const_space = trans->getConstantSpace();
|
|
patexp = new Next2InstructionValue();
|
|
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 << "<flowdest_sym";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << "/>\n";
|
|
}
|
|
|
|
void FlowDestSymbol::saveXmlHeader(ostream &s) const
|
|
|
|
{
|
|
s << "<flowdest_sym_head";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
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 << "<flowref_sym";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << "/>\n";
|
|
}
|
|
|
|
void FlowRefSymbol::saveXmlHeader(ostream &s) const
|
|
|
|
{
|
|
s << "<flowref_sym_head";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
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<namedtempl.size();++i) {
|
|
ConstructTpl *ntpl = namedtempl[i];
|
|
if (ntpl != (ConstructTpl *)0)
|
|
delete ntpl;
|
|
}
|
|
vector<ContextChange *>::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;i<syn.size();++i) {
|
|
if (syn[i] != ' ') {
|
|
hasNonSpace = true;
|
|
break;
|
|
}
|
|
}
|
|
if (hasNonSpace)
|
|
syntrim = syn;
|
|
else
|
|
syntrim = " ";
|
|
if ((firstwhitespace==-1)&&(syntrim == " "))
|
|
firstwhitespace = printpiece.size();
|
|
if (printpiece.empty())
|
|
printpiece.push_back(syntrim);
|
|
else if (printpiece.back() == " " && syntrim == " ") {
|
|
// Don't add more whitespace
|
|
}
|
|
else if (printpiece.back()[0] == '\n' || printpiece.back() == " " || syntrim == " ")
|
|
printpiece.push_back(syntrim);
|
|
else {
|
|
printpiece.back() += syntrim;
|
|
}
|
|
}
|
|
|
|
void Constructor::addEquation(PatternEquation *pe)
|
|
|
|
{
|
|
(pateq=pe)->layClaim();
|
|
}
|
|
|
|
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<string>::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<SubtableSymbol *>(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;i<endind;++i) {
|
|
if (printpiece[i][0] == '\n') {
|
|
int4 index = printpiece[i][1]-'A';
|
|
operands[index]->print(s,walker);
|
|
}
|
|
else
|
|
s << printpiece[i];
|
|
}
|
|
}
|
|
|
|
void Constructor::printBody(ostream &s,ParserWalker &walker) const
|
|
|
|
{
|
|
if (flowthruindex != -1) {
|
|
SubtableSymbol *sym = dynamic_cast<SubtableSymbol *>(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;i<printpiece.size();++i) {
|
|
if (printpiece[i][0]=='\n') {
|
|
int4 index = printpiece[i][1]-'A';
|
|
operands[index]->print(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<int4> &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;i<operands.size();++i) {
|
|
TripleSymbol *sym = operands[i]->getDefiningSymbol();
|
|
if ((sym != (TripleSymbol *)0)&&(sym->getType() == SleighSymbol::subtable_symbol))
|
|
check[i] = 0;
|
|
else
|
|
check[i] = 2;
|
|
}
|
|
}
|
|
|
|
void Constructor::collectLocalExports(vector<uintb> &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;i<operands.size();++i) {
|
|
TripleSymbol *sym = operands[i]->getDefiningSymbol();
|
|
if (sym == parent) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Constructor::saveXml(ostream &s) const
|
|
|
|
{
|
|
s << "<constructor";
|
|
s << " parent=\"0x" << hex << parent->getId() << "\"";
|
|
s << " first=\"" << dec << firstwhitespace << "\"";
|
|
s << " length=\"" << minimumlength << "\"";
|
|
s << " line=\"" << src_index << ":" << lineno << "\">\n";
|
|
for(int4 i=0;i<operands.size();++i)
|
|
s << "<oper id=\"0x" << hex << operands[i]->getId() << "\"/>\n";
|
|
for(int4 i=0;i<printpiece.size();++i) {
|
|
if (printpiece[i][0]=='\n') {
|
|
int4 index = printpiece[i][1]-'A';
|
|
s << "<opprint id=\"" << dec << index << "\"/>\n";
|
|
}
|
|
else {
|
|
s << "<print piece=\"";
|
|
xml_escape(s, printpiece[i].c_str());
|
|
s << "\"/>\n";
|
|
}
|
|
}
|
|
for(int4 i=0;i<context.size();++i)
|
|
context[i]->saveXml(s);
|
|
if (templ != (ConstructTpl *)0)
|
|
templ->saveXml(s,-1);
|
|
for(int4 i=0;i<namedtempl.size();++i) {
|
|
if (namedtempl[i] == (ConstructTpl *)0) // Some sections may be NULL
|
|
continue;
|
|
namedtempl[i]->saveXml(s,i);
|
|
}
|
|
s << "</constructor>\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<OperandSymbol *> patternorder;
|
|
vector<OperandSymbol *> newops; // New order of the operands
|
|
int4 lastsize;
|
|
|
|
pateq->operandOrder(this,patternorder);
|
|
for(int4 i=0;i<operands.size();++i) { // Make sure patternorder contains all operands
|
|
sym = operands[i];
|
|
if (!sym->isMarked()) {
|
|
patternorder.push_back(sym);
|
|
sym->setMark(); // Make sure all operands are marked
|
|
}
|
|
}
|
|
do {
|
|
lastsize = newops.size();
|
|
for(int4 i=0;i<patternorder.size();++i) {
|
|
sym = patternorder[i];
|
|
if (!sym->isMarked()) 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;i<patternorder.size();++i) { // Tack on expression Operands
|
|
sym = patternorder[i];
|
|
if (sym->isOffsetIrrelevant()) {
|
|
newops.push_back(sym);
|
|
sym->clearMark();
|
|
}
|
|
}
|
|
|
|
if (newops.size() != operands.size())
|
|
throw SleighError("Circular offset dependency between operands");
|
|
|
|
|
|
for(int4 i=0;i<newops.size();++i) { // Fix up operand indices
|
|
newops[i]->hand = i;
|
|
newops[i]->localexp->changeIndex(i);
|
|
}
|
|
vector<int4> handmap; // Create index translation map
|
|
for(int4 i=0;i<operands.size();++i)
|
|
handmap.push_back(operands[i]->hand);
|
|
|
|
// Fix up offsetbase
|
|
for(int4 i=0;i<newops.size();++i) {
|
|
sym = newops[i];
|
|
if (sym->offsetbase == -1) continue;
|
|
sym->offsetbase = handmap[sym->offsetbase];
|
|
}
|
|
|
|
if (templ != (ConstructTpl *)0) // Fix up templates
|
|
templ->changeHandleIndex(handmap);
|
|
for(int4 i=0;i<namedtempl.size();++i) {
|
|
ConstructTpl *ntempl = namedtempl[i];
|
|
if (ntempl != (ConstructTpl *)0)
|
|
ntempl->changeHandleIndex(handmap);
|
|
}
|
|
|
|
// Fix up printpiece operand refs
|
|
for(int4 i=0;i<printpiece.size();++i) {
|
|
if (printpiece[i][0] == '\n') {
|
|
int4 index = printpiece[i][1]-'A';
|
|
index = handmap[index];
|
|
printpiece[i][1] = 'A'+index;
|
|
}
|
|
}
|
|
operands = newops;
|
|
}
|
|
|
|
TokenPattern *Constructor::buildPattern(ostream &s)
|
|
|
|
{
|
|
if (pattern != (TokenPattern *)0) return pattern; // Already built
|
|
|
|
pattern = new TokenPattern();
|
|
vector<TokenPattern> oppattern;
|
|
bool recursion = false;
|
|
// Generate pattern for each operand, store in oppattern
|
|
for(int4 i=0;i<operands.size();++i) {
|
|
OperandSymbol *sym = operands[i];
|
|
TripleSymbol *triple = sym->getDefiningSymbol();
|
|
PatternExpression *defexp = sym->getDefiningExpression();
|
|
if (triple != (TripleSymbol *)0) {
|
|
SubtableSymbol *subsym = dynamic_cast<SubtableSymbol *>(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;i<operands.size();++i) { // Unravel relative offsets to absolute (if possible)
|
|
int4 base,offset;
|
|
OperandSymbol *sym = operands[i];
|
|
if (sym->isOffsetIrrelevant()) {
|
|
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;i<context.size();++i)
|
|
context[i]->validate();
|
|
|
|
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<Constructor *>::iterator iter;
|
|
for(iter=construct.begin();iter!=construct.end();++iter)
|
|
delete *iter;
|
|
}
|
|
|
|
void SubtableSymbol::collectLocalValues(vector<uintb> &results) const
|
|
|
|
{
|
|
for(int4 i=0;i<construct.size();++i)
|
|
construct[i]->collectLocalExports(results);
|
|
}
|
|
|
|
void SubtableSymbol::saveXml(ostream &s) const
|
|
|
|
{
|
|
if (decisiontree == (DecisionNode *)0) return; // Not fully formed
|
|
s << "<subtable_sym";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
s << " numct=\"" << dec << construct.size() << "\">\n";
|
|
for(int4 i=0;i<construct.size();++i)
|
|
construct[i]->saveXml(s);
|
|
decisiontree->saveXml(s);
|
|
s << "</subtable_sym>\n";
|
|
}
|
|
|
|
void SubtableSymbol::saveXmlHeader(ostream &s) const
|
|
|
|
{
|
|
s << "<subtable_sym_head";
|
|
SleighSymbol::saveXmlHeader(s);
|
|
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;i<construct.size();++i) {
|
|
pat = construct[i]->getPattern()->getPattern();
|
|
if (pat->numDisjoint() == 0)
|
|
decisiontree->addConstructorPair((const DisjointPattern *)pat,construct[i]);
|
|
else
|
|
for(int4 j=0;j<pat->numDisjoint();++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;i<construct.size();++i) {
|
|
try {
|
|
construct[i]->buildPattern(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<DecisionNode *>::iterator iter;
|
|
for(iter=children.begin();iter!=children.end();++iter)
|
|
delete *iter;
|
|
vector<pair<DisjointPattern *,Constructor *> >::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<DisjointPattern *,Constructor *>(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;i<list.size();++i) {
|
|
val = list[i].first->getLength(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)<<size);
|
|
m = m-1;
|
|
|
|
for(int4 i=0;i<list.size();++i) {
|
|
mask = list[i].first->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)<<size;
|
|
m = m-1;
|
|
|
|
int4 total = 0;
|
|
vector<int4> count(numBins,0);
|
|
|
|
for(i=0;i<list.size();++i) {
|
|
mask = list[i].first->getMask(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<numBins;++i) {
|
|
if (count[i] <= 0) continue;
|
|
if (count[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<maxlength;++sbit) {
|
|
numfixed = getNumFixed(sbit,1,context); // How may patterns specify this bit
|
|
if (numfixed < maxfixed) continue; // Skip this bit, if we don't have maximum specification
|
|
sc = getScore(sbit,1,context);
|
|
|
|
// if we got more patterns this time than previously, and a positive score, reset
|
|
// the high score (we prefer this bit, because it has a higher numfixed, regardless
|
|
// of the difference in score, as long as the new score is positive).
|
|
if ((numfixed > 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<maxlength-size+1;++sbit) {
|
|
if (getNumFixed(sbit,size,context) < maxfixed) continue; // Consider only maximal fields
|
|
sc = getScore(sbit,size,context);
|
|
if (sc > 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<uint4> &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)<<bitsize);
|
|
m = m-1;
|
|
uintm commonMask = m & pat->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<numChildren;++i) {
|
|
DecisionNode *nd = new DecisionNode( this );
|
|
children.push_back( nd );
|
|
}
|
|
for(int4 i=0;i<list.size();++i) {
|
|
vector<uint4> 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;j<vals.size();++j)
|
|
children[vals[j]]->addConstructorPair(list[i].first,list[i].second);
|
|
delete list[i].first; // We no longer need original pattern
|
|
}
|
|
list.clear();
|
|
|
|
for(int4 i=0;i<numChildren;++i)
|
|
children[i]->split(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<pair<DisjointPattern *,Constructor *> > newlist;
|
|
vector<pair<DisjointPattern *,Constructor *> > conflictlist;
|
|
|
|
// Check for identical patterns
|
|
for(i=0;i<list.size();++i) {
|
|
for(j=0;j<i;++j) {
|
|
DisjointPattern *ipat = list[i].first;
|
|
DisjointPattern *jpat = list[j].first;
|
|
if (ipat->identical(jpat))
|
|
props.identicalPattern(list[i].second,list[j].second);
|
|
}
|
|
}
|
|
|
|
newlist = list;
|
|
for(i=0;i<list.size();++i) {
|
|
for(j=0;j<i;++j) {
|
|
DisjointPattern *ipat = newlist[i].first;
|
|
DisjointPattern *jpat = list[j].first;
|
|
if (ipat->specializes(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<DisjointPattern *,Constructor *>(ipat,iconst));
|
|
conflictlist.push_back(pair<DisjointPattern *,Constructor *>(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;i<conflictlist.size();i+=2) {
|
|
DisjointPattern *pat1,*pat2;
|
|
Constructor *const1,*const2;
|
|
pat1 = conflictlist[i].first;
|
|
const1 = conflictlist[i].second;
|
|
pat2 = conflictlist[i+1].first;
|
|
const2 = conflictlist[i+1].second;
|
|
bool resolved = false;
|
|
for(j=0;j<list.size();++j) {
|
|
DisjointPattern *tpat = list[j].first;
|
|
Constructor *tconst = list[j].second;
|
|
if ((tpat == pat1)&&(tconst==const1)) break; // Ran out of possible specializations
|
|
if ((tpat == pat2)&&(tconst==const2)) break;
|
|
if (tpat->resolvesIntersect(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<pair<DisjointPattern *,Constructor *> >::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 << "<decision";
|
|
s << " number=\"" << dec << num << "\"";
|
|
s << " context=\"";
|
|
if (contextdecision)
|
|
s << "true\"";
|
|
else
|
|
s << "false\"";
|
|
s << " start=\"" << startbit << "\"";
|
|
s << " size=\"" << bitsize << "\"";
|
|
s << ">\n";
|
|
for(int4 i=0;i<list.size();++i) {
|
|
s << "<pair id=\"" << dec << list[i].second->getId() << "\">\n";
|
|
list[i].first->saveXml(s);
|
|
s << "</pair>\n";
|
|
}
|
|
for(int4 i=0;i<children.size();++i)
|
|
children[i]->saveXml(s);
|
|
s << "</decision>\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<DisjointPattern *,Constructor *>(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<const PatternValue *> values;
|
|
|
|
patexp->listValues(values); // Get all the expression tokens
|
|
for(int4 i=0;i<values.size();++i) {
|
|
const OperandValue *val = dynamic_cast<const OperandValue *>(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 << "<context_op";
|
|
s << " i=\"" << dec << num << "\"";
|
|
s << " shift=\"" << shift << "\"";
|
|
s << " mask=\"0x" << hex << mask << "\" >\n";
|
|
patexp->saveXml(s);
|
|
s << "</context_op>\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 << "<commit";
|
|
a_v_u(s,"id",sym->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;
|
|
}
|