mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
Merge remote-tracking branch 'origin/GP-5581_sleighPiecewiseUniques--SQUASHED'
This commit is contained in:
commit
6773801f6e
20 changed files with 798 additions and 482 deletions
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -583,9 +583,6 @@ VarnodeTpl *PcodeCompile::buildTruncatedVarnode(VarnodeTpl *basevn,uint4 bitoffs
|
|||
if ((bitoffset % 8) != 0) return (VarnodeTpl *)0;
|
||||
if ((numbits % 8) != 0) return (VarnodeTpl *)0;
|
||||
|
||||
if (basevn->getSpace().isUniqueSpace()) // Do we really want to prevent truncated uniques??
|
||||
return (VarnodeTpl *)0;
|
||||
|
||||
ConstTpl::const_type offset_type = basevn->getOffset().getType();
|
||||
if ((offset_type != ConstTpl::real)&&(offset_type != ConstTpl::handle))
|
||||
return (VarnodeTpl *)0;
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -540,6 +540,18 @@ void VarnodeTpl::decode(Decoder &decoder)
|
|||
decoder.closeElement(el);
|
||||
}
|
||||
|
||||
bool VarnodeTpl::operator==(const VarnodeTpl &op2) const
|
||||
|
||||
{
|
||||
return space==op2.space && offset==op2.offset && size==op2.size;
|
||||
}
|
||||
|
||||
bool VarnodeTpl::operator!=(const VarnodeTpl &op2) const
|
||||
|
||||
{
|
||||
return !(*this == op2);
|
||||
}
|
||||
|
||||
bool VarnodeTpl::operator<(const VarnodeTpl &op2) const
|
||||
|
||||
{
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -91,6 +91,8 @@ public:
|
|||
bool isDynamic(const ParserWalker &walker) const;
|
||||
int4 transfer(const vector<HandleTpl *> ¶ms);
|
||||
bool isZeroSize(void) const { return size.isZero(); }
|
||||
bool operator==(const VarnodeTpl &op2) const;
|
||||
bool operator!=(const VarnodeTpl &op2) const;
|
||||
bool operator<(const VarnodeTpl &op2) const;
|
||||
void setOffset(uintb constVal) { offset = ConstTpl(ConstTpl::real,constVal); }
|
||||
void setRelative(uintb constVal) { offset = ConstTpl(ConstTpl::j_relative,constVal); }
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -180,6 +180,75 @@ SubtableSymbol *WithBlock::getCurrentSubtable(const list<WithBlock> &stack)
|
|||
return (SubtableSymbol *)0;
|
||||
}
|
||||
|
||||
void ConsistencyChecker::OptimizeRecord::copyFromExcludingSize(ConsistencyChecker::OptimizeRecord &that)
|
||||
|
||||
{
|
||||
this->writeop = that.writeop;
|
||||
this->readop = that.readop;
|
||||
this->inslot = that.inslot;
|
||||
this->writecount = that.writecount;
|
||||
this->readcount = that.readcount;
|
||||
this->writesection = that.writesection;
|
||||
this->readsection = that.readsection;
|
||||
this->opttype = that.opttype;
|
||||
}
|
||||
|
||||
void ConsistencyChecker::OptimizeRecord::update(int4 opIdx, int4 slotIdx, int4 secNum)
|
||||
|
||||
{
|
||||
if (slotIdx >= 0) {
|
||||
updateRead(opIdx, slotIdx, secNum);
|
||||
}
|
||||
else {
|
||||
updateWrite(opIdx, secNum);
|
||||
}
|
||||
}
|
||||
|
||||
void ConsistencyChecker::OptimizeRecord::updateRead(int4 i, int4 inslot, int4 secNum)
|
||||
|
||||
{
|
||||
this->readop = i;
|
||||
this->readcount++;
|
||||
this->inslot = inslot;
|
||||
this->readsection = secNum;
|
||||
}
|
||||
|
||||
void ConsistencyChecker::OptimizeRecord::updateWrite(int4 i, int4 secNum)
|
||||
|
||||
{
|
||||
this->writeop = i;
|
||||
this->writecount++;
|
||||
this->writesection = secNum;
|
||||
}
|
||||
|
||||
void ConsistencyChecker::OptimizeRecord::updateExport()
|
||||
|
||||
{
|
||||
this->writeop = 0;
|
||||
this->readop = 0;
|
||||
this->writecount = 2;
|
||||
this->readcount = 2;
|
||||
this->readsection = -2;
|
||||
this->writesection = -2;
|
||||
}
|
||||
|
||||
void ConsistencyChecker::OptimizeRecord::updateCombine(ConsistencyChecker::OptimizeRecord &that)
|
||||
|
||||
{
|
||||
if (that.writecount != 0) {
|
||||
this->writeop = that.writeop;
|
||||
this->writesection = that.writesection;
|
||||
}
|
||||
if (that.readcount != 0) {
|
||||
this->readop = that.readop;
|
||||
this->inslot = that.inslot;
|
||||
this->readsection = that.readsection;
|
||||
}
|
||||
this->writecount += that.writecount;
|
||||
this->readcount += that.readcount;
|
||||
// opttype is not relevant here
|
||||
}
|
||||
|
||||
/// \brief Construct the consistency checker and optimizer
|
||||
///
|
||||
/// \param sleigh is the parsed SLEIGH spec
|
||||
|
@ -1129,6 +1198,90 @@ void ConsistencyChecker::setPostOrder(SubtableSymbol *root)
|
|||
}
|
||||
}
|
||||
|
||||
map<uintb,ConsistencyChecker::OptimizeRecord>::iterator ConsistencyChecker::UniqueState::lesserIter(uintb offset)
|
||||
|
||||
{
|
||||
if (recs.begin() == recs.end()) {
|
||||
return recs.end();
|
||||
}
|
||||
map<uintb,OptimizeRecord>::iterator iter;
|
||||
iter = recs.lower_bound(offset);
|
||||
if (iter == recs.begin()) {
|
||||
return recs.end();
|
||||
}
|
||||
return std::prev(iter);
|
||||
}
|
||||
|
||||
ConsistencyChecker::OptimizeRecord ConsistencyChecker::UniqueState::coalesce(vector<ConsistencyChecker::OptimizeRecord*> &records)
|
||||
|
||||
{
|
||||
uintb minOff = -1;
|
||||
uintb maxOff = -1;
|
||||
vector<OptimizeRecord*>::iterator iter;
|
||||
|
||||
for (iter = records.begin(); iter != records.end(); ++iter) {
|
||||
if (minOff == -1 || (*iter)->offset < minOff) {
|
||||
minOff = (*iter)->offset;
|
||||
}
|
||||
if (maxOff == -1 || (*iter)->offset + (*iter)->size > maxOff) {
|
||||
maxOff = (*iter)->offset + (*iter)->size;
|
||||
}
|
||||
}
|
||||
|
||||
OptimizeRecord result(minOff, maxOff - minOff);
|
||||
|
||||
for (iter = records.begin(); iter != records.end(); ++iter) {
|
||||
result.updateCombine(**iter);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ConsistencyChecker::UniqueState::set(uintb offset, int4 size, OptimizeRecord &rec)
|
||||
|
||||
{
|
||||
vector<OptimizeRecord*> records;
|
||||
getDefinitions(records, offset, size);
|
||||
records.push_back(&rec);
|
||||
OptimizeRecord coalesced = coalesce(records);
|
||||
recs.erase(recs.lower_bound(coalesced.offset), recs.lower_bound(coalesced.offset+coalesced.size));
|
||||
recs.insert(pair<uint4,OptimizeRecord>(coalesced.offset, coalesced));
|
||||
}
|
||||
|
||||
void ConsistencyChecker::UniqueState::getDefinitions(vector<ConsistencyChecker::OptimizeRecord*> &result, uintb offset, int4 size)
|
||||
|
||||
{
|
||||
if (size == 0) {
|
||||
size = 1;
|
||||
}
|
||||
map<uintb,OptimizeRecord>::iterator iter;
|
||||
iter = lesserIter(offset);
|
||||
uintb cursor = offset;
|
||||
if (iter != recs.end() && endOf(iter) > offset) {
|
||||
OptimizeRecord &preRec = iter->second;
|
||||
cursor = endOf(iter);
|
||||
result.push_back(&preRec);
|
||||
}
|
||||
uintb end = offset + size;
|
||||
iter = recs.lower_bound(offset);
|
||||
while (iter != recs.end() && iter->first < end) {
|
||||
if (iter->first > cursor) {
|
||||
// The iterator becomes invalid with this insertion, so take the new one.
|
||||
iter = recs.insert(pair<uint4,OptimizeRecord>(cursor,OptimizeRecord(cursor, iter->first - cursor))).first;
|
||||
result.push_back(&iter->second);
|
||||
iter++; // Put the (now valid) iterator back to where it was.
|
||||
}
|
||||
// No need to truncate, as we're just counting a read
|
||||
result.push_back(&iter->second);
|
||||
cursor = endOf(iter);
|
||||
iter++;
|
||||
}
|
||||
if (end > cursor) {
|
||||
iter = recs.insert(pair<uint4,OptimizeRecord>(cursor,OptimizeRecord(cursor, end - cursor))).first;
|
||||
result.push_back(&iter->second);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Test whether two given Varnodes intersect
|
||||
///
|
||||
/// This test must be conservative. If it can't explicitly prove that the
|
||||
|
@ -1222,30 +1375,31 @@ bool ConsistencyChecker::readWriteInterference(const VarnodeTpl *vn,const OpTpl
|
|||
/// If the Varnode is in the \e unique space, an OptimizationRecord for it is looked
|
||||
/// up based on its offset. Information about how a p-code operator uses the Varnode
|
||||
/// is accumulated in the record.
|
||||
/// \param recs is collection of OptimizationRecords associated with temporary Varnodes
|
||||
/// \param state is collection of OptimizationRecords associated with temporary Varnodes
|
||||
/// \param vn is the given Varnode to check (which may or may not be temporary)
|
||||
/// \param i is the index of the operator using the Varnode (within its p-code section)
|
||||
/// \param inslot is the \e slot index of the Varnode within its operator
|
||||
/// \param secnum is the section number containing the operator
|
||||
void ConsistencyChecker::examineVn(map<uintb,OptimizeRecord> &recs,
|
||||
void ConsistencyChecker::examineVn(UniqueState &state,
|
||||
const VarnodeTpl *vn,uint4 i,int4 inslot,int4 secnum)
|
||||
{
|
||||
if (vn == (const VarnodeTpl *)0) return;
|
||||
if (!vn->getSpace().isUniqueSpace()) return;
|
||||
if (vn->getOffset().getType() != ConstTpl::real) return;
|
||||
|
||||
map<uintb,OptimizeRecord>::iterator iter;
|
||||
iter = recs.insert( pair<uint4,OptimizeRecord>(vn->getOffset().getReal(),OptimizeRecord())).first;
|
||||
if (inslot>=0) {
|
||||
(*iter).second.readop = i;
|
||||
(*iter).second.readcount += 1;
|
||||
(*iter).second.inslot = inslot;
|
||||
(*iter).second.readsection = secnum;
|
||||
uintb offset = vn->getOffset().getReal();
|
||||
int4 size = vn->getSize().getReal();
|
||||
if (inslot >= 0) {
|
||||
vector<OptimizeRecord*> defs;
|
||||
state.getDefinitions(defs,offset,size);
|
||||
for (vector<OptimizeRecord*>::iterator iter=defs.begin();iter!=defs.end();++iter) {
|
||||
(*iter)->updateRead(i,inslot,secnum);
|
||||
}
|
||||
}
|
||||
else {
|
||||
(*iter).second.writeop = i;
|
||||
(*iter).second.writecount += 1;
|
||||
(*iter).second.writesection = secnum;
|
||||
OptimizeRecord rec(offset,size);
|
||||
rec.updateWrite(i,secnum);
|
||||
state.set(offset,size,rec);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1254,9 +1408,9 @@ void ConsistencyChecker::examineVn(map<uintb,OptimizeRecord> &recs,
|
|||
/// For each temporary Varnode, count how many times it is read from or written to
|
||||
/// in the given section of p-code operators.
|
||||
/// \param ct is the given Constructor
|
||||
/// \param recs is the (initially empty) collection of count records
|
||||
/// \param state is the (initially empty) collection of count records
|
||||
/// \param secnum is the given p-code section number
|
||||
void ConsistencyChecker::optimizeGather1(Constructor *ct,map<uintb,OptimizeRecord> &recs,int4 secnum) const
|
||||
void ConsistencyChecker::optimizeGather1(Constructor *ct,UniqueState &state,int4 secnum) const
|
||||
|
||||
{
|
||||
ConstructTpl *tpl;
|
||||
|
@ -1271,10 +1425,10 @@ void ConsistencyChecker::optimizeGather1(Constructor *ct,map<uintb,OptimizeRecor
|
|||
const OpTpl *op = ops[i];
|
||||
for(uint4 j=0;j<op->numInput();++j) {
|
||||
const VarnodeTpl *vnin = op->getIn(j);
|
||||
examineVn(recs,vnin,i,j,secnum);
|
||||
examineVn(state,vnin,i,j,secnum);
|
||||
}
|
||||
const VarnodeTpl *vn = op->getOut();
|
||||
examineVn(recs,vn,i,-1,secnum);
|
||||
examineVn(state,vn,i,-1,secnum);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1284,9 +1438,9 @@ void ConsistencyChecker::optimizeGather1(Constructor *ct,map<uintb,OptimizeRecor
|
|||
/// for the section, and if it involves a temporary, mark it as both read and written, guaranteeing
|
||||
/// that the Varnode is not optimized away.
|
||||
/// \param ct is the given Constructor
|
||||
/// \param recs is the collection of count records
|
||||
/// \param state is the collection of count records
|
||||
/// \param secnum is the given p-code section number
|
||||
void ConsistencyChecker::optimizeGather2(Constructor *ct,map<uintb,OptimizeRecord> &recs,int4 secnum) const
|
||||
void ConsistencyChecker::optimizeGather2(Constructor *ct,UniqueState &state,int4 secnum) const
|
||||
|
||||
{
|
||||
ConstructTpl *tpl;
|
||||
|
@ -1300,29 +1454,29 @@ void ConsistencyChecker::optimizeGather2(Constructor *ct,map<uintb,OptimizeRecor
|
|||
if (hand == (HandleTpl *)0) return;
|
||||
if (hand->getPtrSpace().isUniqueSpace()) {
|
||||
if (hand->getPtrOffset().getType() == ConstTpl::real) {
|
||||
pair<map<uintb,OptimizeRecord>::iterator,bool> res;
|
||||
uintb offset = hand->getPtrOffset().getReal();
|
||||
res = recs.insert( pair<uintb,OptimizeRecord>(offset,OptimizeRecord()));
|
||||
(*res.first).second.writeop = 0;
|
||||
(*res.first).second.readop = 0;
|
||||
(*res.first).second.writecount = 2;
|
||||
(*res.first).second.readcount = 2;
|
||||
(*res.first).second.readsection = -2;
|
||||
(*res.first).second.writesection = -2;
|
||||
int4 size = hand->getPtrSize().getReal();
|
||||
vector<OptimizeRecord*> defs;
|
||||
state.getDefinitions(defs,offset,size);
|
||||
for (vector<OptimizeRecord*>::iterator iter=defs.begin();iter!=defs.end();++iter) {
|
||||
(*iter)->updateExport();
|
||||
// NOTE: Could this just be updateRead?
|
||||
// Technically, an exported handle could be written by the parent....
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hand->getSpace().isUniqueSpace()) {
|
||||
if ((hand->getPtrSpace().getType() == ConstTpl::real)&&
|
||||
(hand->getPtrOffset().getType() == ConstTpl::real)) {
|
||||
pair<map<uintb,OptimizeRecord>::iterator,bool> res;
|
||||
uintb offset = hand->getPtrOffset().getReal();
|
||||
res = recs.insert( pair<uintb,OptimizeRecord>(offset,OptimizeRecord()));
|
||||
(*res.first).second.writeop = 0;
|
||||
(*res.first).second.readop = 0;
|
||||
(*res.first).second.writecount = 2;
|
||||
(*res.first).second.readcount = 2;
|
||||
(*res.first).second.readsection = -2;
|
||||
(*res.first).second.writesection = -2;
|
||||
int4 size = hand->getPtrSize().getReal();
|
||||
vector<OptimizeRecord*> defs;
|
||||
state.getDefinitions(defs,offset,size);
|
||||
for (vector<OptimizeRecord*>::iterator iter=defs.begin();iter!=defs.end();++iter) {
|
||||
(*iter)->updateExport();
|
||||
// NOTE: Could this just be updateRead?
|
||||
// Technically, an exported handle could be written by the parent....
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1336,14 +1490,14 @@ void ConsistencyChecker::optimizeGather2(Constructor *ct,map<uintb,OptimizeRecor
|
|||
/// if propagation is forward, the Varnode must not cross another write.
|
||||
/// If all the requirements pass, return the record indicating that the COPY can be removed.
|
||||
/// \param ct is the Constructor owning the p-code
|
||||
/// \param recs is the collection of OptimizeRecords to search
|
||||
/// \param state is the collection of OptimizeRecords to search
|
||||
/// \return a passing OptimizeRecord or null
|
||||
const ConsistencyChecker::OptimizeRecord *ConsistencyChecker::findValidRule(Constructor *ct,
|
||||
const map<uintb,OptimizeRecord> &recs) const
|
||||
const UniqueState &state) const
|
||||
{
|
||||
map<uintb,OptimizeRecord>::const_iterator iter;
|
||||
iter = recs.begin();
|
||||
while(iter != recs.end()) {
|
||||
iter = state.begin();
|
||||
while(iter!=state.end()) {
|
||||
const OptimizeRecord &currec( (*iter).second );
|
||||
++iter;
|
||||
if ((currec.writecount==1)&&(currec.readcount==1)&&(currec.readsection==currec.writesection)) {
|
||||
|
@ -1354,13 +1508,27 @@ const ConsistencyChecker::OptimizeRecord *ConsistencyChecker::findValidRule(Cons
|
|||
else
|
||||
tpl = ct->getNamedTempl(currec.readsection);
|
||||
const vector<OpTpl *> &ops( tpl->getOpvec() );
|
||||
const OpTpl *op = ops[ currec.readop ];
|
||||
const OpTpl *writeop = ops[ currec.writeop ];
|
||||
const OpTpl *readop = ops[ currec.readop ];
|
||||
if (currec.writeop >= currec.readop) // Read must come after write
|
||||
throw SleighError("Read of temporary before write");
|
||||
if (op->getOpcode() == CPUI_COPY) {
|
||||
|
||||
VarnodeTpl *writevn = writeop->getOut();
|
||||
VarnodeTpl *readvn = readop->getIn(currec.inslot);
|
||||
// Because the record can change size and position, we have to check if the varnode
|
||||
// "connecting" the write and read ops is actually the same varnode. If not, then we can't
|
||||
// optimize it out.
|
||||
// There may be an opportunity here to re-write the size/offset when either the write or read
|
||||
// op is a COPY, but I'll leave that for later discussion.
|
||||
// Actually, maybe not. If the truncate would be of a handle, we can't.
|
||||
if (*writevn != *readvn) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (readop->getOpcode() == CPUI_COPY) {
|
||||
bool saverecord = true;
|
||||
currec.opttype = 0; // Read op is a COPY
|
||||
const VarnodeTpl *vn = op->getOut();
|
||||
const VarnodeTpl *vn = readop->getOut();
|
||||
for(int4 i=currec.writeop+1;i<currec.readop;++i) { // Check for interference between write and read
|
||||
if (readWriteInterference(vn,ops[i],true)) {
|
||||
saverecord = false;
|
||||
|
@ -1370,11 +1538,10 @@ const ConsistencyChecker::OptimizeRecord *ConsistencyChecker::findValidRule(Cons
|
|||
if (saverecord)
|
||||
return &currec;
|
||||
}
|
||||
op = ops[ currec.writeop ];
|
||||
if (op->getOpcode() == CPUI_COPY) {
|
||||
if (writeop->getOpcode() == CPUI_COPY) {
|
||||
bool saverecord = true;
|
||||
currec.opttype = 1; // Write op is a COPY
|
||||
const VarnodeTpl *vn = op->getIn(0);
|
||||
const VarnodeTpl *vn = writeop->getIn(0);
|
||||
for(int4 i=currec.writeop+1;i<currec.readop;++i) { // Check for interference between write and read
|
||||
if (readWriteInterference(vn,ops[i],false)) {
|
||||
saverecord = false;
|
||||
|
@ -1431,13 +1598,13 @@ void ConsistencyChecker::applyOptimization(Constructor *ct,const OptimizeRecord
|
|||
/// An error message is issued if a temporary is read but not written.
|
||||
/// A warning may be issued if a temporary is written but not read.
|
||||
/// \param ct is the Constructor
|
||||
/// \param recs is the collection of records associated with each temporary Varnode
|
||||
void ConsistencyChecker::checkUnusedTemps(Constructor *ct,const map<uintb,OptimizeRecord> &recs)
|
||||
/// \param state is the collection of records associated with each temporary Varnode
|
||||
void ConsistencyChecker::checkUnusedTemps(Constructor *ct,const UniqueState &state)
|
||||
|
||||
{
|
||||
map<uintb,OptimizeRecord>::const_iterator iter;
|
||||
iter = recs.begin();
|
||||
while(iter != recs.end()) {
|
||||
iter = state.begin();
|
||||
while(iter != state.end()) {
|
||||
const OptimizeRecord &currec( (*iter).second );
|
||||
if (currec.readcount == 0) {
|
||||
if (printdeadwarning)
|
||||
|
@ -1485,19 +1652,19 @@ void ConsistencyChecker::optimize(Constructor *ct)
|
|||
|
||||
{
|
||||
const OptimizeRecord *currec;
|
||||
map<uintb,OptimizeRecord> recs;
|
||||
UniqueState state;
|
||||
int4 numsections = ct->getNumSections();
|
||||
do {
|
||||
recs.clear();
|
||||
state.clear();
|
||||
for(int4 i=-1;i<numsections;++i) {
|
||||
optimizeGather1(ct,recs,i);
|
||||
optimizeGather2(ct,recs,i);
|
||||
optimizeGather1(ct,state,i);
|
||||
optimizeGather2(ct,state,i);
|
||||
}
|
||||
currec = findValidRule(ct,recs);
|
||||
currec = findValidRule(ct,state);
|
||||
if (currec != (const OptimizeRecord *)0)
|
||||
applyOptimization(ct,*currec);
|
||||
} while(currec != (const OptimizeRecord *)0);
|
||||
checkUnusedTemps(ct,recs);
|
||||
checkUnusedTemps(ct,state);
|
||||
}
|
||||
|
||||
/// Warnings or errors for individual violations may be printed, depending on settings.
|
||||
|
@ -1589,6 +1756,13 @@ void ConsistencyChecker::optimizeAll(void)
|
|||
}
|
||||
}
|
||||
|
||||
ostream& operator<<(ostream &os, const ConsistencyChecker::OptimizeRecord &rec) {
|
||||
os << "{writeop=" << rec.writeop << " readop=" << rec.readop << " inslot=" << rec.inslot <<
|
||||
" writecount=" << rec.writecount << " readcount=" << rec.readcount <<
|
||||
" opttype=" << rec.opttype << "}";
|
||||
return os;
|
||||
}
|
||||
|
||||
/// Sort based on the containing Varnode, then on the bit boundary
|
||||
/// \param op2 is a field to compare with \b this
|
||||
/// \return \b true if \b this should be sorted before the other field
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -23,12 +23,14 @@
|
|||
#include "filemanage.hh"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace ghidra {
|
||||
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::out_of_range;
|
||||
using std::string;
|
||||
|
||||
/// \brief A helper class to associate a \e named Constructor section with its symbol scope
|
||||
///
|
||||
|
@ -137,26 +139,51 @@ class SleighCompile;
|
|||
/// This class searches for unnecessary truncations and extensions, temporary varnodes that are either dead,
|
||||
/// read before written, or that exceed the standard allocation size.
|
||||
class ConsistencyChecker {
|
||||
|
||||
public:
|
||||
/// \brief Description of how a temporary register is being used within a Constructor
|
||||
///
|
||||
/// This counts reads and writes of the register. If the register is read only once, the
|
||||
/// particular p-code op and input slot reading it is recorded. If the register is written
|
||||
/// only once, the particular p-code op writing it is recorded.
|
||||
struct OptimizeRecord {
|
||||
int4 writeop; ///< Index of the (last) p-code op writing to register (or -1)
|
||||
int4 readop; ///< Index of the (last) p-code op reading the register (or -1)
|
||||
int4 inslot; ///< Input slot of p-code op reading the register (or -1)
|
||||
int4 writecount; ///< Number of times the register is written
|
||||
int4 readcount; ///< Number of times the register is read
|
||||
int4 writesection; ///< Section containing (last) p-code op writing to the register (or -2)
|
||||
int4 readsection; ///< Section containing (last) p-code op reading the register (or -2)
|
||||
mutable int4 opttype; ///< 0 = register read by a COPY, 1 = register written by a COPY (-1 otherwise)
|
||||
uintb offset; ///< Offset of the varnode address
|
||||
int4 size; ///< Size in bytes of the varnode or piece (immutable)
|
||||
int4 writeop; ///< Index of the (last) p-code op writing to register (or -1)
|
||||
int4 readop; ///< Index of the (last) p-code op reading the register (or -1)
|
||||
int4 inslot; ///< Input slot of p-code op reading the register (or -1)
|
||||
int4 writecount; ///< Number of times the register is written
|
||||
int4 readcount; ///< Number of times the register is read
|
||||
int4 writesection; ///< Section containing (last) p-code op writing to the register (or -2)
|
||||
int4 readsection; ///< Section containing (last) p-code op reading the register (or -2)
|
||||
mutable int4 opttype; ///< 0 = register read by a COPY, 1 = register written by a COPY (-1 otherwise)
|
||||
|
||||
/// \brief Construct a record, initializing counts
|
||||
OptimizeRecord(void) {
|
||||
writeop = -1; readop = -1; inslot=-1; writecount=0; readcount=0; writesection=-2; readsection=-2; opttype=-1; }
|
||||
OptimizeRecord(uintb offset, int4 size) {
|
||||
this->offset = offset;
|
||||
this->size = size;
|
||||
writeop = -1; readop = -1; inslot=-1; writecount=0; readcount=0; writesection=-2; readsection=-2; opttype=-1;
|
||||
}
|
||||
void copyFromExcludingSize(OptimizeRecord &that);
|
||||
void update(int4 opIdx, int4 slotIdx, int4 secNum);
|
||||
void updateRead(int4 i, int4 inslot, int4 secNum);
|
||||
void updateWrite(int4 i, int4 secNum);
|
||||
void updateExport();
|
||||
void updateCombine(OptimizeRecord &that);
|
||||
};
|
||||
private:
|
||||
class UniqueState {
|
||||
map<uintb,OptimizeRecord> recs;
|
||||
static uintb endOf(map<uintb,OptimizeRecord>::iterator &iter) { return iter->first + iter->second.size; }
|
||||
OptimizeRecord coalesce(vector<OptimizeRecord*> &records);
|
||||
map<uintb,OptimizeRecord>::iterator lesserIter(uintb offset);
|
||||
public:
|
||||
void clear(void) { recs.clear(); }
|
||||
void set(uintb offset, int4 size, OptimizeRecord &rec);
|
||||
void getDefinitions(vector<OptimizeRecord*> &result, uintb offset, int4 size);
|
||||
map<uintb,OptimizeRecord>::const_iterator begin(void) const { return recs.begin(); }
|
||||
map<uintb,OptimizeRecord>::const_iterator end(void) const { return recs.end(); }
|
||||
};
|
||||
|
||||
SleighCompile *compiler; ///< Parsed form of the SLEIGH file being examined
|
||||
int4 unnecessarypcode; ///< Count of unnecessary extension/truncation operations
|
||||
int4 readnowrite; ///< Count of temporary registers that are read but not written
|
||||
|
@ -185,14 +212,14 @@ class ConsistencyChecker {
|
|||
void setPostOrder(SubtableSymbol *root);
|
||||
|
||||
// Optimization routines
|
||||
static void examineVn(map<uintb,OptimizeRecord> &recs,const VarnodeTpl *vn,uint4 i,int4 inslot,int4 secnum);
|
||||
static void examineVn(UniqueState &state,const VarnodeTpl *vn,uint4 i,int4 inslot,int4 secnum);
|
||||
static bool possibleIntersection(const VarnodeTpl *vn1,const VarnodeTpl *vn2);
|
||||
bool readWriteInterference(const VarnodeTpl *vn,const OpTpl *op,bool checkread) const;
|
||||
void optimizeGather1(Constructor *ct,map<uintb,OptimizeRecord> &recs,int4 secnum) const;
|
||||
void optimizeGather2(Constructor *ct,map<uintb,OptimizeRecord> &recs,int4 secnum) const;
|
||||
const OptimizeRecord *findValidRule(Constructor *ct,const map<uintb,OptimizeRecord> &recs) const;
|
||||
void optimizeGather1(Constructor *ct,UniqueState &state,int4 secnum) const;
|
||||
void optimizeGather2(Constructor *ct,UniqueState &state,int4 secnum) const;
|
||||
const OptimizeRecord *findValidRule(Constructor *ct,const UniqueState &state) const;
|
||||
void applyOptimization(Constructor *ct,const OptimizeRecord &rec);
|
||||
void checkUnusedTemps(Constructor *ct,const map<uintb,OptimizeRecord> &recs);
|
||||
void checkUnusedTemps(Constructor *ct,const UniqueState &state);
|
||||
void checkLargeTemporaries(Constructor *ct,ConstructTpl *ctpl);
|
||||
void optimize(Constructor *ct);
|
||||
public:
|
||||
|
@ -458,6 +485,8 @@ public:
|
|||
int4 run_compilation(const string &filein,const string &fileout);
|
||||
};
|
||||
|
||||
ostream& operator<<(ostream &os, const ConsistencyChecker::OptimizeRecord &rec);
|
||||
|
||||
extern SleighCompile *slgh; ///< A global reference to the SLEIGH compiler accessible to the parse functions
|
||||
extern int yydebug; ///< Debug state for the SLEIGH parse functions
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue